From 9b6e60dc9a11c5d0a3f31444a96a7ae332103003 Mon Sep 17 00:00:00 2001 From: Sandwich Date: Thu, 8 Aug 2019 00:47:10 +0200 Subject: [PATCH 001/659] Doc skeleton --- Doxyfile | 27 +++++++++------- docs.json | 23 +++++++++++++ docs/00_introduction.md | 0 docs/01_installation.md | 0 .../eosio-abidiff.md | 0 .../eosio-abigen.md | 0 .../eosio-cpp.md | 0 .../eosio-init.md | 0 .../eosio-ld.md | 0 .../{upgrading => 04_upgrading}/1.2-to-1.3.md | 0 .../{upgrading => 04_upgrading}/1.5-to-1.6.md | 0 docs/05_best-practices/00_gotchyas.md | 0 .../01_architectural-design.md | 0 .../05_best-practices/02_resource-planning.md | 0 .../03_data-design-and-migration.md | 0 docs/05_best-practices/04_security.md | 0 .../05_defensive-programming.md | 0 .../00_compile-a-contract-via-cli.md | 0 .../00_compiling-contracts-with-cmake | 0 .../how-to-define-a-primary-index.md | 0 .../how-to-define-a-secondary-index.md | 0 .../how-to-define-a-singleton.md | 0 ...to-delete-data-from-a-multi-index-table.md | 0 ...to-insert-data-into-a-multi-index-table.md | 0 .../how-to-instantiate-a-multi_index-table.md | 0 ...o-iterate-and-retrieve-a-multi_index-table | 0 ...ti_index-table-based-on-secondary-index.md | 0 ...modify-structure-of-a-multi_index-table.md | 0 .../02_error-handling/index.md | 0 .../03_how-to-use-generator-attributes.md} | 0 .../04_how-to-configure-cmake.md} | 0 .../05_how-to-use-native-tester.md} | 0 docs/08_faq.md | 0 docs/guides/first-smart-contract.md | 32 ------------------- 34 files changed, 39 insertions(+), 43 deletions(-) create mode 100644 docs.json create mode 100644 docs/00_introduction.md create mode 100644 docs/01_installation.md rename docs/{tools => 03_command-reference}/eosio-abidiff.md (100%) rename docs/{tools => 03_command-reference}/eosio-abigen.md (100%) rename docs/{tools => 03_command-reference}/eosio-cpp.md (100%) rename docs/{tools => 03_command-reference}/eosio-init.md (100%) rename docs/{tools => 03_command-reference}/eosio-ld.md (100%) rename docs/{upgrading => 04_upgrading}/1.2-to-1.3.md (100%) rename docs/{upgrading => 04_upgrading}/1.5-to-1.6.md (100%) create mode 100644 docs/05_best-practices/00_gotchyas.md create mode 100644 docs/05_best-practices/01_architectural-design.md create mode 100644 docs/05_best-practices/02_resource-planning.md create mode 100644 docs/05_best-practices/03_data-design-and-migration.md create mode 100644 docs/05_best-practices/04_security.md create mode 100644 docs/05_best-practices/05_defensive-programming.md create mode 100644 docs/06_how-to-guides/00_compile/00_compile-a-contract-via-cli.md create mode 100644 docs/06_how-to-guides/00_compile/00_compiling-contracts-with-cmake create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-define-a-primary-index.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-define-a-secondary-index.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-define-a-singleton.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-delete-data-from-a-multi-index-table.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-insert-data-into-a-multi-index-table.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-instantiate-a-multi_index-table.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md create mode 100644 docs/06_how-to-guides/01_multi-index/how-to-modify-structure-of-a-multi_index-table.md create mode 100644 docs/06_how-to-guides/02_error-handling/index.md rename docs/{guides/generator-attributes.md => 06_how-to-guides/03_how-to-use-generator-attributes.md} (100%) rename docs/{guides/cmake.md => 06_how-to-guides/04_how-to-configure-cmake.md} (100%) rename docs/{guides/native-tester.md => 06_how-to-guides/05_how-to-use-native-tester.md} (100%) create mode 100644 docs/08_faq.md delete mode 100644 docs/guides/first-smart-contract.md diff --git a/Doxyfile b/Doxyfile index 266e1614ae..4823547b0e 100644 --- a/Doxyfile +++ b/Doxyfile @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = tmp +OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -266,7 +266,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it +# extension. Doxygen has a built-in mapping, but you can options or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: @@ -350,7 +350,7 @@ DISTRIBUTE_GROUP_DOC = NO # \nosubgrouping command. # The default value is: YES. -SUBGROUPING = YES +SUBGROUPING = NO # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) @@ -758,7 +758,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = libraries/eosiolib/core libraries/eosiolib/contracts +INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -809,7 +809,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = *.cpp *.c *.h +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -872,17 +872,17 @@ INPUT_FILTER = # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = *.cpp=cpp_filter +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. -FILTER_SOURCE_FILES = YES +FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# pattern. A pattern will options the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. @@ -907,7 +907,7 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = YES +SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. @@ -1015,7 +1015,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = YES +GENERATE_HTML = NO # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1940,7 +1940,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2360,3 +2360,8 @@ GENERATE_LEGEND = YES # This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + +INPUT = libraries/eosiolib +EXCLUDE = libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h +EXCLUDE_PATTERNS = *.cpp *.c *.h +XML_OUTPUT = "/Users/sandwich/Library/Application Support/thorka/content/local/b6b77b7ab2da57cfb68f3f1766f7151e9faaf93c0fcd6c5ca0b021233f5d08d7/build/DoxygenToXml/xml" \ No newline at end of file diff --git a/docs.json b/docs.json new file mode 100644 index 0000000000..63282bf690 --- /dev/null +++ b/docs.json @@ -0,0 +1,23 @@ +{ + "name": "eosio.cdt", + "generators": [ + { + "name": "collate_markdown", + "options": { + "docs_dir": "docs" + } + }, + { + "name": "doxygen_to_xml", + "options": { + "INPUT": "libraries/eosiolib", + "EXCLUDE": "libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h", + "EXCLUDE_PATTERNS": "*.cpp *.c *.h" + } + }, + { + "name": "doxybook", + "options": {} + } + ] +} diff --git a/docs/00_introduction.md b/docs/00_introduction.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/01_installation.md b/docs/01_installation.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/tools/eosio-abidiff.md b/docs/03_command-reference/eosio-abidiff.md similarity index 100% rename from docs/tools/eosio-abidiff.md rename to docs/03_command-reference/eosio-abidiff.md diff --git a/docs/tools/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md similarity index 100% rename from docs/tools/eosio-abigen.md rename to docs/03_command-reference/eosio-abigen.md diff --git a/docs/tools/eosio-cpp.md b/docs/03_command-reference/eosio-cpp.md similarity index 100% rename from docs/tools/eosio-cpp.md rename to docs/03_command-reference/eosio-cpp.md diff --git a/docs/tools/eosio-init.md b/docs/03_command-reference/eosio-init.md similarity index 100% rename from docs/tools/eosio-init.md rename to docs/03_command-reference/eosio-init.md diff --git a/docs/tools/eosio-ld.md b/docs/03_command-reference/eosio-ld.md similarity index 100% rename from docs/tools/eosio-ld.md rename to docs/03_command-reference/eosio-ld.md diff --git a/docs/upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md similarity index 100% rename from docs/upgrading/1.2-to-1.3.md rename to docs/04_upgrading/1.2-to-1.3.md diff --git a/docs/upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md similarity index 100% rename from docs/upgrading/1.5-to-1.6.md rename to docs/04_upgrading/1.5-to-1.6.md diff --git a/docs/05_best-practices/00_gotchyas.md b/docs/05_best-practices/00_gotchyas.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/05_best-practices/01_architectural-design.md b/docs/05_best-practices/01_architectural-design.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/05_best-practices/02_resource-planning.md b/docs/05_best-practices/02_resource-planning.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/05_best-practices/03_data-design-and-migration.md b/docs/05_best-practices/03_data-design-and-migration.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/05_best-practices/04_security.md b/docs/05_best-practices/04_security.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/05_best-practices/05_defensive-programming.md b/docs/05_best-practices/05_defensive-programming.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/00_compile/00_compile-a-contract-via-cli.md b/docs/06_how-to-guides/00_compile/00_compile-a-contract-via-cli.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/00_compile/00_compiling-contracts-with-cmake b/docs/06_how-to-guides/00_compile/00_compiling-contracts-with-cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/01_multi-index/how-to-define-a-primary-index.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/01_multi-index/how-to-define-a-secondary-index.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/01_multi-index/how-to-define-a-singleton.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/01_multi-index/how-to-delete-data-from-a-multi-index-table.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/01_multi-index/how-to-insert-data-into-a-multi-index-table.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/01_multi-index/how-to-instantiate-a-multi_index-table.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table b/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/01_multi-index/how-to-modify-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/01_multi-index/how-to-modify-structure-of-a-multi_index-table.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/06_how-to-guides/02_error-handling/index.md b/docs/06_how-to-guides/02_error-handling/index.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/guides/generator-attributes.md b/docs/06_how-to-guides/03_how-to-use-generator-attributes.md similarity index 100% rename from docs/guides/generator-attributes.md rename to docs/06_how-to-guides/03_how-to-use-generator-attributes.md diff --git a/docs/guides/cmake.md b/docs/06_how-to-guides/04_how-to-configure-cmake.md similarity index 100% rename from docs/guides/cmake.md rename to docs/06_how-to-guides/04_how-to-configure-cmake.md diff --git a/docs/guides/native-tester.md b/docs/06_how-to-guides/05_how-to-use-native-tester.md similarity index 100% rename from docs/guides/native-tester.md rename to docs/06_how-to-guides/05_how-to-use-native-tester.md diff --git a/docs/08_faq.md b/docs/08_faq.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/guides/first-smart-contract.md b/docs/guides/first-smart-contract.md deleted file mode 100644 index 8be919d63e..0000000000 --- a/docs/guides/first-smart-contract.md +++ /dev/null @@ -1,32 +0,0 @@ -### Building your first smart contract -```c++ -#include -#include - -class [[eosio::contract]] hello : public eosio::contract { - public: - using eosio::contract::contract; - - [[eosio::action]] - void hi(eosio::name nm) { - eosio::print_f("Hello, %\n", nm); - } -}; -``` - -- Navigate to the hello folder in examples (./examples/hello). -- You should then see the hello.cpp file -- Now run the compiler -```sh -$ eosio-cpp -abigen hello.cpp -o hello.wasm -``` -- Or with CMake -```sh -$ mkdir build -$ cd build -$ cmake .. -$ make -``` -This will generate two files: -* The compiled binary wasm (hello.wasm) -* The generated ABI file (hello.abi) From 48b1ecc839a10ac852f83de73b7fe33f05002c0d Mon Sep 17 00:00:00 2001 From: Sandwich Date: Thu, 8 Aug 2019 01:10:23 +0200 Subject: [PATCH 002/659] Formating changes --- docs.json | 23 ------- docs/03_command-reference/eosio-abidiff.md | 24 ------- docs/03_command-reference/eosio-abigen.md | 31 --------- docs/03_command-reference/eosio-cpp.md | 73 ---------------------- docs/03_command-reference/eosio-init.md | 30 --------- docs/03_command-reference/eosio-ld.md | 27 -------- 6 files changed, 208 deletions(-) delete mode 100644 docs.json delete mode 100644 docs/03_command-reference/eosio-abidiff.md delete mode 100644 docs/03_command-reference/eosio-abigen.md delete mode 100644 docs/03_command-reference/eosio-cpp.md delete mode 100644 docs/03_command-reference/eosio-init.md delete mode 100644 docs/03_command-reference/eosio-ld.md diff --git a/docs.json b/docs.json deleted file mode 100644 index 63282bf690..0000000000 --- a/docs.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "eosio.cdt", - "generators": [ - { - "name": "collate_markdown", - "options": { - "docs_dir": "docs" - } - }, - { - "name": "doxygen_to_xml", - "options": { - "INPUT": "libraries/eosiolib", - "EXCLUDE": "libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h", - "EXCLUDE_PATTERNS": "*.cpp *.c *.h" - } - }, - { - "name": "doxybook", - "options": {} - } - ] -} diff --git a/docs/03_command-reference/eosio-abidiff.md b/docs/03_command-reference/eosio-abidiff.md deleted file mode 100644 index bcb93ac8f9..0000000000 --- a/docs/03_command-reference/eosio-abidiff.md +++ /dev/null @@ -1,24 +0,0 @@ -# eosio-abidiff - -Tool to diff two ABI files to flag and output differences. -To report differences with ```eosio-abidiff```, you only need to pass the two ABI file names as command line arguments. - -Example: -```bash -$ eosio-abidiff hello.abi old_hello.abi -``` - -This will generate dump the report output to the console. ---- -``` -OVERVIEW: eosio-abidiff -USAGE: eosio-abidiff [options] ... ... - -OPTIONS: - -Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program -``` diff --git a/docs/03_command-reference/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md deleted file mode 100644 index 0855b94e4f..0000000000 --- a/docs/03_command-reference/eosio-abigen.md +++ /dev/null @@ -1,31 +0,0 @@ -# eosio-abigen -### This tool is deprecated, please use `eosio-cpp` for generation of your ABIs -To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. - -Example: -```bash -$ eosio-abigen hello.cpp --contract=hello --output=hello.abi -``` - -This will generate one file: -* The generated ABI file (hello.abi) ---- -``` -USAGE: eosio-abigen [options] [... ] - -OPTIONS: - -Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program - -eosio-abigen: -generates an ABI from C++ project input - - -extra-arg= - Additional argument to append to the compiler command line - -extra-arg-before= - Additional argument to prepend to the compiler command line - -output= - Set the output filename and fullpath - -p= - Build path -``` diff --git a/docs/03_command-reference/eosio-cpp.md b/docs/03_command-reference/eosio-cpp.md deleted file mode 100644 index 6ebab10a56..0000000000 --- a/docs/03_command-reference/eosio-cpp.md +++ /dev/null @@ -1,73 +0,0 @@ -### Usage ---- -To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. - -###$ eosio-cpp ---- -``` -USAGE: eosio-cpp [options] ... - -OPTIONS: - -Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program - -compiler options: - - -C - Include comments in preprocessed output - -CC - Include comments from within macros in preprocessed output - -D= - Define to (or 1 if omitted) - -E - Only run the preprocessor - -I= - Add directory to include search path - -L= - Add directory to library search path - -MD - Write depfile containing user and system headers - -MF= - Write depfile output - -MMD - Write depfile containing user - -MT= - Specify name of main file output in depfile - -O= - Optimization level s, 0-3 - -R= - Add a resource path for inclusion - -S - Only run preprocess and compilation steps - -U= - Undefine macro - -W= - Enable the specified warning - -abigen - Generate ABI - -abigen_output= - ABIGEN output - -c - Only run preprocess, compile, and assemble steps - -contract= - Contract name - -dD - Print macro definitions in -E mode in addition to normal output - -dI - Print include directives in -E mode in addition to normal output - -dM - Print macro definitions in -E mode instead to normal output - -emit-ast - Emit Clang AST files for source inputs - -emit-llvm - Use the LLVM representation for assembler and object files - -faligned-allocation - Enable C++17 aligned allocation functions - -fasm - Assemble file for x86-64 - -fcolor-diagnostics - Use colors in diagnostics - -fcoroutine-ts - Enable support for the C++ Coroutines TS - -finline-functions - Inline suitable functions - -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline - -fmerge-all-constants - Allow merging of constants - -fnative - Compile and link for x86-64 - -fno-cfl-aa - Disable CFL Alias Analysis - -fno-elide-constructors - Disable C++ copy constructor elision - -fno-lto - Disable LTO - -fno-post-pass - Don't run post processing pass - -fno-stack-first - Don't set the stack first in memory - -fstack-protector - Enable stack protectors for functions potentially vulnerable to stack smashing - -fstack-protector-all - Force the usage of stack protectors for all functions - -fstack-protector-strong - Use a strong heuristic to apply stack protectors to functions - -fstrict-enums - Enable optimizations based on the strict definition of an enum's value range - -fstrict-return - Always treat control flow paths that fall off the end of a non-void function as unreachable - -fstrict-vtable-pointers - Enable optimizations based on the strict rules for overwriting polymorphic C++ objects - -fuse-main - Use main as entry - -include= - Include file before parsing - -isystem= - Add directory to SYSTEM include search path - -l= - Root name of library to link - -lto-opt= - LTO Optimization level (O0-O3) - -o= - Write output to - -std= - Language standard to compile for - -sysroot= - Set the system root directory - -v - Show commands to run and use verbose output - -w - Suppress all warnings -``` diff --git a/docs/03_command-reference/eosio-init.md b/docs/03_command-reference/eosio-init.md deleted file mode 100644 index f721ba33b4..0000000000 --- a/docs/03_command-reference/eosio-init.md +++ /dev/null @@ -1,30 +0,0 @@ -# eosio-init - -This tool is used to generate a skeleton smart contract and directory structure. -To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. -Example: -```bash -$ eosio-abigen hello.cpp --contract=hello --output=hello.abi -``` - -This will generate one file: -* The generated ABI file (hello.abi) ---- -``` -USAGE: eosio-init [options] - -OPTIONS: - -Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program - -eosio-init: -generates an eosio smart contract project - - -bare - produces only a skeleton smart contract without CMake support - -path= - directory to place the project - -project= - output project name -``` diff --git a/docs/03_command-reference/eosio-ld.md b/docs/03_command-reference/eosio-ld.md deleted file mode 100644 index 41c29e2532..0000000000 --- a/docs/03_command-reference/eosio-ld.md +++ /dev/null @@ -1,27 +0,0 @@ -### eosio-ld ---- -``` -USAGE: eosio-ld [options] ... - -OPTIONS: - -Generic Options: - - -help - Display available options (-help-hidden for more) - -help-list - Display list of available options (-help-list-hidden for more) - -version - Display the version of this program - -ld options: - - -L= - Add directory to library search path - -fasm - Assemble file for x86-64 - -fnative - Compile and link for x86-64 - -fno-cfl-aa - Disable CFL Alias Analysis - -fno-lto - Disable LTO - -fno-post-pass - Don't run post processing pass - -fno-stack-first - Don't set the stack first in memory - -fuse-main - Use main as entry - -l= - Root name of library to link - -lto-opt= - LTO Optimization level (O0-O3) - -o= - Write output to -``` From 6f4ea04daf0e6fd2bb21606cac1385e65736dbc7 Mon Sep 17 00:00:00 2001 From: Sandwich Date: Thu, 8 Aug 2019 01:10:52 +0200 Subject: [PATCH 003/659] cmd reference --- docs/03_command-reference/abidiff.md | 22 +++++++++ docs/03_command-reference/abigen.md | 31 +++++++++++++ docs/03_command-reference/cpp.md | 69 ++++++++++++++++++++++++++++ docs/03_command-reference/init.md | 28 +++++++++++ docs/03_command-reference/ld.md | 26 +++++++++++ 5 files changed, 176 insertions(+) create mode 100644 docs/03_command-reference/abidiff.md create mode 100644 docs/03_command-reference/abigen.md create mode 100644 docs/03_command-reference/cpp.md create mode 100644 docs/03_command-reference/init.md create mode 100644 docs/03_command-reference/ld.md diff --git a/docs/03_command-reference/abidiff.md b/docs/03_command-reference/abidiff.md new file mode 100644 index 0000000000..c5308502c1 --- /dev/null +++ b/docs/03_command-reference/abidiff.md @@ -0,0 +1,22 @@ +Tool to diff two ABI files to flag and output differences. +To report differences with ```eosio-abidiff```, you only need to pass the two ABI file names as command line arguments. + +Example: +```bash +$ eosio-abidiff hello.abi old_hello.abi +``` + +This will generate dump the report output to the console. +--- +``` +OVERVIEW: eosio-abidiff +USAGE: eosio-abidiff [options] ... ... + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program +``` diff --git a/docs/03_command-reference/abigen.md b/docs/03_command-reference/abigen.md new file mode 100644 index 0000000000..cd1e4542f1 --- /dev/null +++ b/docs/03_command-reference/abigen.md @@ -0,0 +1,31 @@ +### This tool is deprecated, please use `eosio-cpp` for generation of your ABIs + +To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. + +Example: +```bash +$ eosio-abigen hello.cpp --contract=hello --output=hello.abi +``` + +This will generate one file: +* The generated ABI file (hello.abi) +--- +``` +USAGE: eosio-abigen [options] [... ] + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +eosio-abigen: +generates an ABI from C++ project input + + -extra-arg= - Additional argument to append to the compiler command line + -extra-arg-before= - Additional argument to prepend to the compiler command line + -output= - Set the output filename and fullpath + -p= - Build path +``` diff --git a/docs/03_command-reference/cpp.md b/docs/03_command-reference/cpp.md new file mode 100644 index 0000000000..0c2fe99670 --- /dev/null +++ b/docs/03_command-reference/cpp.md @@ -0,0 +1,69 @@ +To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. + +``` +USAGE: eosio-cpp [options] ... + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +compiler options: + + -C - Include comments in preprocessed output + -CC - Include comments from within macros in preprocessed output + -D= - Define to (or 1 if omitted) + -E - Only run the preprocessor + -I= - Add directory to include search path + -L= - Add directory to library search path + -MD - Write depfile containing user and system headers + -MF= - Write depfile output + -MMD - Write depfile containing user + -MT= - Specify name of main file output in depfile + -O= - Optimization level s, 0-3 + -R= - Add a resource path for inclusion + -S - Only run preprocess and compilation steps + -U= - Undefine macro + -W= - Enable the specified warning + -abigen - Generate ABI + -abigen_output= - ABIGEN output + -c - Only run preprocess, compile, and assemble steps + -contract= - Contract name + -dD - Print macro definitions in -E mode in addition to normal output + -dI - Print include directives in -E mode in addition to normal output + -dM - Print macro definitions in -E mode instead to normal output + -emit-ast - Emit Clang AST files for source inputs + -emit-llvm - Use the LLVM representation for assembler and object files + -faligned-allocation - Enable C++17 aligned allocation functions + -fasm - Assemble file for x86-64 + -fcolor-diagnostics - Use colors in diagnostics + -fcoroutine-ts - Enable support for the C++ Coroutines TS + -finline-functions - Inline suitable functions + -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline + -fmerge-all-constants - Allow merging of constants + -fnative - Compile and link for x86-64 + -fno-cfl-aa - Disable CFL Alias Analysis + -fno-elide-constructors - Disable C++ copy constructor elision + -fno-lto - Disable LTO + -fno-post-pass - Don't run post processing pass + -fno-stack-first - Don't set the stack first in memory + -fstack-protector - Enable stack protectors for functions potentially vulnerable to stack smashing + -fstack-protector-all - Force the usage of stack protectors for all functions + -fstack-protector-strong - Use a strong heuristic to apply stack protectors to functions + -fstrict-enums - Enable optimizations based on the strict definition of an enum's value range + -fstrict-return - Always treat control flow paths that fall off the end of a non-void function as unreachable + -fstrict-vtable-pointers - Enable optimizations based on the strict rules for overwriting polymorphic C++ objects + -fuse-main - Use main as entry + -include= - Include file before parsing + -isystem= - Add directory to SYSTEM include search path + -l= - Root name of library to link + -lto-opt= - LTO Optimization level (O0-O3) + -o= - Write output to + -std= - Language standard to compile for + -sysroot= - Set the system root directory + -v - Show commands to run and use verbose output + -w - Suppress all warnings +``` diff --git a/docs/03_command-reference/init.md b/docs/03_command-reference/init.md new file mode 100644 index 0000000000..4aacbe0192 --- /dev/null +++ b/docs/03_command-reference/init.md @@ -0,0 +1,28 @@ +This tool is used to generate a skeleton smart contract and directory structure. +To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. +Example: +```bash +$ eosio-abigen hello.cpp --contract=hello --output=hello.abi +``` + +This will generate one file: +* The generated ABI file (hello.abi) +--- +``` +USAGE: eosio-init [options] + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +eosio-init: +generates an eosio smart contract project + + -bare - produces only a skeleton smart contract without CMake support + -path= - directory to place the project + -project= - output project name +``` diff --git a/docs/03_command-reference/ld.md b/docs/03_command-reference/ld.md new file mode 100644 index 0000000000..a85476e9e5 --- /dev/null +++ b/docs/03_command-reference/ld.md @@ -0,0 +1,26 @@ +--- +``` +USAGE: eosio-ld [options] ... + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +ld options: + + -L= - Add directory to library search path + -fasm - Assemble file for x86-64 + -fnative - Compile and link for x86-64 + -fno-cfl-aa - Disable CFL Alias Analysis + -fno-lto - Disable LTO + -fno-post-pass - Don't run post processing pass + -fno-stack-first - Don't set the stack first in memory + -fuse-main - Use main as entry + -l= - Root name of library to link + -lto-opt= - LTO Optimization level (O0-O3) + -o= - Write output to +``` From 4c9a6894ea3f82f75448afaac7fdd5fc3680661d Mon Sep 17 00:00:00 2001 From: ovi Date: Sun, 18 Aug 2019 13:27:37 +0300 Subject: [PATCH 004/659] content layout consolidation changes --- README.md | 4 ++-- docs/01_introduction.md | 4 ++++ docs/{00_introduction.md => 02_installation.md} | 0 docs/05_best-practices/01_gotchas.md | 1 + .../02_architectural-design.md} | 0 .../{00_gotchyas.md => 03_resource-planning.md} | 0 ...ral-design.md => 04_data-design-and-migration.md} | 0 .../{02_resource-planning.md => 05_security.md} | 0 ...-and-migration.md => 06_defensive-programming.md} | 0 .../01_compile/01_compile-a-contract-via-cli.md | 1 + .../02_how-to-configure-cmake.md} | 0 .../01_compile/03_compiling-contracts-with-cmake.md} | 0 .../how-to-define-a-primary-index.md | 0 .../how-to-define-a-secondary-index.md | 0 .../how-to-define-a-singleton.md | 0 .../how-to-delete-data-from-a-multi-index-table.md | 0 .../how-to-insert-data-into-a-multi-index-table.md | 0 .../how-to-instantiate-a-multi_index-table.md | 0 ...e-a-multi_index-table-based-on-secondary-index.md | 0 ...w-to-iterate-and-retrieve-a-multi_index-table.md} | 0 .../how-to-modify-data-in-a-multi-index-table.md} | 0 ...how-to-modify-structure-of-a-multi_index-table.md | 0 ...iling-contracts-with-cmake => 03_declarations.md} | 0 ...-multi_index-table => 04_how_to_handle_errors.md} | 0 .../index.md => 05_how_to_use_action_wrappers.md} | 0 .../how_to_restrict_access_to_an_action_by_user.md | 1 + .../01_how-to-use-generator-attributes.md} | 12 +----------- .../07_abi/02_how_to_manully_write_an_ABI_file.md | 11 +++++++++++ ...tive-tester.md => 08_how-to-use-native-tester.md} | 0 docs/{08_faq.md => 07_faq.md} | 0 30 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 docs/01_introduction.md rename docs/{00_introduction.md => 02_installation.md} (100%) create mode 100644 docs/05_best-practices/01_gotchas.md rename docs/{01_installation.md => 05_best-practices/02_architectural-design.md} (100%) rename docs/05_best-practices/{00_gotchyas.md => 03_resource-planning.md} (100%) rename docs/05_best-practices/{01_architectural-design.md => 04_data-design-and-migration.md} (100%) rename docs/05_best-practices/{02_resource-planning.md => 05_security.md} (100%) rename docs/05_best-practices/{03_data-design-and-migration.md => 06_defensive-programming.md} (100%) create mode 100644 docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md rename docs/06_how-to-guides/{04_how-to-configure-cmake.md => 01_compile/02_how-to-configure-cmake.md} (100%) rename docs/{05_best-practices/04_security.md => 06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md} (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-define-a-primary-index.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-define-a-secondary-index.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-define-a-singleton.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-delete-data-from-a-multi-index-table.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-insert-data-into-a-multi-index-table.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-instantiate-a-multi_index-table.md (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md (100%) rename docs/{05_best-practices/05_defensive-programming.md => 06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md} (100%) rename docs/06_how-to-guides/{00_compile/00_compile-a-contract-via-cli.md => 02_multi-index/how-to-modify-data-in-a-multi-index-table.md} (100%) rename docs/06_how-to-guides/{01_multi-index => 02_multi-index}/how-to-modify-structure-of-a-multi_index-table.md (100%) rename docs/06_how-to-guides/{00_compile/00_compiling-contracts-with-cmake => 03_declarations.md} (100%) rename docs/06_how-to-guides/{01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table => 04_how_to_handle_errors.md} (100%) rename docs/06_how-to-guides/{02_error-handling/index.md => 05_how_to_use_action_wrappers.md} (100%) create mode 100644 docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md rename docs/06_how-to-guides/{03_how-to-use-generator-attributes.md => 07_abi/01_how-to-use-generator-attributes.md} (63%) create mode 100644 docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md rename docs/06_how-to-guides/{05_how-to-use-native-tester.md => 08_how-to-use-native-tester.md} (100%) rename docs/{08_faq.md => 07_faq.md} (100%) diff --git a/README.md b/README.md index b171b92909..0c982e35ef 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # EOSIO.CDT (Contract Development Toolkit) ## Version : 1.7.0 -EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate contract writing for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are not available or incomplete. +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate contract writing for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. ## New Introductions As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. ## Important! -EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the **_Differences between Version 1.2.x and Version 1.3.x_** section of this readme. +EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. ### Binary Releases EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. diff --git a/docs/01_introduction.md b/docs/01_introduction.md new file mode 100644 index 0000000000..3c27e16023 --- /dev/null +++ b/docs/01_introduction.md @@ -0,0 +1,4 @@ +Explains the compiler and what the repo is composed of, and links to subpages, underneath header “important concepts” would be links to: + + Dispatcher and Notifications + Multi_index Table and RAM diff --git a/docs/00_introduction.md b/docs/02_installation.md similarity index 100% rename from docs/00_introduction.md rename to docs/02_installation.md diff --git a/docs/05_best-practices/01_gotchas.md b/docs/05_best-practices/01_gotchas.md new file mode 100644 index 0000000000..6f51ff27aa --- /dev/null +++ b/docs/05_best-practices/01_gotchas.md @@ -0,0 +1 @@ +##C++ Do's and Don'ts \ No newline at end of file diff --git a/docs/01_installation.md b/docs/05_best-practices/02_architectural-design.md similarity index 100% rename from docs/01_installation.md rename to docs/05_best-practices/02_architectural-design.md diff --git a/docs/05_best-practices/00_gotchyas.md b/docs/05_best-practices/03_resource-planning.md similarity index 100% rename from docs/05_best-practices/00_gotchyas.md rename to docs/05_best-practices/03_resource-planning.md diff --git a/docs/05_best-practices/01_architectural-design.md b/docs/05_best-practices/04_data-design-and-migration.md similarity index 100% rename from docs/05_best-practices/01_architectural-design.md rename to docs/05_best-practices/04_data-design-and-migration.md diff --git a/docs/05_best-practices/02_resource-planning.md b/docs/05_best-practices/05_security.md similarity index 100% rename from docs/05_best-practices/02_resource-planning.md rename to docs/05_best-practices/05_security.md diff --git a/docs/05_best-practices/03_data-design-and-migration.md b/docs/05_best-practices/06_defensive-programming.md similarity index 100% rename from docs/05_best-practices/03_data-design-and-migration.md rename to docs/05_best-practices/06_defensive-programming.md diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md new file mode 100644 index 0000000000..1c03f3ee44 --- /dev/null +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -0,0 +1 @@ +Compile a contract with eosio-cpp \ No newline at end of file diff --git a/docs/06_how-to-guides/04_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md similarity index 100% rename from docs/06_how-to-guides/04_how-to-configure-cmake.md rename to docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md diff --git a/docs/05_best-practices/04_security.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md similarity index 100% rename from docs/05_best-practices/04_security.md rename to docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-define-a-primary-index.md rename to docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-define-a-secondary-index.md rename to docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-define-a-singleton.md rename to docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-delete-data-from-a-multi-index-table.md rename to docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-insert-data-into-a-multi-index-table.md rename to docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-instantiate-a-multi_index-table.md rename to docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md rename to docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md diff --git a/docs/05_best-practices/05_defensive-programming.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md similarity index 100% rename from docs/05_best-practices/05_defensive-programming.md rename to docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md diff --git a/docs/06_how-to-guides/00_compile/00_compile-a-contract-via-cli.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md similarity index 100% rename from docs/06_how-to-guides/00_compile/00_compile-a-contract-via-cli.md rename to docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-modify-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-structure-of-a-multi_index-table.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-modify-structure-of-a-multi_index-table.md rename to docs/06_how-to-guides/02_multi-index/how-to-modify-structure-of-a-multi_index-table.md diff --git a/docs/06_how-to-guides/00_compile/00_compiling-contracts-with-cmake b/docs/06_how-to-guides/03_declarations.md similarity index 100% rename from docs/06_how-to-guides/00_compile/00_compiling-contracts-with-cmake rename to docs/06_how-to-guides/03_declarations.md diff --git a/docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table b/docs/06_how-to-guides/04_how_to_handle_errors.md similarity index 100% rename from docs/06_how-to-guides/01_multi-index/how-to-iterate-and-retrieve-a-multi_index-table rename to docs/06_how-to-guides/04_how_to_handle_errors.md diff --git a/docs/06_how-to-guides/02_error-handling/index.md b/docs/06_how-to-guides/05_how_to_use_action_wrappers.md similarity index 100% rename from docs/06_how-to-guides/02_error-handling/index.md rename to docs/06_how-to-guides/05_how_to_use_action_wrappers.md diff --git a/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md new file mode 100644 index 0000000000..58c53ed805 --- /dev/null +++ b/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -0,0 +1 @@ +## require_auth, require_auth2 \ No newline at end of file diff --git a/docs/06_how-to-guides/03_how-to-use-generator-attributes.md b/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md similarity index 63% rename from docs/06_how-to-guides/03_how-to-use-generator-attributes.md rename to docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md index ee690aaa46..fcb964e1e2 100644 --- a/docs/06_how-to-guides/03_how-to-use-generator-attributes.md +++ b/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md @@ -1,5 +1,6 @@ ## ABI/Code generator attributes Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. + #### [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): @@ -85,14 +86,3 @@ extern "C" { This will mark a function declaration as being a WebAssembly import. This allows for other compilation modes to specify which functions are import only (i.e. do not link) without having to maintain a secondary file with duplicate declarations. -### Fixing an ABI or Writing an ABI Manually -- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. -- Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. - -### Adding Ricardian Contracts and Clauses to ABI -- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. -- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. diff --git a/docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md b/docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md new file mode 100644 index 0000000000..f2e676eff4 --- /dev/null +++ b/docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md @@ -0,0 +1,11 @@ +## Fixing an ABI or Writing an ABI Manually +- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. +- Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. + +### Adding Ricardian Contracts and Clauses to ABI +- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. + - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. + - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. + - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. + - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. diff --git a/docs/06_how-to-guides/05_how-to-use-native-tester.md b/docs/06_how-to-guides/08_how-to-use-native-tester.md similarity index 100% rename from docs/06_how-to-guides/05_how-to-use-native-tester.md rename to docs/06_how-to-guides/08_how-to-use-native-tester.md diff --git a/docs/08_faq.md b/docs/07_faq.md similarity index 100% rename from docs/08_faq.md rename to docs/07_faq.md From 2d4038d5b0c47ca827029a93fec44d4b14198043 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 22 Aug 2019 12:49:29 +0300 Subject: [PATCH 005/659] More corrections and TO DOs and content --- docs/01_introduction.md | 42 +++++++++- docs/02_installation.md | 82 +++++++++++++++++++ .../{abidiff.md => eosio-abidiff.md} | 4 +- .../{abigen.md => eosio-abigen.md} | 2 + docs/03_command-reference/eosio-abimerge.md | 3 + docs/03_command-reference/eosio-cc.md | 72 ++++++++++++++++ .../{cpp.md => eosio-cpp.md} | 2 + .../{init.md => eosio-init.md} | 2 + .../{ld.md => eosio-ld.md} | 4 + docs/04_upgrading/1.2-to-1.3.md | 3 +- docs/04_upgrading/1.5-to-1.6.md | 4 + docs/05_best-practices/01_gotchas.md | 3 +- .../02_architectural-design.md | 2 + .../05_best-practices/03_resource-planning.md | 2 + .../04_data-design-and-migration.md | 2 + docs/05_best-practices/05_security.md | 2 + .../06_defensive-programming.md | 2 + .../01_compile-a-contract-via-cli.md | 3 +- .../01_compile/02_how-to-configure-cmake.md | 6 +- .../03_compiling-contracts-with-cmake.md | 2 + .../how-to-define-a-primary-index.md | 2 + .../how-to-define-a-secondary-index.md | 2 + .../how-to-define-a-singleton.md | 2 + ...to-delete-data-from-a-multi-index-table.md | 2 + ...to-insert-data-into-a-multi-index-table.md | 2 + .../how-to-instantiate-a-multi_index-table.md | 2 + ...ti_index-table-based-on-secondary-index.md | 2 + ...terate-and-retrieve-a-multi_index-table.md | 2 + ...w-to-modify-data-in-a-multi-index-table.md | 2 + ...modify-structure-of-a-multi_index-table.md | 0 ...fy-the-structure-of-a-multi_index-table.md | 2 + docs/06_how-to-guides/03_declarations.md | 2 + .../04_how_to_handle_errors.md | 2 + .../05_how_to_use_action_wrappers.md | 2 + ...to_restrict_access_to_an_action_by_user.md | 4 +- .../node_modules/.yarn-integrity | 10 +++ .../06_authorization/yarn.lock | 4 + .../01_how-to-use-generator-attributes.md | 2 +- ...> 02_how_to_manually_write_an_ABI_file.md} | 2 +- .../08_how-to-use-native-tester.md | 4 +- ...erred_transaction_from_a_smart_contract.md | 2 + .../10_how_to_debug_a_smart_contract.md | 2 + docs/07_faq.md | 2 + docs/08_troubleshooting.md | 4 + 44 files changed, 290 insertions(+), 16 deletions(-) rename docs/03_command-reference/{abidiff.md => eosio-abidiff.md} (84%) rename docs/03_command-reference/{abigen.md => eosio-abigen.md} (98%) create mode 100644 docs/03_command-reference/eosio-abimerge.md create mode 100644 docs/03_command-reference/eosio-cc.md rename docs/03_command-reference/{cpp.md => eosio-cpp.md} (99%) rename docs/03_command-reference/{init.md => eosio-init.md} (97%) rename docs/03_command-reference/{ld.md => eosio-ld.md} (88%) delete mode 100644 docs/06_how-to-guides/02_multi-index/how-to-modify-structure-of-a-multi_index-table.md create mode 100644 docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md create mode 100644 docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity create mode 100644 docs/06_how-to-guides/06_authorization/yarn.lock rename docs/06_how-to-guides/07_abi/{02_how_to_manully_write_an_ABI_file.md => 02_how_to_manually_write_an_ABI_file.md} (97%) create mode 100644 docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md create mode 100644 docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md create mode 100644 docs/08_troubleshooting.md diff --git a/docs/01_introduction.md b/docs/01_introduction.md index 3c27e16023..0c27aad02b 100644 --- a/docs/01_introduction.md +++ b/docs/01_introduction.md @@ -1,4 +1,40 @@ -Explains the compiler and what the repo is composed of, and links to subpages, underneath header “important concepts” would be links to: +# EOSIO.CDT (Contract Development Toolkit) - Dispatcher and Notifications - Multi_index Table and RAM +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. + +## New Introductions +As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. + +## Important! +EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. + +## Concepts + +### Dispatcher and Notifications +TO DO: Add link to the dispatcher and notifications documentation, where can I find it? +[Dispatcher API reference](https://eosio.github.io/eosio.cdt/1.6.0/group__dispatcher.html) + +### Multi Index Table and RAM +[Multi Index Tables explained by example](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) + +### Smart Contract + +### Action + +### Transaction and Deferred Transaction + +TO DO: Any other concepts that need to go here? + +## Contributing + +[Contributing Guide](../CONTRIBUTING.md) + +[Code of Conduct](../CONTRIBUTING.md#conduct) + +## License + +[MIT](../LICENSE) + +## Important + +See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties or merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. diff --git a/docs/02_installation.md b/docs/02_installation.md index e69de29bb2..01acdc2128 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -0,0 +1,82 @@ +## Binary Releases +EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. + +**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** + +### Mac OS X Brew Install +```sh +$ brew tap eosio/eosio.cdt +$ brew install eosio.cdt +``` +### Mac OS X Brew Uninstall +```sh +$ brew remove eosio.cdt +``` +### Debian Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb +$ sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb +``` +### Debian Package Uninstall +```sh +$ sudo apt remove eosio.cdt +``` + +### Fedora RPM Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.fedora-x86_64.rpm +$ sudo yum install ./eosio.cdt-1.6.1-1.fedora-x86_64.rpm +``` + +### Fedora RPM Package Uninstall +```sh +$ sudo yum remove eosio.cdt +``` + +### Centos RPM Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.centos-x86_64.rpm +$ sudo yum install ./eosio.cdt-1.6.1-1.centos-x86_64.rpm +``` + +### Centos RPM Package Uninstall +```sh +$ sudo yum remove eosio.cdt +``` + +## Guided Installation (Building from Scratch) +```sh +$ git clone --recursive https://github.com/eosio/eosio.cdt +$ cd eosio.cdt +$ ./build.sh +$ sudo ./install.sh +``` + +## Installed Tools +--- +TO DO: is below list correct? is any of them deprecated? eosio-abimerge should it be listed here? +* eosio-cpp +* eosio-cc +* eosio-ld +* eosio-init +* eosio-abidiff +* eosio-wasm2wast +* eosio-wast2wasm +* eosio-ranlib +* eosio-ar +* eosio-objdump +* eosio-readelf + +TO DO: +these tools are not installed after brew install, how can I get them? +eosio-abidiff +eosio-ranlib +eosio-ar +eosio-objdump +eosio-readelf +eosio-merge + + +License +---- +[MIT](../LICENCE) diff --git a/docs/03_command-reference/abidiff.md b/docs/03_command-reference/eosio-abidiff.md similarity index 84% rename from docs/03_command-reference/abidiff.md rename to docs/03_command-reference/eosio-abidiff.md index c5308502c1..adba0081f1 100644 --- a/docs/03_command-reference/abidiff.md +++ b/docs/03_command-reference/eosio-abidiff.md @@ -1,4 +1,6 @@ -Tool to diff two ABI files to flag and output differences. +## eosio-abidiff tool + +The eosio-abidiff tool is used to diff two ABI files to flag and output differences. To report differences with ```eosio-abidiff```, you only need to pass the two ABI file names as command line arguments. Example: diff --git a/docs/03_command-reference/abigen.md b/docs/03_command-reference/eosio-abigen.md similarity index 98% rename from docs/03_command-reference/abigen.md rename to docs/03_command-reference/eosio-abigen.md index cd1e4542f1..c8b9dcea27 100644 --- a/docs/03_command-reference/abigen.md +++ b/docs/03_command-reference/eosio-abigen.md @@ -1,3 +1,5 @@ +## eosio-abigen tool + ### This tool is deprecated, please use `eosio-cpp` for generation of your ABIs To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. diff --git a/docs/03_command-reference/eosio-abimerge.md b/docs/03_command-reference/eosio-abimerge.md new file mode 100644 index 0000000000..7dedb91a43 --- /dev/null +++ b/docs/03_command-reference/eosio-abimerge.md @@ -0,0 +1,3 @@ +# eosio-abimerge tool + +TO DO: Verify if it is final, complete, first. \ No newline at end of file diff --git a/docs/03_command-reference/eosio-cc.md b/docs/03_command-reference/eosio-cc.md new file mode 100644 index 0000000000..ff63caaae0 --- /dev/null +++ b/docs/03_command-reference/eosio-cc.md @@ -0,0 +1,72 @@ +## eosio-cc tool + +To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. + +``` +USAGE: eosio-cc [options] ... + +OPTIONS: + +Generic Options: + + -help - Display available options (-help-hidden for more) + -help-list - Display list of available options (-help-list-hidden for more) + -version - Display the version of this program + +compiler options: + + -C - Include comments in preprocessed output + -CC - Include comments from within macros in preprocessed output + -D= - Define to (or 1 if omitted) + -E - Only run the preprocessor + -I= - Add directory to include search path + -L= - Add directory to library search path + -MD - Write depfile containing user and system headers + -MF= - Write depfile output + -MMD - Write depfile containing user + -MT= - Specify name of main file output in depfile + -O= - Optimization level s, 0-3 + -R= - Add a resource path for inclusion + -S - Only run preprocess and compilation steps + -U= - Undefine macro + -W= - Enable the specified warning + -abigen - Generate ABI + -abigen_output= - ABIGEN output + -c - Only run preprocess, compile, and assemble steps + -contract= - Contract name + -dD - Print macro definitions in -E mode in addition to normal output + -dI - Print include directives in -E mode in addition to normal output + -dM - Print macro definitions in -E mode instead to normal output + -emit-ast - Emit Clang AST files for source inputs + -emit-llvm - Use the LLVM representation for assembler and object files + -fasm - Assemble file for x86-64 + -fcolor-diagnostics - Use colors in diagnostics + -finline-functions - Inline suitable functions + -finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline + -fmerge-all-constants - Allow merging of constants + -fnative - Compile and link for x86-64 + -fno-cfl-aa - Disable CFL Alias Analysis + -fno-elide-constructors - Disable C++ copy constructor elision + -fno-lto - Disable LTO + -fno-post-pass - Don't run post processing pass + -fno-stack-first - Don't set the stack first in memory + -fquery - Produce binaries for wasmql + -fquery-client - Produce binaries for wasmql + -fquery-server - Produce binaries for wasmql + -fstack-protector - Enable stack protectors for functions potentially vulnerable to stack smashing + -fstack-protector-all - Force the usage of stack protectors for all functions + -fstack-protector-strong - Use a strong heuristic to apply stack protectors to functions + -fstrict-enums - Enable optimizations based on the strict definition of an enum's value range + -fstrict-return - Always treat control flow paths that fall off the end of a non-void function as unreachable + -fstrict-vtable-pointers - Enable optimizations based on the strict rules for overwriting polymorphic C++ objects + -fuse-main - Use main as entry + -include= - Include file before parsing + -isystem= - Add directory to SYSTEM include search path + -l= - Root name of library to link + -lto-opt= - LTO Optimization level (O0-O3) + -o= - Write output to + -stack-size= - Specifies the maximum stack size for the contract. Defaults to 8192 bytes. + -sysroot= - Set the system root directory + -v - Show commands to run and use verbose output + -w - Suppress all warnings +``` diff --git a/docs/03_command-reference/cpp.md b/docs/03_command-reference/eosio-cpp.md similarity index 99% rename from docs/03_command-reference/cpp.md rename to docs/03_command-reference/eosio-cpp.md index 0c2fe99670..acaf507841 100644 --- a/docs/03_command-reference/cpp.md +++ b/docs/03_command-reference/eosio-cpp.md @@ -1,3 +1,5 @@ +## eosio-cpp tool + To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. ``` diff --git a/docs/03_command-reference/init.md b/docs/03_command-reference/eosio-init.md similarity index 97% rename from docs/03_command-reference/init.md rename to docs/03_command-reference/eosio-init.md index 4aacbe0192..0702b09585 100644 --- a/docs/03_command-reference/init.md +++ b/docs/03_command-reference/eosio-init.md @@ -1,3 +1,5 @@ +## eosio-init tool + This tool is used to generate a skeleton smart contract and directory structure. To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. Example: diff --git a/docs/03_command-reference/ld.md b/docs/03_command-reference/eosio-ld.md similarity index 88% rename from docs/03_command-reference/ld.md rename to docs/03_command-reference/eosio-ld.md index a85476e9e5..56d21dc1bf 100644 --- a/docs/03_command-reference/ld.md +++ b/docs/03_command-reference/eosio-ld.md @@ -1,3 +1,7 @@ +## eosio-ld tool + +The eosio-ld tool is a the custom web assembly linker for EOSIO platform smart contracts. + --- ``` USAGE: eosio-ld [options] ... diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index d76ef1f15e..282dab121a 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -222,5 +222,4 @@ For an example contract of ABI generation please see the file ./examples/abigen_ License ---- - -MIT +[MIT](../LICENCE) diff --git a/docs/04_upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md index c78d18a4ee..0059ded2be 100644 --- a/docs/04_upgrading/1.5-to-1.6.md +++ b/docs/04_upgrading/1.5-to-1.6.md @@ -138,3 +138,7 @@ If the dispatcher fails to find a suitable action to dispatch, then the new patt If the dispatcher is in notification handling mode and if your contract receives an `eosio::onerror` notification, then the contract will assert with an error code. You can circumvent this check if you explicitly supply an error handler for it ([[eosio::on_notify("eosio::onerror")]]). For a real world example of this new style of contract in use see `tests/unit/test_contracts/simple_test.cpp`. + +License +---- +[MIT](../LICENCE) diff --git a/docs/05_best-practices/01_gotchas.md b/docs/05_best-practices/01_gotchas.md index 6f51ff27aa..826d36fde5 100644 --- a/docs/05_best-practices/01_gotchas.md +++ b/docs/05_best-practices/01_gotchas.md @@ -1 +1,2 @@ -##C++ Do's and Don'ts \ No newline at end of file +##C++ Do's and Don'ts +TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/02_architectural-design.md b/docs/05_best-practices/02_architectural-design.md index e69de29bb2..19809e80c8 100644 --- a/docs/05_best-practices/02_architectural-design.md +++ b/docs/05_best-practices/02_architectural-design.md @@ -0,0 +1,2 @@ +## Architectura design +TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md index e69de29bb2..30a5e24419 100644 --- a/docs/05_best-practices/03_resource-planning.md +++ b/docs/05_best-practices/03_resource-planning.md @@ -0,0 +1,2 @@ +## Resource planning +TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index e69de29bb2..b8d77e68c4 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -0,0 +1,2 @@ +## Data design and migration +TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/05_security.md b/docs/05_best-practices/05_security.md index e69de29bb2..80d021e6da 100644 --- a/docs/05_best-practices/05_security.md +++ b/docs/05_best-practices/05_security.md @@ -0,0 +1,2 @@ +## Security +TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/06_defensive-programming.md b/docs/05_best-practices/06_defensive-programming.md index e69de29bb2..776fe7f50f 100644 --- a/docs/05_best-practices/06_defensive-programming.md +++ b/docs/05_best-practices/06_defensive-programming.md @@ -0,0 +1,2 @@ +## Defensive programming +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index 1c03f3ee44..2326cd14f5 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1 +1,2 @@ -Compile a contract with eosio-cpp \ No newline at end of file +## How to compile a contract via CLI +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md index 0ab8518474..06598198dc 100644 --- a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -1,6 +1,6 @@ -# CMake +## How to configure CMake -## CMake Configuration +### CMake Configuration To compile an EOSIO smart contract with CMake you'll need a CMake file. The new `eosio-init` tool can be used to generate the directory structure stub .hpp/.cpp files and subsequent cmake files. Or the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. For example: @@ -33,7 +33,7 @@ public: EOSIO_DISPATCH( test, (testact) ) ``` -## CMake Macros +### CMake Macros - `add_contract` is used to build your smart contract and generate an ABI, the first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. - `target_ricardian_directory` can be used to add the directory where your ricardian contracts live to a specific cmake target. - (new for native tester) `add_native_library` and `add_native_executable` CMake macros have been added (these are a drop in replacement for add_library and add_executable). diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index e69de29bb2..333b3dc6f6 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -0,0 +1,2 @@ +## How to compile a smart contract with CMake +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index e69de29bb2..f520b72565 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -0,0 +1,2 @@ +## How to define a primary index +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index e69de29bb2..702dc2bcec 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -0,0 +1,2 @@ +## How to define a secondady index +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index e69de29bb2..e7a6c476b2 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -0,0 +1,2 @@ +## How to define a singleton +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index e69de29bb2..2edd6a3458 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -0,0 +1,2 @@ +## How to delete data from a multi index table +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index e69de29bb2..79c173508b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -0,0 +1,2 @@ +## How to insert data into a multi index table +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md index e69de29bb2..dfe4d9d852 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md @@ -0,0 +1,2 @@ +## How to instantiate a multi index table +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index e69de29bb2..26f0746fa3 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -0,0 +1,2 @@ +## How to iterate and retreive a multi index table based on secondary index +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index e69de29bb2..6c9852cbac 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -0,0 +1,2 @@ +## How to iterate and retrieve a multi index table +TO DO: add content diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index e69de29bb2..61bef0072e 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -0,0 +1,2 @@ +## How to modify data in a multi index table +TO DO: add content diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-structure-of-a-multi_index-table.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md new file mode 100644 index 0000000000..103a13828a --- /dev/null +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -0,0 +1,2 @@ +## How to modify the structure of a multi index table +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/03_declarations.md b/docs/06_how-to-guides/03_declarations.md index e69de29bb2..4b8ce8ef05 100644 --- a/docs/06_how-to-guides/03_declarations.md +++ b/docs/06_how-to-guides/03_declarations.md @@ -0,0 +1,2 @@ +## How to declare ... +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/04_how_to_handle_errors.md b/docs/06_how-to-guides/04_how_to_handle_errors.md index e69de29bb2..468ea94343 100644 --- a/docs/06_how-to-guides/04_how_to_handle_errors.md +++ b/docs/06_how-to-guides/04_how_to_handle_errors.md @@ -0,0 +1,2 @@ +## How to handle errors +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/05_how_to_use_action_wrappers.md b/docs/06_how-to-guides/05_how_to_use_action_wrappers.md index e69de29bb2..f0e145b116 100644 --- a/docs/06_how-to-guides/05_how_to_use_action_wrappers.md +++ b/docs/06_how-to-guides/05_how_to_use_action_wrappers.md @@ -0,0 +1,2 @@ +## How to use action wrappers +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md index 58c53ed805..b4c1000886 100644 --- a/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1 +1,3 @@ -## require_auth, require_auth2 \ No newline at end of file +## How to restrict access to an acction by user +TO DO: add content +require_auth, require_auth2 \ No newline at end of file diff --git a/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity b/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity new file mode 100644 index 0000000000..5e070b6b57 --- /dev/null +++ b/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity @@ -0,0 +1,10 @@ +{ + "systemParams": "darwin-x64-72", + "modulesFolders": [], + "flags": [], + "linkedModules": [], + "topLevelPatterns": [], + "lockfileEntries": {}, + "files": [], + "artifacts": {} +} \ No newline at end of file diff --git a/docs/06_how-to-guides/06_authorization/yarn.lock b/docs/06_how-to-guides/06_authorization/yarn.lock new file mode 100644 index 0000000000..fb57ccd13a --- /dev/null +++ b/docs/06_how-to-guides/06_authorization/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + diff --git a/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md b/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md index fcb964e1e2..67a74f8344 100644 --- a/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md +++ b/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md @@ -1,4 +1,4 @@ -## ABI/Code generator attributes +## How to use ABI/Code generator attributes Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. #### [[eosio::action]] diff --git a/docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md b/docs/06_how-to-guides/07_abi/02_how_to_manually_write_an_ABI_file.md similarity index 97% rename from docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md rename to docs/06_how-to-guides/07_abi/02_how_to_manually_write_an_ABI_file.md index f2e676eff4..ac229e8e1e 100644 --- a/docs/06_how-to-guides/07_abi/02_how_to_manully_write_an_ABI_file.md +++ b/docs/06_how-to-guides/07_abi/02_how_to_manually_write_an_ABI_file.md @@ -1,4 +1,4 @@ -## Fixing an ABI or Writing an ABI Manually +## How to manually write, or fix, an ABI file - Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. diff --git a/docs/06_how-to-guides/08_how-to-use-native-tester.md b/docs/06_how-to-guides/08_how-to-use-native-tester.md index b52e450f74..3919c4dcde 100644 --- a/docs/06_how-to-guides/08_how-to-use-native-tester.md +++ b/docs/06_how-to-guides/08_how-to-use-native-tester.md @@ -1,5 +1,5 @@ -## Native Tester/Compilation -As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. `eosio-cc\cpp` and `eosio-ld` now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) +## How to use native tester/compilation +As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. `eosio-cc\cpp` and `eosio-ld` now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) #### Getting Started Once you have your smart contract written then a test source file can be written. diff --git a/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md b/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md new file mode 100644 index 0000000000..8600728894 --- /dev/null +++ b/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md @@ -0,0 +1,2 @@ +## How to push a deffered transaction from a smart contract to another +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md b/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md new file mode 100644 index 0000000000..60183a6e3b --- /dev/null +++ b/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md @@ -0,0 +1,2 @@ +## How to debug a smart contract +TO DO: add content \ No newline at end of file diff --git a/docs/07_faq.md b/docs/07_faq.md index e69de29bb2..75a5e5890f 100644 --- a/docs/07_faq.md +++ b/docs/07_faq.md @@ -0,0 +1,2 @@ +## FAQ +TO DO: add content \ No newline at end of file diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md new file mode 100644 index 0000000000..644e850ded --- /dev/null +++ b/docs/08_troubleshooting.md @@ -0,0 +1,4 @@ +## Troubleshooting +TO DO: add content + eosio-cpp process never completes + (Auto referencing issue) … find a good way to describe it. From 68fc602044afda1444c68304d0e9de8602a9a565 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 22 Aug 2019 14:23:53 +0300 Subject: [PATCH 006/659] more content and corrections --- .../05_best-practices/03_resource-planning.md | 21 +- .../05_securing_your_contract.md | 14 + docs/05_best-practices/05_security.md | 2 - .../01_compile-a-contract-via-cli.md | 26 +- .../how-to-define-a-primary-index.md | 239 +++++++++++++++++- .../how-to-define-a-secondary-index.md | 3 +- ...to-delete-data-from-a-multi-index-table.md | 3 +- ...to-insert-data-into-a-multi-index-table.md | 3 +- ...ti_index-table-based-on-secondary-index.md | 3 +- ...terate-and-retrieve-a-multi_index-table.md | 1 + ...w-to-modify-data-in-a-multi-index-table.md | 1 + ...fy-the-structure-of-a-multi_index-table.md | 3 +- docs/06_how-to-guides/03_declarations.md | 2 - ...e_errors.md => 03_how_to_handle_errors.md} | 0 .../04_how_to_use_action_wrappers.md | 6 + ...to_restrict_access_to_an_action_by_user.md | 0 .../05_how_to_use_action_wrappers.md | 2 - .../01_how-to-use-generator-attributes.md | 12 +- .../02_how_to_manually_write_an_ABI_file.md | 0 .../node_modules/.yarn-integrity | 10 - .../06_authorization/yarn.lock | 4 - ...ster.md => 07_how-to-use-native-tester.md} | 2 +- ...erred_transaction_from_a_smart_contract.md | 10 + .../09_how_to_debug_a_smart_contract.md | 120 +++++++++ ...erred_transaction_from_a_smart_contract.md | 2 - .../10_how_to_debug_a_smart_contract.md | 2 - 26 files changed, 452 insertions(+), 39 deletions(-) create mode 100644 docs/05_best-practices/05_securing_your_contract.md delete mode 100644 docs/05_best-practices/05_security.md delete mode 100644 docs/06_how-to-guides/03_declarations.md rename docs/06_how-to-guides/{04_how_to_handle_errors.md => 03_how_to_handle_errors.md} (100%) create mode 100644 docs/06_how-to-guides/04_how_to_use_action_wrappers.md rename docs/06_how-to-guides/{06_authorization => 05_authorization}/how_to_restrict_access_to_an_action_by_user.md (100%) delete mode 100644 docs/06_how-to-guides/05_how_to_use_action_wrappers.md rename docs/06_how-to-guides/{07_abi => 06_abi}/01_how-to-use-generator-attributes.md (92%) rename docs/06_how-to-guides/{07_abi => 06_abi}/02_how_to_manually_write_an_ABI_file.md (100%) delete mode 100644 docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity delete mode 100644 docs/06_how-to-guides/06_authorization/yarn.lock rename docs/06_how-to-guides/{08_how-to-use-native-tester.md => 07_how-to-use-native-tester.md} (99%) create mode 100644 docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md create mode 100644 docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md delete mode 100644 docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md delete mode 100644 docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md index 30a5e24419..77d617a51a 100644 --- a/docs/05_best-practices/03_resource-planning.md +++ b/docs/05_best-practices/03_resource-planning.md @@ -1,2 +1,21 @@ ## Resource planning -TO DO: add content \ No newline at end of file + +How much RAM do I need? This is not an easy question to answer, and there's really no perfect answer for it. You need to find out by measuring your contracts' actions and by planning accordingly based on your predictions on how fast and how much your blockchain application will grow. If your blockchain application growth is requiring more storage capacity you'll need to buy more RAM. If it requires more actions to be executed in the 3 day window (the staking time) you need to stake more tokens for CPU bandwidth. If your blockchain application growth means more actions will be stored on the blockchain then you also will need to expand your NET bandwidth maximum limit by staking more tokens for NET bandwidth. + +*Ok, you say, but how much?* + +You need to test and simulate various business scenarios that apply to your blockchain application and measure their resource usage. Hence, the existence of the public test networks. These allow you to measure how much RAM, CPU, and NET each action consume, and measure worst and best case business scenarios. You can then extrapolate and build a fairly good view of your blockchain application's resource needs. + +Once you have a fair idea of how your contract, blockchain application, and user base are consuming blockchain resources on a public test-net you can estimate what you'll need to start with on any EOSIO-based networks, public or private. From that point onward, as with any other application, it is advisable to have monitors that tell you statistics and metrics about your application performance. + +Of course some aspects might differ from network to network, because each network might have altered its system contracts. The EOSIO code base is open sourced and it can be tailored to each network's requirements. You need to be aware of these differences and take them into account if this is the case with a network you're testing on. + +The EOSIO community is also providing tools that can help you in this endeavor. One example is https://www.eosrp.io +Because the RAM price varies and because the CPU and NET bandwidth allocations vary too, as we explained in the previous section, this tool can help you estimate how much of each resource you can allocate based on a specific amount of tokens and vice-versa. + +Another aspect of resource planning involves making sure your contract is efficient, that is, not consuming resources unnecessarily. Therefore, it is beneficial for you to find answers to the following questions when writing your own smart contracts and blockchain applications: + + * Is your smart contract storing only the information that is necessary to be stored on a blockchain and for the rest is using alternative ways for storing data (e.g. IPFS)? + * If you have multiple smart contracts, are they communicating between them too much via inline actions? Could some of the smart contracts be merged into one and thus eliminate the need to spawn inline actions between them, reducing the overall inline actions count and thus resource consumption? + * Could you change your smart contracts so that your clients pay for some parts of the RAM used? Recall how originally the addressbook contract was making each new account added to the book pay for the RAM needed to store its individual data? + * Or conversely, are you making your clients pay too much RAM or CPU in order to access your contracts actions, to the point where you are prohibiting their use of your smart contract? Would it be better for your blockchain application's growth and success to take on some of those costs? diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md new file mode 100644 index 0000000000..0148889147 --- /dev/null +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -0,0 +1,14 @@ +## Securing your contract +These are basic recommendations that should be the foundation of securing your smart contract: + +1. The master git branch has the `has_auth`, `require_auth`, `require_auth2` and `require_recipient` methods available in the EOSIO library. They can be found in detail [here](https://eosio.github.io/eosio.cdt/1.6.0-rc1/group__action.html#function-requirerecipient) and implemented [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L144) (they end up calling the methods implemented in the `apply_context` class). + +2. Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. You saw earlier how changing one parameter value in the multi-index `emplace` and `modify` methods changed the account that is billed for the RAM and CPU needed to execute that action. + +3. Have a solid and comprehensive development process that includes security considerations from day one of the product planning and development. + +4. Test your smart contracts with every update announced for the blockchain you have deployed to. To ease your work, automate the testing as much as possible so you can run them often, and improve them periodically. + +5. Conduct independent smart contract audits, at least two from different organizations. + +6. Host periodic bug bounties on your smart contracts and keep a continuous commitment to reward real security problems reported at any time. \ No newline at end of file diff --git a/docs/05_best-practices/05_security.md b/docs/05_best-practices/05_security.md deleted file mode 100644 index 80d021e6da..0000000000 --- a/docs/05_best-practices/05_security.md +++ /dev/null @@ -1,2 +0,0 @@ -## Security -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index 2326cd14f5..f79f677c48 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1,2 +1,26 @@ ## How to compile a contract via CLI -TO DO: add content \ No newline at end of file + +Prerequisites: +--- +You have the source of your contrat saved in one of your local folders, e.g. `./examples/hello` +For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) + +Follow these steps to compile your contract +--- + +1. Navigate to the hello folder in examples (./examples/hello) +2. You should then see the hello.cpp file +3. Now run the compiler +``` +$ eosio-cpp -abigen hello.cpp -o hello.wasm +``` +4. Or with CMake +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +``` +This will generate two files: +- The compiled binary wasm (hello.wasm) +- The generated ABI file (hello.abi) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index f520b72565..dcaee53c0f 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,2 +1,239 @@ ## How to define a primary index -TO DO: add content \ No newline at end of file +TO DO: review this content, make sure it is an how to (a receipe not how to cook) + +EOSIO has the ability to sort tables by up to 16 indices. In the following section, we're going to add another index to the `addressbook` contract, so we can iterate through the records in a different way. +[block:api-header] +{ + "title": "Step 1: Remove existing data from table" +} +[/block] +As mentioned earlier, **a table's struct cannot be modified when it has data in it.** The first step allows the removal of the data already added. + +Remove all records of alice and bob that were added in previous tutorials. +[block:code] +{ + "codes": [ + { + "code": "cleos push action addressbook erase '[\"alice\"]' -p alice@active", + "language": "shell" + } + ] +} +[/block] + +[block:code] +{ + "codes": [ + { + "code": "cleos push action addressbook erase '[\"bob\"]' -p bob@active", + "language": "shell" + } + ] +} +[/block] + +[block:api-header] +{ + "title": "Step 2: Add new index member and getter" +} +[/block] +Add a new member variable and its getter to the `addressbook.cpp` contract. Since the secondary index needs to be numeric field so a `uint64_t` age variable is added. +[block:code] +{ + "codes": [ + { + "code": "uint64_t age;\nuint64_t get_secondary_1() const { return age;}", + "language": "cplusplus", + "name": null + } + ] +} +[/block] + +[block:api-header] +{ + "title": "Step 3: Add secondary index to `addresses` table configuration" +} +[/block] +A field has been defined as the secondary index, next the `address_index` table needs to be reconfigured. +[block:code] +{ + "codes": [ + { + "code": "typedef eosio::multi_index<\"people\"_n, person, \nindexed_by<\"byage\"_n, const_mem_fun>\n > address_index;", + "language": "cplusplus" + } + ] +} +[/block] +In the third parameter, we pass a `index_by` struct which is used to instantiate a index. + +In that `index_by` struct, we specify the name of index as `"byage"` and the second type parameter as a function call operator should extract a const value as an index key. In this case, we point it to the getter we created earlier so this multiple index table will index records by `age` variable. +[block:code] +{ + "codes": [ + { + "code": "indexed_by<\"byage\"_n, const_mem_fun>", + "language": "cplusplus" + } + ] +} +[/block] + +[block:api-header] +{ + "title": "Step 4: Modify code" +} +[/block] +With all the changes in previous steps, we can now update the `upsert` function. Change the function parameter list to the following: +[block:code] +{ + "codes": [ + { + "code": " void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state)", + "language": "cplusplus" + } + ] +} +[/block] +Add additional lines to update `age` field in `upsert` function as the following: +[block:code] +{ + "codes": [ + { + "code": " void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {\n require_auth( user );\n address_index addresses(_code, _code.value);\n auto iterator = addresses.find(user.value);\n if( iterator == addresses.end() )\n {\n addresses.emplace(user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n // -- Add code below --\n row.age = age; \n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n else {\n std::string changes;\n addresses.modify(iterator, user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n // -- Add code below --\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n }", + "language": "cplusplus" + } + ] +} +[/block] + +[block:api-header] +{ + "title": "Step 5: Compile and Deploy" +} +[/block] +Compile +[block:code] +{ + "codes": [ + { + "code": "eosio-cpp -o addressbook.wasm addressbook.cpp --abigen\n", + "language": "shell" + } + ] +} +[/block] +Deploy +[block:code] +{ + "codes": [ + { + "code": "cleos set contract addressbook CONTRACTS_DIR/addressbook", + "language": "shell" + } + ] +} +[/block] + +[block:api-header] +{ + "title": "Step 6: Test it" +} +[/block] +Insert records +[block:code] +{ + "codes": [ + { + "code": "cleos push action addressbook upsert '[\"alice\", \"alice\", \"liddell\", 9, \"123 drink me way\", \"wonderland\", \"amsterdam\"]' -p alice@active", + "language": "shell" + } + ] +} +[/block] + +[block:code] +{ + "codes": [ + { + "code": "cleos push action addressbook upsert '[\"bob\", \"bob\", \"is a guy\", 49, \"doesnt exist\", \"somewhere\", \"someplace\"]' -p bob@active", + "language": "shell" + } + ] +} +[/block] +Look up alice's address by the age index. Here the `--index 2` parameter is used to indicate that the query applies to the secondary index (index #2) +[block:code] +{ + "codes": [ + { + "code": "cleos get table addressbook addressbook people --upper 10 \\\n--key-type i64 \\\n--index 2", + "language": "shell" + } + ] +} +[/block] +You should see something like the following +[block:code] +{ + "codes": [ + { + "code": "{\n \"rows\": [{\n \"key\": \"alice\",\n \"first_name\": \"alice\",\n \"last_name\": \"liddell\",\n \"age\": 9,\n \"street\": \"123 drink me way\",\n \"city\": \"wonderland\",\n \"state\": \"amsterdam\"\n }\n ],\n \"more\": false\n}", + "language": "json" + } + ] +} +[/block] +Look it up by Bob's age +[block:code] +{ + "codes": [ + { + "code": "cleos get table addressbook addressbook people --upper 50 --key-type i64 --index 2", + "language": "shell" + } + ] +} +[/block] +It should return +[block:code] +{ + "codes": [ + { + "code": "{\n \"rows\": [{\n \"key\": \"alice\",\n \"first_name\": \"alice\",\n \"last_name\": \"liddell\",\n \"age\": 9,\n \"street\": \"123 drink me way\",\n \"city\": \"wonderland\",\n \"state\": \"amsterdam\"\n },{\n \"key\": \"bob\",\n \"first_name\": \"bob\",\n \"last_name\": \"is a loser\",\n \"age\": 49,\n \"street\": \"doesnt exist\",\n \"city\": \"somewhere\",\n \"state\": \"someplace\"\n }\n ],\n \"more\": false\n}", + "language": "json" + } + ] +} +[/block] + +All good! + +[block:api-header] +{ + "title": "Wrapping Up" +} +[/block] +The complete `addressbook` contract up to this point: +[block:code] +{ + "codes": [ + { + "code": "#include \n#include \n\nusing namespace eosio;\n\nclass [[eosio::contract]] addressbook : public eosio::contract {\n\npublic:\n using contract::contract;\n \n addressbook(name receiver, name code, datastream ds): contract(receiver, code, ds) {}\n\n [[eosio::action]]\n void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {\n require_auth( user );\n address_index addresses(_code, _code.value);\n auto iterator = addresses.find(user.value);\n if( iterator == addresses.end() )\n {\n addresses.emplace(user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n else {\n std::string changes;\n addresses.modify(iterator, user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n }\n\n [[eosio::action]]\n void erase(name user) {\n require_auth(user);\n\n address_index addresses(_self, _code.value);\n\n auto iterator = addresses.find(user.value);\n eosio_assert(iterator != addresses.end(), \"Record does not exist\");\n addresses.erase(iterator);\n }\n\nprivate:\n struct [[eosio::table]] person {\n name key;\n std::string first_name;\n std::string last_name;\n uint64_t age;\n std::string street;\n std::string city;\n std::string state;\n \n uint64_t primary_key() const { return key.value; }\n uint64_t get_secondary_1() const { return age;}\n \n };\n\n typedef eosio::multi_index<\"people\"_n, person, indexed_by<\"byage\"_n, const_mem_fun>> address_index;\n \n};\n\nEOSIO_DISPATCH( addressbook, (upsert)(erase))", + "language": "cplusplus" + } + ] +} +[/block] +If you wanted to use the secondary indexes in code, we need to get the index using `get_index()` +[block:code] +{ + "codes": [ + { + "code": "[[eosio::action]]\nvoid findByAge(name user, uint64_t age) {\n require_auth(user); \n \n address_index addresses(get_self(), get_first_receiver().value);\n \n auto age_index = addresses.get_index<\"byage\"_n>();\n auto itr = age_index.find(age);\n check(itr != age_index.end(), \"Yes, we have someone with that age\");\n}", + "language": "cplusplus" + } + ] +} +[/block] diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 702dc2bcec..813a080bfd 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,2 +1,3 @@ ## How to define a secondady index -TO DO: add content \ No newline at end of file +TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 2edd6a3458..f1652b426e 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,2 +1,3 @@ ## How to delete data from a multi index table -TO DO: add content \ No newline at end of file +TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 79c173508b..318c53fd0a 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,2 +1,3 @@ ## How to insert data into a multi index table -TO DO: add content \ No newline at end of file +TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 26f0746fa3..d46dc3394c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,2 +1,3 @@ ## How to iterate and retreive a multi index table based on secondary index -TO DO: add content \ No newline at end of file +TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 6c9852cbac..460ab1668d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,2 +1,3 @@ ## How to iterate and retrieve a multi index table TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 61bef0072e..1814a1c616 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,2 +1,3 @@ ## How to modify data in a multi index table TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 103a13828a..9e08cec9ad 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,2 +1,3 @@ ## How to modify the structure of a multi index table -TO DO: add content \ No newline at end of file +TO DO: add content +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file diff --git a/docs/06_how-to-guides/03_declarations.md b/docs/06_how-to-guides/03_declarations.md deleted file mode 100644 index 4b8ce8ef05..0000000000 --- a/docs/06_how-to-guides/03_declarations.md +++ /dev/null @@ -1,2 +0,0 @@ -## How to declare ... -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/04_how_to_handle_errors.md b/docs/06_how-to-guides/03_how_to_handle_errors.md similarity index 100% rename from docs/06_how-to-guides/04_how_to_handle_errors.md rename to docs/06_how-to-guides/03_how_to_handle_errors.md diff --git a/docs/06_how-to-guides/04_how_to_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_use_action_wrappers.md new file mode 100644 index 0000000000..e77ad76891 --- /dev/null +++ b/docs/06_how-to-guides/04_how_to_use_action_wrappers.md @@ -0,0 +1,6 @@ +## How to use action wrappers +TO DO: add content +sample: +https://developers.eos.io/eosio-home/docs/sending-an-inline-transaction-to-external-contract +api reference: +https://eosio.github.io/eosio.cdt/1.6.0-rc1/structeosio_1_1action__wrapper.html \ No newline at end of file diff --git a/docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md similarity index 100% rename from docs/06_how-to-guides/06_authorization/how_to_restrict_access_to_an_action_by_user.md rename to docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md diff --git a/docs/06_how-to-guides/05_how_to_use_action_wrappers.md b/docs/06_how-to-guides/05_how_to_use_action_wrappers.md deleted file mode 100644 index f0e145b116..0000000000 --- a/docs/06_how-to-guides/05_how_to_use_action_wrappers.md +++ /dev/null @@ -1,2 +0,0 @@ -## How to use action wrappers -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md b/docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md similarity index 92% rename from docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md rename to docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md index 67a74f8344..1898a75687 100644 --- a/docs/06_how-to-guides/07_abi/01_how-to-use-generator-attributes.md +++ b/docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md @@ -1,7 +1,7 @@ ## How to use ABI/Code generator attributes Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. -#### [[eosio::action]] +### [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): ```c++ @@ -29,7 +29,7 @@ struct __attribute__((eosio_action)) testa { ``` If your action name is not a valid [EOSIO name](https://developers.eos.io/eosio-cpp/docs/naming-conventions) you can explicitly specify the name in the attribute ```c++ [[eosio::action("")]]``` -#### [[eosio::table]] +### [[eosio::table]] Example (two ways to declare a table for ABI generation): ``` struct [[eosio::table]] testtable { @@ -46,14 +46,14 @@ typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; ``` If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. -#### [[eosio::contract("\")]] +### [[eosio::contract("\")]] ``` class [[eosio::contract("")]] test_contract : public eosio::contract { }; ``` This will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. -#### [[eosio::on_notify("\::\")]] +### [[eosio::on_notify("\::\")]] ``` [[eosio::on_notify("eosio.token::transfer")]] void on_token_transfer(name from, name to, assert quantity, std::string memo) { @@ -66,7 +66,7 @@ void on_any_transfer(name from, name to, assert quantity, std::string memo) { } ``` -#### [[eosio::wasm_entry]] +### [[eosio::wasm_entry]] ``` [[eosio::wasm_entry]] void some_function(...) { @@ -76,7 +76,7 @@ void some_function(...) { This will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. -#### [[eosio::wasm_import]] +### [[eosio::wasm_import]] ``` extern "C" { __attribute__((eosio_wasm_import)) diff --git a/docs/06_how-to-guides/07_abi/02_how_to_manually_write_an_ABI_file.md b/docs/06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md similarity index 100% rename from docs/06_how-to-guides/07_abi/02_how_to_manually_write_an_ABI_file.md rename to docs/06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md diff --git a/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity b/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity deleted file mode 100644 index 5e070b6b57..0000000000 --- a/docs/06_how-to-guides/06_authorization/node_modules/.yarn-integrity +++ /dev/null @@ -1,10 +0,0 @@ -{ - "systemParams": "darwin-x64-72", - "modulesFolders": [], - "flags": [], - "linkedModules": [], - "topLevelPatterns": [], - "lockfileEntries": {}, - "files": [], - "artifacts": {} -} \ No newline at end of file diff --git a/docs/06_how-to-guides/06_authorization/yarn.lock b/docs/06_how-to-guides/06_authorization/yarn.lock deleted file mode 100644 index fb57ccd13a..0000000000 --- a/docs/06_how-to-guides/06_authorization/yarn.lock +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - diff --git a/docs/06_how-to-guides/08_how-to-use-native-tester.md b/docs/06_how-to-guides/07_how-to-use-native-tester.md similarity index 99% rename from docs/06_how-to-guides/08_how-to-use-native-tester.md rename to docs/06_how-to-guides/07_how-to-use-native-tester.md index 3919c4dcde..497f0ec907 100644 --- a/docs/06_how-to-guides/08_how-to-use-native-tester.md +++ b/docs/06_how-to-guides/07_how-to-use-native-tester.md @@ -1,7 +1,7 @@ ## How to use native tester/compilation As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. `eosio-cc\cpp` and `eosio-ld` now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) -#### Getting Started +### Getting Started Once you have your smart contract written then a test source file can be written. `hello.hpp` diff --git a/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md b/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md new file mode 100644 index 0000000000..d16eac1687 --- /dev/null +++ b/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md @@ -0,0 +1,10 @@ +## How to push a deferred transaction from a smart contract to another + +Excerpt from: https://developers.eos.io/eosio-nodeos/docs/communication-model#section-deferred-communication + +"Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. + +As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction." + +TO DO: review the content below, is it ok to make this statement here? +Because of all considerations mentioned above we do not reccommend the use of deferred transactions and we are considering to deprecate them in the future versions. diff --git a/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md b/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md new file mode 100644 index 0000000000..9c6bc8f7db --- /dev/null +++ b/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md @@ -0,0 +1,120 @@ +## How to debug a smart contract +TO DO: should we also include IDE configurations (one? multiple?) + +In order to be able to debug your smart contract, you will need to setup local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. + +When you are creating your smart contract for the first time, it is recommended to test and debug your smart contract on a private testnet first, since you have full control of the whole blockchain and can easily add suitable logging. This enables you to have unlimited amount of eos needed and you can just reset the state of the blockchain whenever you want. When it is ready for production, debugging on the public testnet (or official testnet) can be done by connecting your local nodeos to the public testnet (or official testnet) so you can see the log of the testnet in your local nodeos. + +The concept is the same, so for the following guide, debugging on the private testnet will be covered. + +If you haven't set up your own local nodeos, please follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. + +## Method +The main method used to debug smart contract is **Caveman Debugging**, where we utilize the printing functionality to inspect the value of a variable and check the flow of the contract. Printing in smart contract can be done through the Print API. The C++ API is the wrapper for C API, so most often we will just use the C++ API. + +## Print +Print C API supports the following data type that you can print: +- prints - a null terminated char array (string) +- prints_l - any char array (string) with given size +- printi - 64-bit signed integer +- printui - 64-bit unsigned integer +- printi128 - 128-bit signed integer +- printui128 - 128-bit unsigned integer +- printsf - single-precision floating point number +- printdf - double encoded as 64-bit unsigned integer +- printqf - quadruple encoded as 64-bit unsigned integer +- printn - 64 bit names as base32 encoded string +- printhex - hex given binary of data and its size + +While Print C++ API wraps some of the above C API by overriding the print() function so user doesn't need to determine which specific print function he needs to use. Print C++ API supports +- a null terminated char array (string) +- integer (128-bit unsigned, 64-bit unsigned, 32-bit unsigned, signed, unsigned) +- base32 string encoded as 64-bit unsigned integer +- struct that has print() method + +## Example +Let's write a new contract as example for debugging + +### debug.hpp + +```cpp +#include +#include + +namespace debug { + struct foo { + account_name from; + account_name to; + uint64_t amount; + void print() const { + eosio::print("Foo from ", eosio::name(from), " to ",eosio::name(to), " with amount ", amount, "\n"); + } + }; +} +``` +### debug.cpp + +```cpp +#include + +extern "C" { + + void apply( uint64_t code, uint64_t action ) { + if (code == N(debug)) { + eosio::print("Code is debug\n"); + if (action == N(foo)) { + eosio::print("Action is foo\n"); + debug::foo f = eosio::unpack_action_data(); + if (f.amount >= 100) { + eosio::print("Amount is larger or equal than 100\n"); + } else { + eosio::print("Amount is smaller than 100\n"); + eosio::print("Increase amount by 10\n"); + f.amount += 10; + eosio::print(f); + } + } + } + } +} // extern "C" +``` +### debug.abi + +```cpp +{ + "structs": [{ + "name": "foo", + "base": "", + "fields": { + "from": "account_name", + "to": "account_name", + "amount": "uint64" + } + } + ], + "actions": [{ + "action_name": "foo", + "type": "foo" + } + ] +} +``` +Let's deploy it and send a message to it. Assume that you have `debug` account created and have its key in your wallet. + +```bash +$ eosio-cpp -abigen debug.cpp -o debug.wasm +$ cleos set contract debug CONTRACT_DIR/debug -p youraccount@active +$ cleos push action debug foo '{"from":"inita", "to":"initb", "amount":10}' --scope debug +``` + +When you check your local `nodeos` node log, you will see the following lines after the above message is sent. + +``` +Code is debug +Action is foo +Amount is smaller than 100 +Increase amount by 10 +Foo from inita to initb with amount 20 +``` + +There, you can confirm that your message is going to the right control flow and the amount is updated correctly. You might see the above message at least 2 times and that's normal because each transaction is being applied during verification, block generation, and block application. \ No newline at end of file diff --git a/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md b/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md deleted file mode 100644 index 8600728894..0000000000 --- a/docs/06_how-to-guides/09_how_to_push_a_deferred_transaction_from_a_smart_contract.md +++ /dev/null @@ -1,2 +0,0 @@ -## How to push a deffered transaction from a smart contract to another -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md b/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md deleted file mode 100644 index 60183a6e3b..0000000000 --- a/docs/06_how-to-guides/10_how_to_debug_a_smart_contract.md +++ /dev/null @@ -1,2 +0,0 @@ -## How to debug a smart contract -TO DO: add content \ No newline at end of file From b47a097da1b629c3e05e319d53c6e0cd15d0e9d2 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 22 Aug 2019 23:21:29 +0300 Subject: [PATCH 007/659] introduce index.md from introdution.md --- docs/{01_introduction.md => index.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{01_introduction.md => index.md} (100%) diff --git a/docs/01_introduction.md b/docs/index.md similarity index 100% rename from docs/01_introduction.md rename to docs/index.md From faf2e0998b54accbccacf646491bdc1ac7285194 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 11:14:10 +0300 Subject: [PATCH 008/659] clean up eosio-abimerge since it is not available in 1.6 --- docs/03_command-reference/eosio-abimerge.md | 3 --- docs/05_best-practices/02_architectural-design.md | 2 +- .../how_to_restrict_access_to_an_action_by_user.md | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 docs/03_command-reference/eosio-abimerge.md diff --git a/docs/03_command-reference/eosio-abimerge.md b/docs/03_command-reference/eosio-abimerge.md deleted file mode 100644 index 7dedb91a43..0000000000 --- a/docs/03_command-reference/eosio-abimerge.md +++ /dev/null @@ -1,3 +0,0 @@ -# eosio-abimerge tool - -TO DO: Verify if it is final, complete, first. \ No newline at end of file diff --git a/docs/05_best-practices/02_architectural-design.md b/docs/05_best-practices/02_architectural-design.md index 19809e80c8..4001e88960 100644 --- a/docs/05_best-practices/02_architectural-design.md +++ b/docs/05_best-practices/02_architectural-design.md @@ -1,2 +1,2 @@ -## Architectura design +## Architectural design TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index b4c1000886..9b036eed64 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,3 +1,3 @@ -## How to restrict access to an acction by user +## How to restrict access to an action by user TO DO: add content require_auth, require_auth2 \ No newline at end of file From 32254e270b6f4bba6b9d3dc7cbd4c9da08bde862 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 11:15:10 +0300 Subject: [PATCH 009/659] Resolves #635 --- docs/index.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 0c27aad02b..4e9726d0c9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,19 +11,21 @@ EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary ## Concepts ### Dispatcher and Notifications -TO DO: Add link to the dispatcher and notifications documentation, where can I find it? [Dispatcher API reference](https://eosio.github.io/eosio.cdt/1.6.0/group__dispatcher.html) +[schemata:link to glossary] ### Multi Index Table and RAM [Multi Index Tables explained by example](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) +[schemata:link to glossary] ### Smart Contract +[schemata:link to glossary] ### Action +[schemata:link to glossary] ### Transaction and Deferred Transaction - -TO DO: Any other concepts that need to go here? +[schemata:link to glossary] ## Contributing From 4c0fe2eb13ab8dccb24cc52ccaf8990db450b26e Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 11:54:46 +0300 Subject: [PATCH 010/659] Resolves #616 --- .../01_compile-a-contract-via-cli.md | 12 ++++------ .../03_compiling-contracts-with-cmake.md | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index f79f677c48..ac604c6b3f 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -9,18 +9,14 @@ Follow these steps to compile your contract --- 1. Navigate to the hello folder in examples (./examples/hello) -2. You should then see the hello.cpp file -3. Now run the compiler -``` -$ eosio-cpp -abigen hello.cpp -o hello.wasm -``` -4. Or with CMake +2. You should then see the ./src/hello.cpp file +3. Now run following commands: ``` $ mkdir build $ cd build -$ cmake .. -$ make +$ eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ ``` + This will generate two files: - The compiled binary wasm (hello.wasm) - The generated ABI file (hello.abi) diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index 333b3dc6f6..712b680795 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -1,2 +1,22 @@ ## How to compile a smart contract with CMake -TO DO: add content \ No newline at end of file + +Prerequisites: +--- +You have the source of your contrat saved in one of your local folders, e.g. `./examples/hello` +For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) + +Follow these steps to compile your contract +--- + +1. Navigate to the hello folder in examples (./examples/hello) +2. You should then see the ./src/hello.cpp file +3. Now run following commands: +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +``` +This will generate two files: +- The compiled binary wasm (hello.wasm) +- The generated ABI file (hello.abi) From 0d368234fc9abf8e21ebf58bdb39653cc5202d98 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 12:11:02 +0300 Subject: [PATCH 011/659] Resolved #610 --- docs/02_installation.md | 7 ++----- .../01_compile/01_compile-a-contract-via-cli.md | 2 +- .../01_compile/03_compiling-contracts-with-cmake.md | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/02_installation.md b/docs/02_installation.md index 01acdc2128..e40bd5c2e7 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -44,7 +44,7 @@ $ sudo yum install ./eosio.cdt-1.6.1-1.centos-x86_64.rpm $ sudo yum remove eosio.cdt ``` -## Guided Installation (Building from Scratch) +## Guided Installation or Building from Scratch ```sh $ git clone --recursive https://github.com/eosio/eosio.cdt $ cd eosio.cdt @@ -54,7 +54,6 @@ $ sudo ./install.sh ## Installed Tools --- -TO DO: is below list correct? is any of them deprecated? eosio-abimerge should it be listed here? * eosio-cpp * eosio-cc * eosio-ld @@ -67,14 +66,12 @@ TO DO: is below list correct? is any of them deprecated? eosio-abimerge should i * eosio-objdump * eosio-readelf -TO DO: -these tools are not installed after brew install, how can I get them? +Below tools are not installed after brew install, you get them only by building the repository and installing from scracth, [see here](#guided_installation_or_building_from_scratch) eosio-abidiff eosio-ranlib eosio-ar eosio-objdump eosio-readelf -eosio-merge License diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index ac604c6b3f..c1210f2f4b 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -11,7 +11,7 @@ Follow these steps to compile your contract 1. Navigate to the hello folder in examples (./examples/hello) 2. You should then see the ./src/hello.cpp file 3. Now run following commands: -``` +```sh $ mkdir build $ cd build $ eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index 712b680795..1c8902d65a 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -11,7 +11,7 @@ Follow these steps to compile your contract 1. Navigate to the hello folder in examples (./examples/hello) 2. You should then see the ./src/hello.cpp file 3. Now run following commands: -``` +```sh $ mkdir build $ cd build $ cmake .. From 885eb2038dd529fd3a0c1d22bef681d43bece923 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 17:56:13 +0300 Subject: [PATCH 012/659] resolves #629 --- ...to_restrict_access_to_an_action_by_user.md | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 9b036eed64..c22cc8d322 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,3 +1,21 @@ ## How to restrict access to an action by user -TO DO: add content -require_auth, require_auth2 \ No newline at end of file + +Prerequisites: https://developers.eos.io/eosio-home/docs/your-first-contract + +The below code is enforcing the action hi to be executed only by the same user that is sent as paramater to the action. + +```cpp +void hi( name user ) { + require_auth( user ); + print( "Hello, ", name{user} ); +} +``` + +The below code is enforcing the action hi to be executed only by the same user that is sent as paramater to the action and only if the active key is provided, that is, if the same user is signing the transaction with a different key (e.g. code, owner) the execution of the action is halted. + +```cpp +void hi( name user ) { + require_auth2(user, N(active)); + print( "Hello, ", name{user} ); +} +``` \ No newline at end of file From 1a7328cc63a363d56f7e9034b1eec6ea8ab97dfa Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 28 Aug 2019 18:01:41 +0300 Subject: [PATCH 013/659] Improvements for #629 --- .../how_to_restrict_access_to_an_action_by_user.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index c22cc8d322..2ef24f7747 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -2,7 +2,7 @@ Prerequisites: https://developers.eos.io/eosio-home/docs/your-first-contract -The below code is enforcing the action hi to be executed only by the same user that is sent as paramater to the action. +The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). ```cpp void hi( name user ) { @@ -11,7 +11,7 @@ void hi( name user ) { } ``` -The below code is enforcing the action hi to be executed only by the same user that is sent as paramater to the action and only if the active key is provided, that is, if the same user is signing the transaction with a different key (e.g. code, owner) the execution of the action is halted. +The below code is enforcing the action hi to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. ```cpp void hi( name user ) { From b7b300f7025c1cfed24dfa180d01590053f04f54 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 29 Aug 2019 09:04:32 +0300 Subject: [PATCH 014/659] Resolves #629 --- ...to_restrict_access_to_an_action_by_user.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 2ef24f7747..cb587c0108 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,7 +1,10 @@ ## How to restrict access to an action by user -Prerequisites: https://developers.eos.io/eosio-home/docs/your-first-contract +Prerequisites: It is assumed you have the sources for a contract and one of the actions defined is getting as parameter an account name and it is printing the account name. +An example of this contract can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/src/hello.cpp) + +### Using require_auth The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). ```cpp @@ -11,11 +14,23 @@ void hi( name user ) { } ``` +### Using require_auth2 + The below code is enforcing the action hi to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. ```cpp +#include + void hi( name user ) { - require_auth2(user, N(active)); + require_auth2(nm.value, "active"_n.value); print( "Hello, ", name{user} ); } +``` + +Don't forget to inlcude the right libraries to your include path, for example your build command line should look like this +```sh +cd /local_path_to/eosio.cdt/examples/hello/ +mkdir build +cd build +eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ -I ../../../libraries/eosiolib/ ``` \ No newline at end of file From 166d31fb1db586796fdee0f611dd29da1e330641 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 29 Aug 2019 18:25:05 +0300 Subject: [PATCH 015/659] Resolves #628 --- ...4_how_to_create_and_use_action_wrappers.md | 43 +++++++++++++++++++ .../04_how_to_use_action_wrappers.md | 6 --- 2 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md delete mode 100644 docs/06_how-to-guides/04_how_to_use_action_wrappers.md diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md new file mode 100644 index 0000000000..4f578e3444 --- /dev/null +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -0,0 +1,43 @@ +## How to create and use action wrappers + +### Create action wrappers +One of the good examples for creating action wrappers is the `eosio.token` contract [code](https://github.com/EOSIO/eosio.contracts/blob/867f6f291db05cb663505f21ba8f7c3adca20678/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L150). + +This is how are defined the action wrappers for the following actions `create`, `issue`, `transfer` in token contract: + +```cpp +[[eosio::action]] +void create( name issuer, asset maximum_supply ); + +[[eosio::action]] +void issue( name to, asset quantity, string memo ); + +[[eosio::action]] +void transfer( name from, + name to, + asset quantity, + string memo ); + +// The first parameter of the action wrapper template is the action eosio::name and second parameter is the reference to the action method +using create_action = eosio::action_wrapper<"create"_n, &token::create>; +using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>; +using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>; + +// ... +``` +__Note__: // The first parameter of the action wrapper template is the action eosio::name and second parameter is the reference to the action method. + + +### Use action wrappers +And this is how you use the previously created action wrapper for `transfer` action: +```cpp +#include + +// specify the contract to send the action to as the first argument +token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n}); + +// specify the transfer arguments as postional arguments +payout.send(get_self(), to, quantity, memo); +``` + +__Note:__ You have to include the header file where the action wrappers are defined. \ No newline at end of file diff --git a/docs/06_how-to-guides/04_how_to_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_use_action_wrappers.md deleted file mode 100644 index e77ad76891..0000000000 --- a/docs/06_how-to-guides/04_how_to_use_action_wrappers.md +++ /dev/null @@ -1,6 +0,0 @@ -## How to use action wrappers -TO DO: add content -sample: -https://developers.eos.io/eosio-home/docs/sending-an-inline-transaction-to-external-contract -api reference: -https://eosio.github.io/eosio.cdt/1.6.0-rc1/structeosio_1_1action__wrapper.html \ No newline at end of file From f9d9bbe3c1a5e295d55da60addcbbd6fbabe1db8 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 2 Sep 2019 18:08:09 +0300 Subject: [PATCH 016/659] Adding content for singleton how to and implementation for singleton example implementation which compiles with both cmake and eosio-cpp --- .../how-to-define-a-singleton.md | 52 ++++++++++++++++++- examples/singleton_example/CMakeLists.txt | 17 ++++++ examples/singleton_example/README.txt | 12 +++++ .../include/singleton_example.hpp | 28 ++++++++++ .../ricardian/singleton_example.contracts.md | 3 ++ examples/singleton_example/src/CMakeLists.txt | 8 +++ .../src/singleton_example.cpp | 14 +++++ 7 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 examples/singleton_example/CMakeLists.txt create mode 100644 examples/singleton_example/README.txt create mode 100644 examples/singleton_example/include/singleton_example.hpp create mode 100644 examples/singleton_example/ricardian/singleton_example.contracts.md create mode 100644 examples/singleton_example/src/CMakeLists.txt create mode 100644 examples/singleton_example/src/singleton_example.cpp diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index e7a6c476b2..97d5b8b0d5 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,2 +1,52 @@ ## How to define a singleton -TO DO: add content \ No newline at end of file + +This is how you define a simple singleton, which is storing an account name as primary data and a uint64_t as secondary data in structure test table; the structure testtable can be extended to be defined by multiple data members, here we defined only to for demonstration purposes. + +```cpp +#include +#include +#include +using namespace eosio; + +CONTRACT singleton_example : public contract { + public: + using contract::contract; + singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), + singleton_instance(receiver, receiver.value) + {} + + ACTION set( name user, uint64_t value ); + ACTION get( ); + + TABLE testtable { + name primary_value; + uint64_t secondary_value; + }; + + using singleton_type = eosio::singleton<"testtable"_n, testtable>; + singleton_type singleton_instance; + + using set_action = action_wrapper<"set"_n, &singleton_example::set>; + using get_action = action_wrapper<"get"_n, &singleton_example::get>; +}; +``` + +And this is a possible implementation for the two `get` and `set` actions. Note that the `set` action makes use of the singleton's set method which has as second parameter the account to pay for the new value, in this case, the same account name that is stored in the primary value, however, it can be a different account. + +```cpp + #include + + ACTION singleton_example::set( name user, uint64_t value ) { + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); + } + + ACTION singleton_example::get( ) { + eosio::print("Value stored for: {%} is {%}\n", + singleton_instance.get().primary_value.value, + singleton_instance.get().secondary_value); + } +``` \ No newline at end of file diff --git a/examples/singleton_example/CMakeLists.txt b/examples/singleton_example/CMakeLists.txt new file mode 100644 index 0000000000..cc78459a7b --- /dev/null +++ b/examples/singleton_example/CMakeLists.txt @@ -0,0 +1,17 @@ +include(ExternalProject) +# if no cdt root is given use default path +if(EOSIO_CDT_ROOT STREQUAL "" OR NOT EOSIO_CDT_ROOT) + find_package(eosio.cdt) +endif() + +ExternalProject_Add( + singleton_example_project + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src + BINARY_DIR ${CMAKE_BINARY_DIR}/singleton_example + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_ROOT}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake + UPDATE_COMMAND "" + PATCH_COMMAND "" + TEST_COMMAND "" + INSTALL_COMMAND "" + BUILD_ALWAYS 1 +) \ No newline at end of file diff --git a/examples/singleton_example/README.txt b/examples/singleton_example/README.txt new file mode 100644 index 0000000000..33f6df682f --- /dev/null +++ b/examples/singleton_example/README.txt @@ -0,0 +1,12 @@ +--- singleton_example Project --- + + - How to Build - + - cd to 'build' directory + - run the command 'cmake ..' + - run the command 'make' + + - After build - + - The built smart contract is under the 'singleton_example' directory in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point in to the './build/singleton_example' directory + + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp new file mode 100644 index 0000000000..344c69f542 --- /dev/null +++ b/examples/singleton_example/include/singleton_example.hpp @@ -0,0 +1,28 @@ +#include +#include +#include +using namespace eosio; + +CONTRACT singleton_example : public contract { + public: + using contract::contract; + singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), + singleton_instance(receiver, receiver.value) + {} + + ACTION set( name user, uint64_t value ); + ACTION get( ); + + TABLE testtable { + name primary_value; + uint64_t secondary_value; + uint64_t primary_key() const { return primary_value.value; } + }; + + using singleton_type = eosio::singleton<"testtable"_n, testtable>; + singleton_type singleton_instance; + + using set_action = action_wrapper<"set"_n, &singleton_example::set>; + using get_action = action_wrapper<"get"_n, &singleton_example::get>; +}; diff --git a/examples/singleton_example/ricardian/singleton_example.contracts.md b/examples/singleton_example/ricardian/singleton_example.contracts.md new file mode 100644 index 0000000000..5c7d6556a7 --- /dev/null +++ b/examples/singleton_example/ricardian/singleton_example.contracts.md @@ -0,0 +1,3 @@ +

hi

+ +Stub for hi action's ricardian contract \ No newline at end of file diff --git a/examples/singleton_example/src/CMakeLists.txt b/examples/singleton_example/src/CMakeLists.txt new file mode 100644 index 0000000000..8e5dbe960f --- /dev/null +++ b/examples/singleton_example/src/CMakeLists.txt @@ -0,0 +1,8 @@ +project(singleton_example) + +set(EOSIO_WASM_OLD_BEHAVIOR "Off") +find_package(eosio.cdt) + +add_contract( singleton_example singleton_example singleton_example.cpp ) +target_include_directories( singleton_example PUBLIC ${CMAKE_SOURCE_DIR}/../include ) +target_ricardian_directory( singleton_example ${CMAKE_SOURCE_DIR}/../ricardian ) \ No newline at end of file diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp new file mode 100644 index 0000000000..fa384b254e --- /dev/null +++ b/examples/singleton_example/src/singleton_example.cpp @@ -0,0 +1,14 @@ + #include + + ACTION singleton_example::set( name user, uint64_t value ) { + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); + } + + ACTION singleton_example::get( ) { + eosio::print("Value stored for: {%} is {%}\n", + singleton_instance.get().primary_value.value, + singleton_instance.get().secondary_value); + } From 109167142a572aecb17ce8e686cfd6726302493a Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 2 Sep 2019 18:13:05 +0300 Subject: [PATCH 017/659] Resolves #619 --- .../02_multi-index/how-to-define-a-singleton.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 97d5b8b0d5..5cd6b525e0 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,6 +1,6 @@ ## How to define a singleton -This is how you define a simple singleton, which is storing an account name as primary data and a uint64_t as secondary data in structure test table; the structure testtable can be extended to be defined by multiple data members, here we defined only to for demonstration purposes. +This an example of how you can define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`; the structure testtable can be extended to be defined by multiple data members, here we defined only two for demonstration purposes. ```cpp #include @@ -32,7 +32,7 @@ CONTRACT singleton_example : public contract { }; ``` -And this is a possible implementation for the two `get` and `set` actions. Note that the `set` action makes use of the singleton's set method which has as second parameter the account to pay for the new value, in this case, the same account name that is stored in the primary value, however, it can be a different account. +And below is a possible implementation for the two `get` and `set` actions defined above and demonstrate the usage of a couple of singleton methods. Note that the `set` action makes use of the singleton's `set` method for which parameter is the account to pay for the new value stored, in this case, the same account name that is stored in the primary value, however, it can be a different account if the so required. ```cpp #include From 4dec73a91c04d5143e258e478e0e37f1032a12a5 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 3 Sep 2019 10:11:06 +0300 Subject: [PATCH 018/659] Add content for 'How to instantiate a multi index table' section. Resolves #622 --- .../how-to-define-a-singleton.md | 2 + .../how-to-instantiate-a-multi_index-table.md | 43 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 5cd6b525e0..461525dac1 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -2,6 +2,7 @@ This an example of how you can define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`; the structure testtable can be extended to be defined by multiple data members, here we defined only two for demonstration purposes. +__singleton_example.hpp__ ```cpp #include #include @@ -34,6 +35,7 @@ CONTRACT singleton_example : public contract { And below is a possible implementation for the two `get` and `set` actions defined above and demonstrate the usage of a couple of singleton methods. Note that the `set` action makes use of the singleton's `set` method for which parameter is the account to pay for the new value stored, in this case, the same account name that is stored in the primary value, however, it can be a different account if the so required. +__singleton_example.cpp__ ```cpp #include diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md index dfe4d9d852..99dc89cab4 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md @@ -1,2 +1,43 @@ ## How to instantiate a multi index table -TO DO: add content \ No newline at end of file + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + ACTION set( name user ); + ACTION print( name user ); + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + name test_primary; + uint64_t datum; + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtabname"_n, test_table> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file From d359ae1cc8ca2f01ed040e4e5a008a5d855da2e3 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 3 Sep 2019 17:12:34 +0300 Subject: [PATCH 019/659] Resolves #618 --- .../how-to-define-a-primary-index.md | 250 ++---------------- .../how-to-define-a-secondary-index.md | 78 +++++- .../how-to-instantiate-a-multi_index-table.md | 21 +- 3 files changed, 107 insertions(+), 242 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index dcaee53c0f..d6866c4b87 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,239 +1,23 @@ ## How to define a primary index -TO DO: review this content, make sure it is an how to (a receipe not how to cook) -EOSIO has the ability to sort tables by up to 16 indices. In the following section, we're going to add another index to the `addressbook` contract, so we can iterate through the records in a different way. -[block:api-header] -{ - "title": "Step 1: Remove existing data from table" -} -[/block] -As mentioned earlier, **a table's struct cannot be modified when it has data in it.** The first step allows the removal of the data already added. +How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi_index-table.md), and as par of the definition of the multi index table, the definition of a primary index is mandatory. You can find in the how to section linked previously the full example of a multi index table including the primary index definition. -Remove all records of alice and bob that were added in previous tutorials. -[block:code] -{ - "codes": [ - { - "code": "cleos push action addressbook erase '[\"alice\"]' -p alice@active", - "language": "shell" - } - ] -} -[/block] +For a quick reference of how a primary index is defined see below: -[block:code] -{ - "codes": [ - { - "code": "cleos push action addressbook erase '[\"bob\"]' -p bob@active", - "language": "shell" - } - ] -} -[/block] +```cpp + // ... -[block:api-header] -{ - "title": "Step 2: Add new index member and getter" -} -[/block] -Add a new member variable and its getter to the `addressbook.cpp` contract. Since the secondary index needs to be numeric field so a `uint64_t` age variable is added. -[block:code] -{ - "codes": [ - { - "code": "uint64_t age;\nuint64_t get_secondary_1() const { return age;}", - "language": "cplusplus", - "name": null - } - ] -} -[/block] + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // ... +``` -[block:api-header] -{ - "title": "Step 3: Add secondary index to `addresses` table configuration" -} -[/block] -A field has been defined as the secondary index, next the `address_index` table needs to be reconfigured. -[block:code] -{ - "codes": [ - { - "code": "typedef eosio::multi_index<\"people\"_n, person, \nindexed_by<\"byage\"_n, const_mem_fun>\n > address_index;", - "language": "cplusplus" - } - ] -} -[/block] -In the third parameter, we pass a `index_by` struct which is used to instantiate a index. - -In that `index_by` struct, we specify the name of index as `"byage"` and the second type parameter as a function call operator should extract a const value as an index key. In this case, we point it to the getter we created earlier so this multiple index table will index records by `age` variable. -[block:code] -{ - "codes": [ - { - "code": "indexed_by<\"byage\"_n, const_mem_fun>", - "language": "cplusplus" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Step 4: Modify code" -} -[/block] -With all the changes in previous steps, we can now update the `upsert` function. Change the function parameter list to the following: -[block:code] -{ - "codes": [ - { - "code": " void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state)", - "language": "cplusplus" - } - ] -} -[/block] -Add additional lines to update `age` field in `upsert` function as the following: -[block:code] -{ - "codes": [ - { - "code": " void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {\n require_auth( user );\n address_index addresses(_code, _code.value);\n auto iterator = addresses.find(user.value);\n if( iterator == addresses.end() )\n {\n addresses.emplace(user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n // -- Add code below --\n row.age = age; \n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n else {\n std::string changes;\n addresses.modify(iterator, user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n // -- Add code below --\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n }", - "language": "cplusplus" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Step 5: Compile and Deploy" -} -[/block] -Compile -[block:code] -{ - "codes": [ - { - "code": "eosio-cpp -o addressbook.wasm addressbook.cpp --abigen\n", - "language": "shell" - } - ] -} -[/block] -Deploy -[block:code] -{ - "codes": [ - { - "code": "cleos set contract addressbook CONTRACTS_DIR/addressbook", - "language": "shell" - } - ] -} -[/block] - -[block:api-header] -{ - "title": "Step 6: Test it" -} -[/block] -Insert records -[block:code] -{ - "codes": [ - { - "code": "cleos push action addressbook upsert '[\"alice\", \"alice\", \"liddell\", 9, \"123 drink me way\", \"wonderland\", \"amsterdam\"]' -p alice@active", - "language": "shell" - } - ] -} -[/block] - -[block:code] -{ - "codes": [ - { - "code": "cleos push action addressbook upsert '[\"bob\", \"bob\", \"is a guy\", 49, \"doesnt exist\", \"somewhere\", \"someplace\"]' -p bob@active", - "language": "shell" - } - ] -} -[/block] -Look up alice's address by the age index. Here the `--index 2` parameter is used to indicate that the query applies to the secondary index (index #2) -[block:code] -{ - "codes": [ - { - "code": "cleos get table addressbook addressbook people --upper 10 \\\n--key-type i64 \\\n--index 2", - "language": "shell" - } - ] -} -[/block] -You should see something like the following -[block:code] -{ - "codes": [ - { - "code": "{\n \"rows\": [{\n \"key\": \"alice\",\n \"first_name\": \"alice\",\n \"last_name\": \"liddell\",\n \"age\": 9,\n \"street\": \"123 drink me way\",\n \"city\": \"wonderland\",\n \"state\": \"amsterdam\"\n }\n ],\n \"more\": false\n}", - "language": "json" - } - ] -} -[/block] -Look it up by Bob's age -[block:code] -{ - "codes": [ - { - "code": "cleos get table addressbook addressbook people --upper 50 --key-type i64 --index 2", - "language": "shell" - } - ] -} -[/block] -It should return -[block:code] -{ - "codes": [ - { - "code": "{\n \"rows\": [{\n \"key\": \"alice\",\n \"first_name\": \"alice\",\n \"last_name\": \"liddell\",\n \"age\": 9,\n \"street\": \"123 drink me way\",\n \"city\": \"wonderland\",\n \"state\": \"amsterdam\"\n },{\n \"key\": \"bob\",\n \"first_name\": \"bob\",\n \"last_name\": \"is a loser\",\n \"age\": 49,\n \"street\": \"doesnt exist\",\n \"city\": \"somewhere\",\n \"state\": \"someplace\"\n }\n ],\n \"more\": false\n}", - "language": "json" - } - ] -} -[/block] - -All good! - -[block:api-header] -{ - "title": "Wrapping Up" -} -[/block] -The complete `addressbook` contract up to this point: -[block:code] -{ - "codes": [ - { - "code": "#include \n#include \n\nusing namespace eosio;\n\nclass [[eosio::contract]] addressbook : public eosio::contract {\n\npublic:\n using contract::contract;\n \n addressbook(name receiver, name code, datastream ds): contract(receiver, code, ds) {}\n\n [[eosio::action]]\n void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {\n require_auth( user );\n address_index addresses(_code, _code.value);\n auto iterator = addresses.find(user.value);\n if( iterator == addresses.end() )\n {\n addresses.emplace(user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n else {\n std::string changes;\n addresses.modify(iterator, user, [&]( auto& row ) {\n row.key = user;\n row.first_name = first_name;\n row.last_name = last_name;\n row.age = age;\n row.street = street;\n row.city = city;\n row.state = state;\n });\n }\n }\n\n [[eosio::action]]\n void erase(name user) {\n require_auth(user);\n\n address_index addresses(_self, _code.value);\n\n auto iterator = addresses.find(user.value);\n eosio_assert(iterator != addresses.end(), \"Record does not exist\");\n addresses.erase(iterator);\n }\n\nprivate:\n struct [[eosio::table]] person {\n name key;\n std::string first_name;\n std::string last_name;\n uint64_t age;\n std::string street;\n std::string city;\n std::string state;\n \n uint64_t primary_key() const { return key.value; }\n uint64_t get_secondary_1() const { return age;}\n \n };\n\n typedef eosio::multi_index<\"people\"_n, person, indexed_by<\"byage\"_n, const_mem_fun>> address_index;\n \n};\n\nEOSIO_DISPATCH( addressbook, (upsert)(erase))", - "language": "cplusplus" - } - ] -} -[/block] -If you wanted to use the secondary indexes in code, we need to get the index using `get_index()` -[block:code] -{ - "codes": [ - { - "code": "[[eosio::action]]\nvoid findByAge(name user, uint64_t age) {\n require_auth(user); \n \n address_index addresses(get_self(), get_first_receiver().value);\n \n auto age_index = addresses.get_index<\"byage\"_n>();\n auto itr = age_index.find(age);\n check(itr != age_index.end(), \"Yes, we have someone with that age\");\n}", - "language": "cplusplus" - } - ] -} -[/block] +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 813a080bfd..d739f8c1f7 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,3 +1,77 @@ ## How to define a secondady index -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file + +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi_index-table.md). + +The steps below show how to add a secondary index to the existing multi index table. + +__First__, you have to add a second field `secondary` to the data structure that defines the row of the table, in our case `test_table`, then add the `by_secondary( )` method which is the index accessor method to the new field value added. The secondary index which we will create in second step will index this new data structure field. + +```cpp + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; +``` + +__Second__, in the `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template, which needs two parameters, the name of the index `"secid"_n`, and a function call operator which extracts the value from the `secondary` data member as an index key, this is achieved by employing the `eosio::const_mem_fun` template which receives two paras: the data structure `test_table` and the reference to the getter function member `by_secondary`. + +```cpp + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; +``` + +The full code with all the changes described above will look like this: + +```cpp +#include +using namespace eosio; + +// multi index example contract class +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + ACTION set( name user ); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md index 99dc89cab4..9e96d2ffd8 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md @@ -1,10 +1,14 @@ ## How to instantiate a multi index table +Prerequisites: To instantiate a multi index table you need to make use of the eosio::multi_index template and to define the structure of the table row data first along with the primary index which has to be based on an existing field. The definition of the primary index is mandatory. +One example to accomplish this is exemplified below. + __multi_index_example.hpp__ ```cpp #include using namespace eosio; +// multi index example contract class CONTRACT multi_index_example : public contract { public: using contract::contract; @@ -16,24 +20,27 @@ CONTRACT multi_index_example : public contract { // instantiate multi index instance as data member (find it defined below) testtab(receiver, receiver.value) { } - ACTION set( name user ); - ACTION print( name user ); - // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure TABLE test_table { - name test_primary; - uint64_t datum; - uint64_t primary_key( ) const { return test_primary.value; } + // this field is used later for definition of the primary index + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } }; // for ease of use we define a type alias `test_tables` - typedef eosio::multi_index<"testtabname"_n, test_table> test_tables; + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; // here we declare a data member of type test_tables, it gets instantiated // in the constructor of our contract class test_tables testtab; + ACTION set( name user ); + ACTION print( name user ); + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; }; From ae35a0708105a5957353c24d9fe510dae1e692e8 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 3 Sep 2019 19:20:56 +0300 Subject: [PATCH 020/659] Resolves #624 --- .../how-to-define-a-primary-index.md | 2 +- .../how-to-define-a-secondary-index.md | 2 +- .../how-to-define-a-singleton.md | 5 +- ...to-delete-data-from-a-multi-index-table.md | 5 +- ...to-insert-data-into-a-multi-index-table.md | 5 +- ...how-to-instantiate-a-multi-index-table.md} | 0 ...ti_index-table-based-on-secondary-index.md | 3 + ...terate-and-retrieve-a-multi_index-table.md | 151 +++++++++++++++++- ...w-to-modify-data-in-a-multi-index-table.md | 5 +- ...fy-the-structure-of-a-multi_index-table.md | 5 +- 10 files changed, 174 insertions(+), 9 deletions(-) rename docs/06_how-to-guides/02_multi-index/{how-to-instantiate-a-multi_index-table.md => how-to-instantiate-a-multi-index-table.md} (100%) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index d6866c4b87..c12af99096 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,6 +1,6 @@ ## How to define a primary index -How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi_index-table.md), and as par of the definition of the multi index table, the definition of a primary index is mandatory. You can find in the how to section linked previously the full example of a multi index table including the primary index definition. +How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index is mandatory. You can find in the how to section linked previously the full example of a multi index table including the primary index definition. For a quick reference of how a primary index is defined see below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index d739f8c1f7..2d755373f3 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,6 +1,6 @@ ## How to define a secondady index -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi_index-table.md). +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 461525dac1..6cbac6098c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -51,4 +51,7 @@ __singleton_example.cpp__ singleton_instance.get().primary_value.value, singleton_instance.get().secondary_value); } -``` \ No newline at end of file +``` + +__Note__ +A full example project demonstrating the instantiation and usage of singleton can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/singleton_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index f1652b426e..a04a2b80e0 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,3 +1,6 @@ ## How to delete data from a multi index table TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 318c53fd0a..330b036a57 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,3 +1,6 @@ ## How to insert data into a multi index table TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md similarity index 100% rename from docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi_index-table.md rename to docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index d46dc3394c..73373a572d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,3 +1,6 @@ ## How to iterate and retreive a multi index table based on secondary index TO DO: add content https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 460ab1668d..0428751c2a 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,3 +1,150 @@ ## How to iterate and retrieve a multi index table -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file + +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +Let's say we have the multi index contract definition example from below: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + ACTION set( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; +}; +``` + +The steps below show how to iterate and retrieve a multi index table. +Let's add to the above multi index example contract an action `print` which gets as parameter an acount name, searches for it in the multi index table using the primary index and prints out the value stored in that row for field `datum` if found, otherwise asserts with a custom message. + +1. In the contract definition __multi_index_example.hpp__ you have to add this: +```cpp + // this is the print action we want to add + ACTION print( name user ); + + // for ease of use, we are defining the action_wrapper for print action + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +``` + +2. And in the contract implementation __multi_index_example.cpp__ add this: +```cpp + ACTION multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "test table not set" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} +``` + +3. Finally the whole definition and implementation files for the contract should look like this: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + ACTION set( name user ); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +__multi_index_example.cpp__ +```cpp +#include + +ACTION multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + + if ( itr == testtab.end() ) { + // user is not already in table, we use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +ACTION multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "test table not set" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} +``` + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 1814a1c616..78e96c521d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,3 +1,6 @@ ## How to modify data in a multi index table TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 9e08cec9ad..eb35782799 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,3 +1,6 @@ ## How to modify the structure of a multi index table TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices \ No newline at end of file +https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +__Note__ +A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file From 5c26927fcb766c2865e2f8eb663bab62ee08bc7e Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 13:58:33 +0300 Subject: [PATCH 021/659] Resolves #623 --- .../how-to-define-a-secondary-index.md | 3 +- ...ti_index-table-based-on-secondary-index.md | 164 +++++++++++++++++- 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 2d755373f3..e16b003a2f 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -27,8 +27,9 @@ __Second__, in the `test_table` alias definition (typedef), add the definition o typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; ``` -The full code with all the changes described above will look like this: +The full contract definition code with all the changes described above will look like this: +__multi_index_example.hpp__ ```cpp #include using namespace eosio; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 73373a572d..90b38ab6e0 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,166 @@ ## How to iterate and retreive a multi index table based on secondary index -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +Prerequisites: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md), like below: + +```cpp +#include +using namespace eosio; + +// multi index example contract class +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + ACTION set( name user ); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary` let's define a third action `bysec` which will do exactly that. + +1. In the contract definition add the new action definition, using the `ACTION` macro and the `eosio::action_wrapper` template like this: + +```cpp + ACTION bysec( name secid ); + + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; +``` + +2. In the contract implementation add the new action implementation like this: + +```cpp +// iterates the multi index table rows using the secondary index and prints the row's values +ACTION multi_index_example::bysec( name secid ) { + // access the secondary index + auto idx = testtab.get_index<"secid"_n>(); + // iterate through secondary index + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + // print each row's values + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); + } +} +``` + +3. The full code for both the contract definition and contract implementation follow: + +__multi_index_example.hpp__ +```cpp +#include +using namespace eosio; + +// multi index example contract class +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + + // contract class constructor + multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) + testtab(receiver, receiver.value) { } + + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary index + uint64_t primary_key( ) const { return test_primary.value; } + uint64_t by_secondary( ) const { return secondary.value; } + }; + + // for ease of use we define a type alias `test_tables` + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + // here we declare a data member of type test_tables, it gets instantiated + // in the constructor of our contract class + test_tables testtab; + + ACTION set( name user ); + ACTION print( name user ); + ACTION bysec( name secid ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; + using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; +}; +``` + +__multi_index_example.cpp__ +```cpp +#include + +ACTION multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + + if ( itr == testtab.end() ) { + // user is not already in table, we use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} + +ACTION multi_index_example::print( name user ) { + // searches for the row that corresponds to the user parameter + auto itr = testtab.find(user.value); + + // asserts if the row was found for user parameter, if fails use the given message + check( itr != testtab.end(), "test table not set" ); + + // prints the test_primary and datum fields stored for user parameter + eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); +} + +// iterates the multi index table rows using the secondary index and prints the row's values +ACTION multi_index_example::bysec( name secid ) { + // access the secondary index + auto idx = testtab.get_index<"secid"_n>(); + + // iterate through secondary index + for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { + // print each row's values + eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); + } +} +``` __Note__ A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file From fe75a8d7023e7a294b9cdd5b37a6b217400d448f Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 14:15:04 +0300 Subject: [PATCH 022/659] Corrections and improvements --- .../how-to-define-a-primary-index.md | 2 +- .../how-to-define-a-secondary-index.md | 7 ++++--- .../how-to-instantiate-a-multi-index-table.md | 8 +++++--- ...a-multi_index-table-based-on-secondary-index.md | 14 +++++++++----- ...-to-iterate-and-retrieve-a-multi_index-table.md | 10 ++++++---- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index c12af99096..6a07f89463 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -12,7 +12,7 @@ For a quick reference of how a primary index is defined see below: name test_primary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } }; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index e16b003a2f..e629dfe9a9 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -15,7 +15,7 @@ __First__, you have to add a second field `secondary` to the data structure that name secondary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } uint64_t by_secondary( ) const { return secondary.value; } }; @@ -54,12 +54,13 @@ CONTRACT multi_index_example : public contract { name secondary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; // here we declare a data member of type test_tables, it gets instantiated diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 9e96d2ffd8..0f04896710 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -1,6 +1,7 @@ ## How to instantiate a multi index table -Prerequisites: To instantiate a multi index table you need to make use of the eosio::multi_index template and to define the structure of the table row data first along with the primary index which has to be based on an existing field. The definition of the primary index is mandatory. +Prerequisites: To instantiate a multi index table you need to make use of the eosio::multi_index template, create a struct which can be stored in the multi index table, and define getters on the fields you want to index. Remember that one of these getters must be named "primary_key()", if you don't have this the compiler (eosio-cpp) will generate an error it can't find the field to use as the primary key. + One example to accomplish this is exemplified below. __multi_index_example.hpp__ @@ -27,11 +28,12 @@ CONTRACT multi_index_example : public contract { name test_primary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; // here we declare a data member of type test_tables, it gets instantiated diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 90b38ab6e0..1afc6f6ee6 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,8 @@ ## How to iterate and retreive a multi index table based on secondary index -Prerequisites: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md), like below: +Prerequisites: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). + +Let's work with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: ```cpp #include @@ -26,12 +28,13 @@ CONTRACT multi_index_example : public contract { name secondary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; // here we declare a data member of type test_tables, it gets instantiated @@ -98,12 +101,13 @@ CONTRACT multi_index_example : public contract { name secondary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; // here we declare a data member of type test_tables, it gets instantiated diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 0428751c2a..0e56d2a095 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -28,11 +28,12 @@ CONTRACT multi_index_example : public contract { name test_primary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; // here we declare a data member of type test_tables, it gets instantiated @@ -97,11 +98,12 @@ CONTRACT multi_index_example : public contract { name test_primary; // additional data stored in table row uint64_t datum; - // mandatory definition for primary index + // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables` + // for ease of use we define a type alias `test_tables`, based on the multi_index + // template type, parametarized with the test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; // here we declare a data member of type test_tables, it gets instantiated From e6445313e4b96a13d2bd5e5ffeb03f91035cf109 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 15:49:52 +0300 Subject: [PATCH 023/659] Resolves #621 #625 --- .../how-to-define-a-primary-index.md | 35 ++++++++++++------- .../how-to-define-a-secondary-index.md | 8 ++--- ...to-insert-data-into-a-multi-index-table.md | 22 ++++++++++-- .../how-to-instantiate-a-multi-index-table.md | 8 ++--- ...ti_index-table-based-on-secondary-index.md | 16 ++++----- ...terate-and-retrieve-a-multi_index-table.md | 16 ++++----- ...w-to-modify-data-in-a-multi-index-table.md | 20 +++++++++-- 7 files changed, 84 insertions(+), 41 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 6a07f89463..2be47ee5ae 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,22 +1,31 @@ ## How to define a primary index -How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index is mandatory. You can find in the how to section linked previously the full example of a multi index table including the primary index definition. +How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index key getter is mandatory. You can find in the section linked previously the full example of a multi index table including the primary index definition. -For a quick reference of how a primary index is defined see below: +For a quick reference of how a multi index table and the primary key index getter are defined see below: ```cpp - // ... + // ... - TABLE test_table { - // this field is used later for definition of the primary index - name test_primary; - // additional data stored in table row - uint64_t datum; - // mandatory definition for primary key getter - uint64_t primary_key( ) const { return test_primary.value; } - }; - - // ... + // the data structure which defines each row of the table + TABLE test_table { + // this field is used later for definition of the primary index + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + // ... + + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; + + // the multi index table instance declared as a data member of type test_tables + test_tables testtab; ``` __Note__ diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index e629dfe9a9..5281bee67c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -59,12 +59,12 @@ CONTRACT multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 330b036a57..7e6132ecf6 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,6 +1,24 @@ ## How to insert data into a multi index table -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To insert data into a multi index table you make use of the multi index table iterator to find out if the data doesn't already exist and then use the `emplace` method to make the insertion, see below: + +```cpp +ACTION multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + + if ( itr == testtab.end() ) { + // user is not already in table, we use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; + u.datum = 0; + }); + } +} +``` __Note__ A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 0f04896710..eebced274d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -32,12 +32,12 @@ CONTRACT multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 1afc6f6ee6..6dbac9aefc 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -33,12 +33,12 @@ CONTRACT multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); @@ -106,12 +106,12 @@ CONTRACT multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name, the + // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 0e56d2a095..92158aeb8d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -32,12 +32,12 @@ CONTRACT multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); @@ -102,12 +102,12 @@ CONTRACT multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // for ease of use we define a type alias `test_tables`, based on the multi_index - // template type, parametarized with the test_table data structure, and the secondary index + // the multi index type definition, for ease of use we define a type alias `test_tables`, + // based on the multi_index template type, parametarized with a random name and + // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; - // here we declare a data member of type test_tables, it gets instantiated - // in the constructor of our contract class + // the multi index table instance declared as a data member of type test_tables test_tables testtab; ACTION set( name user ); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 78e96c521d..bb8b57b3fb 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,6 +1,22 @@ ## How to modify data in a multi index table -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To modify data from a multi index table you make use of the multi index table iterator to find out if the data exists first, and then use the `modidfy` method to make the update, see below: + +```cpp +ACTION multi_index_example::mod( name user, uint32_t n ) { + // check if the user already exists + auto itr = testtab.find(user.value); + check( itr != testtab.end(), "test table not set" ); + + // if we got so far it means user exist so we can update its datum field + testtab.modify( itr, _self, [&]( auto& row ) { + row.secondary = user; + row.datum = n; + }); +} +``` __Note__ A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file From c86b6d8e7cb07ed40bbb5ad56623afb0f934e202 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 16:09:22 +0300 Subject: [PATCH 024/659] Resolves #620 --- ...to-delete-data-from-a-multi-index-table.md | 21 +++++++++++++++++-- ...ti_index-table-based-on-secondary-index.md | 2 +- ...terate-and-retrieve-a-multi_index-table.md | 4 ++-- ...w-to-modify-data-in-a-multi-index-table.md | 4 ++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index a04a2b80e0..70757e1c38 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,6 +1,23 @@ ## How to delete data from a multi index table -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices + +Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). + +To delete data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `delete` method to delete the row from table, see below: + +```cpp +ACTION multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { + printf("user does not exist in table, nothing to delete" ); + return; + } + + // if we got so far it means user exists so we can delete it using + // the iterator found based on its primary key + testtab.erase( itr ); +} +``` __Note__ A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 6dbac9aefc..2e20443cdd 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -147,7 +147,7 @@ ACTION multi_index_example::print( name user ) { auto itr = testtab.find(user.value); // asserts if the row was found for user parameter, if fails use the given message - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); // prints the test_primary and datum fields stored for user parameter eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 92158aeb8d..c480212bab 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -65,7 +65,7 @@ Let's add to the above multi index example contract an action `print` which gets auto itr = testtab.find(user.value); // asserts if the row was found for user parameter, if fails use the given message - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); // prints the test_primary and datum fields stored for user parameter eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); @@ -141,7 +141,7 @@ ACTION multi_index_example::print( name user ) { auto itr = testtab.find(user.value); // asserts if the row was found for user parameter, if fails use the given message - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); // prints the test_primary and datum fields stored for user parameter eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index bb8b57b3fb..7d81f9cbea 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -2,13 +2,13 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To modify data from a multi index table you make use of the multi index table iterator to find out if the data exists first, and then use the `modidfy` method to make the update, see below: +To modify data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `modidfy` method to make the update, see below: ```cpp ACTION multi_index_example::mod( name user, uint32_t n ) { // check if the user already exists auto itr = testtab.find(user.value); - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); // if we got so far it means user exist so we can update its datum field testtab.modify( itr, _self, [&]( auto& row ) { From 680b2a686a338b15ee21a6d172fade0126fa41cf Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 16:09:59 +0300 Subject: [PATCH 025/659] Add del action to the multi index table example --- .../include/multi_index_example.hpp | 15 +++++++++------ .../src/multi_index_example.cpp | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/examples/multi_index_example/include/multi_index_example.hpp b/examples/multi_index_example/include/multi_index_example.hpp index ef4905ffea..dc2b591d79 100644 --- a/examples/multi_index_example/include/multi_index_example.hpp +++ b/examples/multi_index_example/include/multi_index_example.hpp @@ -7,11 +7,6 @@ CONTRACT multi_index_example : public contract { multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - ACTION set(name user); - ACTION print( name user ); - ACTION bysec( name secid ); - ACTION mod( name user, uint32_t n ); - TABLE test_table { name test_primary; name secondary; @@ -22,9 +17,17 @@ CONTRACT multi_index_example : public contract { typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + test_tables testtab; + + ACTION set(name user); + ACTION print( name user ); + ACTION bysec( name secid ); + ACTION mod( name user, uint32_t n ); + ACTION del( name user ); + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; - test_tables testtab; + using del_action = action_wrapper<"del"_n, &multi_index_example::del>; }; diff --git a/examples/multi_index_example/src/multi_index_example.cpp b/examples/multi_index_example/src/multi_index_example.cpp index c784f406ef..09074da094 100644 --- a/examples/multi_index_example/src/multi_index_example.cpp +++ b/examples/multi_index_example/src/multi_index_example.cpp @@ -12,7 +12,7 @@ ACTION multi_index_example::set( name user ) { ACTION multi_index_example::print( name user ) { auto itr = testtab.find(user.value); - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); } @@ -26,9 +26,22 @@ ACTION multi_index_example::bysec( name secid ) { ACTION multi_index_example::mod( name user, uint32_t n ) { auto itr = testtab.find(user.value); - check( itr != testtab.end(), "test table not set" ); + check( itr != testtab.end(), "user does not exist in table" ); testtab.modify( itr, _self, [&]( auto& row ) { row.secondary = user; row.datum = n; }); } + +ACTION multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { + printf("user does not exist in table, nothing to delete" ); + return; + } + + // if we got so far it means user exists so we can delete it using + // the iterator found based on its primary key + testtab.erase( itr ); +} From 202bf878251594084709908597011ecde03208db Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 16:15:10 +0300 Subject: [PATCH 026/659] Resolves #617 --- .../02_multi-index/how-to-define-a-primary-index.md | 2 +- .../02_multi-index/how-to-instantiate-a-multi-index-table.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 2be47ee5ae..567f210c36 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,6 +1,6 @@ ## How to define a primary index -How to declare and instantiate an instance of a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index key getter is mandatory. You can find in the section linked previously the full example of a multi index table including the primary index definition. +How to declare and instantiate a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index key getter is mandatory. You can find in the section linked previously the full example of a multi index table including the primary index definition. For a quick reference of how a multi index table and the primary key index getter are defined see below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index eebced274d..492295fad6 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to instantiate a multi index table -Prerequisites: To instantiate a multi index table you need to make use of the eosio::multi_index template, create a struct which can be stored in the multi index table, and define getters on the fields you want to index. Remember that one of these getters must be named "primary_key()", if you don't have this the compiler (eosio-cpp) will generate an error it can't find the field to use as the primary key. +Prerequisites: To instantiate a multi index table you need to make use of the `eosio::multi_index` template, create a struct which can be stored in the multi index table, and define getters on the fields you want to index. Remember that one of these getters must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error it can't find the field to use as the primary key. One example to accomplish this is exemplified below. From 5eca9de3fc03bcaac081b4168747a9e7548b13a0 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 4 Sep 2019 17:13:09 +0300 Subject: [PATCH 027/659] Resolves #626 --- .../how-to-modify-the-structure-of-a-multi_index-table.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index eb35782799..127a511bcc 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,6 +1,3 @@ ## How to modify the structure of a multi index table -TO DO: add content -https://dash.readme.io/project/eosio-home/v2.3.9/docs/secondary-indices -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +Currently on EOSIO platform the multi index table structure can not be modified after the multi index table has been defined and deployed through a contract the first time. That is very important to know when you design your table structure based on your requirements. Subsequent versions of your contract if they will need to modify the table structure the only way to do it would be by creating an adition table with the new structure and either migrate the old data to the new table or use both tables. If a migration strategy of old data to the new table will be implemented very good care has to be employed while doing it to avoid loss of data. From b4bca3915a9a2c54a78110fa4302a0d64eeabf8a Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 14:01:37 +0300 Subject: [PATCH 028/659] Adding binary extension tutorial and content for 'modifying the structure of a multi index table' section. Resolves #626 --- ...fy-the-structure-of-a-multi_index-table.md | 31 +- docs/09_tutorials/01_binary-extension.md | 718 ++++++++++++++++++ 2 files changed, 748 insertions(+), 1 deletion(-) create mode 100644 docs/09_tutorials/01_binary-extension.md diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 127a511bcc..3ff8ebe516 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,3 +1,32 @@ ## How to modify the structure of a multi index table -Currently on EOSIO platform the multi index table structure can not be modified after the multi index table has been defined and deployed through a contract the first time. That is very important to know when you design your table structure based on your requirements. Subsequent versions of your contract if they will need to modify the table structure the only way to do it would be by creating an adition table with the new structure and either migrate the old data to the new table or use both tables. If a migration strategy of old data to the new table will be implemented very good care has to be employed while doing it to avoid loss of data. +Modifying a multi index table structure that has already been deployed to an EOSIO based blockchain has to be done depending on your requirements by following different strategies which we are outlining below: + +### If you don't mind to lose the existing data + +If you don't mind to lose the data from the initial table you can follow these two steps +- Erase all records from first table +- Deploy a new contract with modified table structure + +### If you want to keep the existing data + +If you want to keep the existing data there are two ways to do it: + +#### 1. Using binary extentions +To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md) + +#### 2. Migrate the existing data to a second table + +##### A. Migration without downtime, but slower + +1. Create the new version of your multi index table alongside the old one, +2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, +3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. + +##### B. Migration with downtime, but faster + +If you prefer less code complexity and can accept downtime for your application: +1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, +2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. + +Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) \ No newline at end of file diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md new file mode 100644 index 0000000000..3f3d09d674 --- /dev/null +++ b/docs/09_tutorials/01_binary-extension.md @@ -0,0 +1,718 @@ +## eosio::binary_extension + +Let's fully explain what the `eosio::binary_extension` type is, what it does, and why we need it for contract upgrades in certain situations. + +You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in file: `eosio.cdt/libraries/eosiolib/core/eosio/binary_extension.hpp`. + +Our primary concern when using this type is when we are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. + +By wrapping the new field in an `eosio::binary_extension`, you are enabling your contract to be backwards compatible for future use. Note that this new field/parameter **MUST** be appended at the end of a data structure (this is due to implementation details in `eosio::multi_index`, which relies on the `boost::multi_index` type), or at the end of the parameter list in an action declaration. + +If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be uncallable. + +
+ +But let's see how the `eosio::binary_extension` type works with a good example. + +Take a moment to study this smart contract and its corresponding `.abi`. + +This contract not only serves as a good example to the `eosio::binary_extension` type, but can also be used as a gateway for developing smart contracts on the eosio protocol. + +**binary_extension_contract.hpp** + +```c++ +#include // eosio::contract +#include // eosio::binary_extension +#include // eosio::datastream +#include // eosio::name +#include // eosio::indexed_by, eosio::multi_index +#include // eosio::print_f + +class [[eosio::contract]] binary_extension_contract : public eosio::contract { +public: + using contract::contract; + binary_extension_contract(eosio::name receiver, eosio::name code, eosio::datastream ds) + : contract{receiver, code, ds}, _table{receiver, receiver.value} + { } + + [[eosio::action]] void regpkey (eosio::name primary_key); ///< Register primary key. + [[eosio::action]] void printbyp(eosio::name primary_key); ///< Print by primary key. + [[eosio::action]] void printbys(eosio::name secondary_key); ///< Print by secondary key. + [[eosio::action]] void modifyp (eosio::name primary_key, eosio::name n); ///< Modify primary key by primary key. + [[eosio::action]] void modifys (eosio::name primary_key, eosio::name n); ///< Modify secondary key by primary key. + + struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } + }; + + using index1 = eosio::indexed_by<"index1"_n, eosio::const_mem_fun>; + using index2 = eosio::indexed_by<"index2"_n, eosio::const_mem_fun>; + using table = eosio::multi_index<"table"_n, structure, index1, index2>; + +private: + table _table; +}; + +``` + +**binary_extension_contract.cpp** + +```c++ +#include "binary_extension_contract.hpp" + +using eosio::name; + +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbyp(eosio::name primary_key) { + eosio::print_f("`printbyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value) }; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; printing.\n", primary_key.to_string()); + eosio::print_f("{%, %}\n", iter->_primary_key, iter->_secondary_key); + } + else { + eosio::print_f("`_primary_key`: % not found; not printing.\n", primary_key.to_string()); + } + + eosio::print_f("`printbyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::printbys(eosio::name secondary_key) { + eosio::print_f("`printbys` executing.\n"); + + auto index{_table.get_index<"index2"_n>()}; + auto iter {index.find(secondary_key.value)}; + + if (iter != _table.get_index<"index2"_n>().end()) { + eosio::print_f("`_secondary_key`: % found; printing.\n", secondary_key.to_string()); + printbyp(iter->_primary_key); + } + else { + eosio::print_f("`_secondary_key`: % not found; not printing.\n", secondary_key.to_string()); + } + + eosio::print_f("`printbys` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifyp(eosio::name primary_key, name n) { + eosio::print_f("`modifyp` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_primary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._primary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_primary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifyp` finished executing.\n"); +} + +[[eosio::action]] void binary_extension_contract::modifys(eosio::name primary_key, name n) { + eosio::print_f("`modifys` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; + auto iter {index.find(primary_key.value)}; + + if (iter != _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % found; modifying `_secondary_key`.\n", primary_key.to_string()); + index.modify(iter, _self, [&](auto& row) { + row._secondary_key = n; + }); + } + else { + eosio::print_f("`_primary_key`: % not found; not modifying `_secondary_key`.\n", primary_key.to_string()); + } + + eosio::print_f("`modifys` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** + +```javascript +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "modifyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "modifys", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "n", + "type": "name" + } + ] + }, + { + "name": "printbyp", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "printbys", + "base": "", + "fields": [ + { + "name": "secondary_key", + "type": "name" + } + ] + }, + { + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] + }, + { + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] + } + ], + "actions": [ + { + "name": "modifyp", + "type": "modifyp", + "ricardian_contract": "" + }, + { + "name": "modifys", + "type": "modifys", + "ricardian_contract": "" + }, + { + "name": "printbyp", + "type": "printbyp", + "ricardian_contract": "" + }, + { + "name": "printbys", + "type": "printbys", + "ricardian_contract": "" + }, + { + "name": "regpkey", + "type": "regpkey", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "table", + "type": "structure", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [] +} +``` + +
+ +Take note of the action `regpkey`, and the struct `structure` in `con.hpp` and `con.cpp`; the parts of the contract we will be upgrading. + +**binary_extension_contract.hpp** + +```c++ +[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```c++ +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```c++ +[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + row._secondary_key = "nothin"_n; + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +And their corresponding sections in the `.abi` files: + +**binary_extension_contract.abi** + +```javascript +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + } + ] +} +``` + +```javascript +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + } + ] +} +``` + +
+ +Now, let's start up a blockchain instance, compile this smart contract, and test it out. + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 6c5c7d869a5be67611869b5f300bc452bc57d258d11755f12ced99c7d7fe154c 4160 bytes 729 us +# eosio <= eosio::setcode "0000000000ea30550000d7600061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea3055d1020e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Next, let's push some data to our contract. + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 3c708f10dcbf4412801d901eb82687e82287c2249a29a2f4e746d0116d6795f0 104 bytes 248 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Finally, let's read back the data we have just written. + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: e9b77d3cfba322a7a3a93970c0c883cb8b67e2072a26d714d46eef9d79b2f55e 104 bytes 227 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +
+ +Now, let's upgrade the smart contract by adding a new field to the table and a new parameter to an action while **NOT** wrapping the new field/parameter in an `eosio::binary_extension` type and see what happens: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; ++ if (secondary_key) { ++ row._secondary_key = secondary_key; ++ } ++ else { + row._secondary_key = "nothin"_n; ++ } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" ++ }, ++ { ++ "name": "secondary_key", ++ "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" ++ }, ++ { ++ "name": "_non_binary_extension_key", ++ "type": "name" + } + ] +} +``` + +Next, let's upgrade the contract and try to read from our table and write to our table the original way: + +``` +~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm +``` + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: b8ea485842fa5645e61d35edd97e78858e062409efcd0a4099d69385d9bc6b3e 4408 bytes 664 us +# eosio <= eosio::setcode "0000000000ea30550000a2660061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60067... +# eosio <= eosio::setabi "0000000000ea305583030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +Error 3050003: eosio_assert_message assertion failure +Error Details: +assertion failure with message: read +``` + +Whoops! We aren't able to read the data we've previously written to our table! + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +Error 3015014: Pack data exception +Error Details: +Missing field 'secondary_key' in input object while processing struct 'regpkey' +``` + +Whoops! We aren't able to write to our table the original way with the upgraded action either! + +
+ +Ok, let's back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: + +**binary_extension_contract.hpp** + +```diff ++[[eosio::action]] void regpkey (eosio::name primary_key. eosio::binary_extension secondary_key); +-[[eosio::action]] void regpkey (eosio::name primary_key, eosio::name secondary_key); +``` + +```diff +struct [[eosio::table]] structure { + eosio::name _primary_key; + eosio::name _secondary_key; ++ eosio::binary_extension _binary_extension_key; +- eosio::name _non_binary_extension_key; + + uint64_t primary_key() const { return _primary_key.value; } + uint64_t secondary_key() const { return _secondary_key.value; } +}; +``` + +**binary_extension_contract.cpp** + +```diff ++[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, binary_extension secondary_key) { +-[[eosio::action]] void binary_extension_contract::regpkey(name primary_key, name secondary_key) { + eosio::print_f("`regpkey` executing.\n"); + + auto index{_table.get_index<"index1"_n>()}; ///< `index` represents `_table` organized by `index1`. + auto iter {index.find(primary_key.value) }; ///< Note: the type returned by `index.find` is different than the type returned by `_table.find`. + + if (iter == _table.get_index<"index1"_n>().end()) { + eosio::print_f("`_primary_key`: % not found; registering.\n", primary_key.to_string()); + _table.emplace(_self, [&](auto& row) { + row._primary_key = primary_key; + if (secondary_key) { ++ row._secondary_key = secondary_key.value(); +- row._secondary_key = secondary_key; + } + else { + row._secondary_key = "nothin"_n; + } + }); + } + else { + eosio::print_f("`_primary_key`: % found; not registering.\n", primary_key.to_string()); + } + + eosio::print_f("`regpkey` finished executing.\n"); +} +``` + +**binary_extension_contract.abi** +```diff +{ + "name": "regpkey", + "base": "", + "fields": [ + { + "name": "primary_key", + "type": "name" + }, + { + "name": "secondary_key", ++ "type": "name$" +- "type": "name" + } + ] +} +``` + +```diff +{ + "name": "structure", + "base": "", + "fields": [ + { + "name": "_primary_key", + "type": "name" + }, + { + "name": "_secondary_key", + "type": "name" + }, + { ++ "name": "_binary_extension_key", ++ "type": "name$" +- "name": "_non_binary_extension_key", +- "type": "name" + } + ] +} +``` + +Note the `$` after the types now; this indicates that this type is an `eosio::binary_extension` type field. +```diff +{ + "name": "secondary_key", ++ "type": "name$" +- "type": "name" +} +``` + +```diff +{ + "name": "_binary_extension_key", ++ "type": "name$" +- "type": "name" +} +``` + +Now, let's upgrade the contract again and try to read/write from/to our table: + +``` +~/binary_extension_contract $ cleos set contract eosio ./ +``` + +``` +Reading WASM from /Users/john.debord/binary_extension_contract/binary_extension_contract.wasm... +Publishing contract... +executed transaction: 497584d4e43ec114dbef83c134570492893f49eacb555d0cd47d08ea4a3a72f7 4696 bytes 648 us +# eosio <= eosio::setcode "0000000000ea30550000cb6a0061736d01000000018f011760000060017f0060027f7f0060037f7f7f017f6000017e60017... +# eosio <= eosio::setabi "0000000000ea305581030e656f73696f3a3a6162692f312e310006076d6f646966797000020b7072696d6172795f6b65790... +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio +``` + +``` +executed transaction: 6108f3206e1824fe3a1fdcbc2fe733f38dc07ae3d411a1ccf777ecef56ddec97 104 bytes 224 us +# eosio <= eosio::printbyp {"primary_key":"eosio.name"} +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`printbyp` executing. +`_primary_key`: eosio.name found; printing. +{eosio.name, nothin} +`printbyp` finished executing. +[(eosio,printbyp)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +``` +~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio +``` + +``` +executed transaction: 75a135d1279a9c967078b0ebe337dc0cd58e1ccd07e370a899d9769391509afc 104 bytes 227 us +# eosio <= eosio::regpkey {"primary_key":"eosio.name2"} +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT BEGIN ===================== +`regpkey` executing. +`_primary_key`: eosio.name2 not found; registering. +`regpkey` finished executing. +[(eosio,regpkey)->eosio]: CONSOLE OUTPUT END ===================== +warning: transaction executed locally, but may not be confirmed by the network yet +``` + +Nice! The smart contract is now backwards compatible for the future use of its tables and/or actions. + +
+ +Just keep these simple rules in mind when upgrading a smart contract. +If you are adding a new field to a struct currently in use by a `eosio::multi_index` be **SURE** to: +- add the field at the end of the struct. +- wrap the type using an `eosio::binary_extension` type. From 3ecce78d7214865909412b497b02bfb878f13004 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 14:06:24 +0300 Subject: [PATCH 029/659] Cosmetic changes. --- ...fy-the-structure-of-a-multi_index-table.md | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 3ff8ebe516..a7f9bc1fee 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -2,31 +2,32 @@ Modifying a multi index table structure that has already been deployed to an EOSIO based blockchain has to be done depending on your requirements by following different strategies which we are outlining below: -### If you don't mind to lose the existing data +### 1. If you don't mind to lose the existing data -If you don't mind to lose the data from the initial table you can follow these two steps -- Erase all records from first table -- Deploy a new contract with modified table structure +If you don't mind to lose the data from the initial table you can follow these two steps: +1.1. Erase all records from first table +1.2.Deploy a new contract with modified table structure -### If you want to keep the existing data +### 2. If you want to keep the existing data If you want to keep the existing data there are two ways to do it: -#### 1. Using binary extentions +#### 2.1. Using binary extentions To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md) -#### 2. Migrate the existing data to a second table +#### 2.2. Migrate the existing data to a second table -##### A. Migration without downtime, but slower +##### 2.2.1. Migration without downtime, but slower -1. Create the new version of your multi index table alongside the old one, -2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, -3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. +a. Create the new version of your multi index table alongside the old one, +b. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, +c. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. -##### B. Migration with downtime, but faster +##### 2.2.2. Migration with downtime, but faster If you prefer less code complexity and can accept downtime for your application: -1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, -2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. + +a. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, +b. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) \ No newline at end of file From 2c7fc5f35b87e1951215f1b04cd65e90768cf158 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 14:08:28 +0300 Subject: [PATCH 030/659] Correcting the final note. --- ...-modify-the-structure-of-a-multi_index-table.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index a7f9bc1fee..010376b96c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -13,21 +13,21 @@ If you don't mind to lose the data from the initial table you can follow these t If you want to keep the existing data there are two ways to do it: #### 2.1. Using binary extentions -To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md) +To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md). #### 2.2. Migrate the existing data to a second table ##### 2.2.1. Migration without downtime, but slower -a. Create the new version of your multi index table alongside the old one, -b. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, -c. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. +1. Create the new version of your multi index table alongside the old one, +2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, +3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. ##### 2.2.2. Migration with downtime, but faster If you prefer less code complexity and can accept downtime for your application: -a. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, -b. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. +1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, +2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. -Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) \ No newline at end of file +__Note__: Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) \ No newline at end of file From eaeb6bba0e1320b5f1c5737d078cc5a0bef9a6cf Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 14:10:01 +0300 Subject: [PATCH 031/659] update the headlines size --- ...-modify-the-structure-of-a-multi_index-table.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 010376b96c..6251c53329 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,29 +1,29 @@ -## How to modify the structure of a multi index table +# How to modify the structure of a multi index table Modifying a multi index table structure that has already been deployed to an EOSIO based blockchain has to be done depending on your requirements by following different strategies which we are outlining below: -### 1. If you don't mind to lose the existing data +## 1. If you don't mind to lose the existing data If you don't mind to lose the data from the initial table you can follow these two steps: 1.1. Erase all records from first table 1.2.Deploy a new contract with modified table structure -### 2. If you want to keep the existing data +## 2. If you want to keep the existing data If you want to keep the existing data there are two ways to do it: -#### 2.1. Using binary extentions +### 2.1. Using binary extentions To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md). -#### 2.2. Migrate the existing data to a second table +### 2.2. Migrate the existing data to a second table -##### 2.2.1. Migration without downtime, but slower +#### 2.2.1. Migration without downtime, but slower 1. Create the new version of your multi index table alongside the old one, 2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, 3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. -##### 2.2.2. Migration with downtime, but faster +#### 2.2.2. Migration with downtime, but faster If you prefer less code complexity and can accept downtime for your application: From 64ed5fa9af065e9b8e7c1e85b5eb67b99a68fb28 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 15:23:36 +0300 Subject: [PATCH 032/659] Adding corrections to two sections --- .../how_to_restrict_access_to_an_action_by_user.md | 2 +- ...to_push_a_deferred_transaction_from_a_smart_contract.md | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index cb587c0108..703d06fdf8 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -16,7 +16,7 @@ void hi( name user ) { ### Using require_auth2 -The below code is enforcing the action hi to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. +The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. ```cpp #include diff --git a/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md b/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md index d16eac1687..f57a664740 100644 --- a/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md +++ b/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md @@ -1,10 +1,7 @@ ## How to push a deferred transaction from a smart contract to another -Excerpt from: https://developers.eos.io/eosio-nodeos/docs/communication-model#section-deferred-communication +Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. -"Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. +As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. -As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction." - -TO DO: review the content below, is it ok to make this statement here? Because of all considerations mentioned above we do not reccommend the use of deferred transactions and we are considering to deprecate them in the future versions. From b54fb8a31269e50285549d5a0f104911fc13090a Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 15:28:09 +0300 Subject: [PATCH 033/659] fix broken link to binary extension md file --- .../how-to-modify-the-structure-of-a-multi_index-table.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 6251c53329..c64de3e2af 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -13,7 +13,7 @@ If you don't mind to lose the data from the initial table you can follow these t If you want to keep the existing data there are two ways to do it: ### 2.1. Using binary extentions -To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/binary-extension.md). +To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). ### 2.2. Migrate the existing data to a second table From 863db7ad8e52bc495b212d93dd231f701e468e04 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 16:31:40 +0300 Subject: [PATCH 034/659] Adding variants documentation. --- ...fy-the-structure-of-a-multi_index-table.md | 9 +++-- docs/09_tutorials/01_binary-extension.md | 6 ++-- docs/09_tutorials/02_abi_variants.md | 35 +++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 docs/09_tutorials/02_abi_variants.md diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index c64de3e2af..eed9e9b199 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -15,15 +15,18 @@ If you want to keep the existing data there are two ways to do it: ### 2.1. Using binary extentions To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). -### 2.2. Migrate the existing data to a second table +### 2.2. Using ABI variants +To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi_variants.md). -#### 2.2.1. Migration without downtime, but slower +### 2.3. Migrate the existing data to a second table + +#### 2.3.1. Migration without downtime, but slower 1. Create the new version of your multi index table alongside the old one, 2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, 3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. -#### 2.2.2. Migration with downtime, but faster +#### 2.3.2. Migration with downtime, but faster If you prefer less code complexity and can accept downtime for your application: diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md index 3f3d09d674..adf5fbc0f3 100644 --- a/docs/09_tutorials/01_binary-extension.md +++ b/docs/09_tutorials/01_binary-extension.md @@ -714,5 +714,7 @@ Nice! The smart contract is now backwards compatible for the future use of its t Just keep these simple rules in mind when upgrading a smart contract. If you are adding a new field to a struct currently in use by a `eosio::multi_index` be **SURE** to: -- add the field at the end of the struct. -- wrap the type using an `eosio::binary_extension` type. +- add the field at the end of the struct, +- and wrap the type using an `eosio::binary_extension` type. + +Also, there are a few restrictions you have to be aware of which are outlined [here](https://github.com/EOSIO/eos/issues/5600). \ No newline at end of file diff --git a/docs/09_tutorials/02_abi_variants.md b/docs/09_tutorials/02_abi_variants.md new file mode 100644 index 0000000000..f6d2ca3adf --- /dev/null +++ b/docs/09_tutorials/02_abi_variants.md @@ -0,0 +1,35 @@ +## ABI variants + +ABI Text format supports a section at the same level as types, structs, etc. named variants. Example: + +```json +"variants": [ + { + "name": "operation_amount", + "types": [ + "extended_asset", + "float64", + "time_point_sec" + ] + }, + { + "name": "operation_subaccount", + "types": [ + "name", + "extended_symbol", + "symbol_code" + ] + }, + { + "name": "subop", + "types": [ + "event", + "balance_change", + "set_value", + "error" + ] + } +], +``` + +The implementation for this section can be found [here](https://github.com/EOSIO/eos/pull/5652). From 7675e481acaa516a60eeea3e2fae7b02dabee8d6 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 16:32:35 +0300 Subject: [PATCH 035/659] Rename abi variants md file --- docs/09_tutorials/{02_abi_variants.md => 02_abi-variants.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/09_tutorials/{02_abi_variants.md => 02_abi-variants.md} (100%) diff --git a/docs/09_tutorials/02_abi_variants.md b/docs/09_tutorials/02_abi-variants.md similarity index 100% rename from docs/09_tutorials/02_abi_variants.md rename to docs/09_tutorials/02_abi-variants.md From 634da167b2e0c3ebde28db06edead175674efbe1 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 16:33:20 +0300 Subject: [PATCH 036/659] correct the link the abi variants md file --- .../how-to-modify-the-structure-of-a-multi_index-table.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index eed9e9b199..526cc5f250 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -16,7 +16,7 @@ If you want to keep the existing data there are two ways to do it: To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). ### 2.2. Using ABI variants -To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi_variants.md). +To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi-variants.md). ### 2.3. Migrate the existing data to a second table From c83886dd11e812a65d2bfff046997ac3538dfcb9 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 16:47:50 +0300 Subject: [PATCH 037/659] Improve on the abi variants documentation --- docs/09_tutorials/02_abi-variants.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index f6d2ca3adf..5879dc0ea3 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -1,6 +1,7 @@ ## ABI variants -ABI Text format supports a section at the same level as types, structs, etc. named variants. Example: +ABI text format supports a section at the same level as types, structs, etc. named variants. +Example: ```json "variants": [ @@ -32,4 +33,8 @@ ABI Text format supports a section at the same level as types, structs, etc. nam ], ``` -The implementation for this section can be found [here](https://github.com/EOSIO/eos/pull/5652). +Once a table has a variant, it's safe to add more types to the variant over time. It works like a cpp union type, multiple types can be defined in a variant yet only one of those type data can be stored at a time. So this way, if at a later time I want to change the type of a column for my deployed table, I can add that type to the variant `types` array and thus new rows inserted in the table could have this new type added. + +TO DO: Any restrictions, pitfalls, gotchas, things to be aware of? + +__Note__: The implementation for this section can be found [here](https://github.com/EOSIO/eos/pull/5652). From 98f5fbf0440444e16a2288d340459c582831a53d Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 5 Sep 2019 16:55:09 +0300 Subject: [PATCH 038/659] More explanations on the abi variants tutorial --- docs/09_tutorials/02_abi-variants.md | 40 +++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 5879dc0ea3..a15d119749 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -1,7 +1,7 @@ ## ABI variants -ABI text format supports a section at the same level as types, structs, etc. named variants. -Example: +ABI text format supports a section at the same level as `types`, `structs`, etc. named `variants`. +__Example:__ ```json "variants": [ @@ -18,7 +18,6 @@ Example: "types": [ "name", "extended_symbol", - "symbol_code" ] }, { @@ -33,7 +32,40 @@ Example: ], ``` -Once a table has a variant, it's safe to add more types to the variant over time. It works like a cpp union type, multiple types can be defined in a variant yet only one of those type data can be stored at a time. So this way, if at a later time I want to change the type of a column for my deployed table, I can add that type to the variant `types` array and thus new rows inserted in the table could have this new type added. +Once a table has a variant, it's safe to add more types to the variant over time. It works like a cpp union type, multiple types can be defined in a variant yet only one of those types data can be stored at a time. + +So this way, let's say I want to change the type of a column with variant `operation_subaccount` from `name` to `symbol_code` for my deployed table with the ABI text defined above, I can add the `symbol_code` type to the variant's `types` array and thus new rows inserted in the table can have data of type `symbol_code` for the column with variant `operation_subaccount`. +The ABI text section defining the variants would look like this: + +```json +"variants": [ + { + "name": "operation_amount", + "types": [ + "extended_asset", + "float64", + "time_point_sec" + ] + }, + { + "name": "operation_subaccount", + "types": [ + "name", + "extended_symbol", + "symbol_code" + ] + }, + { + "name": "subop", + "types": [ + "event", + "balance_change", + "set_value", + "error" + ] + } +], +``` TO DO: Any restrictions, pitfalls, gotchas, things to be aware of? From 9110569003e2c0a57ff6f86818281e5717084328 Mon Sep 17 00:00:00 2001 From: jgiszczak Date: Thu, 5 Sep 2019 11:43:23 -0500 Subject: [PATCH 039/659] Add missing header formatting tags. --- .../how-to-modify-the-structure-of-a-multi_index-table.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 526cc5f250..aace329fe1 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -5,8 +5,8 @@ Modifying a multi index table structure that has already been deployed to an EOS ## 1. If you don't mind to lose the existing data If you don't mind to lose the data from the initial table you can follow these two steps: -1.1. Erase all records from first table -1.2.Deploy a new contract with modified table structure +### 1.1. Erase all records from first table +### 1.2.Deploy a new contract with modified table structure ## 2. If you want to keep the existing data @@ -33,4 +33,4 @@ If you prefer less code complexity and can accept downtime for your application: 1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, 2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. -__Note__: Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) \ No newline at end of file +__Note__: Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) From ede2149141d22ac5ac98f69814472e120f0b5968 Mon Sep 17 00:00:00 2001 From: jgiszczak Date: Thu, 5 Sep 2019 11:45:03 -0500 Subject: [PATCH 040/659] Change new header tags to bulleted list tags. --- .../how-to-modify-the-structure-of-a-multi_index-table.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index aace329fe1..1c1acf1a85 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -5,8 +5,8 @@ Modifying a multi index table structure that has already been deployed to an EOS ## 1. If you don't mind to lose the existing data If you don't mind to lose the data from the initial table you can follow these two steps: -### 1.1. Erase all records from first table -### 1.2.Deploy a new contract with modified table structure +* 1.1. Erase all records from first table +* 1.2. Deploy a new contract with modified table structure ## 2. If you want to keep the existing data From 28e2c20ba13011ac3b14e50f752983e671cc712e Mon Sep 17 00:00:00 2001 From: jgiszczak Date: Thu, 5 Sep 2019 11:51:25 -0500 Subject: [PATCH 041/659] Corrections to language. One more shot at reasonable step prefixes in the first section. --- ...to-modify-the-structure-of-a-multi_index-table.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 1c1acf1a85..3e2b64f5ab 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -1,12 +1,12 @@ # How to modify the structure of a multi index table -Modifying a multi index table structure that has already been deployed to an EOSIO based blockchain has to be done depending on your requirements by following different strategies which we are outlining below: +Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements: ## 1. If you don't mind to lose the existing data If you don't mind to lose the data from the initial table you can follow these two steps: -* 1.1. Erase all records from first table -* 1.2. Deploy a new contract with modified table structure +1. Erase all records from first table +2. Deploy a new contract with modified table structure ## 2. If you want to keep the existing data @@ -22,15 +22,15 @@ To learn how to modify the structure using ABI variants please read this [tutori #### 2.3.1. Migration without downtime, but slower -1. Create the new version of your multi index table alongside the old one, -2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs, +1. Create the new version of your multi index table alongside the old one; +2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs. 3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. #### 2.3.2. Migration with downtime, but faster If you prefer less code complexity and can accept downtime for your application: -1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a big number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a reduced number of rows each time it runs, +1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a large number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a limited number of rows each time it runs; 2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. __Note__: Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) From bfc3a760dd93ce6c9cdc91a16b6368aece519ab2 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 9 Sep 2019 14:38:48 +0300 Subject: [PATCH 042/659] Adding content for ABI variants --- docs/09_tutorials/02_abi-variants.md | 209 ++++++++++++++++++--------- 1 file changed, 144 insertions(+), 65 deletions(-) diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index a15d119749..3d42b30c9f 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -1,72 +1,151 @@ ## ABI variants -ABI text format supports a section at the same level as `types`, `structs`, etc. named `variants`. -__Example:__ - -```json -"variants": [ - { - "name": "operation_amount", - "types": [ - "extended_asset", - "float64", - "time_point_sec" - ] - }, - { - "name": "operation_subaccount", - "types": [ - "name", - "extended_symbol", - ] - }, - { - "name": "subop", - "types": [ - "event", - "balance_change", - "set_value", - "error" - ] - } -], +ABI variants give the flexibility of using more than one type for a defined variable or data member. +In EOSIO the variants are making use of the standard template library `variant` which was introduced in C++ 17. An instance of `std::variant` at any given time either holds a value of one of its alternative types, or in the case of error - no value. Because of this trait, variants can be used to build the multi index table structure and have flexibility in doing it, and used in conjunction with ABI extensions it allows for modification of the structure of an exiting multi index table, a.k.a. table. + +### Use variant when building the multi index table the first time + +To define a `variant` for your table structure one example is shown below + +```cpp + std::variant variant_field; +``` + +This defines `variant` which can hold three different types, one at a time though. +So the contract interface could look like this: + +```diff +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + + TABLE test_table { + name test_primary; + name secondary; + uint64_t datum; ++ std::variant variant_field; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ std::variant get_variant_field()const { ++ return std::visit( ++ [](auto&& arg) -> std::variant { ++ return arg; ++ }, ++ variant_field); + } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + ACTION set(name user); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; +``` + +Notice above the declaration of the `variant_field` data memember and also the declaration and inline implementation for the `get_variant_field()` accessor for this data member. + +In the future, this allows you the flexibility to store in the `variant_field` three different types of data `int8_t`, `int16_t`, and `int32_t`, and also allows you to add more types in the list of supported types for this field. One important thing to keep in mind is that you can only append at the end of the supported types, you can not modify the existing supported types order nor drop one of them, you can only append at the end of the list. That means if you want in the next version of your contract to add also type `int32_t` to the supported list types for this field your contract implementation could look like this: + +```diff +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + + TABLE test_table { + name test_primary; + name secondary; + uint64_t datum; ++ std::variant variant_field; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ std::variant get_variant_field()const { ++ return std::visit( ++ [](auto&& arg) -> std::variant { ++ return arg; ++ }, ++ variant_field); + } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + ACTION set(name user); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; ``` -Once a table has a variant, it's safe to add more types to the variant over time. It works like a cpp union type, multiple types can be defined in a variant yet only one of those types data can be stored at a time. - -So this way, let's say I want to change the type of a column with variant `operation_subaccount` from `name` to `symbol_code` for my deployed table with the ABI text defined above, I can add the `symbol_code` type to the variant's `types` array and thus new rows inserted in the table can have data of type `symbol_code` for the column with variant `operation_subaccount`. -The ABI text section defining the variants would look like this: - -```json -"variants": [ - { - "name": "operation_amount", - "types": [ - "extended_asset", - "float64", - "time_point_sec" - ] - }, - { - "name": "operation_subaccount", - "types": [ - "name", - "extended_symbol", - "symbol_code" - ] - }, - { - "name": "subop", - "types": [ - "event", - "balance_change", - "set_value", - "error" - ] - } -], +Now you can deploy the contract and it will be backwards compatible with the previous existing multi index table. + +### Use variant when changing an already deployed multi index table + +Prerequisites: For exemplification we are going to use the contract defined in this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md). We are assumming you deployed it and now we are going to change the table structure. + +To change the existing table structure we are going to use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). Let's say you want to add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: + +```cpp + eosio::binary_extension> binary_extension_variant_key; +``` + +Notice, the use of the `eosio::binary_extension` template which wraps the `std::variant` template parameterized with the types we want to support for the new data field. The full contract implementation can look like this: + +```diff +#include +#include +using namespace eosio; + +CONTRACT multi_index_example : public contract { + public: + using contract::contract; + multi_index_example( name receiver, name code, datastream ds ) + : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + + TABLE test_table { + name test_primary; + name secondary; + uint64_t datum; ++ eosio::binary_extension> binary_extension_variant_key; + + uint64_t primary_key()const { return test_primary.value; } + uint64_t by_secondary()const { return secondary.value; } ++ eosio::binary_extension> get_binary_extension_variant_field()const { ++ return binary_extension_variant_key; ++ } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; + + test_tables testtab; + + ACTION set(name user); + ACTION print( name user ); + + using set_action = action_wrapper<"set"_n, &multi_index_example::set>; + using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +}; ``` -TO DO: Any restrictions, pitfalls, gotchas, things to be aware of? +N.B. Be aware that we do not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how to ABI gets generated! -__Note__: The implementation for this section can be found [here](https://github.com/EOSIO/eos/pull/5652). +__Note__: The implementation for ABI `variants' section can be found [here](https://github.com/EOSIO/eos/pull/5652). From 2368d127bb456d1960585216e72c5ee606769fc5 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 9 Sep 2019 15:12:04 +0300 Subject: [PATCH 043/659] replace CONTRACT, ACTION and TABLE macros with the [[eosio::...]] corresponding ones --- .../01_compile/02_how-to-configure-cmake.md | 4 +-- .../how-to-define-a-primary-index.md | 2 +- .../how-to-define-a-secondary-index.md | 10 +++---- .../how-to-define-a-singleton.md | 12 ++++---- ...to-delete-data-from-a-multi-index-table.md | 2 +- ...to-insert-data-into-a-multi-index-table.md | 2 +- .../how-to-instantiate-a-multi-index-table.md | 8 ++--- ...ti_index-table-based-on-secondary-index.md | 30 +++++++++---------- ...terate-and-retrieve-a-multi_index-table.md | 22 +++++++------- ...w-to-modify-data-in-a-multi-index-table.md | 2 +- .../07_how-to-use-native-tester.md | 4 +-- docs/09_tutorials/02_abi-variants.md | 24 +++++++-------- 12 files changed, 61 insertions(+), 61 deletions(-) diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md index 06598198dc..688e106905 100644 --- a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -22,11 +22,11 @@ In `test.cpp`: #include using namespace eosio; -CONTRACT test : public eosio::contract { +class [[eosio::contract]] test : public eosio::contract { public: using contract::contract; - ACTION testact( name test ) { + [[eosio::action]] void testact( name test ) { } }; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 567f210c36..ce96a1faae 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -8,7 +8,7 @@ For a quick reference of how a multi index table and the primary key index gette // ... // the data structure which defines each row of the table - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; // additional data stored in table row diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 5281bee67c..596f6f31c9 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -9,7 +9,7 @@ __First__, you have to add a second field `secondary` to the data structure that ```cpp // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; name secondary; @@ -35,7 +35,7 @@ __multi_index_example.hpp__ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -48,7 +48,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; name secondary; @@ -67,8 +67,8 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); - ACTION print( name user ); + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 6cbac6098c..19190c68bc 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -9,7 +9,7 @@ __singleton_example.hpp__ #include using namespace eosio; -CONTRACT singleton_example : public contract { +class [[eosio::contract]] singleton_example : public contract { public: using contract::contract; singleton_example( name receiver, name code, datastream ds ) : @@ -17,10 +17,10 @@ CONTRACT singleton_example : public contract { singleton_instance(receiver, receiver.value) {} - ACTION set( name user, uint64_t value ); - ACTION get( ); + [[eosio::action]] void set( name user, uint64_t value ); + [[eosio::action]] void get( ); - TABLE testtable { + struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; }; @@ -39,14 +39,14 @@ __singleton_example.cpp__ ```cpp #include - ACTION singleton_example::set( name user, uint64_t value ) { + [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { auto entry_stored = singleton_instance.get(); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); } - ACTION singleton_example::get( ) { + [[eosio::action]] void singleton_example::get( ) { eosio::print("Value stored for: {%} is {%}\n", singleton_instance.get().primary_value.value, singleton_instance.get().secondary_value); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 70757e1c38..4d63fabdaa 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -5,7 +5,7 @@ Prerequisites: it is assumed you already have a multi index table instance defin To delete data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `delete` method to delete the row from table, see below: ```cpp -ACTION multi_index_example::del( name user ) { +[[eosio::action]] void multi_index_example::del( name user ) { // check if the user already exists auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 7e6132ecf6..0c232c4178 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -5,7 +5,7 @@ Prerequisites: it is assumed you already have a multi index table instance defin To insert data into a multi index table you make use of the multi index table iterator to find out if the data doesn't already exist and then use the `emplace` method to make the insertion, see below: ```cpp -ACTION multi_index_example::set( name user ) { +[[eosio::action]] void multi_index_example::set( name user ) { // check if the user already exists auto itr = testtab.find(user.value); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 492295fad6..376244f18c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -10,7 +10,7 @@ __multi_index_example.hpp__ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -23,7 +23,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; // additional data stored in table row @@ -40,8 +40,8 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); - ACTION print( name user ); + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 2e20443cdd..9b1d084bd9 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -9,7 +9,7 @@ Let's work with this example below which shows the definition of a `multi_index_ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -22,7 +22,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; name secondary; @@ -41,8 +41,8 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); - ACTION print( name user ); + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -51,10 +51,10 @@ CONTRACT multi_index_example : public contract { To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary` let's define a third action `bysec` which will do exactly that. -1. In the contract definition add the new action definition, using the `ACTION` macro and the `eosio::action_wrapper` template like this: +1. In the contract definition add the new action definition, using the `[[eosio::action]] void` and the `eosio::action_wrapper` template like this: ```cpp - ACTION bysec( name secid ); + [[eosio::action]] void bysec( name secid ); using bysec_action = action_wrapper<"bysec"_n, &multi_index_example::bysec>; ``` @@ -63,7 +63,7 @@ To iterate and retreive the multi index table `testtab` defined in `multi_index_ ```cpp // iterates the multi index table rows using the secondary index and prints the row's values -ACTION multi_index_example::bysec( name secid ) { +[[eosio::action]] void multi_index_example::bysec( name secid ) { // access the secondary index auto idx = testtab.get_index<"secid"_n>(); // iterate through secondary index @@ -82,7 +82,7 @@ __multi_index_example.hpp__ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -95,7 +95,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; name secondary; @@ -114,9 +114,9 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); - ACTION print( name user ); - ACTION bysec( name secid ); + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); + [[eosio::action]] void bysec( name secid ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -128,7 +128,7 @@ __multi_index_example.cpp__ ```cpp #include -ACTION multi_index_example::set( name user ) { +[[eosio::action]] void multi_index_example::set( name user ) { // check if the user already exists auto itr = testtab.find(user.value); @@ -142,7 +142,7 @@ ACTION multi_index_example::set( name user ) { } } -ACTION multi_index_example::print( name user ) { +[[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter auto itr = testtab.find(user.value); @@ -154,7 +154,7 @@ ACTION multi_index_example::print( name user ) { } // iterates the multi index table rows using the secondary index and prints the row's values -ACTION multi_index_example::bysec( name secid ) { +[[eosio::action]] void multi_index_example::bysec( name secid ) { // access the secondary index auto idx = testtab.get_index<"secid"_n>(); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index c480212bab..eb54231650 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -10,7 +10,7 @@ __multi_index_example.hpp__ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -23,7 +23,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; // additional data stored in table row @@ -40,7 +40,7 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); + [[eosio::action]] void set( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; }; @@ -52,7 +52,7 @@ Let's add to the above multi index example contract an action `print` which gets 1. In the contract definition __multi_index_example.hpp__ you have to add this: ```cpp // this is the print action we want to add - ACTION print( name user ); + [[eosio::action]] void print( name user ); // for ease of use, we are defining the action_wrapper for print action using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -60,7 +60,7 @@ Let's add to the above multi index example contract an action `print` which gets 2. And in the contract implementation __multi_index_example.cpp__ add this: ```cpp - ACTION multi_index_example::print( name user ) { + [[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter auto itr = testtab.find(user.value); @@ -80,7 +80,7 @@ __multi_index_example.hpp__ using namespace eosio; // multi index example contract class -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; @@ -93,7 +93,7 @@ CONTRACT multi_index_example : public contract { // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure - TABLE test_table { + struct [[eosio::table]] test_table { // this field is used later for definition of the primary index name test_primary; // additional data stored in table row @@ -110,8 +110,8 @@ CONTRACT multi_index_example : public contract { // the multi index table instance declared as a data member of type test_tables test_tables testtab; - ACTION set( name user ); - ACTION print( name user ); + [[eosio::action]] void set( name user ); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -122,7 +122,7 @@ __multi_index_example.cpp__ ```cpp #include -ACTION multi_index_example::set( name user ) { +[[eosio::action]] void multi_index_example::set( name user ) { // check if the user already exists auto itr = testtab.find(user.value); @@ -136,7 +136,7 @@ ACTION multi_index_example::set( name user ) { } } -ACTION multi_index_example::print( name user ) { +[[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter auto itr = testtab.find(user.value); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 7d81f9cbea..46c06d3449 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -5,7 +5,7 @@ Prerequisites: it is assumed you already have a multi index table instance defin To modify data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `modidfy` method to make the update, see below: ```cpp -ACTION multi_index_example::mod( name user, uint32_t n ) { +[[eosio::action]] void multi_index_example::mod( name user, uint32_t n ) { // check if the user already exists auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); diff --git a/docs/06_how-to-guides/07_how-to-use-native-tester.md b/docs/06_how-to-guides/07_how-to-use-native-tester.md index 497f0ec907..3c52788b1d 100644 --- a/docs/06_how-to-guides/07_how-to-use-native-tester.md +++ b/docs/06_how-to-guides/07_how-to-use-native-tester.md @@ -10,11 +10,11 @@ Once you have your smart contract written then a test source file can be written using namespace eosio; -CONTRACT hello : public eosio::contract { +class [[eosio::contract]] hello : public eosio::contract { public: using contract::contract; - ACTION hi( name user ); + [[eosio::action]] void hi( name user ); // accessor for external contracts to easily send inline actions to your contract using hi_action = action_wrapper<"hi"_n, &hello::hi>; diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 3d42b30c9f..be74303942 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -18,13 +18,13 @@ So the contract interface could look like this: #include using namespace eosio; -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - TABLE test_table { + struct [[eosio::table]] test_table { name test_primary; name secondary; uint64_t datum; @@ -45,8 +45,8 @@ CONTRACT multi_index_example : public contract { test_tables testtab; - ACTION set(name user); - ACTION print( name user ); + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -61,13 +61,13 @@ In the future, this allows you the flexibility to store in the `variant_field` t #include using namespace eosio; -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - TABLE test_table { + struct [[eosio::table]] test_table { name test_primary; name secondary; uint64_t datum; @@ -88,8 +88,8 @@ CONTRACT multi_index_example : public contract { test_tables testtab; - ACTION set(name user); - ACTION print( name user ); + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; @@ -115,13 +115,13 @@ Notice, the use of the `eosio::binary_extension` template which wraps the `std:: #include using namespace eosio; -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - TABLE test_table { + struct [[eosio::table]] test_table { name test_primary; name secondary; uint64_t datum; @@ -138,8 +138,8 @@ CONTRACT multi_index_example : public contract { test_tables testtab; - ACTION set(name user); - ACTION print( name user ); + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; From 5f08d260c84339640ea251dc98bdce1d030ce948 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 10 Sep 2019 11:50:12 +0300 Subject: [PATCH 044/659] introduce IDE sections and resolves #627 --- docs/06_how-to-guides/03_how_to_handle_errors.md | 11 ++++++++++- .../09_how_to_debug_a_smart_contract.md | 1 - .../10_ide_configuration/configure_eclipse.md | 1 + .../10_ide_configuration/configure_vs_code.md | 1 + docs/08_troubleshooting.md | 4 ++-- 5 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md create mode 100644 docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md diff --git a/docs/06_how-to-guides/03_how_to_handle_errors.md b/docs/06_how-to-guides/03_how_to_handle_errors.md index 468ea94343..39041ac750 100644 --- a/docs/06_how-to-guides/03_how_to_handle_errors.md +++ b/docs/06_how-to-guides/03_how_to_handle_errors.md @@ -1,2 +1,11 @@ ## How to handle errors -TO DO: add content \ No newline at end of file + +Contracts are able to use `uint64_t` error codes as an alternative (and cheaper) means of signaling error conditions as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. They assume that the contract develop respects the following restrictions: + +1. 0 (inclusive) to 5,000,000,000,000,000,000 (exclusive): Available for contract developers to use to signal errors specific to their contracts. + +2. 5,000,000,000,000,000,000 (inclusive) to 8,000,000,000,000,000,000 (exclusive): Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). + +3. 8,000,000,000,000,000,000 (inclusive) to 10,000,000,000,000,000,000 (exclusive): Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. + +4. 10,000,000,000,000,000,000 (inclusive) to 18,446,744,073,709,551,615 (inclusive): Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. \ No newline at end of file diff --git a/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md b/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md index 9c6bc8f7db..ddacbdcdbf 100644 --- a/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md +++ b/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md @@ -1,5 +1,4 @@ ## How to debug a smart contract -TO DO: should we also include IDE configurations (one? multiple?) In order to be able to debug your smart contract, you will need to setup local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. diff --git a/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md b/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md new file mode 100644 index 0000000000..54d1f2bb08 --- /dev/null +++ b/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md @@ -0,0 +1 @@ +TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md b/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md new file mode 100644 index 0000000000..54d1f2bb08 --- /dev/null +++ b/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md @@ -0,0 +1 @@ +TO DO: add content \ No newline at end of file diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 644e850ded..5eca155f83 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,4 +1,4 @@ ## Troubleshooting TO DO: add content - eosio-cpp process never completes - (Auto referencing issue) … find a good way to describe it. + - eosio-cpp process never completes + - auto referencing issue ... find a good way to describe it. From 6f0d991d094f46dc4894438717001002c111b61e Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 18 Sep 2019 23:38:38 +0300 Subject: [PATCH 045/659] update the examples code and READMEs --- examples/hello/README.txt | 12 ++++++++++-- examples/hello/include/hello.hpp | 6 +++--- examples/hello/src/hello.cpp | 4 ++-- examples/multi_index_example/README.txt | 12 ++++++++++-- .../include/multi_index_example.hpp | 14 +++++++------- .../src/multi_index_example.cpp | 10 +++++----- examples/send_inline/README.txt | 12 ++++++++++-- examples/send_inline/include/send_inline.hpp | 4 ++-- examples/send_inline/src/send_inline.cpp | 2 +- examples/singleton_example/README.txt | 12 ++++++++++-- .../include/singleton_example.hpp | 8 ++++---- .../singleton_example/src/singleton_example.cpp | 4 ++-- 12 files changed, 66 insertions(+), 34 deletions(-) diff --git a/examples/hello/README.txt b/examples/hello/README.txt index b200d54092..5fce538c28 100644 --- a/examples/hello/README.txt +++ b/examples/hello/README.txt @@ -1,6 +1,6 @@ --- hello Project --- - - How to Build - + -- How to Build with cmake and make -- - cd to 'build' directory - run the command 'cmake ..' - run the command 'make' @@ -9,4 +9,12 @@ - The built smart contract is under the 'hello' directory in the 'build' directory - You can then do a 'set contract' action with 'cleos' and point in to the './build/hello' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file +- Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to Build with eosio-cpp -- + - cd to 'build' directory + - rum the command 'eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/' + + - After build - + - The built smart contract is in the './build/' directory + - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory diff --git a/examples/hello/include/hello.hpp b/examples/hello/include/hello.hpp index a8abfc60b8..a456255361 100644 --- a/examples/hello/include/hello.hpp +++ b/examples/hello/include/hello.hpp @@ -1,12 +1,12 @@ #include using namespace eosio; -CONTRACT hello : public contract { +class [[eosio::contract]] hello : public contract { public: using contract::contract; - ACTION hi( name nm ); - ACTION check( name nm ); + [[eosio::action]] void hi( name nm ); + [[eosio::action]] void check( name nm ); using hi_action = action_wrapper<"hi"_n, &hello::hi>; using check_action = action_wrapper<"check"_n, &hello::check>; diff --git a/examples/hello/src/hello.cpp b/examples/hello/src/hello.cpp index 7b2c68387d..09fe27e2d2 100644 --- a/examples/hello/src/hello.cpp +++ b/examples/hello/src/hello.cpp @@ -1,9 +1,9 @@ #include -ACTION hello::hi( name nm ) { +[[eosio::action]] void hello::hi( name nm ) { print_f("Name : %\n", nm); } -ACTION hello::check( name nm ) { +[[eosio::action]] void hello::check( name nm ) { print_f("Name : %\n", nm); eosio::check(nm == "hello"_n, "check name not equal to `hello`"); } diff --git a/examples/multi_index_example/README.txt b/examples/multi_index_example/README.txt index 844225edaa..7251422b19 100644 --- a/examples/multi_index_example/README.txt +++ b/examples/multi_index_example/README.txt @@ -1,6 +1,6 @@ --- multi_index_example Project --- - - How to Build - + -- How to Build with cmake and make -- - cd to 'build' directory - run the command 'cmake ..' - run the command 'make' @@ -9,4 +9,12 @@ - The built smart contract is under the 'multi_index_example' directory in the 'build' directory - You can then do a 'set contract' action with 'cleos' and point in to the './build/multi_index_example' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to Build with eosio-cpp -- + - cd to 'build' directory + - rum the command 'eosio-cpp -abigen ../src/multi_index_example.cpp -o multi_index_example.wasm -I ../include/' + + - After build - + - The built smart contract is in the './build/' directory + - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory diff --git a/examples/multi_index_example/include/multi_index_example.hpp b/examples/multi_index_example/include/multi_index_example.hpp index dc2b591d79..0d989e63f1 100644 --- a/examples/multi_index_example/include/multi_index_example.hpp +++ b/examples/multi_index_example/include/multi_index_example.hpp @@ -1,13 +1,13 @@ #include using namespace eosio; -CONTRACT multi_index_example : public contract { +class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), testtab(receiver, receiver.value) {} - TABLE test_table { + struct [[eosio::table]] test_table { name test_primary; name secondary; uint64_t datum; @@ -19,11 +19,11 @@ CONTRACT multi_index_example : public contract { test_tables testtab; - ACTION set(name user); - ACTION print( name user ); - ACTION bysec( name secid ); - ACTION mod( name user, uint32_t n ); - ACTION del( name user ); + [[eosio::action]] void set(name user); + [[eosio::action]] void print( name user ); + [[eosio::action]] void bysec( name secid ); + [[eosio::action]] void mod( name user, uint32_t n ); + [[eosio::action]] void del( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; diff --git a/examples/multi_index_example/src/multi_index_example.cpp b/examples/multi_index_example/src/multi_index_example.cpp index 09074da094..2e2dd4c09e 100644 --- a/examples/multi_index_example/src/multi_index_example.cpp +++ b/examples/multi_index_example/src/multi_index_example.cpp @@ -1,5 +1,5 @@ #include -ACTION multi_index_example::set( name user ) { +[[eosio::action]] void multi_index_example::set( name user ) { auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { testtab.emplace( _self, [&]( auto& u ) { @@ -10,13 +10,13 @@ ACTION multi_index_example::set( name user ) { } } -ACTION multi_index_example::print( name user ) { +[[eosio::action]] void multi_index_example::print( name user ) { auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); } -ACTION multi_index_example::bysec( name secid ) { +[[eosio::action]] void multi_index_example::bysec( name secid ) { auto idx = testtab.get_index<"secid"_n>(); for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { print( itr->test_primary ); @@ -24,7 +24,7 @@ ACTION multi_index_example::bysec( name secid ) { } -ACTION multi_index_example::mod( name user, uint32_t n ) { +[[eosio::action]] void multi_index_example::mod( name user, uint32_t n ) { auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); testtab.modify( itr, _self, [&]( auto& row ) { @@ -33,7 +33,7 @@ ACTION multi_index_example::mod( name user, uint32_t n ) { }); } -ACTION multi_index_example::del( name user ) { +[[eosio::action]] void multi_index_example::del( name user ) { // check if the user already exists auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { diff --git a/examples/send_inline/README.txt b/examples/send_inline/README.txt index cf339a7835..c929af03a2 100644 --- a/examples/send_inline/README.txt +++ b/examples/send_inline/README.txt @@ -1,6 +1,6 @@ --- send_inline Project --- - - How to Build - + -- How to Build with cmake and make -- - cd to 'build' directory - run the command 'cmake ..' - run the command 'make' @@ -9,4 +9,12 @@ - The built smart contract is under the 'send_inline' directory in the 'build' directory - You can then do a 'set contract' action with 'cleos' and point in to the './build/send_inline' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to Build with eosio-cpp -- + - cd to 'build' directory + - rum the command 'eosio-cpp -abigen ../src/send_inline.cpp -o send_inline.wasm -I ../include/ -I ../../hello/include/' + + - After build - + - The built smart contract is in the './build/' directory + - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory diff --git a/examples/send_inline/include/send_inline.hpp b/examples/send_inline/include/send_inline.hpp index 7efde6e619..432c689aab 100644 --- a/examples/send_inline/include/send_inline.hpp +++ b/examples/send_inline/include/send_inline.hpp @@ -1,11 +1,11 @@ #include using namespace eosio; -CONTRACT send_inline : public contract { +class [[eosio::contract]] send_inline : public contract { public: using contract::contract; - ACTION test( name user, name inline_code ); + [[eosio::action]] void test( name user, name inline_code ); using test_action = action_wrapper<"test"_n, &send_inline::test>; }; diff --git a/examples/send_inline/src/send_inline.cpp b/examples/send_inline/src/send_inline.cpp index 058c613221..a76d5afe21 100644 --- a/examples/send_inline/src/send_inline.cpp +++ b/examples/send_inline/src/send_inline.cpp @@ -1,6 +1,6 @@ #include #include -ACTION send_inline::test( name user, name inline_code ) { +[[eosio::action]] void send_inline::test( name user, name inline_code ) { print_f( "Hello % from send_inline", user ); // constructor takes two arguments (the code the contract is deployed on and the set of permissions) hello::hi_action hi(inline_code, {_self, "active"_n}); diff --git a/examples/singleton_example/README.txt b/examples/singleton_example/README.txt index 33f6df682f..3749e9afd4 100644 --- a/examples/singleton_example/README.txt +++ b/examples/singleton_example/README.txt @@ -1,6 +1,6 @@ --- singleton_example Project --- - - How to Build - + -- How to Build with cmake and make -- - cd to 'build' directory - run the command 'cmake ..' - run the command 'make' @@ -9,4 +9,12 @@ - The built smart contract is under the 'singleton_example' directory in the 'build' directory - You can then do a 'set contract' action with 'cleos' and point in to the './build/singleton_example' directory - - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt \ No newline at end of file + - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt + + -- How to Build with eosio-cpp -- + - cd to 'build' directory + - rum the command 'eosio-cpp -abigen ../src/singleton_example.cpp -o singleton_example.wasm -I ../include/' + + - After build - + - The built smart contract is in the './build/' directory + - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index 344c69f542..0e75c6722b 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -3,7 +3,7 @@ #include using namespace eosio; -CONTRACT singleton_example : public contract { +class [[eosio::contract]] singleton_example : public contract { public: using contract::contract; singleton_example( name receiver, name code, datastream ds ) : @@ -11,10 +11,10 @@ CONTRACT singleton_example : public contract { singleton_instance(receiver, receiver.value) {} - ACTION set( name user, uint64_t value ); - ACTION get( ); + [[eosio::action]] void set( name user, uint64_t value ); + [[eosio::action]] void get( ); - TABLE testtable { + struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; uint64_t primary_key() const { return primary_value.value; } diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp index fa384b254e..619af5e384 100644 --- a/examples/singleton_example/src/singleton_example.cpp +++ b/examples/singleton_example/src/singleton_example.cpp @@ -1,13 +1,13 @@ #include - ACTION singleton_example::set( name user, uint64_t value ) { + [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { auto entry_stored = singleton_instance.get(); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); } - ACTION singleton_example::get( ) { + [[eosio::action]] void singleton_example::get( ) { eosio::print("Value stored for: {%} is {%}\n", singleton_instance.get().primary_value.value, singleton_instance.get().secondary_value); From 8d3f983f4746b7b34b458b8b208158916122d2f0 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 19 Sep 2019 16:28:47 +0300 Subject: [PATCH 046/659] improvements on the 'compile' how tos --- .../01_compile-a-contract-via-cli.md | 12 ++++---- .../01_compile/02_how-to-configure-cmake.md | 29 ++++++++++++++----- .../03_compiling-contracts-with-cmake.md | 13 ++++----- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index c1210f2f4b..4ade9faa7b 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -8,15 +8,13 @@ For details on how to create your first contract follow [this tutorial here](htt Follow these steps to compile your contract --- -1. Navigate to the hello folder in examples (./examples/hello) -2. You should then see the ./src/hello.cpp file -3. Now run following commands: +1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file +2. Now run following commands: ```sh $ mkdir build $ cd build $ eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ ``` - -This will generate two files: -- The compiled binary wasm (hello.wasm) -- The generated ABI file (hello.abi) +3. This will generate two files: +- The compiled binary wasm, hello.wasm +- The generated ABI file, hello.abi diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md index 688e106905..b42ef43c7c 100644 --- a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -1,11 +1,26 @@ ## How to configure CMake ### CMake Configuration -To compile an EOSIO smart contract with CMake you'll need a CMake file. The new `eosio-init` tool can be used to generate the directory structure stub .hpp/.cpp files and subsequent cmake files. Or the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. -For example: +#### Automatic generation of CMake configuration -In `CMakeLists.txt`: +To compile an EOSIO smart contract with CMake you'll need a CMake file. To use the new `eosio-init` tool to generate the directory structure stub .hpp/.cpp files and the cmake configuration files follow these steps + +1. cd ~ +2. eosio-init --path=. --project=test_contract +3. cd test_contract +4. cd build +5. cmake .. +6. make +7. ls -al test_contract + +At this point you'll have in the folder ~/test_contract/test_contract the test_contract.abi and test_contract.wasm files, for test_contract minimalist example ready to be deployed. + +#### Manual generation of CMake configuration + +To create manually the cmake configuration the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. + +1. In `CMakeLists.txt`: ``` cmake_minimum_required(VERSION 3.5) project(test_example VERSION 1.0.0) @@ -15,9 +30,7 @@ find_package(eosio.cdt) add_contract( test test test.cpp ) ``` - -In `test.cpp`: - +2. In `test.cpp`: ``` #include using namespace eosio; @@ -33,7 +46,7 @@ public: EOSIO_DISPATCH( test, (testact) ) ``` -### CMake Macros +3. Employ as needed any of the below useful CMake macros: - `add_contract` is used to build your smart contract and generate an ABI, the first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. - `target_ricardian_directory` can be used to add the directory where your ricardian contracts live to a specific cmake target. -- (new for native tester) `add_native_library` and `add_native_executable` CMake macros have been added (these are a drop in replacement for add_library and add_executable). +- `add_native_library` and `add_native_executable`, these are new CMake macros for native tester, and they are a drop in replacement for `add_library` and `add_executable`. diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index 1c8902d65a..962f3203f9 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -5,18 +5,17 @@ Prerequisites: You have the source of your contrat saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) -Follow these steps to compile your contract +Follow these steps to compile your contract: --- -1. Navigate to the hello folder in examples (./examples/hello) -2. You should then see the ./src/hello.cpp file -3. Now run following commands: +1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file +2. Run following commands: ```sh $ mkdir build $ cd build $ cmake .. $ make ``` -This will generate two files: -- The compiled binary wasm (hello.wasm) -- The generated ABI file (hello.abi) +3. This will generate two files: +- The compiled binary wasm, hello.wasm +- The generated ABI file, hello.abi From ad74f8e6eacc43fc7a078cf068b6e4ce7e5d633c Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 20 Sep 2019 09:33:58 +0300 Subject: [PATCH 047/659] move how to handle errors into an explanatory `errors handling`, re-work the how to define a primary index into to be more like a how to. --- .../07_errors_handling.md} | 2 +- .../how-to-define-a-primary-index.md | 67 +++++++++++++++---- 2 files changed, 56 insertions(+), 13 deletions(-) rename docs/{06_how-to-guides/03_how_to_handle_errors.md => 05_best-practices/07_errors_handling.md} (98%) diff --git a/docs/06_how-to-guides/03_how_to_handle_errors.md b/docs/05_best-practices/07_errors_handling.md similarity index 98% rename from docs/06_how-to-guides/03_how_to_handle_errors.md rename to docs/05_best-practices/07_errors_handling.md index 39041ac750..872386c26f 100644 --- a/docs/06_how-to-guides/03_how_to_handle_errors.md +++ b/docs/05_best-practices/07_errors_handling.md @@ -1,4 +1,4 @@ -## How to handle errors +## Errors handling Contracts are able to use `uint64_t` error codes as an alternative (and cheaper) means of signaling error conditions as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. They assume that the contract develop respects the following restrictions: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index ce96a1faae..4a0985a7fd 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,15 +1,48 @@ ## How to define a primary index -How to declare and instantiate a multi index table can be found [here](./how-to-instantiate-a-multi-index-table.md), and as par of the definition of the multi index table, the definition of a primary index key getter is mandatory. You can find in the section linked previously the full example of a multi index table including the primary index definition. - -For a quick reference of how a multi index table and the primary key index getter are defined see below: +To define a primary index for a multi index data structure it is mandatory when definint a multi index table structure. See for exemplification the following steps: +1. Include the `eosio.hpp` header and declare the `eosio` namespace usage +``` +#include +using namespace eosio; +``` +2. Define the data structure for the multi index table ```cpp - // ... + // the data structure in which we will define each row of the table + struct [[eosio::table]] test_table { + }; +``` +3. Add to the data structure the fields which define the multi index table +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { ++ // this field stores a name for each row of the multi index table ++ name test_primary; ++ // additional data stored in table row, e.g. an uint64_t type data ++ uint64_t datum; + }; +``` +4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t and must be unique +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; ++ // mandatory definition for primary key getter ++ uint64_t primary_key( ) const { return test_primary.value; } + }; +``` +__Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. + +5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name and the test_table data structure defined above +```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; // additional data stored in table row uint64_t datum; @@ -17,16 +50,26 @@ For a quick reference of how a multi index table and the primary key index gette uint64_t primary_key( ) const { return test_primary.value; } }; - // ... ++ typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; +``` - // the multi index type definition, for ease of use we define a type alias `test_tables`, - // based on the multi_index template type, parametarized with a random name and - // the test_table data structure +6. Define the multi index table instance declared as a data member of type `test_tables` defined in the privious step +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; - - // the multi index table instance declared as a data member of type test_tables - test_tables testtab; ++ test_tables testtab; ``` +Now you have instantiated the `testtab` as a multi index table which has a primary index defined for its `test_primary` data member. + __Note__ A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file From ee5b882730817fa555ae11f5374b4c49dacf0721 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 20 Sep 2019 10:10:07 +0300 Subject: [PATCH 048/659] more re-work of to dos to be more like to dos and clean up --- .../how-to-define-a-primary-index.md | 2 +- .../how-to-define-a-secondary-index.md | 36 +++++--- .../how-to-instantiate-a-multi-index-table.md | 87 ++++++++++++++++++- ...ti_index-table-based-on-secondary-index.md | 10 ++- ...terate-and-retrieve-a-multi_index-table.md | 10 ++- docs/09_tutorials/02_abi-variants.md | 9 +- .../include/singleton_example.hpp | 1 - 7 files changed, 128 insertions(+), 27 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 4a0985a7fd..83c7a066bf 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,6 +1,6 @@ ## How to define a primary index -To define a primary index for a multi index data structure it is mandatory when definint a multi index table structure. See for exemplification the following steps: +To define a primary index for a multi index data structure it is mandatory when defining a multi index table structure. See for exemplification the following steps: 1. Include the `eosio.hpp` header and declare the `eosio` namespace usage ``` diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 596f6f31c9..9e99c453c3 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -4,30 +4,45 @@ Prerequisites: it is assumed you already have a multi index table instance defin The steps below show how to add a secondary index to the existing multi index table. -__First__, you have to add a second field `secondary` to the data structure that defines the row of the table, in our case `test_table`, then add the `by_secondary( )` method which is the index accessor method to the new field value added. The secondary index which we will create in second step will index this new data structure field. +1. Add a second field let's say `secondary` to the data structure that defines the row of the table, in our case `test_table` +```diff + // the row structure of the multi index table, that is, each row of the table + // will contain an instance of this type of structure + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; ++ name secondary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; +``` -```cpp +2. Add `by_secondary( )` method which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field. +```diff // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; name secondary; // additional data stored in table row uint64_t datum; // mandatory definition for primary key getter uint64_t primary_key( ) const { return test_primary.value; } - uint64_t by_secondary( ) const { return secondary.value; } ++ uint64_t by_secondary( ) const { return secondary.value; } }; ``` -__Second__, in the `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template, which needs two parameters, the name of the index `"secid"_n`, and a function call operator which extracts the value from the `secondary` data member as an index key, this is achieved by employing the `eosio::const_mem_fun` template which receives two paras: the data structure `test_table` and the reference to the getter function member `by_secondary`. +3. In `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template, which needs two parameters, the name of the index `"secid"_n`, and a function call operator which extracts the value from the `secondary` data member as an index key, this is achieved by employing the `eosio::const_mem_fun` template which receives two paras: the data structure `test_table` and the reference to the getter function member `by_secondary`. -```cpp - typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; +```diff +- typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ++ typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; ``` -The full contract definition code with all the changes described above will look like this: +The full contract definition code with all the changes described above could look like this: __multi_index_example.hpp__ ```cpp @@ -44,12 +59,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; name secondary; // additional data stored in table row diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 376244f18c..d25aa89b60 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -1,8 +1,86 @@ ## How to instantiate a multi index table -Prerequisites: To instantiate a multi index table you need to make use of the `eosio::multi_index` template, create a struct which can be stored in the multi index table, and define getters on the fields you want to index. Remember that one of these getters must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error it can't find the field to use as the primary key. +1. Include the `eosio.hpp` header and declare the `eosio` namespace usage +``` +#include +using namespace eosio; +``` +2. Define the data structure for the multi index table +```cpp + // the data structure in which we will define each row of the table + struct [[eosio::table]] test_table { + }; +``` +3. Add to the data structure the fields which define the multi index table +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { ++ // this field stores a name for each row of the multi index table ++ name test_primary; ++ // additional data stored in table row, e.g. an uint64_t type data ++ uint64_t datum; + }; +``` +4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t, it must be unique and and it must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error saying it can't find the field to use as the primary key: +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; ++ // mandatory definition for primary key getter ++ uint64_t primary_key( ) const { return test_primary.value; } + }; +``` + +__Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. + +5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name and the test_table data structure defined above +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + ++ typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; +``` + +6. Define the multi index table data member of type `test_tables` defined in the privious step +```diff + // the data structure which defines each row of the table + struct [[eosio::table]] test_table { + // this field stores a name for each row of the multi index table + name test_primary; + // additional data stored in table row + uint64_t datum; + // mandatory definition for primary key getter + uint64_t primary_key( ) const { return test_primary.value; } + }; + + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ++ test_tables testtab; +``` + +7. Instantiate the data member `testtab` by passing in its constructor a `code` and a `scope`, these two combined with "tablename" provide access to the partition of the RAM cache used by this multi index table, in our example we will initialize the `testtab` data member in the smart contract constructor + +```diff +// contract class constructor +multi_index_example( name receiver, name code, datastream ds ) : + // contract base class contructor + contract(receiver, code, ds), + // instantiate multi index instance as data member (find it defined below) ++ testtab(receiver, receiver.value) + { } +``` +Now you have instantiated the `testtab` variable as a multi index table which has a primary index defined for its `test_primary` data member. -One example to accomplish this is exemplified below. +Here is how the definition of a `multi_index_example` contract containing a multi index table could look like after following all the steps above. __multi_index_example.hpp__ ```cpp @@ -19,12 +97,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; // additional data stored in table row uint64_t datum; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 9b1d084bd9..fb6b4de276 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -18,12 +18,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; name secondary; // additional data stored in table row @@ -91,12 +92,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; name secondary; // additional data stored in table row diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index eb54231650..6a84aa627f 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -19,12 +19,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; // additional data stored in table row uint64_t datum; @@ -89,12 +90,13 @@ class [[eosio::contract]] multi_index_example : public contract { // contract base class contructor contract(receiver, code, ds), // instantiate multi index instance as data member (find it defined below) - testtab(receiver, receiver.value) { } + testtab(receiver, receiver.value) + { } // the row structure of the multi index table, that is, each row of the table // will contain an instance of this type of structure struct [[eosio::table]] test_table { - // this field is used later for definition of the primary index + // this field stores a name for each row of the multi index table name test_primary; // additional data stored in table row uint64_t datum; diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index be74303942..59ffa5ee0b 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -22,7 +22,8 @@ class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) - : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } struct [[eosio::table]] test_table { name test_primary; @@ -65,7 +66,8 @@ class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) - : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } struct [[eosio::table]] test_table { name test_primary; @@ -119,7 +121,8 @@ class [[eosio::contract]] multi_index_example : public contract { public: using contract::contract; multi_index_example( name receiver, name code, datastream ds ) - : contract(receiver, code, ds), testtab(receiver, receiver.value) {} + : contract(receiver, code, ds), testtab(receiver, receiver.value) + { } struct [[eosio::table]] test_table { name test_primary; diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index 0e75c6722b..9772b9bbf0 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -1,5 +1,4 @@ #include -#include #include using namespace eosio; From b32a0ba40fd90179f0c683a7896251e9c9057404 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 20 Sep 2019 10:43:48 +0300 Subject: [PATCH 049/659] more work to make how tos be more like how tos --- .../how-to-define-a-primary-index.md | 2 +- .../how-to-define-a-singleton.md | 53 +++++++++++++++++-- ...to-delete-data-from-a-multi-index-table.md | 27 +++++++++- ...to-insert-data-into-a-multi-index-table.md | 29 +++++++++- .../how-to-instantiate-a-multi-index-table.md | 4 +- 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 83c7a066bf..4214ae9901 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -38,7 +38,7 @@ using namespace eosio; __Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name and the test_table data structure defined above +5. For ease of use we define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 19190c68bc..a031d9fb31 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,11 +1,56 @@ ## How to define a singleton -This an example of how you can define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`; the structure testtable can be extended to be defined by multiple data members, here we defined only two for demonstration purposes. +This how you can define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`; the structure testtable can be extended to be defined by multiple data members, here we defined only two for demonstration purposes. + +1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage +``` +#include +using namespace eosio; +``` + +2. Define the data structure for the multi index table +```cpp +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; +``` + +3. For ease of use we define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above +```diff +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; ++using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; +``` + +4. Define the singleton table instance declared as a data member of type `singleton_type` defined in the privious step +```diff +struct [[eosio::table]] testtable { + name primary_value; + uint64_t secondary_value; +}; + +using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; ++singleton_type singleton_instance; +``` + +5. Instantiate the data member `singleton_instance` by passing in its constructor the `receiver` and the `code` (in our case `receiver.value`) parameters, these two combined with "testsingletona" provide access to the partition of the RAM cache used by this singleton, in our example we will initialize the `singleton_instance` data member in the smart contract constructor, see below: +```diff +// singleton contract constructor +singleton_example( name receiver, name code, datastream ds ) : + contract(receiver, code, ds), ++ singleton_instance(receiver, receiver.value) + { } +} +``` + +Now you have defined and instantiated a singleton. Below you can find exemplified a possible implementation for the full class singleton example contract. __singleton_example.hpp__ ```cpp #include -#include #include using namespace eosio; @@ -15,7 +60,7 @@ class [[eosio::contract]] singleton_example : public contract { singleton_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), singleton_instance(receiver, receiver.value) - {} + { } [[eosio::action]] void set( name user, uint64_t value ); [[eosio::action]] void get( ); @@ -25,7 +70,7 @@ class [[eosio::contract]] singleton_example : public contract { uint64_t secondary_value; }; - using singleton_type = eosio::singleton<"testtable"_n, testtable>; + using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 4d63fabdaa..833e73eb91 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -2,8 +2,33 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To delete data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `delete` method to delete the row from table, see below: +To delete data from a multi index table follow the steps below: +1. Make use of the multi index table iterator to find out if the data exists +```cpp +[[eosio::action]] void multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); +} +``` + +2. If the data exists use the `delete` method to delete the row from table +```diff +[[eosio::action]] void multi_index_example::del( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); ++ if ( itr == testtab.end() ) { ++ printf("user does not exist in table, nothing to delete" ); ++ return; ++ } + ++ // if we got so far it means user exists so we can delete it using ++ // the iterator found based on its primary key ++ testtab.erase( itr ); +} +``` + +Here's how the full code looks like after following the steps above: ```cpp [[eosio::action]] void multi_index_example::del( name user ) { // check if the user already exists diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 0c232c4178..c1c8cfc384 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -2,8 +2,35 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To insert data into a multi index table you make use of the multi index table iterator to find out if the data doesn't already exist and then use the `emplace` method to make the insertion, see below: +To insert data into a multi index table follow the following steps +1. Make use of the multi index table iterator to find out if the data doesn't already exist +```cpp +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + +} +``` + +2. Use the `emplace` method to make the insertion +```diff +[[eosio::action]] void multi_index_example::set( name user ) { + // check if the user already exists + auto itr = testtab.find(user.value); + ++ if ( itr == testtab.end() ) { ++ // user is not already in table, we use emplace to insert a new row data structure in table ++ testtab.emplace( _self, [&]( auto& u ) { ++ u.test_primary = user; ++ u.secondary = "second"_n; ++ u.datum = 0; ++ }); ++ } +} +``` + +Here's how the full code looks like after following the steps above: ```cpp [[eosio::action]] void multi_index_example::set( name user ) { // check if the user already exists diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index d25aa89b60..ee82758b6f 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -36,7 +36,7 @@ using namespace eosio; __Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name and the test_table data structure defined above +5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { @@ -67,7 +67,7 @@ __Note__ Other, secondary, indexes if they will be defined can have duplicates. + test_tables testtab; ``` -7. Instantiate the data member `testtab` by passing in its constructor a `code` and a `scope`, these two combined with "tablename" provide access to the partition of the RAM cache used by this multi index table, in our example we will initialize the `testtab` data member in the smart contract constructor +7. Instantiate the data member `testtab` by passing in its constructor the `scope` (in our case `receiver`) and the `code` parameters, these two combined with table name `"testtaba"` provide access to the partition of the RAM cache used by this multi index table, in our example we will initialize the `testtab` data member in the smart contract constructor ```diff // contract class constructor From 1b8c67185dd0c277d1eeb50ea8a25dccaeb98aec Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 20 Sep 2019 23:54:22 +0300 Subject: [PATCH 050/659] more to dos refactoring --- ...terate-and-retrieve-a-multi_index-table.md | 8 ++--- ...w-to-modify-data-in-a-multi-index-table.md | 33 +++++++++++++++---- ...to_restrict_access_to_an_action_by_user.md | 2 +- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 6a84aa627f..04da9510eb 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -47,10 +47,10 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -The steps below show how to iterate and retrieve a multi index table. -Let's add to the above multi index example contract an action `print` which gets as parameter an acount name, searches for it in the multi index table using the primary index and prints out the value stored in that row for field `datum` if found, otherwise asserts with a custom message. +The steps below show how to iterate and retrieve a multi index table. + +1. Let's add to the above multi index example contract an action `print` which gets as parameter an acount name -1. In the contract definition __multi_index_example.hpp__ you have to add this: ```cpp // this is the print action we want to add [[eosio::action]] void print( name user ); @@ -59,7 +59,7 @@ Let's add to the above multi index example contract an action `print` which gets using print_action = action_wrapper<"print"_n, &multi_index_example::print>; ``` -2. And in the contract implementation __multi_index_example.cpp__ add this: +2. Now let's implement the action code, by searching for the `user` name in the multi index table using the primary index and print out the value stored in that row for field `datum` if found, otherwise asserts with a custom message.In the contract definition: ```cpp [[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 46c06d3449..f538834cb0 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -2,19 +2,38 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To modify data from a multi index table you make use of the multi index table iterator to find out if the data exists, and then use the `modidfy` method to make the update, see below: +To modify data in the multi index table defined in the above tutorial we will implement an action `mod` which will receive as parameter the `user` which is the key of the row we want to modify and the `value` param which is the value to update with the row. +1. Make use of the multi index table iterator to find out if the data exists ```cpp -[[eosio::action]] void multi_index_example::mod( name user, uint32_t n ) { +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { + // check if the user already exists + auto itr = testtab.find(user.value); +} +``` + +2. If the row we want to update is not found we assert by using the `check` method and yield an error message +```diff +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { + // check if the user already exists + auto itr = testtab.find(user.value); ++ check( itr != testtab.end(), "user does not exist in table" ); +} +``` + +3. If the row we want to update is found, the `check' method will do nothing and the iterator `itr` will be pointing at the row which we want to update, so we'll use the multi index `modidfy` method to make the update like below + +```diff +[[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { // check if the user already exists auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); - // if we got so far it means user exist so we can update its datum field - testtab.modify( itr, _self, [&]( auto& row ) { - row.secondary = user; - row.datum = n; - }); ++ // if we got so far it means user exist so we can update its datum field ++ testtab.modify( itr, _self, [&]( auto& row ) { ++ row.secondary = user; ++ row.datum = value; ++ }); } ``` diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 703d06fdf8..3827ff9f42 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -27,7 +27,7 @@ void hi( name user ) { } ``` -Don't forget to inlcude the right libraries to your include path, for example your build command line should look like this +__Note__ Don't forget to inlcude the right libraries to your include path, for example your build command line should look like this ```sh cd /local_path_to/eosio.cdt/examples/hello/ mkdir build From a369392c813042dfcd6ae100d118c9f73e91056c Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 10:39:39 +0300 Subject: [PATCH 051/659] Re-work for to dos. --- .../01_abi-code-generator-attributes-explained.md} | 2 +- .../02_manually_write_an_ABI_file_explained.md} | 2 +- .../09_deferred_transactions.md} | 2 +- .../how_to_restrict_access_to_an_action_by_user.md | 14 ++++---------- 4 files changed, 7 insertions(+), 13 deletions(-) rename docs/{06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md => 05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md} (98%) rename docs/{06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md => 05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md} (97%) rename docs/{06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md => 05_best-practices/09_deferred_transactions.md} (92%) diff --git a/docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md similarity index 98% rename from docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md rename to docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md index 1898a75687..bed4d1c24d 100644 --- a/docs/06_how-to-guides/06_abi/01_how-to-use-generator-attributes.md +++ b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md @@ -1,4 +1,4 @@ -## How to use ABI/Code generator attributes +## ABI/Code generator attributes explained Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. ### [[eosio::action]] diff --git a/docs/06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md similarity index 97% rename from docs/06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md rename to docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md index ac229e8e1e..94df724639 100644 --- a/docs/06_how-to-guides/06_abi/02_how_to_manually_write_an_ABI_file.md +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -1,4 +1,4 @@ -## How to manually write, or fix, an ABI file +## Manually write, or fix, an ABI file - Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. diff --git a/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md b/docs/05_best-practices/09_deferred_transactions.md similarity index 92% rename from docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md rename to docs/05_best-practices/09_deferred_transactions.md index f57a664740..cd814de44f 100644 --- a/docs/06_how-to-guides/08_how_to_push_a_deferred_transaction_from_a_smart_contract.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -1,4 +1,4 @@ -## How to push a deferred transaction from a smart contract to another +## Deferred transactions Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 3827ff9f42..3780be84c6 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -2,9 +2,9 @@ Prerequisites: It is assumed you have the sources for a contract and one of the actions defined is getting as parameter an account name and it is printing the account name. -An example of this contract can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/src/hello.cpp) +To restrict access to the `hi` action you can do it in two ways, explained below. -### Using require_auth +1. Using require_auth The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). ```cpp @@ -14,7 +14,7 @@ void hi( name user ) { } ``` -### Using require_auth2 +2. Or using require_auth2 The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. @@ -27,10 +27,4 @@ void hi( name user ) { } ``` -__Note__ Don't forget to inlcude the right libraries to your include path, for example your build command line should look like this -```sh -cd /local_path_to/eosio.cdt/examples/hello/ -mkdir build -cd build -eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/ -I ../../../libraries/eosiolib/ -``` \ No newline at end of file +An example of this contract can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/src/hello.cpp) From cc13b190be516980806579991253426bbd20ac64 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 11:03:21 +0300 Subject: [PATCH 052/659] tos re-work --- .../10_native-tester-compilation.md} | 0 .../11_debuggin_a_smart_contract.md} | 2 +- .../04_how_to_create_and_use_action_wrappers.md | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename docs/{06_how-to-guides/07_how-to-use-native-tester.md => 05_best-practices/10_native-tester-compilation.md} (100%) rename docs/{06_how-to-guides/09_how_to_debug_a_smart_contract.md => 05_best-practices/11_debuggin_a_smart_contract.md} (99%) diff --git a/docs/06_how-to-guides/07_how-to-use-native-tester.md b/docs/05_best-practices/10_native-tester-compilation.md similarity index 100% rename from docs/06_how-to-guides/07_how-to-use-native-tester.md rename to docs/05_best-practices/10_native-tester-compilation.md diff --git a/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md b/docs/05_best-practices/11_debuggin_a_smart_contract.md similarity index 99% rename from docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md rename to docs/05_best-practices/11_debuggin_a_smart_contract.md index ddacbdcdbf..364c5b26d4 100644 --- a/docs/06_how-to-guides/09_how_to_debug_a_smart_contract.md +++ b/docs/05_best-practices/11_debuggin_a_smart_contract.md @@ -1,4 +1,4 @@ -## How to debug a smart contract +## Debugging a smart contract In order to be able to debug your smart contract, you will need to setup local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index 4f578e3444..b7a3143012 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -1,7 +1,6 @@ ## How to create and use action wrappers ### Create action wrappers -One of the good examples for creating action wrappers is the `eosio.token` contract [code](https://github.com/EOSIO/eosio.contracts/blob/867f6f291db05cb663505f21ba8f7c3adca20678/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L150). This is how are defined the action wrappers for the following actions `create`, `issue`, `transfer` in token contract: @@ -40,4 +39,6 @@ token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n}); payout.send(get_self(), to, quantity, memo); ``` -__Note:__ You have to include the header file where the action wrappers are defined. \ No newline at end of file +__Note:__ You have to include the header file where the action wrappers are defined. + +For a full example of using and creating actions wrappers see the \ No newline at end of file From 4fb0c77c60f42a085e88feed976b28c8ce2021fb Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 12:20:40 +0300 Subject: [PATCH 053/659] update the action wrappers how to --- ...4_how_to_create_and_use_action_wrappers.md | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index b7a3143012..a2e75223a3 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -1,44 +1,40 @@ ## How to create and use action wrappers -### Create action wrappers - -This is how are defined the action wrappers for the following actions `create`, `issue`, `transfer` in token contract: - +1. Let's assume you have a contract `multi_index_example` with an action `mod` defined like below in file `multi_index_example.hpp`, it modifies ```cpp -[[eosio::action]] -void create( name issuer, asset maximum_supply ); - -[[eosio::action]] -void issue( name to, asset quantity, string memo ); - -[[eosio::action]] -void transfer( name from, - name to, - asset quantity, - string memo ); - -// The first parameter of the action wrapper template is the action eosio::name and second parameter is the reference to the action method -using create_action = eosio::action_wrapper<"create"_n, &token::create>; -using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>; -using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>; - -// ... +class [[eosio::contract]] multi_index_example : public contract { + // ... + [[eosio::action]] void mod( name user, uint32_t n ); + // ... +} ``` -__Note__: // The first parameter of the action wrapper template is the action eosio::name and second parameter is the reference to the action method. - - -### Use action wrappers -And this is how you use the previously created action wrapper for `transfer` action: +2. To define an action wrapper for the `mod` action, make use of the `eosio::action_wrapper` template, with the first parameter the action name as a `eosio::name` and second parameter as the reference to the action method +```diff +class [[eosio::contract]] multi_index_example : public contract { + // ... + [[eosio::action]] void mod(name user); + // ... ++ using mod_action = action_wrapper<"mod"_n, &multi_index_example::mod>; + // ... +} +``` +3. To use the action wrapper, you have to include the header file where the action wrapper is defined ```cpp -#include - -// specify the contract to send the action to as the first argument -token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n}); +#include +``` +4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case we assume the contract is deployed to `multiindexex` account, and a stucture which is defined by self account and the `active` permission, you can modify these based on your requirements. +```diff +#include -// specify the transfer arguments as postional arguments -payout.send(get_self(), to, quantity, memo); ++multi_index_example::mod_action modaction("multiindexex"_n, {get_self(), "active"_n}); ``` +5. And finally call the `send` method of the action wrapper and pass in the `mod` action's parameters as positional arguments +```diff +#include + +multi_index_example::mod_action modaction("multiindexex"_n, {get_self(), 1}); -__Note:__ You have to include the header file where the action wrappers are defined. ++modaction.send(get_self(), "eostutorial"_n, 1, memo); +``` -For a full example of using and creating actions wrappers see the \ No newline at end of file +For a full example see the [`multi_index` contract implementation](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). From 93981e604121a9868a0b9c73e689143d19e502da Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 12:29:55 +0300 Subject: [PATCH 054/659] Clean up based on peer review --- .../how-to-modify-data-in-a-multi-index-table.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index f538834cb0..d086228387 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -2,26 +2,24 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To modify data in the multi index table defined in the above tutorial we will implement an action `mod` which will receive as parameter the `user` which is the key of the row we want to modify and the `value` param which is the value to update with the row. +To modify data in the multi index table defined in the above tutorial you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. 1. Make use of the multi index table iterator to find out if the data exists ```cpp [[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { - // check if the user already exists auto itr = testtab.find(user.value); } ``` -2. If the row we want to update is not found we assert by using the `check` method and yield an error message +2. If the row you want to update is not found then assert by using the `check` method and yield an error message ```diff [[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { - // check if the user already exists auto itr = testtab.find(user.value); + check( itr != testtab.end(), "user does not exist in table" ); } ``` -3. If the row we want to update is found, the `check' method will do nothing and the iterator `itr` will be pointing at the row which we want to update, so we'll use the multi index `modidfy` method to make the update like below +3. If the row you want to update is found, the `check` method will do nothing and the iterator `itr` will be pointing at the row which you want to update, so then use the multi index `modify` method to make the update like below ```diff [[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { @@ -29,7 +27,6 @@ To modify data in the multi index table defined in the above tutorial we will im auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); -+ // if we got so far it means user exist so we can update its datum field + testtab.modify( itr, _self, [&]( auto& row ) { + row.secondary = user; + row.datum = value; @@ -37,5 +34,5 @@ To modify data in the multi index table defined in the above tutorial we will im } ``` -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). From 6228204bb80c17ef69e50f5845848bd3dc45f576 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 12:36:25 +0300 Subject: [PATCH 055/659] reverting Doxyfle, should be the same as the one in develop branch --- Doxyfile | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Doxyfile b/Doxyfile index 4823547b0e..ffc9f183be 100644 --- a/Doxyfile +++ b/Doxyfile @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = tmp # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -266,7 +266,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can options or extend it +# extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: @@ -350,7 +350,7 @@ DISTRIBUTE_GROUP_DOC = NO # \nosubgrouping command. # The default value is: YES. -SUBGROUPING = NO +SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) @@ -758,7 +758,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = +INPUT = libraries/eosiolib/core libraries/eosiolib/contracts # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -809,7 +809,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = *.cpp *.c *.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -872,17 +872,17 @@ INPUT_FILTER = # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = +FILTER_PATTERNS = *.cpp=cpp_filter # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. -FILTER_SOURCE_FILES = NO +FILTER_SOURCE_FILES = YES # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will options the setting for FILTER_PATTERN (if any) and +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. @@ -907,7 +907,7 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. @@ -1015,7 +1015,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = NO +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1940,7 +1940,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = YES +MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2359,9 +2359,4 @@ GENERATE_LEGEND = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = YES - -INPUT = libraries/eosiolib -EXCLUDE = libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h -EXCLUDE_PATTERNS = *.cpp *.c *.h -XML_OUTPUT = "/Users/sandwich/Library/Application Support/thorka/content/local/b6b77b7ab2da57cfb68f3f1766f7151e9faaf93c0fcd6c5ca0b021233f5d08d7/build/DoxygenToXml/xml" \ No newline at end of file +DOT_CLEANUP = YES \ No newline at end of file From 356079117532e1fe912a88c9c5fd31b39ef8643d Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 12:37:29 +0300 Subject: [PATCH 056/659] Doxyfile update --- Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index ffc9f183be..266e1614ae 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2359,4 +2359,4 @@ GENERATE_LEGEND = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = YES \ No newline at end of file +DOT_CLEANUP = YES From 8249e7e1cf2cebd576032cb7bedd15b4b0faf73a Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 13:46:19 +0300 Subject: [PATCH 057/659] clean the we, ours, let's --- .../05_best-practices/03_resource-planning.md | 2 +- .../09_deferred_transactions.md | 3 +- .../10_native-tester-compilation.md | 2 +- .../11_debuggin_a_smart_contract.md | 6 ++-- .../how-to-define-a-primary-index.md | 3 +- .../how-to-define-a-secondary-index.md | 16 +++------ .../how-to-define-a-singleton.md | 11 +++--- ...to-delete-data-from-a-multi-index-table.md | 22 ++---------- ...to-insert-data-into-a-multi-index-table.md | 24 ++----------- .../how-to-instantiate-a-multi-index-table.md | 14 ++++---- ...ti_index-table-based-on-secondary-index.md | 14 ++++---- ...terate-and-retrieve-a-multi_index-table.md | 30 ++++++++-------- ...4_how_to_create_and_use_action_wrappers.md | 4 +-- docs/09_tutorials/01_binary-extension.md | 34 +++++++------------ docs/09_tutorials/02_abi-variants.md | 12 ++++--- 15 files changed, 74 insertions(+), 123 deletions(-) diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md index 77d617a51a..fa5c696824 100644 --- a/docs/05_best-practices/03_resource-planning.md +++ b/docs/05_best-practices/03_resource-planning.md @@ -11,7 +11,7 @@ Once you have a fair idea of how your contract, blockchain application, and user Of course some aspects might differ from network to network, because each network might have altered its system contracts. The EOSIO code base is open sourced and it can be tailored to each network's requirements. You need to be aware of these differences and take them into account if this is the case with a network you're testing on. The EOSIO community is also providing tools that can help you in this endeavor. One example is https://www.eosrp.io -Because the RAM price varies and because the CPU and NET bandwidth allocations vary too, as we explained in the previous section, this tool can help you estimate how much of each resource you can allocate based on a specific amount of tokens and vice-versa. +Because the RAM price varies and because the CPU and NET bandwidth allocations vary too, as it is explained in the previous section, this tool can help you estimate how much of each resource you can allocate based on a specific amount of tokens and vice-versa. Another aspect of resource planning involves making sure your contract is efficient, that is, not consuming resources unnecessarily. Therefore, it is beneficial for you to find answers to the following questions when writing your own smart contracts and blockchain applications: diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md index cd814de44f..c145c29392 100644 --- a/docs/05_best-practices/09_deferred_transactions.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -4,4 +4,5 @@ Deferred communication conceptually takes the form of action notifications sent As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. -Because of all considerations mentioned above we do not reccommend the use of deferred transactions and we are considering to deprecate them in the future versions. +[[warning | Warning about deferred transaction usage]] +| Because of all considerations mentioned above it is not reccommended the use of `deferred transactions` and it is very seriousely taken in consideration the option to be deprecated in the future versions. diff --git a/docs/05_best-practices/10_native-tester-compilation.md b/docs/05_best-practices/10_native-tester-compilation.md index 3c52788b1d..fc12c00e67 100644 --- a/docs/05_best-practices/10_native-tester-compilation.md +++ b/docs/05_best-practices/10_native-tester-compilation.md @@ -34,7 +34,7 @@ using namespace eosio::native; EOSIO_TEST_BEGIN(hello_test) // These can be redefined by the user to suit there needs per unit test - // the idea is that in a future release we will have a base library that + // the idea is that in a future release there will be a base library that // initializes these to "useable" default implementations and probably // helpers to more easily define read_action_data and action_data_size intrinsics // like these" diff --git a/docs/05_best-practices/11_debuggin_a_smart_contract.md b/docs/05_best-practices/11_debuggin_a_smart_contract.md index 364c5b26d4..2c82aa4e09 100644 --- a/docs/05_best-practices/11_debuggin_a_smart_contract.md +++ b/docs/05_best-practices/11_debuggin_a_smart_contract.md @@ -9,7 +9,7 @@ The concept is the same, so for the following guide, debugging on the private te If you haven't set up your own local nodeos, please follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. ## Method -The main method used to debug smart contract is **Caveman Debugging**, where we utilize the printing functionality to inspect the value of a variable and check the flow of the contract. Printing in smart contract can be done through the Print API. The C++ API is the wrapper for C API, so most often we will just use the C++ API. +The main method used to debug smart contract is **Caveman Debugging**, where it is utilized the printing functionality to inspect the value of a variable and check the flow of the contract. Printing in smart contract can be done through the Print API. The C++ API is the wrapper for C API, so most often it will be used the C++ API. ## Print Print C API supports the following data type that you can print: @@ -32,7 +32,7 @@ While Print C++ API wraps some of the above C API by overriding the print() func - struct that has print() method ## Example -Let's write a new contract as example for debugging +Here's an example contract for debugging ### debug.hpp @@ -98,7 +98,7 @@ extern "C" { ] } ``` -Let's deploy it and send a message to it. Assume that you have `debug` account created and have its key in your wallet. +Deploy it and send a message to it. It is assumed that you have `debug` account created and have its key in your wallet. ```bash $ eosio-cpp -abigen debug.cpp -o debug.wasm diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 4214ae9901..a850f8a806 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -9,7 +9,6 @@ using namespace eosio; ``` 2. Define the data structure for the multi index table ```cpp - // the data structure in which we will define each row of the table struct [[eosio::table]] test_table { }; ``` @@ -38,7 +37,7 @@ using namespace eosio; __Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use we define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +5. For ease of use define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 9e99c453c3..9198ce7e56 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,13 +1,11 @@ -## How to define a secondady index +## How to define a secondary index Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. -1. Add a second field let's say `secondary` to the data structure that defines the row of the table, in our case `test_table` +1. Add a second field, `secondary`, to the data structure that defines the row of the table, in your case `test_table` ```diff - // the row structure of the multi index table, that is, each row of the table - // will contain an instance of this type of structure struct [[eosio::table]] test_table { // this field stores a name for each row of the multi index table name test_primary; @@ -21,8 +19,6 @@ The steps below show how to add a secondary index to the existing multi index ta 2. Add `by_secondary( )` method which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field. ```diff - // the row structure of the multi index table, that is, each row of the table - // will contain an instance of this type of structure struct [[eosio::table]] test_table { // this field stores a name for each row of the multi index table name test_primary; @@ -62,8 +58,6 @@ class [[eosio::contract]] multi_index_example : public contract { testtab(receiver, receiver.value) { } - // the row structure of the multi index table, that is, each row of the table - // will contain an instance of this type of structure struct [[eosio::table]] test_table { // this field stores a name for each row of the multi index table name test_primary; @@ -75,7 +69,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use a type alias `test_tables` is defined, // based on the multi_index template type, parametarized with a random name, the // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; @@ -91,5 +85,5 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index a031d9fb31..6eaefc05b1 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,6 +1,6 @@ ## How to define a singleton -This how you can define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`; the structure testtable can be extended to be defined by multiple data members, here we defined only two for demonstration purposes. +To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable` follow the steps below: 1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage ``` @@ -16,7 +16,7 @@ struct [[eosio::table]] testtable { }; ``` -3. For ease of use we define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above +3. For ease of use define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above ```diff struct [[eosio::table]] testtable { name primary_value; @@ -36,7 +36,7 @@ using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; +singleton_type singleton_instance; ``` -5. Instantiate the data member `singleton_instance` by passing in its constructor the `receiver` and the `code` (in our case `receiver.value`) parameters, these two combined with "testsingletona" provide access to the partition of the RAM cache used by this singleton, in our example we will initialize the `singleton_instance` data member in the smart contract constructor, see below: +5. Instantiate the data member `singleton_instance` by passing to its constructor the `receiver` and the `code` (in this case `receiver.value`) parameters; these two combined with "testsingletona" provide access to the partition of the RAM cache used by this singleton. In this example you will initialize the `singleton_instance` data member in the smart contract constructor, see below: ```diff // singleton contract constructor singleton_example( name receiver, name code, datastream ds ) : @@ -98,5 +98,6 @@ __singleton_example.cpp__ } ``` -__Note__ -A full example project demonstrating the instantiation and usage of singleton can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/singleton_example). \ No newline at end of file + +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of singleton can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/singleton_example). diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 833e73eb91..21af15e186 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -22,27 +22,9 @@ To delete data from a multi index table follow the steps below: + return; + } -+ // if we got so far it means user exists so we can delete it using -+ // the iterator found based on its primary key + testtab.erase( itr ); } ``` -Here's how the full code looks like after following the steps above: -```cpp -[[eosio::action]] void multi_index_example::del( name user ) { - // check if the user already exists - auto itr = testtab.find(user.value); - if ( itr == testtab.end() ) { - printf("user does not exist in table, nothing to delete" ); - return; - } - - // if we got so far it means user exists so we can delete it using - // the iterator found based on its primary key - testtab.erase( itr ); -} -``` - -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index c1c8cfc384..3df94b3233 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -13,14 +13,13 @@ To insert data into a multi index table follow the following steps } ``` -2. Use the `emplace` method to make the insertion +2. Use the `emplace` method to make the insertion if the user is not already in table ```diff [[eosio::action]] void multi_index_example::set( name user ) { // check if the user already exists auto itr = testtab.find(user.value); + if ( itr == testtab.end() ) { -+ // user is not already in table, we use emplace to insert a new row data structure in table + testtab.emplace( _self, [&]( auto& u ) { + u.test_primary = user; + u.secondary = "second"_n; @@ -30,22 +29,5 @@ To insert data into a multi index table follow the following steps } ``` -Here's how the full code looks like after following the steps above: -```cpp -[[eosio::action]] void multi_index_example::set( name user ) { - // check if the user already exists - auto itr = testtab.find(user.value); - - if ( itr == testtab.end() ) { - // user is not already in table, we use emplace to insert a new row data structure in table - testtab.emplace( _self, [&]( auto& u ) { - u.test_primary = user; - u.secondary = "second"_n; - u.datum = 0; - }); - } -} -``` - -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index ee82758b6f..45b369ec4b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -7,7 +7,6 @@ using namespace eosio; ``` 2. Define the data structure for the multi index table ```cpp - // the data structure in which we will define each row of the table struct [[eosio::table]] test_table { }; ``` @@ -34,9 +33,10 @@ using namespace eosio; }; ``` -__Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. +[[Info | Additional indexes information]] +| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use we define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +5. For ease of use define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { @@ -67,7 +67,7 @@ __Note__ Other, secondary, indexes if they will be defined can have duplicates. + test_tables testtab; ``` -7. Instantiate the data member `testtab` by passing in its constructor the `scope` (in our case `receiver`) and the `code` parameters, these two combined with table name `"testtaba"` provide access to the partition of the RAM cache used by this multi index table, in our example we will initialize the `testtab` data member in the smart contract constructor +7. Instantiate the data member `testtab` by passing to its constructor the `scope` (in this case `receiver`) and the `code` parameters, these two combined with table name `"testtaba"` provide access to the partition of the RAM cache used by this multi index table, in this example you will initialize the `testtab` data member in the smart contract constructor ```diff // contract class constructor @@ -111,7 +111,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use define a type alias `test_tables`, // based on the multi_index template type, parametarized with a random name and // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; @@ -127,5 +127,5 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index fb6b4de276..4aeb705c3a 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -2,7 +2,7 @@ Prerequisites: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). -Let's work with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: +You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: ```cpp #include @@ -34,7 +34,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use define a type alias `test_tables`, // based on the multi_index template type, parametarized with a random name, the // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; @@ -50,7 +50,7 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary` let's define a third action `bysec` which will do exactly that. +To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary` define a third action `bysec` which will do exactly that. 1. In the contract definition add the new action definition, using the `[[eosio::action]] void` and the `eosio::action_wrapper` template like this: @@ -108,7 +108,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t by_secondary( ) const { return secondary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use define a type alias `test_tables`, // based on the multi_index template type, parametarized with a random name, the // test_table data structure, and the secondary index typedef eosio::multi_index<"testtaba"_n, test_table, eosio::indexed_by<"secid"_n, eosio::const_mem_fun>> test_tables; @@ -135,7 +135,7 @@ __multi_index_example.cpp__ auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { - // user is not already in table, we use emplace to insert a new row data structure in table + // user is not found in table, use emplace to insert a new row data structure in table testtab.emplace( _self, [&]( auto& u ) { u.test_primary = user; u.secondary = "second"_n; @@ -168,5 +168,5 @@ __multi_index_example.cpp__ } ``` -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 04da9510eb..b0d38c5308 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -2,7 +2,7 @@ Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -Let's say we have the multi index contract definition example from below: +For exemplification define the multi index contract definition like below: __multi_index_example.hpp__ ```cpp @@ -33,7 +33,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use define a type alias `test_tables`, // based on the multi_index template type, parametarized with a random name and // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; @@ -49,17 +49,18 @@ class [[eosio::contract]] multi_index_example : public contract { The steps below show how to iterate and retrieve a multi index table. -1. Let's add to the above multi index example contract an action `print` which gets as parameter an acount name +1. Add to the above multi index example contract an action `print` which gets as parameter an acount name ```cpp - // this is the print action we want to add - [[eosio::action]] void print( name user ); - - // for ease of use, we are defining the action_wrapper for print action - using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +[[eosio::action]] void print( name user ); ``` +2. For ease of use add the action wrapper defition as well +```diff +[[eosio::action]] void print( name user ); -2. Now let's implement the action code, by searching for the `user` name in the multi index table using the primary index and print out the value stored in that row for field `datum` if found, otherwise asserts with a custom message.In the contract definition: ++using print_action = action_wrapper<"print"_n, &multi_index_example::print>; +``` +3. Implement the action code, by searching for the `user` name in the multi index table using the primary index and print out the value stored in that row for field `datum` if found, otherwise asserts with a custom message. In the contract definition add the folloing implementation for `print` action: ```cpp [[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter @@ -72,8 +73,7 @@ The steps below show how to iterate and retrieve a multi index table. eosio::print_f("Test Table : {%, %}\n", itr->test_primary, itr->datum); } ``` - -3. Finally the whole definition and implementation files for the contract should look like this: +4. Finally the whole definition and implementation files for the contract should look like this: __multi_index_example.hpp__ ```cpp @@ -104,7 +104,7 @@ class [[eosio::contract]] multi_index_example : public contract { uint64_t primary_key( ) const { return test_primary.value; } }; - // the multi index type definition, for ease of use we define a type alias `test_tables`, + // the multi index type definition, for ease of use define a type alias `test_tables`, // based on the multi_index template type, parametarized with a random name and // the test_table data structure typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; @@ -129,7 +129,7 @@ __multi_index_example.cpp__ auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { - // user is not already in table, we use emplace to insert a new row data structure in table + // user is not found in table, use emplace to insert a new row data structure in table testtab.emplace( _self, [&]( auto& u ) { u.test_primary = user; u.secondary = "second"_n; @@ -150,5 +150,5 @@ __multi_index_example.cpp__ } ``` -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index a2e75223a3..1181149dec 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -1,6 +1,6 @@ ## How to create and use action wrappers -1. Let's assume you have a contract `multi_index_example` with an action `mod` defined like below in file `multi_index_example.hpp`, it modifies +1. Start with a contract `multi_index_example` which has an action `mod` defined like below in file `multi_index_example.hpp`; the action modifies the integer value `n` stored for row with key `user`. ```cpp class [[eosio::contract]] multi_index_example : public contract { // ... @@ -22,7 +22,7 @@ class [[eosio::contract]] multi_index_example : public contract { ```cpp #include ``` -4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case we assume the contract is deployed to `multiindexex` account, and a stucture which is defined by self account and the `active` permission, you can modify these based on your requirements. +4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case it is assumed the contract is deployed to `multiindexex` account, and a stucture which is defined to parameters: the self account and the `active` permission (you can modify these two parameters based on your requirements). ```diff #include diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md index adf5fbc0f3..104af6d235 100644 --- a/docs/09_tutorials/01_binary-extension.md +++ b/docs/09_tutorials/01_binary-extension.md @@ -1,18 +1,14 @@ ## eosio::binary_extension -Let's fully explain what the `eosio::binary_extension` type is, what it does, and why we need it for contract upgrades in certain situations. - You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in file: `eosio.cdt/libraries/eosiolib/core/eosio/binary_extension.hpp`. -Our primary concern when using this type is when we are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. +The primary concern when using this type is when you are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. By wrapping the new field in an `eosio::binary_extension`, you are enabling your contract to be backwards compatible for future use. Note that this new field/parameter **MUST** be appended at the end of a data structure (this is due to implementation details in `eosio::multi_index`, which relies on the `boost::multi_index` type), or at the end of the parameter list in an action declaration. If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be uncallable. -
- -But let's see how the `eosio::binary_extension` type works with a good example. +
How the `eosio::binary_extension` type works Take a moment to study this smart contract and its corresponding `.abi`. @@ -283,7 +279,7 @@ using eosio::name;
-Take note of the action `regpkey`, and the struct `structure` in `con.hpp` and `con.cpp`; the parts of the contract we will be upgrading. +Take note of the action `regpkey`, and the struct `structure` in `con.hpp` and `con.cpp`; the parts of the contract you will be upgrading. **binary_extension_contract.hpp** @@ -359,9 +355,7 @@ And their corresponding sections in the `.abi` files: } ``` -
- -Now, let's start up a blockchain instance, compile this smart contract, and test it out. +
Start up a blockchain instance, compile this smart contract, and test it out. ``` ~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm @@ -380,7 +374,7 @@ executed transaction: 6c5c7d869a5be67611869b5f300bc452bc57d258d11755f12ced99c7d7 warning: transaction executed locally, but may not be confirmed by the network yet ``` -Next, let's push some data to our contract. +Next, push some data to the contract defined. ``` ~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name"}' -p eosio @@ -397,7 +391,7 @@ executed transaction: 3c708f10dcbf4412801d901eb82687e82287c2249a29a2f4e746d0116d warning: transaction executed locally, but may not be confirmed by the network yet ``` -Finally, let's read back the data we have just written. +Finally, read back the data you have just written. ``` ~/binary_extension_contract $ cleos push action eosio printbyp '{"primary_key":"eosio.name"}' -p eosio @@ -415,9 +409,7 @@ executed transaction: e9b77d3cfba322a7a3a93970c0c883cb8b67e2072a26d714d46eef9d79 warning: transaction executed locally, but may not be confirmed by the network yet ``` -
- -Now, let's upgrade the smart contract by adding a new field to the table and a new parameter to an action while **NOT** wrapping the new field/parameter in an `eosio::binary_extension` type and see what happens: +
Upgrade the smart contract by adding a new field to the table and a new parameter to an action while **NOT** wrapping the new field/parameter in an `eosio::binary_extension` type and see what happens: **binary_extension_contract.hpp** @@ -506,7 +498,7 @@ struct [[eosio::table]] structure { } ``` -Next, let's upgrade the contract and try to read from our table and write to our table the original way: +Next, upgrade the contract and try to read from table and write to table the original way: ``` ~/binary_extension_contract $ eosio-cpp binary_extension_contract.cpp -o binary_extension_contract.wasm @@ -535,7 +527,7 @@ Error Details: assertion failure with message: read ``` -Whoops! We aren't able to read the data we've previously written to our table! +Whoops! You aren't able to read the data you've previously written to table! ``` ~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio @@ -547,11 +539,9 @@ Error Details: Missing field 'secondary_key' in input object while processing struct 'regpkey' ``` -Whoops! We aren't able to write to our table the original way with the upgraded action either! - -
+Whoops! you aren't able to write to table the original way with the upgraded action either! -Ok, let's back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: +
Ok, back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: **binary_extension_contract.hpp** @@ -662,7 +652,7 @@ Note the `$` after the types now; this indicates that this type is an `eosio::bi } ``` -Now, let's upgrade the contract again and try to read/write from/to our table: +Now, upgrade the contract again and try to read/write from/to table: ``` ~/binary_extension_contract $ cleos set contract eosio ./ diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 59ffa5ee0b..b423edd3bd 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -102,15 +102,15 @@ Now you can deploy the contract and it will be backwards compatible with the pre ### Use variant when changing an already deployed multi index table -Prerequisites: For exemplification we are going to use the contract defined in this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md). We are assumming you deployed it and now we are going to change the table structure. +Prerequisites: For exemplification it will be used the contract defined in this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md). It is assumed you deployed it and now you are going to change the table structure. -To change the existing table structure we are going to use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). Let's say you want to add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: +To change the existing table structure you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: ```cpp eosio::binary_extension> binary_extension_variant_key; ``` -Notice, the use of the `eosio::binary_extension` template which wraps the `std::variant` template parameterized with the types we want to support for the new data field. The full contract implementation can look like this: +Notice, the use of the `eosio::binary_extension` template which wraps the `std::variant` template parameterized with the types you want to support for the new data field. The full contract implementation can look like this: ```diff #include @@ -149,6 +149,8 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -N.B. Be aware that we do not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how to ABI gets generated! +[[warning | Not recommended warning]] +| Be aware, it is not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how to ABI gets generated! -__Note__: The implementation for ABI `variants' section can be found [here](https://github.com/EOSIO/eos/pull/5652). +[[Info | Implemenatation location]] +| The implementation for ABI `variants' section can be found [here](https://github.com/EOSIO/eos/pull/5652). \ No newline at end of file From d92156e22087e50706d529529b6ae35f00b4e631 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 13:50:03 +0300 Subject: [PATCH 058/659] replace "note" with callouts --- .../02_multi-index/how-to-define-a-primary-index.md | 7 ++++--- .../how-to-modify-the-structure-of-a-multi_index-table.md | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index a850f8a806..3c52ba607b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -35,7 +35,8 @@ using namespace eosio; }; ``` -__Note__ Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. +[[Info | Secondary indexes information]] +| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. 5. For ease of use define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff @@ -70,5 +71,5 @@ __Note__ Other, secondary, indexes if they will be defined can have duplicates. Now you have instantiated the `testtab` as a multi index table which has a primary index defined for its `test_primary` data member. -__Note__ -A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file +[[Info | Full example location]] +| A full example project demonstrating the instantiation and usage of multi index table can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md index 3e2b64f5ab..dc1c277291 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md @@ -33,4 +33,6 @@ If you prefer less code complexity and can accept downtime for your application: 1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a large number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a limited number of rows each time it runs; 2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. -__Note__: Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) +[[caution]] +| Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) + From 24f89ac15bee43ce05c7a2d3c5c15e139f8674cd Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 23 Sep 2019 13:58:16 +0300 Subject: [PATCH 059/659] More correction based on peer review feedback --- .../08_abi/01_abi-code-generator-attributes-explained.md | 8 ++++---- .../how_to_restrict_access_to_an_action_by_user.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md index bed4d1c24d..50c52fbab0 100644 --- a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md +++ b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md @@ -1,5 +1,5 @@ ## ABI/Code generator attributes explained -Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. +The new ABI generator tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. ### [[eosio::action]] This attribute marks either a struct or a method as an action. @@ -51,7 +51,7 @@ If you don't want to use the multi-index you can explicitly specify the name in class [[eosio::contract("")]] test_contract : public eosio::contract { }; ``` -This will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. +The code above will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. ### [[eosio::on_notify("\::\")]] ``` @@ -74,7 +74,7 @@ void some_function(...) { } ``` -This will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. +The code above will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. ### [[eosio::wasm_import]] ``` @@ -84,5 +84,5 @@ extern "C" { } ``` -This will mark a function declaration as being a WebAssembly import. This allows for other compilation modes to specify which functions are import only (i.e. do not link) without having to maintain a secondary file with duplicate declarations. +The code above will mark a function declaration as being a WebAssembly import. This allows for other compilation modes to specify which functions are import only (i.e. do not link) without having to maintain a secondary file with duplicate declarations. diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 3780be84c6..4acb7f6bc8 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -5,7 +5,7 @@ Prerequisites: It is assumed you have the sources for a contract and one of the To restrict access to the `hi` action you can do it in two ways, explained below. 1. Using require_auth -The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). +The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). ```cpp void hi( name user ) { @@ -16,7 +16,7 @@ void hi( name user ) { 2. Or using require_auth2 -The below code is enforcing the action `hi` to be executed only by the account that is sent as paramater to the action and only if the permission used to sign the transaction is the 'active' one, that is, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. +The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action and only if the permission used to sign the transaction is the 'active' one. In other words, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. ```cpp #include From 25b061d0262f4504ca40ab6d0944221e87cad4dd Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 25 Sep 2019 10:21:13 +0300 Subject: [PATCH 060/659] fix singleton example and clean up documentation --- docs/05_best-practices/01_gotchas.md | 2 - .../02_architectural-design.md | 2 - .../04_data-design-and-migration.md | 43 ++++++++++++++++++- .../06_defensive-programming.md | 2 - ...fy-the-structure-of-a-multi_index-table.md | 38 ---------------- .../10_ide_configuration/configure_eclipse.md | 1 - .../10_ide_configuration/configure_vs_code.md | 1 - docs/07_faq.md | 2 - .../include/singleton_example.hpp | 2 +- .../src/singleton_example.cpp | 32 +++++++++----- 10 files changed, 63 insertions(+), 62 deletions(-) delete mode 100644 docs/05_best-practices/01_gotchas.md delete mode 100644 docs/05_best-practices/02_architectural-design.md delete mode 100644 docs/05_best-practices/06_defensive-programming.md delete mode 100644 docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md delete mode 100644 docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md delete mode 100644 docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md delete mode 100644 docs/07_faq.md diff --git a/docs/05_best-practices/01_gotchas.md b/docs/05_best-practices/01_gotchas.md deleted file mode 100644 index 826d36fde5..0000000000 --- a/docs/05_best-practices/01_gotchas.md +++ /dev/null @@ -1,2 +0,0 @@ -##C++ Do's and Don'ts -TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/02_architectural-design.md b/docs/05_best-practices/02_architectural-design.md deleted file mode 100644 index 4001e88960..0000000000 --- a/docs/05_best-practices/02_architectural-design.md +++ /dev/null @@ -1,2 +0,0 @@ -## Architectural design -TO DO: add content \ No newline at end of file diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index b8d77e68c4..5352b41d25 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -1,2 +1,41 @@ -## Data design and migration -TO DO: add content \ No newline at end of file +# Data design and migration + +EOSIO based blockchains allow for smart contract code update, that is, you can upload a new version of the smart contract code easily however when it comes to data update and/or migration a few things need to be considered. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below we will go over a few possbile approaches which you can consider when you design your smart contract data and its migration. + +# How to modify the structure of a multi index table + +Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements: + +## 1. If you don't mind to lose the existing data + +If you don't mind to lose the data from the initial table you can follow these two steps: +1. Erase all records from first table +2. Deploy a new contract with modified table structure + +## 2. If you want to keep the existing data + +If you want to keep the existing data there are two ways to do it: + +### 2.1. Using binary extentions +To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). + +### 2.2. Using ABI variants +To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi-variants.md). + +### 2.3. Migrate the existing data to a second table + +#### 2.3.1. Migration without downtime, but slower + +1. Create the new version of your multi index table alongside the old one; +2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs. +3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. + +#### 2.3.2. Migration with downtime, but faster + +If you prefer less code complexity and can accept downtime for your application: + +1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a large number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a limited number of rows each time it runs; +2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. + +[[caution]] +| Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) diff --git a/docs/05_best-practices/06_defensive-programming.md b/docs/05_best-practices/06_defensive-programming.md deleted file mode 100644 index 776fe7f50f..0000000000 --- a/docs/05_best-practices/06_defensive-programming.md +++ /dev/null @@ -1,2 +0,0 @@ -## Defensive programming -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md deleted file mode 100644 index dc1c277291..0000000000 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-the-structure-of-a-multi_index-table.md +++ /dev/null @@ -1,38 +0,0 @@ -# How to modify the structure of a multi index table - -Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements: - -## 1. If you don't mind to lose the existing data - -If you don't mind to lose the data from the initial table you can follow these two steps: -1. Erase all records from first table -2. Deploy a new contract with modified table structure - -## 2. If you want to keep the existing data - -If you want to keep the existing data there are two ways to do it: - -### 2.1. Using binary extentions -To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). - -### 2.2. Using ABI variants -To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi-variants.md). - -### 2.3. Migrate the existing data to a second table - -#### 2.3.1. Migration without downtime, but slower - -1. Create the new version of your multi index table alongside the old one; -2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs. -3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table. - -#### 2.3.2. Migration with downtime, but faster - -If you prefer less code complexity and can accept downtime for your application: - -1. Deploy a version of your contract solely for migration purposes, and run migration transactions on every row of your table until complete. If the first table is big, e.g. has a large number of rows, the transaction time limit could be reached while running the migration transactions. To mitigate this implement the migrate function to move a limited number of rows each time it runs; -2. Deploy a new contract using only the new version of the table, at which point, your migration and downtime is complete. - -[[caution]] -| Both of the above migration methods require some pre-planning (like the ability to put your contract into a maintenance mode for user feedback) - diff --git a/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md b/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md deleted file mode 100644 index 54d1f2bb08..0000000000 --- a/docs/06_how-to-guides/10_ide_configuration/configure_eclipse.md +++ /dev/null @@ -1 +0,0 @@ -TO DO: add content \ No newline at end of file diff --git a/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md b/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md deleted file mode 100644 index 54d1f2bb08..0000000000 --- a/docs/06_how-to-guides/10_ide_configuration/configure_vs_code.md +++ /dev/null @@ -1 +0,0 @@ -TO DO: add content \ No newline at end of file diff --git a/docs/07_faq.md b/docs/07_faq.md deleted file mode 100644 index 75a5e5890f..0000000000 --- a/docs/07_faq.md +++ /dev/null @@ -1,2 +0,0 @@ -## FAQ -TO DO: add content \ No newline at end of file diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index 9772b9bbf0..531c14f6d7 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -17,7 +17,7 @@ class [[eosio::contract]] singleton_example : public contract { name primary_value; uint64_t secondary_value; uint64_t primary_key() const { return primary_value.value; } - }; + } tt; using singleton_type = eosio::singleton<"testtable"_n, testtable>; singleton_type singleton_instance; diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp index 619af5e384..730078ba85 100644 --- a/examples/singleton_example/src/singleton_example.cpp +++ b/examples/singleton_example/src/singleton_example.cpp @@ -1,14 +1,24 @@ - #include +#include - [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - auto entry_stored = singleton_instance.get(); - entry_stored.primary_value = user; - entry_stored.secondary_value = value; - singleton_instance.set(entry_stored, user); +[[eosio::action]] void singleton_example::set( name user, uint64_t value ) { + if (!singleton_instance.exists()) + { + singleton_instance.get_or_create(user, tt); } + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); +} - [[eosio::action]] void singleton_example::get( ) { - eosio::print("Value stored for: {%} is {%}\n", - singleton_instance.get().primary_value.value, - singleton_instance.get().secondary_value); - } +[[eosio::action]] void singleton_example::get( ) { + if (singleton_instance.exists()) + eosio::print( + "Value stored for: ", + name{singleton_instance.get().primary_value.value}, + " is ", + singleton_instance.get().secondary_value, + "\n"); + else + eosio::print("Singleton is empty\n"); +} From 564271f22b23b545d432877564b5d1dc3173e0f5 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 26 Sep 2019 10:24:27 +0300 Subject: [PATCH 061/659] fill up more troubleshooting items and improve the how to define a singleton how to --- .../how-to-define-a-singleton.md | 34 +++++--- docs/08_troubleshooting.md | 82 ++++++++++++++++++- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 6eaefc05b1..c97f5fb29b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -68,7 +68,7 @@ class [[eosio::contract]] singleton_example : public contract { struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; - }; + } tt; using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; singleton_type singleton_instance; @@ -82,20 +82,30 @@ And below is a possible implementation for the two `get` and `set` actions defin __singleton_example.cpp__ ```cpp - #include +#include - [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - auto entry_stored = singleton_instance.get(); - entry_stored.primary_value = user; - entry_stored.secondary_value = value; - singleton_instance.set(entry_stored, user); +[[eosio::action]] void singleton_example::set( name user, uint64_t value ) { + if (!singleton_instance.exists()) + { + singleton_instance.get_or_create(user, tt); } + auto entry_stored = singleton_instance.get(); + entry_stored.primary_value = user; + entry_stored.secondary_value = value; + singleton_instance.set(entry_stored, user); +} - [[eosio::action]] void singleton_example::get( ) { - eosio::print("Value stored for: {%} is {%}\n", - singleton_instance.get().primary_value.value, - singleton_instance.get().secondary_value); - } +[[eosio::action]] void singleton_example::get( ) { + if (singleton_instance.exists()) + eosio::print( + "Value stored for: ", + name{singleton_instance.get().primary_value.value}, + " is ", + singleton_instance.get().secondary_value, + "\n"); + else + eosio::print("Singleton is empty\n"); +} ``` diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 5eca155f83..6654a45925 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,4 +1,80 @@ ## Troubleshooting -TO DO: add content - - eosio-cpp process never completes - - auto referencing issue ... find a good way to describe it. + +1. __Problem__: if when sending an action to the blockchian you get the error below +```{ + "code":500, + "message":"Internal Service Error", + "error":{ + "code":3090003, + "name":"unsatisfied_authorization", + "what":"Provided keys, permissions, and delays do not satisfy declared authorizations", + "details":[ + { + "message":"transaction declares authority '{"actor":"account_name","permission":"permission_name"}', but does not have signatures for it under a provided delay of 0 ms, provided permissions [], provided keys ["EOS5ZcMvpgtDMdVtvCFewAQYTyfN6Vqhg4kdgauffx3jiaKaeWfY1"], and a delay max limit of 3888000000 ms", + "file":"authorization_manager.cpp", + "line_number":524, + "method":"check_authorization" + } + ] + } +} +``` +__Possbile solution__: verify if you did not forget to set code for contract, is it possbile that you only set the abi for the contract but not the code as well? + +2. __Problem__: when sending an action to the blockchain an error similar to the one below is encountered: +```sh +Error 3015014: Pack data exception +Error Details: +Unexpected input encountered while processing struct 'action_name_here' +``` +__Possible solution__: did not specified correct parameter when sending the action to the blockchain. When no parameter is needed the command should look like the one below: +```sh +cleos push action eostutorial1 get '[]' -p eostutorial1@active +``` + +The command above is one way of sending correctly `get` action with no parameters to the blockchain. + +3. __Problem__: when sending an action to the blockchain an error similar to the one below is encountered: +```sh +error 2019-09-25T07:38:14.859 thread-0 main.cpp:3449 main ] Failed with error: Assert Exception (10) +!action_type.empty(): Unknown action action_name in contract eostutorial1 +``` +__Possible solution__: verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. + +4. __Problem__: when deploying a contract code to the blockchain a similar error with the ones below is encountered: +```sh +Error 3160010: No abi file found +or +Error 3160009: No wasm file found +``` +__Possible solution__: verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. + +5. __Problem__: Action triggers ram charge which cannot be initiated from a notification, +__Possible solution__: The reason for this error is because the notification action doesn't have authorization to by the needed RAM. + +6. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the custom message that you wrote when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +```sh +Error 3050003: eosio_assert_message assertion failure +Error Details: +assertion failure with message: singleton does not exist +pending console output: +``` +__Possible solution__: it is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + + +7. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. +__Possible solution__: it is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + + +8. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. +```sh +error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) +Couldn't parse type_name +``` +__Possible solution__: it is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. + +8. __Problem__: eosio-cpp process never completes. +__Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) + +9. __Problem__: you can not find the `now()` time function. +__Possible solution__: It has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `current_time()` or `now()` no matter how many times you call it. \ No newline at end of file From 4efa362426a8ffeb3cea7547cbb6737002cc7dba Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 27 Sep 2019 11:54:20 +0300 Subject: [PATCH 062/659] Corrections for action wrappers how to and troubleshooting content aditions. --- ...4_how_to_create_and_use_action_wrappers.md | 4 +- docs/08_troubleshooting.md | 49 ++++++++++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index 1181149dec..bc324ffe1b 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -22,7 +22,7 @@ class [[eosio::contract]] multi_index_example : public contract { ```cpp #include ``` -4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case it is assumed the contract is deployed to `multiindexex` account, and a stucture which is defined to parameters: the self account and the `active` permission (you can modify these two parameters based on your requirements). +4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case it is assumed the contract is deployed to `multiindexex` account, and a stucture which is defined by two parameters: the self account and the `active` permission (you can modify these two parameters based on your requirements). ```diff #include @@ -34,7 +34,7 @@ class [[eosio::contract]] multi_index_example : public contract { multi_index_example::mod_action modaction("multiindexex"_n, {get_self(), 1}); -+modaction.send(get_self(), "eostutorial"_n, 1, memo); ++modaction.send("eostutorial"_n, 1); ``` For a full example see the [`multi_index` contract implementation](https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example). diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 6654a45925..efe97cc9cb 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,6 +1,6 @@ ## Troubleshooting -1. __Problem__: if when sending an action to the blockchian you get the error below +1. __Problem__: when sending an action to the blockchian you get the error below ```{ "code":500, "message":"Internal Service Error", @@ -31,7 +31,6 @@ __Possible solution__: did not specified correct parameter when sending the acti ```sh cleos push action eostutorial1 get '[]' -p eostutorial1@active ``` - The command above is one way of sending correctly `get` action with no parameters to the blockchain. 3. __Problem__: when sending an action to the blockchain an error similar to the one below is encountered: @@ -49,23 +48,21 @@ Error 3160009: No wasm file found ``` __Possible solution__: verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. -5. __Problem__: Action triggers ram charge which cannot be initiated from a notification, -__Possible solution__: The reason for this error is because the notification action doesn't have authorization to by the needed RAM. +5. __Problem__: Action triggers ram charge which cannot be initiated from a notification. +__Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control -6. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the custom message that you wrote when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +6. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: ```sh Error 3050003: eosio_assert_message assertion failure Error Details: assertion failure with message: singleton does not exist pending console output: ``` -__Possible solution__: it is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. - +__Possible solution__: it is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 7. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. __Possible solution__: it is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. - 8. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. ```sh error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) @@ -73,8 +70,38 @@ Couldn't parse type_name ``` __Possible solution__: it is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -8. __Problem__: eosio-cpp process never completes. +9. __Problem__: eosio-cpp process never completes. __Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) -9. __Problem__: you can not find the `now()` time function. -__Possible solution__: It has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `current_time()` or `now()` no matter how many times you call it. \ No newline at end of file +10. __Problem__: you can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. +__Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. + +10. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +```sh +Error 3050004: eosio_assert_code assertion failure +Error Details: +assertion failure with error code: 8000000000000000000 +``` +__Possible solution__: If you are referincing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. + +11. __Problem__: Print statements from smart contract code are not seen in the output. +__Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterrating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iterration will be printed, nothing else after that, nothing from the second iterration onwards either. + +The below code will print just the first line of the iterration. + +```cpp + auto index=0; + for (auto& item : testtab) + { + eosio::print_f("{item %}={%, %, %} \n", ++index, item.test_primary, item.secondary, item.datum); + } +``` + +The below code will print all lines of the iterration separated by `'|'` char. +```cpp + auto index=0; + for (auto& item : testtab) + { + eosio::print_f("{item %}={%, %, %} |", ++index, item.test_primary, item.secondary, item.datum); + } +``` From 92c5d6ee837e8008bac38dd1cba8bddf5a39b632 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 27 Sep 2019 11:58:51 +0300 Subject: [PATCH 063/659] typos and capitals --- docs/08_troubleshooting.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index efe97cc9cb..91008647b8 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,6 +1,6 @@ ## Troubleshooting -1. __Problem__: when sending an action to the blockchian you get the error below +1. __Problem__: When sending an action to the blockchian you get the error below ```{ "code":500, "message":"Internal Service Error", @@ -19,34 +19,34 @@ } } ``` -__Possbile solution__: verify if you did not forget to set code for contract, is it possbile that you only set the abi for the contract but not the code as well? +__Possbile solution__: Verify if you did not forget to set code for contract, is it possbile that you only set the abi for the contract but not the code as well? -2. __Problem__: when sending an action to the blockchain an error similar to the one below is encountered: +2. __Problem__: When sending an action to the blockchain an error similar to the one below is encountered: ```sh Error 3015014: Pack data exception Error Details: Unexpected input encountered while processing struct 'action_name_here' ``` -__Possible solution__: did not specified correct parameter when sending the action to the blockchain. When no parameter is needed the command should look like the one below: +__Possible solution__: You did not specify correctly the parameter when sending the action to the blockchain. When no parameter is needed the command should look like the one below: ```sh cleos push action eostutorial1 get '[]' -p eostutorial1@active ``` The command above is one way of sending correctly `get` action with no parameters to the blockchain. -3. __Problem__: when sending an action to the blockchain an error similar to the one below is encountered: +3. __Problem__: When sending an action to the blockchain an error similar to the one below is encountered: ```sh error 2019-09-25T07:38:14.859 thread-0 main.cpp:3449 main ] Failed with error: Assert Exception (10) !action_type.empty(): Unknown action action_name in contract eostutorial1 ``` -__Possible solution__: verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. +__Possible solution__: Verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. -4. __Problem__: when deploying a contract code to the blockchain a similar error with the ones below is encountered: +4. __Problem__: When deploying a contract code to the blockchain a similar error with the ones below is encountered: ```sh Error 3160010: No abi file found or Error 3160009: No wasm file found ``` -__Possible solution__: verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. +__Possible solution__: Verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. 5. __Problem__: Action triggers ram charge which cannot be initiated from a notification. __Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control @@ -58,22 +58,22 @@ Error Details: assertion failure with message: singleton does not exist pending console output: ``` -__Possible solution__: it is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. +__Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 7. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. -__Possible solution__: it is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. +__Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 8. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. ```sh error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) Couldn't parse type_name ``` -__Possible solution__: it is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. +__Possible solution__: It is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 9. __Problem__: eosio-cpp process never completes. __Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) -10. __Problem__: you can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. +10. __Problem__: You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. 10. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: From 3f4f77852d4d46c4210cc61a02f2fb1a79e06956 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 27 Sep 2019 12:01:44 +0300 Subject: [PATCH 064/659] correction on the items indexes --- docs/08_troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 91008647b8..bd6f0fef50 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -76,7 +76,7 @@ __Possible solution__: make sure you have at least 2 cores on the host that exec 10. __Problem__: You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. -10. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +11. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: ```sh Error 3050004: eosio_assert_code assertion failure Error Details: @@ -84,7 +84,7 @@ assertion failure with error code: 8000000000000000000 ``` __Possible solution__: If you are referincing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. -11. __Problem__: Print statements from smart contract code are not seen in the output. +12. __Problem__: Print statements from smart contract code are not seen in the output. __Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterrating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iterration will be printed, nothing else after that, nothing from the second iterration onwards either. The below code will print just the first line of the iterration. From f0535c9adf42474bdf98dbd4acbda8854f097c90 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 27 Sep 2019 12:03:43 +0300 Subject: [PATCH 065/659] cosmetic changes --- docs/08_troubleshooting.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index bd6f0fef50..5803a64d40 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -49,6 +49,7 @@ Error 3160009: No wasm file found __Possible solution__: Verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. 5. __Problem__: Action triggers ram charge which cannot be initiated from a notification. + __Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control 6. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: @@ -61,6 +62,7 @@ pending console output: __Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 7. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. + __Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 8. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. @@ -71,9 +73,11 @@ Couldn't parse type_name __Possible solution__: It is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. 9. __Problem__: eosio-cpp process never completes. + __Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) 10. __Problem__: You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. + __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. 11. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: @@ -85,6 +89,7 @@ assertion failure with error code: 8000000000000000000 __Possible solution__: If you are referincing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. 12. __Problem__: Print statements from smart contract code are not seen in the output. + __Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterrating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iterration will be printed, nothing else after that, nothing from the second iterration onwards either. The below code will print just the first line of the iterration. From 495a2e19ece1eaf31a4c5b89ed23c06942abfb25 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 27 Sep 2019 17:22:02 +0300 Subject: [PATCH 066/659] update the examples to follow the same coding style as the contract code in eosio.contracts --- examples/hello/include/hello.hpp | 6 ++++-- examples/hello/src/hello.cpp | 6 ++++-- .../include/multi_index_example.hpp | 15 ++++++++++----- .../src/multi_index_example.cpp | 16 ++++++++++------ examples/send_inline/include/send_inline.hpp | 3 ++- examples/send_inline/src/send_inline.cpp | 3 ++- .../include/singleton_example.hpp | 6 ++++-- .../singleton_example/src/singleton_example.cpp | 6 ++++-- 8 files changed, 40 insertions(+), 21 deletions(-) diff --git a/examples/hello/include/hello.hpp b/examples/hello/include/hello.hpp index a456255361..3019d18a30 100644 --- a/examples/hello/include/hello.hpp +++ b/examples/hello/include/hello.hpp @@ -5,8 +5,10 @@ class [[eosio::contract]] hello : public contract { public: using contract::contract; - [[eosio::action]] void hi( name nm ); - [[eosio::action]] void check( name nm ); + [[eosio::action]] + void hi( name nm ); + [[eosio::action]] + void check( name nm ); using hi_action = action_wrapper<"hi"_n, &hello::hi>; using check_action = action_wrapper<"check"_n, &hello::check>; diff --git a/examples/hello/src/hello.cpp b/examples/hello/src/hello.cpp index 09fe27e2d2..8c858132d7 100644 --- a/examples/hello/src/hello.cpp +++ b/examples/hello/src/hello.cpp @@ -1,9 +1,11 @@ #include -[[eosio::action]] void hello::hi( name nm ) { +[[eosio::action]] +void hello::hi( name nm ) { print_f("Name : %\n", nm); } -[[eosio::action]] void hello::check( name nm ) { +[[eosio::action]] +void hello::check( name nm ) { print_f("Name : %\n", nm); eosio::check(nm == "hello"_n, "check name not equal to `hello`"); } diff --git a/examples/multi_index_example/include/multi_index_example.hpp b/examples/multi_index_example/include/multi_index_example.hpp index 0d989e63f1..bd08eb9a7e 100644 --- a/examples/multi_index_example/include/multi_index_example.hpp +++ b/examples/multi_index_example/include/multi_index_example.hpp @@ -19,11 +19,16 @@ class [[eosio::contract]] multi_index_example : public contract { test_tables testtab; - [[eosio::action]] void set(name user); - [[eosio::action]] void print( name user ); - [[eosio::action]] void bysec( name secid ); - [[eosio::action]] void mod( name user, uint32_t n ); - [[eosio::action]] void del( name user ); + [[eosio::action]] + void set(name user); + [[eosio::action]] + void print( name user ); + [[eosio::action]] + void bysec( name secid ); + [[eosio::action]] + void mod( name user, uint32_t n ); + [[eosio::action]] + void del( name user ); using set_action = action_wrapper<"set"_n, &multi_index_example::set>; using print_action = action_wrapper<"print"_n, &multi_index_example::print>; diff --git a/examples/multi_index_example/src/multi_index_example.cpp b/examples/multi_index_example/src/multi_index_example.cpp index 2e2dd4c09e..0072c3566f 100644 --- a/examples/multi_index_example/src/multi_index_example.cpp +++ b/examples/multi_index_example/src/multi_index_example.cpp @@ -1,5 +1,6 @@ #include -[[eosio::action]] void multi_index_example::set( name user ) { +[[eosio::action]] +void multi_index_example::set( name user ) { auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { testtab.emplace( _self, [&]( auto& u ) { @@ -10,21 +11,23 @@ } } -[[eosio::action]] void multi_index_example::print( name user ) { +[[eosio::action]] +void multi_index_example::print( name user ) { auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); eosio::print_f("Test Table : {%, %, %}\n", itr->test_primary, itr->secondary, itr->datum); } -[[eosio::action]] void multi_index_example::bysec( name secid ) { +[[eosio::action]] +void multi_index_example::bysec( name secid ) { auto idx = testtab.get_index<"secid"_n>(); for ( auto itr = idx.begin(); itr != idx.end(); itr++ ) { print( itr->test_primary ); } } - -[[eosio::action]] void multi_index_example::mod( name user, uint32_t n ) { +[[eosio::action]] +void multi_index_example::mod( name user, uint32_t n ) { auto itr = testtab.find(user.value); check( itr != testtab.end(), "user does not exist in table" ); testtab.modify( itr, _self, [&]( auto& row ) { @@ -33,7 +36,8 @@ }); } -[[eosio::action]] void multi_index_example::del( name user ) { +[[eosio::action]] +void multi_index_example::del( name user ) { // check if the user already exists auto itr = testtab.find(user.value); if ( itr == testtab.end() ) { diff --git a/examples/send_inline/include/send_inline.hpp b/examples/send_inline/include/send_inline.hpp index 432c689aab..af99668590 100644 --- a/examples/send_inline/include/send_inline.hpp +++ b/examples/send_inline/include/send_inline.hpp @@ -5,7 +5,8 @@ class [[eosio::contract]] send_inline : public contract { public: using contract::contract; - [[eosio::action]] void test( name user, name inline_code ); + [[eosio::action]] + void test( name user, name inline_code ); using test_action = action_wrapper<"test"_n, &send_inline::test>; }; diff --git a/examples/send_inline/src/send_inline.cpp b/examples/send_inline/src/send_inline.cpp index a76d5afe21..96647e0914 100644 --- a/examples/send_inline/src/send_inline.cpp +++ b/examples/send_inline/src/send_inline.cpp @@ -1,6 +1,7 @@ #include #include -[[eosio::action]] void send_inline::test( name user, name inline_code ) { +[[eosio::action]] +void send_inline::test( name user, name inline_code ) { print_f( "Hello % from send_inline", user ); // constructor takes two arguments (the code the contract is deployed on and the set of permissions) hello::hi_action hi(inline_code, {_self, "active"_n}); diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index 531c14f6d7..8b67639c62 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -10,8 +10,10 @@ class [[eosio::contract]] singleton_example : public contract { singleton_instance(receiver, receiver.value) {} - [[eosio::action]] void set( name user, uint64_t value ); - [[eosio::action]] void get( ); + [[eosio::action]] + void set( name user, uint64_t value ); + [[eosio::action]] + void get( ); struct [[eosio::table]] testtable { name primary_value; diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp index 730078ba85..4e896bb25a 100644 --- a/examples/singleton_example/src/singleton_example.cpp +++ b/examples/singleton_example/src/singleton_example.cpp @@ -1,6 +1,7 @@ #include -[[eosio::action]] void singleton_example::set( name user, uint64_t value ) { +[[eosio::action]] +void singleton_example::set( name user, uint64_t value ) { if (!singleton_instance.exists()) { singleton_instance.get_or_create(user, tt); @@ -11,7 +12,8 @@ singleton_instance.set(entry_stored, user); } -[[eosio::action]] void singleton_example::get( ) { +[[eosio::action]] +void singleton_example::get( ) { if (singleton_instance.exists()) eosio::print( "Value stored for: ", From f8b88b70c358cec9f9cc3ff50e76e042a0d65ed5 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 30 Sep 2019 19:45:01 +0300 Subject: [PATCH 067/659] fix typos and add more item in troubleshooting doc --- docs/08_troubleshooting.md | 42 ++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 5803a64d40..09caa37dc8 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,6 +1,6 @@ ## Troubleshooting -1. __Problem__: When sending an action to the blockchian you get the error below +1. __Problem__: When sending an action to the blockchain you get the error below ```{ "code":500, "message":"Internal Service Error", @@ -19,7 +19,7 @@ } } ``` -__Possbile solution__: Verify if you did not forget to set code for contract, is it possbile that you only set the abi for the contract but not the code as well? +__Possbile solution__: Verify if you did not forget to set code for contract, is it possible that you only set the `abi` for the contract but not the code as well? 2. __Problem__: When sending an action to the blockchain an error similar to the one below is encountered: ```sh @@ -46,13 +46,13 @@ Error 3160010: No abi file found or Error 3160009: No wasm file found ``` -__Possible solution__: Verify that abi and wasm files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. +__Possible solution__: Verify that `abi` and `wasm` files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. 5. __Problem__: Action triggers ram charge which cannot be initiated from a notification. __Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control -6. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +6. __Problem__: You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: ```sh Error 3050003: eosio_assert_message assertion failure Error Details: @@ -61,11 +61,11 @@ pending console output: ``` __Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -7. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. +7. __Problem__: You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. __Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -8. __Problem__: You successfuly re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. +8. __Problem__: You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. ```sh error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) Couldn't parse type_name @@ -80,19 +80,19 @@ __Possible solution__: make sure you have at least 2 cores on the host that exec __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. -11. __Problem__: You successfuly re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +11. __Problem__: You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: ```sh Error 3050004: eosio_assert_code assertion failure Error Details: assertion failure with error code: 8000000000000000000 ``` -__Possible solution__: If you are referincing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. +__Possible solution__: If you are referencing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. 12. __Problem__: Print statements from smart contract code are not seen in the output. -__Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterrating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iterration will be printed, nothing else after that, nothing from the second iterration onwards either. +__Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iteration will be printed, nothing else after that, nothing from the second iteration onwards either. -The below code will print just the first line of the iterration. +The below code will print just the first line of the iteration. ```cpp auto index=0; @@ -102,7 +102,7 @@ The below code will print just the first line of the iterration. } ``` -The below code will print all lines of the iterration separated by `'|'` char. +The below code will print all lines of the iteration separated by `'|'` char. ```cpp auto index=0; for (auto& item : testtab) @@ -110,3 +110,23 @@ The below code will print all lines of the iterration separated by `'|'` char. eosio::print_f("{item %}={%, %, %} |", ++index, item.test_primary, item.secondary, item.datum); } ``` + +12. __Problem__: Print statements from smart contract code are not shown in the `expected order`. + +__Possible solution__: The key point here is the `expected order` and what you think it should be. Although the EOSIO is single threaded, when looking at your smart contract action code implementation, which let's say it has a series of `print` (either `print_f` or `printf`) statements, they might not necessarily be outputted in the order the `apparent` code workflow is. One example is when inline transactions are sent from your smart contract action code, and you expect to see the `print` statements from within the inline action code outputted before the `print` statements made after the inline action `send` statement. For better exemplification let's look at the code below: + +```cpp +[[eosio::action]] void multi_index_example::mod( name user, uint64_t n ) { + + // `mod` action implementation code goes here... + + print_f("Output line before the inline send action.") + + singleton_set_action singleton_set("eostutorial1"_n, {get_self(), "active"_n}); + singleton_set.send(get_self(), n, get_self()); + + print_f("Output line after the inline send action.") +} +``` + +The code above has one `print` statement before the `singleton_set.send` and another one after the `singleton_set.send`. If you wrote some more `print` statements in the code that implements the `singleton_set.send` action and expect to see them before the second `print` statement then it is a wrong assumption. The inline actions are broadcasted to the network and they are executed at a different time, asynchronous of the current execution thread of the current `multi_index_example::mod` action, therefor it is impossible to predict when the `print` statements from inline action code will be outputted. \ No newline at end of file From 16ed17573c81e16f4261bb5c12cb9a376cd2f0a2 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 1 Oct 2019 13:58:57 +0300 Subject: [PATCH 068/659] clean up the readme --- README.md | 76 +-------------------------------------------------- docs/index.md | 1 + 2 files changed, 2 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 0c982e35ef..a0bac52a07 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,7 @@ # EOSIO.CDT (Contract Development Toolkit) ## Version : 1.7.0 -EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate contract writing for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. - -## New Introductions -As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. - -## Important! -EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. - -### Binary Releases -EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. - -**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** - -#### Mac OS X Brew Install -```sh -$ brew tap eosio/eosio.cdt -$ brew install eosio.cdt -``` -#### Mac OS X Brew Uninstall -```sh -$ brew remove eosio.cdt -``` -#### Debian Package Install -```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb -$ sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb -``` -#### Debian Package Uninstall -```sh -$ sudo apt remove eosio.cdt -``` - -#### Fedora RPM Package Install -```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.fedora-x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.1-1.fedora-x86_64.rpm -``` - -#### Fedora RPM Package Uninstall -```sh -$ sudo yum remove eosio.cdt -``` - -#### Centos RPM Package Install -```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.centos-x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.1-1.centos-x86_64.rpm -``` - -#### Centos RPM Package Uninstall -```sh -$ sudo yum remove eosio.cdt -``` - -### Guided Installation (Building from Scratch) -```sh -$ git clone --recursive https://github.com/eosio/eosio.cdt -$ cd eosio.cdt -$ ./build.sh -$ sudo ./install.sh -``` - -### Installed Tools ---- -* eosio-cpp -* eosio-cc -* eosio-ld -* eosio-init -* eosio-abidiff -* eosio-wasm2wast -* eosio-wast2wasm -* eosio-ranlib -* eosio-ar -* eosio-objdump -* eosio-readelf +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. ## Contributing diff --git a/docs/index.md b/docs/index.md index 4e9726d0c9..e3d160b886 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,5 @@ # EOSIO.CDT (Contract Development Toolkit) +## Version : 1.7.0 EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. From 71bd635fb18094e742f6853f49e7c026ed694503 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 4 Oct 2019 22:40:26 +0300 Subject: [PATCH 069/659] fix manual build steps and uninstall manual installation --- docs/02_installation.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/02_installation.md b/docs/02_installation.md index e40bd5c2e7..85ad764d7f 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -48,10 +48,28 @@ $ sudo yum remove eosio.cdt ```sh $ git clone --recursive https://github.com/eosio/eosio.cdt $ cd eosio.cdt -$ ./build.sh -$ sudo ./install.sh +$ mkdir build +$ cd build +$ cmake .. +$ make -j8 ``` +From here onward you can build your contracts code by simply exporting the `build` directory to your path, so you don't have to install globally (makes things cleaner). +Or you can install globally by running this command + +```sh +sudo make install +``` + +### Uninstall after manual installation + +```sh +$ sudo rm -fr /usr/local/eosio.cdt +$ sudo rm -fr /usr/local/lib/cmake/eosio.cdt +$ sudo rm /usr/local/bin/eosio-* +``` + + ## Installed Tools --- * eosio-cpp From 4f2961fbe5baecc02d266547db5d61abb08871f3 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 7 Oct 2019 13:10:55 +0300 Subject: [PATCH 070/659] Addressing the feedback from PR review. --- README.md | 117 +++++++++++++++++- docs/02_installation.md | 28 ++--- docs/03_command-reference/eosio-cc.md | 2 +- docs/03_command-reference/eosio-cpp.md | 2 +- docs/04_upgrading/1.2-to-1.3.md | 14 +-- docs/04_upgrading/1.5-to-1.6.md | 2 +- .../05_best-practices/03_resource-planning.md | 4 +- .../04_data-design-and-migration.md | 10 +- ...rrors_handling.md => 07_error_handling.md} | 2 +- ...abi-code-generator-attributes-explained.md | 29 +++-- ...02_manually_write_an_ABI_file_explained.md | 4 +- .../09_deferred_transactions.md | 2 +- .../11_debuggin_a_smart_contract.md | 10 +- .../01_compile-a-contract-via-cli.md | 4 +- .../01_compile/02_how-to-configure-cmake.md | 12 +- .../03_compiling-contracts-with-cmake.md | 4 +- .../how-to-define-a-primary-index.md | 8 +- .../how-to-define-a-secondary-index.md | 6 +- .../how-to-define-a-singleton.md | 9 +- ...to-delete-data-from-a-multi-index-table.md | 2 +- ...to-insert-data-into-a-multi-index-table.md | 2 +- .../how-to-instantiate-a-multi-index-table.md | 2 +- ...ti_index-table-based-on-secondary-index.md | 6 +- ...terate-and-retrieve-a-multi_index-table.md | 4 +- ...w-to-modify-data-in-a-multi-index-table.md | 6 +- ...4_how_to_create_and_use_action_wrappers.md | 2 +- ...to_restrict_access_to_an_action_by_user.md | 6 +- docs/09_tutorials/02_abi-variants.md | 8 +- examples/hello/README.txt | 18 +-- examples/multi_index_example/README.txt | 16 +-- examples/send_inline/README.txt | 16 +-- examples/singleton_example/README.txt | 16 +-- examples_v2/hello/include/hello.hpp | 13 ++ 33 files changed, 252 insertions(+), 134 deletions(-) rename docs/05_best-practices/{07_errors_handling.md => 07_error_handling.md} (98%) create mode 100644 examples_v2/hello/include/hello.hpp diff --git a/README.md b/README.md index a0bac52a07..83cdba2b8a 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,126 @@ # EOSIO.CDT (Contract Development Toolkit) ## Version : 1.7.0 -EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. +EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. + +## New Introductions +As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. + +## Important! +EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. + +## Concepts + +### Dispatcher and Notifications +[Dispatcher API reference](https://eosio.github.io/eosio.cdt/1.6.0/group__dispatcher.html) +[schemata:link to glossary] + +### Multi Index Table and RAM +[Multi Index Tables explained by example](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) +[schemata:link to glossary] + +### Smart Contract +[schemata:link to glossary] + +### Action +[schemata:link to glossary] + +### Transaction and Deferred Transaction +[schemata:link to glossary] + +## Binary Releases +EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. + +**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** + +### Mac OS X Brew Install +```sh +$ brew tap eosio/eosio.cdt +$ brew install eosio.cdt +``` + +### Mac OS X Brew Uninstall +```sh +$ brew remove eosio.cdt +``` + +### Debian Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +$ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +``` + +### Debian Package Uninstall +```sh +$ sudo apt remove eosio.cdt +``` + +### RPM Package Install +```sh +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm +$ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm +``` + +### RPM Package Uninstall +```sh +$ sudo yum remove eosio.cdt +``` + +## Guided Installation or Building from Scratch +```sh +$ git clone --recursive https://github.com/eosio/eosio.cdt +$ cd eosio.cdt +$ mkdir build +$ cd build +$ cmake .. +$ make -j8 +``` + +From here onward you can build your contracts code by simply exporting the `build` directory to your path, so you don't have to install globally (makes things cleaner). +Or you can install globally by running this command + +```sh +sudo make install +``` + +### Uninstall after manual installation + +```sh +$ sudo rm -fr /usr/local/eosio.cdt +$ sudo rm -fr /usr/local/lib/cmake/eosio.cdt +$ sudo rm /usr/local/bin/eosio-* +``` + +## Installed Tools +--- +* eosio-cpp +* eosio-cc +* eosio-ld +* eosio-init +* eosio-abidiff +* eosio-wasm2wast +* eosio-wast2wasm +* eosio-ranlib +* eosio-ar +* eosio-objdump +* eosio-readelf + +Below tools are not installed after brew install, you get them only by building the repository and installing from scracth, [see here](#guided_installation_or_building_from_scratch) +eosio-abidiff +eosio-ranlib +eosio-ar +eosio-objdump +eosio-readelf ## Contributing -[Contributing Guide](./CONTRIBUTING.md) +[Contributing Guide](../CONTRIBUTING.md) -[Code of Conduct](./CONTRIBUTING.md#conduct) +[Code of Conduct](../CONTRIBUTING.md#conduct) ## License -[MIT](./LICENSE) +[MIT](../LICENSE) ## Important diff --git a/docs/02_installation.md b/docs/02_installation.md index 85ad764d7f..59f43e9c0a 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -8,38 +8,30 @@ EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Li $ brew tap eosio/eosio.cdt $ brew install eosio.cdt ``` + ### Mac OS X Brew Uninstall ```sh $ brew remove eosio.cdt ``` + ### Debian Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb -$ sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +$ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb ``` + ### Debian Package Uninstall ```sh $ sudo apt remove eosio.cdt ``` -### Fedora RPM Package Install -```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.fedora-x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.1-1.fedora-x86_64.rpm -``` - -### Fedora RPM Package Uninstall -```sh -$ sudo yum remove eosio.cdt -``` - -### Centos RPM Package Install +### RPM Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.1/eosio.cdt-1.6.1-1.centos-x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.1-1.centos-x86_64.rpm +$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm +$ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm ``` -### Centos RPM Package Uninstall +### RPM Package Uninstall ```sh $ sudo yum remove eosio.cdt ``` @@ -94,4 +86,4 @@ eosio-readelf License ---- -[MIT](../LICENCE) +[MIT](../LICENSE) diff --git a/docs/03_command-reference/eosio-cc.md b/docs/03_command-reference/eosio-cc.md index ff63caaae0..003e129210 100644 --- a/docs/03_command-reference/eosio-cc.md +++ b/docs/03_command-reference/eosio-cc.md @@ -1,6 +1,6 @@ ## eosio-cc tool -To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. +To manually compile the source code, use `eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. ``` USAGE: eosio-cc [options] ... diff --git a/docs/03_command-reference/eosio-cpp.md b/docs/03_command-reference/eosio-cpp.md index acaf507841..ad1002d498 100644 --- a/docs/03_command-reference/eosio-cpp.md +++ b/docs/03_command-reference/eosio-cpp.md @@ -1,6 +1,6 @@ ## eosio-cpp tool -To manually compile the source code, use `eosio-cpp/eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. +To manually compile the source code, use `eosio-cpp` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. ``` USAGE: eosio-cpp [options] ... diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index 282dab121a..1879ed19d0 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -211,15 +211,15 @@ For an example contract of ABI generation please see the file ./examples/abigen_ - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. ### Adding Ricardian Contracts and Clauses to ABI -- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. -- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. +- As of EOSIO.CDT v1.4.0, the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- The Ricardian contract should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. +- For each Ricardian contract, the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. +- For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. +- The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. +- To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. License ---- -[MIT](../LICENCE) +[MIT](../../LICENSE) diff --git a/docs/04_upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md index 0059ded2be..a870b8bec0 100644 --- a/docs/04_upgrading/1.5-to-1.6.md +++ b/docs/04_upgrading/1.5-to-1.6.md @@ -141,4 +141,4 @@ For a real world example of this new style of contract in use see `tests/unit/te License ---- -[MIT](../LICENCE) +[MIT](../../LICENSE) diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md index fa5c696824..1ba7fb6f62 100644 --- a/docs/05_best-practices/03_resource-planning.md +++ b/docs/05_best-practices/03_resource-planning.md @@ -4,7 +4,7 @@ How much RAM do I need? This is not an easy question to answer, and there's real *Ok, you say, but how much?* -You need to test and simulate various business scenarios that apply to your blockchain application and measure their resource usage. Hence, the existence of the public test networks. These allow you to measure how much RAM, CPU, and NET each action consume, and measure worst and best case business scenarios. You can then extrapolate and build a fairly good view of your blockchain application's resource needs. +You need to test and simulate various business scenarios that apply to your blockchain application and measure their resource usage. Hence, the existence of the public test networks. These allow you to measure how much RAM, CPU, and NET each action consumes, and to measure worst and best case business scenarios. You can then extrapolate and build a fairly good view of your blockchain application's resource needs. Once you have a fair idea of how your contract, blockchain application, and user base are consuming blockchain resources on a public test-net you can estimate what you'll need to start with on any EOSIO-based networks, public or private. From that point onward, as with any other application, it is advisable to have monitors that tell you statistics and metrics about your application performance. @@ -18,4 +18,4 @@ Another aspect of resource planning involves making sure your contract is effici * Is your smart contract storing only the information that is necessary to be stored on a blockchain and for the rest is using alternative ways for storing data (e.g. IPFS)? * If you have multiple smart contracts, are they communicating between them too much via inline actions? Could some of the smart contracts be merged into one and thus eliminate the need to spawn inline actions between them, reducing the overall inline actions count and thus resource consumption? * Could you change your smart contracts so that your clients pay for some parts of the RAM used? Recall how originally the addressbook contract was making each new account added to the book pay for the RAM needed to store its individual data? - * Or conversely, are you making your clients pay too much RAM or CPU in order to access your contracts actions, to the point where you are prohibiting their use of your smart contract? Would it be better for your blockchain application's growth and success to take on some of those costs? + * Or conversely, are you making your clients pay too much RAM or CPU in order to access your contracts' actions, to the point where you are prohibiting their use of your smart contract? Would it be better for your blockchain application's growth and success to take on some of those costs? diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index 5352b41d25..c9b5741561 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -1,14 +1,14 @@ # Data design and migration -EOSIO based blockchains allow for smart contract code update, that is, you can upload a new version of the smart contract code easily however when it comes to data update and/or migration a few things need to be considered. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below we will go over a few possbile approaches which you can consider when you design your smart contract data and its migration. +EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below we will go over a few possible approaches which you can consider when you design your smart contract data and its migration. # How to modify the structure of a multi index table Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements: -## 1. If you don't mind to lose the existing data +## 1. If you don't mind losing the existing data -If you don't mind to lose the data from the initial table you can follow these two steps: +If you don't mind losing the data from the initial table you can follow these two steps: 1. Erase all records from first table 2. Deploy a new contract with modified table structure @@ -17,10 +17,10 @@ If you don't mind to lose the data from the initial table you can follow these t If you want to keep the existing data there are two ways to do it: ### 2.1. Using binary extentions -To learn how to modify the structure using binary extensions please read this [tutorial](../../09_tutorials/01_binary-extension.md). +To learn how to modify the structure using binary extensions please read this [tutorial](../09_tutorials/01_binary-extension.md). ### 2.2. Using ABI variants -To learn how to modify the structure using ABI variants please read this [tutorial](../../09_tutorials/02_abi-variants.md). +To learn how to modify the structure using ABI variants please read this [tutorial](../09_tutorials/02_abi-variants.md). ### 2.3. Migrate the existing data to a second table diff --git a/docs/05_best-practices/07_errors_handling.md b/docs/05_best-practices/07_error_handling.md similarity index 98% rename from docs/05_best-practices/07_errors_handling.md rename to docs/05_best-practices/07_error_handling.md index 872386c26f..162977af7d 100644 --- a/docs/05_best-practices/07_errors_handling.md +++ b/docs/05_best-practices/07_error_handling.md @@ -1,4 +1,4 @@ -## Errors handling +## Error handling Contracts are able to use `uint64_t` error codes as an alternative (and cheaper) means of signaling error conditions as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. They assume that the contract develop respects the following restrictions: diff --git a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md index 50c52fbab0..937f18cab4 100644 --- a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md +++ b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md @@ -1,10 +1,10 @@ ## ABI/Code generator attributes explained -The new ABI generator tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. +The new ABI generator tool uses C++11 or GNU style attributes to mark `actions` and `tables`. ### [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): -```c++ +```cpp // this is the C++11 and greater style attribute [[eosio::action]] void testa( name n ) { @@ -27,11 +27,12 @@ struct __attribute__((eosio_action)) testa { EOSLIB_SERIALIZE( testa, (n) ) }; ``` + If your action name is not a valid [EOSIO name](https://developers.eos.io/eosio-cpp/docs/naming-conventions) you can explicitly specify the name in the attribute ```c++ [[eosio::action("")]]``` ### [[eosio::table]] Example (two ways to declare a table for ABI generation): -``` +```cpp struct [[eosio::table]] testtable { uint64_t owner; /* all other fields */ @@ -44,40 +45,42 @@ struct __attribute__((eosio_table)) testtable { typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; ``` + If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. -### [[eosio::contract("\")]] -``` -class [[eosio::contract("")]] test_contract : public eosio::contract { +### [[eosio::contract("ANY_NAME_YOU_LIKE")]] +```cpp +class [[eosio::contract("ANY_NAME_YOU_LIKE")]] test_contract : public eosio::contract { }; ``` + The code above will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. -### [[eosio::on_notify("\::\")]] -``` +### [[eosio::on_notify("VALID_EOSIO_ACCOUNT_NAME::VALID_EOSIO_ACTION_NAME")]] +```cpp [[eosio::on_notify("eosio.token::transfer")]] void on_token_transfer(name from, name to, assert quantity, std::string memo) { - do something on transfer from eosio.token... + // do something on eosio.token contract's transfer action from any account to the account where the contract is deployed. } [[eosio::on_notify("*::transfer")]] void on_any_transfer(name from, name to, assert quantity, std::string memo) { - do something on transfer from any account... + // do something on any contract's transfer action from any account to the account where the contract is deployed. } ``` ### [[eosio::wasm_entry]] -``` +```cpp [[eosio::wasm_entry]] void some_function(...) { - do something... + // do something } ``` The code above will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. ### [[eosio::wasm_import]] -``` +```cpp extern "C" { __attribute__((eosio_wasm_import)) void some_intrinsic(...); diff --git a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md index 94df724639..d508ac3fe5 100644 --- a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -3,9 +3,9 @@ - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. ### Adding Ricardian Contracts and Clauses to ABI -- As of EOSIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- , the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. - The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - - For each Ricardian clause the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. + - For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md index c145c29392..0989b6372c 100644 --- a/docs/05_best-practices/09_deferred_transactions.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -5,4 +5,4 @@ Deferred communication conceptually takes the form of action notifications sent As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. [[warning | Warning about deferred transaction usage]] -| Because of all considerations mentioned above it is not reccommended the use of `deferred transactions` and it is very seriousely taken in consideration the option to be deprecated in the future versions. +| Because of the above, it is not recommended to use `deferred transactions`. There is consideration to deprecate deferred transactions in a future version. diff --git a/docs/05_best-practices/11_debuggin_a_smart_contract.md b/docs/05_best-practices/11_debuggin_a_smart_contract.md index 2c82aa4e09..00c6fbd617 100644 --- a/docs/05_best-practices/11_debuggin_a_smart_contract.md +++ b/docs/05_best-practices/11_debuggin_a_smart_contract.md @@ -1,6 +1,6 @@ ## Debugging a smart contract -In order to be able to debug your smart contract, you will need to setup local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. +In order to be able to debug your smart contract, you will need to setup a local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of a public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. When you are creating your smart contract for the first time, it is recommended to test and debug your smart contract on a private testnet first, since you have full control of the whole blockchain and can easily add suitable logging. This enables you to have unlimited amount of eos needed and you can just reset the state of the blockchain whenever you want. When it is ready for production, debugging on the public testnet (or official testnet) can be done by connecting your local nodeos to the public testnet (or official testnet) so you can see the log of the testnet in your local nodeos. @@ -9,7 +9,7 @@ The concept is the same, so for the following guide, debugging on the private te If you haven't set up your own local nodeos, please follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. ## Method -The main method used to debug smart contract is **Caveman Debugging**, where it is utilized the printing functionality to inspect the value of a variable and check the flow of the contract. Printing in smart contract can be done through the Print API. The C++ API is the wrapper for C API, so most often it will be used the C++ API. +The main method used to debug smart contract is **Caveman Debugging**. Printing is utilized to inspect the value of a variable and check the flow of the contract. Printing in smart contracts can be done through the Print API. The C++ API is a wrapper for C API and is the recommended API. ## Print Print C API supports the following data type that you can print: @@ -25,7 +25,7 @@ Print C API supports the following data type that you can print: - printn - 64 bit names as base32 encoded string - printhex - hex given binary of data and its size -While Print C++ API wraps some of the above C API by overriding the print() function so user doesn't need to determine which specific print function he needs to use. Print C++ API supports +The Print C++ API wraps some of the above C API by overriding the print() function, so the user doesn't need to determine which specific print function to use. Print C++ API supports: - a null terminated char array (string) - integer (128-bit unsigned, 64-bit unsigned, 32-bit unsigned, signed, unsigned) - base32 string encoded as 64-bit unsigned integer @@ -79,7 +79,7 @@ extern "C" { ``` ### debug.abi -```cpp +```json { "structs": [{ "name": "foo", @@ -98,7 +98,7 @@ extern "C" { ] } ``` -Deploy it and send a message to it. It is assumed that you have `debug` account created and have its key in your wallet. +Deploy it and push an action to it. It is assumed you have a `debug` account created and have its key in your wallet. ```bash $ eosio-cpp -abigen debug.cpp -o debug.wasm diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index 4ade9faa7b..665e137664 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1,8 +1,8 @@ ## How to compile a contract via CLI -Prerequisites: +### Preconditions: --- -You have the source of your contrat saved in one of your local folders, e.g. `./examples/hello` +You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) Follow these steps to compile your contract diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md index b42ef43c7c..8811abf5d1 100644 --- a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -4,7 +4,7 @@ #### Automatic generation of CMake configuration -To compile an EOSIO smart contract with CMake you'll need a CMake file. To use the new `eosio-init` tool to generate the directory structure stub .hpp/.cpp files and the cmake configuration files follow these steps +To compile an EOSIO smart contract with CMake, you'll need a CMake file. To use the new `eosio-init` tool to generate the directory structure stub .hpp/.cpp files and the cmake configuration files follow these steps: 1. cd ~ 2. eosio-init --path=. --project=test_contract @@ -14,11 +14,11 @@ To compile an EOSIO smart contract with CMake you'll need a CMake file. To use t 6. make 7. ls -al test_contract -At this point you'll have in the folder ~/test_contract/test_contract the test_contract.abi and test_contract.wasm files, for test_contract minimalist example ready to be deployed. +At this point, you'll have the `test_contract.abi` and `test_contract.wasm` files in `~/test_contract/test_contract`. These files are ready to be deployed. #### Manual generation of CMake configuration -To create manually the cmake configuration the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. +To create manually the cmake configuration, the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. 1. In `CMakeLists.txt`: ``` @@ -46,7 +46,7 @@ public: EOSIO_DISPATCH( test, (testact) ) ``` -3. Employ as needed any of the below useful CMake macros: -- `add_contract` is used to build your smart contract and generate an ABI, the first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. +3. The following CMake macros are provided: +- `add_contract` is used to build your smart contract and generate an ABI. The first parameter is the contract name, the second is the cmake target name, and the rest are the CPP files needed to build the contract. - `target_ricardian_directory` can be used to add the directory where your ricardian contracts live to a specific cmake target. -- `add_native_library` and `add_native_executable`, these are new CMake macros for native tester, and they are a drop in replacement for `add_library` and `add_executable`. +- `add_native_library` and `add_native_executable` are CMake macros for the native tester. They are drop in replacements for `add_library` and `add_executable`. diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index 962f3203f9..a84dd9007a 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -1,8 +1,8 @@ ## How to compile a smart contract with CMake -Prerequisites: +### Preconditions: --- -You have the source of your contrat saved in one of your local folders, e.g. `./examples/hello` +You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) Follow these steps to compile your contract: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index 3c52ba607b..dc1eb6265d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,6 +1,6 @@ ## How to define a primary index -To define a primary index for a multi index data structure it is mandatory when defining a multi index table structure. See for exemplification the following steps: +A primary key is required when defining a multi index table structure. See the following example: 1. Include the `eosio.hpp` header and declare the `eosio` namespace usage ``` @@ -22,7 +22,7 @@ using namespace eosio; + uint64_t datum; }; ``` -4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t and must be unique +4. Add the definition of the primary index for the multi index table. The primary index type must be uint64_t and must be unique ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { @@ -38,7 +38,7 @@ using namespace eosio; [[Info | Secondary indexes information]] | Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +5. For ease of use, define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { @@ -53,7 +53,7 @@ using namespace eosio; + typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; ``` -6. Define the multi index table instance declared as a data member of type `test_tables` defined in the privious step +Declare the multi index table as a data member of type `test_tables`, as defined above. ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 9198ce7e56..128b58362a 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,6 +1,6 @@ ## How to define a secondary index -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. @@ -17,7 +17,7 @@ The steps below show how to add a secondary index to the existing multi index ta }; ``` -2. Add `by_secondary( )` method which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field. +2. Add `by_secondary( )` method, which is the index accessor method to the new field value added. The secondary index, that will be added in step 3, will index this new data structure field. ```diff struct [[eosio::table]] test_table { // this field stores a name for each row of the multi index table @@ -31,7 +31,7 @@ The steps below show how to add a secondary index to the existing multi index ta }; ``` -3. In `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template, which needs two parameters, the name of the index `"secid"_n`, and a function call operator which extracts the value from the `secondary` data member as an index key, this is achieved by employing the `eosio::const_mem_fun` template which receives two paras: the data structure `test_table` and the reference to the getter function member `by_secondary`. +3. In the `test_table` alias definition (typedef), add the definition of the secondary index by making use of the `eosio::indexed_by` template. `eosio::index_by` needs two parameters: the name of the index, `"secid"_n`, and a function call operator which extracts the value from the secondary data member as an index key. The function call operator is achieved by employing the `eosio::const_mem_fun` template which receives two parameters: the data structure `test_table` and the reference to the getter function member `by_secondary`. ```diff - typedef eosio::multi_index<"testtaba"_n, test_table> test_tables; diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index c97f5fb29b..ce861a6103 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,10 +1,11 @@ ## How to define a singleton -To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable` follow the steps below: +To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`, follow the steps below: 1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage ``` #include +#include using namespace eosio; ``` @@ -16,7 +17,7 @@ struct [[eosio::table]] testtable { }; ``` -3. For ease of use define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above +3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above ```diff struct [[eosio::table]] testtable { name primary_value; @@ -46,7 +47,7 @@ singleton_example( name receiver, name code, datastream ds ) : } ``` -Now you have defined and instantiated a singleton. Below you can find exemplified a possible implementation for the full class singleton example contract. +Now you have defined and instantiated a singleton. Below you can find a possible implementation for the full class singleton example contract. __singleton_example.hpp__ ```cpp @@ -78,7 +79,7 @@ class [[eosio::contract]] singleton_example : public contract { }; ``` -And below is a possible implementation for the two `get` and `set` actions defined above and demonstrate the usage of a couple of singleton methods. Note that the `set` action makes use of the singleton's `set` method for which parameter is the account to pay for the new value stored, in this case, the same account name that is stored in the primary value, however, it can be a different account if the so required. +And below is a possible implementation for the two `get` and `set` actions defined above. It also demonstrates the usage of a couple of singleton methods. Note that the `set` action makes use of the singleton's `set` method, for which parameter is the account to pay for the new value stored. In this case, the same account name that is stored in the primary value is the payer. However, it can be a different account if so required. __singleton_example.cpp__ ```cpp diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 21af15e186..d5ca8e614b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to delete data from a multi index table -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To delete data from a multi index table follow the steps below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 3df94b3233..24d2bea38c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to insert data into a multi index table -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To insert data into a multi index table follow the following steps diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 45b369ec4b..c1c2d33877 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -36,7 +36,7 @@ using namespace eosio; [[Info | Additional indexes information]] | Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double. -5. For ease of use define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above +5. For ease of use, define a type alias `test_tables` based on the multi_index template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 4aeb705c3a..40d40a3b00 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,6 @@ ## How to iterate and retreive a multi index table based on secondary index -Prerequisites: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). +### Preconditions: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: @@ -50,9 +50,9 @@ class [[eosio::contract]] multi_index_example : public contract { }; ``` -To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary` define a third action `bysec` which will do exactly that. +To iterate and retreive the multi index table `testtab` defined in `multi_index_example` contract based on secondary index `by_secondary`, define a third action `bysec` which will do exactly that. -1. In the contract definition add the new action definition, using the `[[eosio::action]] void` and the `eosio::action_wrapper` template like this: +1. In the contract definition, add the new action definition, using the `[[eosio::action]] void` and the `eosio::action_wrapper` template like this: ```cpp [[eosio::action]] void bysec( name secid ); diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index b0d38c5308..a451b60a5b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,6 +1,6 @@ ## How to iterate and retrieve a multi index table -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). For exemplification define the multi index contract definition like below: @@ -60,7 +60,7 @@ The steps below show how to iterate and retrieve a multi index table. +using print_action = action_wrapper<"print"_n, &multi_index_example::print>; ``` -3. Implement the action code, by searching for the `user` name in the multi index table using the primary index and print out the value stored in that row for field `datum` if found, otherwise asserts with a custom message. In the contract definition add the folloing implementation for `print` action: +3. Implement the action code, by searching for the `user` name in the multi index table using the primary index. If found, print out the value stored in that row for field `datum`. Otherwise asserts with a custom message. In the contract definition add the following implementation for `print` action: ```cpp [[eosio::action]] void multi_index_example::print( name user ) { // searches for the row that corresponds to the user parameter diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index d086228387..04f78ff9e3 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,8 +1,8 @@ ## How to modify data in a multi index table -Prerequisites: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). -To modify data in the multi index table defined in the above tutorial you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. +To modify data in the multi index table defined in the above tutorial, you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. 1. Make use of the multi index table iterator to find out if the data exists ```cpp @@ -11,7 +11,7 @@ To modify data in the multi index table defined in the above tutorial you will i } ``` -2. If the row you want to update is not found then assert by using the `check` method and yield an error message +2. If the row you want to update is not found, then assert by using the `check` method and yield an error message ```diff [[eosio::action]] void multi_index_example::mod( name user, uint32_t value ) { auto itr = testtab.find(user.value); diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index bc324ffe1b..e6f354f770 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -22,7 +22,7 @@ class [[eosio::contract]] multi_index_example : public contract { ```cpp #include ``` -4. And then instantiate the `mod_action` defined above specifying the contract to send the action to as the first argument, in this case it is assumed the contract is deployed to `multiindexex` account, and a stucture which is defined by two parameters: the self account and the `active` permission (you can modify these two parameters based on your requirements). +4. Then instantiate the `mod_action` defined above, specifying the contract to send the action to as the first argument. In this case, it is assumed the contract is deployed to `multiindexex` account, and a structure which is defined by two parameters: the self account, obtained by `get_self()` call, and the `active` permission (you can modify these two parameters based on your requirements). ```diff #include diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 4acb7f6bc8..489e646dea 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,8 +1,8 @@ -## How to restrict access to an action by user +## How to restrict access to an action by a user -Prerequisites: It is assumed you have the sources for a contract and one of the actions defined is getting as parameter an account name and it is printing the account name. +### Preconditions: It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. -To restrict access to the `hi` action you can do it in two ways, explained below. +To restrict access to the `hi` action, you can do it in two ways: 1. Using require_auth The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index b423edd3bd..b986362ea5 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -1,7 +1,7 @@ ## ABI variants ABI variants give the flexibility of using more than one type for a defined variable or data member. -In EOSIO the variants are making use of the standard template library `variant` which was introduced in C++ 17. An instance of `std::variant` at any given time either holds a value of one of its alternative types, or in the case of error - no value. Because of this trait, variants can be used to build the multi index table structure and have flexibility in doing it, and used in conjunction with ABI extensions it allows for modification of the structure of an exiting multi index table, a.k.a. table. +In EOSIO, the variants make use of the standard template library `variant` which was introduced in C++ 17. An instance of `std::variant` at any given time either holds a value of one of its alternative types, or in the case of error - no value. Because of this trait, variants can be used to build the multi index table structure with flexibility. Used in conjunction with ABI extensions, it allows for modification of the structure of an exiting multi index table, a.k.a. table. ### Use variant when building the multi index table the first time @@ -56,7 +56,7 @@ class [[eosio::contract]] multi_index_example : public contract { Notice above the declaration of the `variant_field` data memember and also the declaration and inline implementation for the `get_variant_field()` accessor for this data member. -In the future, this allows you the flexibility to store in the `variant_field` three different types of data `int8_t`, `int16_t`, and `int32_t`, and also allows you to add more types in the list of supported types for this field. One important thing to keep in mind is that you can only append at the end of the supported types, you can not modify the existing supported types order nor drop one of them, you can only append at the end of the list. That means if you want in the next version of your contract to add also type `int32_t` to the supported list types for this field your contract implementation could look like this: +In the future, this allows you the flexibility to store in the `variant_field` three different types of data `int8_t`, `int16_t`, and `int32_t`, and also allows you to add more types in the list of supported types for this field. One important thing to keep in mind is that you can only append at the end of the supported types, you can not modify the existing supported types order nor drop one of them. That means if you want in the next version of your contract to add also type `int32_t` to the supported list types for this field, your contract implementation could look like this: ```diff #include @@ -102,9 +102,9 @@ Now you can deploy the contract and it will be backwards compatible with the pre ### Use variant when changing an already deployed multi index table -Prerequisites: For exemplification it will be used the contract defined in this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md). It is assumed you deployed it and now you are going to change the table structure. +#### Preconditions: The contract defined in the this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) will be used. It is assumed you deployed it and now you are going to change the table structure. -To change the existing table structure you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: +To change the existing table structure, you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: ```cpp eosio::binary_extension> binary_extension_variant_key; diff --git a/examples/hello/README.txt b/examples/hello/README.txt index 5fce538c28..62876f1852 100644 --- a/examples/hello/README.txt +++ b/examples/hello/README.txt @@ -1,20 +1,20 @@ --- hello Project --- - -- How to Build with cmake and make -- - - cd to 'build' directory + -- How to Build with CMake and Make -- + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'hello' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/hello' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/hello' directory -- Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt +- Additions to cmake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt - -- How to Build with eosio-cpp -- - - cd to 'build' directory - - rum the command 'eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/' + -- How to build with eosio-cpp -- + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/' - After build - - - The built smart contract is in the './build/' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/multi_index_example/README.txt b/examples/multi_index_example/README.txt index 7251422b19..6472e46aeb 100644 --- a/examples/multi_index_example/README.txt +++ b/examples/multi_index_example/README.txt @@ -1,20 +1,20 @@ --- multi_index_example Project --- - -- How to Build with cmake and make -- - - cd to 'build' directory + -- How to Build with CMake and Make -- + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'multi_index_example' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/multi_index_example' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/multi_index_example' directory - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt - -- How to Build with eosio-cpp -- - - cd to 'build' directory - - rum the command 'eosio-cpp -abigen ../src/multi_index_example.cpp -o multi_index_example.wasm -I ../include/' + -- How to build with eosio-cpp -- + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/multi_index_example.cpp -o multi_index_example.wasm -I ../include/' - After build - - - The built smart contract is in the './build/' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/send_inline/README.txt b/examples/send_inline/README.txt index c929af03a2..cc86cbc385 100644 --- a/examples/send_inline/README.txt +++ b/examples/send_inline/README.txt @@ -1,20 +1,20 @@ --- send_inline Project --- - -- How to Build with cmake and make -- - - cd to 'build' directory + -- How to Build with CMake and Make -- + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'send_inline' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/send_inline' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/send_inline' directory - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt - -- How to Build with eosio-cpp -- - - cd to 'build' directory - - rum the command 'eosio-cpp -abigen ../src/send_inline.cpp -o send_inline.wasm -I ../include/ -I ../../hello/include/' + -- How to build with eosio-cpp -- + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/send_inline.cpp -o send_inline.wasm -I ../include/ -I ../../hello/include/' - After build - - - The built smart contract is in the './build/' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples/singleton_example/README.txt b/examples/singleton_example/README.txt index 3749e9afd4..8d948e46a0 100644 --- a/examples/singleton_example/README.txt +++ b/examples/singleton_example/README.txt @@ -1,20 +1,20 @@ --- singleton_example Project --- - -- How to Build with cmake and make -- - - cd to 'build' directory + -- How to Build with CMake and Make -- + - cd into the 'build' directory - run the command 'cmake ..' - run the command 'make' - After build - - The built smart contract is under the 'singleton_example' directory in the 'build' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/singleton_example' directory + - You can then do a 'set contract' action with 'cleos' and point to the './build/singleton_example' directory - Additions to CMake should be done to the CMakeLists.txt in the './src' directory and not in the top level CMakeLists.txt - -- How to Build with eosio-cpp -- - - cd to 'build' directory - - rum the command 'eosio-cpp -abigen ../src/singleton_example.cpp -o singleton_example.wasm -I ../include/' + -- How to build with eosio-cpp -- + - cd into the 'build' directory + - run the command 'eosio-cpp -abigen ../src/singleton_example.cpp -o singleton_example.wasm -I ../include/' - After build - - - The built smart contract is in the './build/' directory - - You can then do a 'set contract' action with 'cleos' and point in to the './build/' directory + - The built smart contract is in the 'build' directory + - You can then do a 'set contract' action with 'cleos' and point to the 'build' directory diff --git a/examples_v2/hello/include/hello.hpp b/examples_v2/hello/include/hello.hpp new file mode 100644 index 0000000000..a456255361 --- /dev/null +++ b/examples_v2/hello/include/hello.hpp @@ -0,0 +1,13 @@ +#include +using namespace eosio; + +class [[eosio::contract]] hello : public contract { + public: + using contract::contract; + + [[eosio::action]] void hi( name nm ); + [[eosio::action]] void check( name nm ); + + using hi_action = action_wrapper<"hi"_n, &hello::hi>; + using check_action = action_wrapper<"check"_n, &hello::check>; +}; From 063b5e93b1567d09605c16a5020ff79acb6d4040 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 7 Oct 2019 23:49:01 +0300 Subject: [PATCH 071/659] get rid of deprecated files references in sample code --- docs/05_best-practices/11_debuggin_a_smart_contract.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/05_best-practices/11_debuggin_a_smart_contract.md b/docs/05_best-practices/11_debuggin_a_smart_contract.md index 00c6fbd617..a45a10aabc 100644 --- a/docs/05_best-practices/11_debuggin_a_smart_contract.md +++ b/docs/05_best-practices/11_debuggin_a_smart_contract.md @@ -37,16 +37,13 @@ Here's an example contract for debugging ### debug.hpp ```cpp -#include -#include - namespace debug { struct foo { account_name from; account_name to; uint64_t amount; void print() const { - eosio::print("Foo from ", eosio::name(from), " to ",eosio::name(to), " with amount ", amount, "\n"); + eosio::print("Foo from ", eosio::name(from), " to ", eosio::name(to), " with amount ", amount, "\n"); } }; } From 1cdcaa0dcf1028a4b7defabf36fc4fc9b01eed36 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 8 Oct 2019 01:25:46 +0300 Subject: [PATCH 072/659] Address PR review feedback --- docs/04_upgrading/1.2-to-1.3.md | 2 +- .../04_data-design-and-migration.md | 2 +- ...02_manually_write_an_ABI_file_explained.md | 4 +- .../10_native-tester-compilation.md | 2 +- .../01_compile-a-contract-via-cli.md | 2 +- .../03_compiling-contracts-with-cmake.md | 2 +- .../how-to-define-a-secondary-index.md | 2 +- ...to-delete-data-from-a-multi-index-table.md | 2 +- ...to-insert-data-into-a-multi-index-table.md | 2 +- ...ti_index-table-based-on-secondary-index.md | 2 +- ...terate-and-retrieve-a-multi_index-table.md | 2 +- ...w-to-modify-data-in-a-multi-index-table.md | 2 +- ...to_restrict_access_to_an_action_by_user.md | 2 +- docs/09_tutorials/01_binary-extension.md | 89 +++++++++++++++++-- docs/09_tutorials/02_abi-variants.md | 2 +- 15 files changed, 98 insertions(+), 21 deletions(-) diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index 1879ed19d0..f168999746 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -207,7 +207,7 @@ For an example contract of ABI generation please see the file ./examples/abigen_ ### Fixing an ABI or Writing an ABI Manually - The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually. -- The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. +- The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. ### Adding Ricardian Contracts and Clauses to ABI diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index c9b5741561..65d3ffdf8e 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -1,6 +1,6 @@ # Data design and migration -EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below we will go over a few possible approaches which you can consider when you design your smart contract data and its migration. +EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below you will find a few possible approaches which you can consider when you design your smart contract data and its migration. # How to modify the structure of a multi index table diff --git a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md index d508ac3fe5..803098b889 100644 --- a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -1,5 +1,5 @@ ## Manually write, or fix, an ABI file -- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. +- Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. ### Adding Ricardian Contracts and Clauses to ABI @@ -7,5 +7,5 @@ - The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. + - The option `-R` has been added to [`eosio-cpp`](../../03_command-reference/eosio-cpp.md) and [`eosio-abigen`](../../03_command-reference/eosio-abigen.md) to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. diff --git a/docs/05_best-practices/10_native-tester-compilation.md b/docs/05_best-practices/10_native-tester-compilation.md index fc12c00e67..8ef328af7f 100644 --- a/docs/05_best-practices/10_native-tester-compilation.md +++ b/docs/05_best-practices/10_native-tester-compilation.md @@ -1,5 +1,5 @@ ## How to use native tester/compilation -As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. `eosio-cc\cpp` and `eosio-ld` now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) +As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. [`eosio-cc`](../03_command-reference/eosio-cc.md), [`eosio-cpp`](../03_command-reference/eosio-cpp.md) and [`eosio-ld`](../03_command-reference/eosio-ld.md) now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) ### Getting Started Once you have your smart contract written then a test source file can be written. diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index 665e137664..6e527c2a67 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1,6 +1,6 @@ ## How to compile a contract via CLI -### Preconditions: +### Preconditions --- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index a84dd9007a..bac74f9bbe 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -1,6 +1,6 @@ ## How to compile a smart contract with CMake -### Preconditions: +### Preconditions --- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 128b58362a..4df568052d 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,6 +1,6 @@ ## How to define a secondary index -### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index d5ca8e614b..f017e930df 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to delete data from a multi index table -### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To delete data from a multi index table follow the steps below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index 24d2bea38c..e08fb2c8c1 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to insert data into a multi index table -### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To insert data into a multi index table follow the following steps diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 40d40a3b00..71db17d652 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,6 @@ ## How to iterate and retreive a multi index table based on secondary index -### Preconditions: It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). +### Preconditions It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index a451b60a5b..f8f63bc6b6 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,6 +1,6 @@ ## How to iterate and retrieve a multi index table -### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). For exemplification define the multi index contract definition like below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index 04f78ff9e3..e2547b25a0 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,6 +1,6 @@ ## How to modify data in a multi index table -### Preconditions: it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To modify data in the multi index table defined in the above tutorial, you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 489e646dea..f0761d1053 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,6 +1,6 @@ ## How to restrict access to an action by a user -### Preconditions: It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. +### Preconditions It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. To restrict access to the `hi` action, you can do it in two ways: diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md index 104af6d235..b48f8cb80b 100644 --- a/docs/09_tutorials/01_binary-extension.md +++ b/docs/09_tutorials/01_binary-extension.md @@ -1,12 +1,12 @@ -## eosio::binary_extension +# eosio::binary_extension -You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in file: `eosio.cdt/libraries/eosiolib/core/eosio/binary_extension.hpp`. +You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in [binary_extension.hpp](https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/binary_extension.hpp). The primary concern when using this type is when you are adding a new field to a smart contract's data structure that is currently utilized in an `eosio::multi_index` type (AKA a _table_), or when adding a new parameter to an action declaration. By wrapping the new field in an `eosio::binary_extension`, you are enabling your contract to be backwards compatible for future use. Note that this new field/parameter **MUST** be appended at the end of a data structure (this is due to implementation details in `eosio::multi_index`, which relies on the `boost::multi_index` type), or at the end of the parameter list in an action declaration. -If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be uncallable. +If you don't wrap the new field in an `eosio::binary_extension`, the `eosio::multi_index` table will be reformatted in such a way that disallows reads to the former datum; or in an action's case, the function will be un-callable.
How the `eosio::binary_extension` type works @@ -527,7 +527,7 @@ Error Details: assertion failure with message: read ``` -Whoops! You aren't able to read the data you've previously written to table! +Whoops, you aren't able to read the data you've previously written to table. ``` ~/binary_extension_contract $ cleos push action eosio regpkey '{"primary_key":"eosio.name2"}' -p eosio @@ -539,7 +539,7 @@ Error Details: Missing field 'secondary_key' in input object while processing struct 'regpkey' ``` -Whoops! you aren't able to write to table the original way with the upgraded action either! +Whoops, you aren't able to write to table the original way with the upgraded action either.
Ok, back up and wrap the new field and the new action parameter in an `eosio::binary_extension` type: @@ -707,4 +707,81 @@ If you are adding a new field to a struct currently in use by a `eosio::multi_in - add the field at the end of the struct, - and wrap the type using an `eosio::binary_extension` type. -Also, there are a few restrictions you have to be aware of which are outlined [here](https://github.com/EOSIO/eos/issues/5600). \ No newline at end of file +# There are a few restrictions you have to be aware of, and they are outlined below + +Binary extensions only operate correctly in certain locations. + +* ok: a non-embedded struct stored in a row may have binary extensions at its end +* ok: an action may use binary extensions to add additional arguments to its end +* ok: a struct with binary extensions may be used inside another struct, but only if the inner struct is the last field of the outer struct and the outer struct is allowed to contain binary extensions +* not ok: a struct with binary extensions may not be used inside an array +* not ok: a struct with binary extensions may not be used as a base of another struct +* not ok: fields with types which don't end in `$` following fields with types which do +* not ok: `$` used anywhere except in struct field types + +## ABI version string + +`eosio::abi/1.1` + +## ABI Text format + +Types may have a `$` suffix. During binary-to-json conversion, fields with a `$` type don't error out when end-of-data has been reached; instead they're omitted. During json-to-binary conversion, missing fields don't error out as long as no non-missing fields follow in the ABI. This omits the bytes from the output stream. + +e.g. + +```json + { + "name": "my_table_struct", + "base": "", + "fields": [ + { + "name": "required_field_1", + "type": "string" + }, + { + "name": "required_field_2", + "type": "float32[]" + }, + { + "name": "optional_field_3", + "type": "float32[]$" + }, + { + "name": "optional_field_4", + "type": "string$" + }, + ] + }, +``` + +## JSON representation + +Missing fields aren't included; null isn't used. E.g. all of these are valid JSON representations of `my_table_struct`: + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4] +} +``` + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4], + "optional_field_3": [5,6,7,8] +} +``` + +```json +{ + "required_field_1": "foo", + "required_field_2": [1,2,3,4], + "optional_field_3": [5,6,7,8], + "optional_field_4": "bar" +} +``` + +## ABI Binary format + +`$` can be included in type strings. No other changes. diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index b986362ea5..50c2606cb6 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -102,7 +102,7 @@ Now you can deploy the contract and it will be backwards compatible with the pre ### Use variant when changing an already deployed multi index table -#### Preconditions: The contract defined in the this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) will be used. It is assumed you deployed it and now you are going to change the table structure. +#### Preconditions The contract defined in the this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) will be used. It is assumed you deployed it and now you are going to change the table structure. To change the existing table structure, you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: From ffe740c57537903e904b8c57ffddde65655240fa Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Tue, 8 Oct 2019 12:14:47 -0400 Subject: [PATCH 073/659] eosio/producer -> eosio/ci (#700) --- .cicd/helpers/docker-hash.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/helpers/docker-hash.sh b/.cicd/helpers/docker-hash.sh index 3bbb644c06..6dcd24b3c2 100644 --- a/.cicd/helpers/docker-hash.sh +++ b/.cicd/helpers/docker-hash.sh @@ -17,7 +17,7 @@ function determine-hash() { if [[ ! -z $IMAGE_TAG ]]; then determine-hash "$CICD_DIR/docker/${IMAGE_TAG}.dockerfile" - export FULL_TAG="eosio/producer:eosio-cdt-$HASHED_IMAGE_TAG" + export FULL_TAG="eosio/ci:eosio-cdt-$HASHED_IMAGE_TAG" else echo "Please set ENV::IMAGE_TAG to match the name of a platform dockerfile..." exit 1 From 69e91c9132dce58102d92609918fd978ecba8f19 Mon Sep 17 00:00:00 2001 From: Emory Barlow Date: Tue, 8 Oct 2019 14:13:23 -0400 Subject: [PATCH 074/659] For proper package naming centos needs to be el7 --- .cicd/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 8c75bb6f09..7bd46ae51b 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -161,7 +161,7 @@ steps: env: BUILDKITE_AGENT_ACCESS_TOKEN: IMAGE_TAG: "centos-7.6" - OS: "centos" # OS and PKGTYPE required for lambdas + OS: "el7" # OS and PKGTYPE required for lambdas PKGTYPE: "rpm" agents: queue: "automation-eos-builder-fleet" @@ -208,4 +208,4 @@ steps: - "./.cicd/submodule-regression-checker.sh" agents: queue: "automation-basic-builder-fleet" - timeout: 5 \ No newline at end of file + timeout: 5 From 5aecd5e75f0dce7d16a49d63270bdb6df8004250 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 10 Oct 2019 16:53:38 -0400 Subject: [PATCH 075/659] 10.14.4 -> 10.14.6 (#706) --- .cicd/pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 7bd46ae51b..4ec15ffbee 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -58,7 +58,7 @@ steps: - chef/anka#v0.5.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.4_6C_14G_40G + vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -127,7 +127,7 @@ steps: - chef/anka#v0.5.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.4_6C_14G_40G + vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -193,7 +193,7 @@ steps: - chef/anka#v0.5.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.4_6C_14G_40G + vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" always-pull: true debug: true From 29e23f0c43bc2a960df397958f5814e5dac05598 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 11 Oct 2019 10:06:28 +0300 Subject: [PATCH 076/659] Resolves #683 --- libraries/eosiolib/contracts/eosio/multi_index.hpp | 8 ++++---- libraries/eosiolib/multi_index.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/multi_index.hpp b/libraries/eosiolib/contracts/eosio/multi_index.hpp index e20603cb38..99beafe527 100644 --- a/libraries/eosiolib/contracts/eosio/multi_index.hpp +++ b/libraries/eosiolib/contracts/eosio/multi_index.hpp @@ -1010,10 +1010,10 @@ class multi_index const_iterator begin()const { return cbegin(); } /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. * @ingroup multiindex * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * @return An iterator referring to the `past-the-end` element in the multi index container. * * Example: * @@ -1034,10 +1034,10 @@ class multi_index const_iterator cend()const { return const_iterator( this ); } /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. * @ingroup multiindex * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * @return An iterator referring to the `past-the-end` element in the multi index container. * * Example: * diff --git a/libraries/eosiolib/multi_index.hpp b/libraries/eosiolib/multi_index.hpp index 24938c2561..a5c6db2289 100644 --- a/libraries/eosiolib/multi_index.hpp +++ b/libraries/eosiolib/multi_index.hpp @@ -828,9 +828,9 @@ class multi_index const_iterator begin()const { return cbegin(); } /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * @return An iterator referring to the `past-the-end` element in the multi index container. * * Example: * @@ -851,9 +851,9 @@ class multi_index const_iterator cend()const { return const_iterator( this ); } /** - * Returns an iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. * - * @return An iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. + * @return An iterator referring to the `past-the-end` element in the multi index container. * * Example: * From 144d0438d728e54d3789861f44a85e46ee25c711 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 11 Oct 2019 11:41:35 +0300 Subject: [PATCH 077/659] address more PR feedback received --- README.md | 21 +------------- docs/02_installation.md | 2 +- docs/03_command-reference/eosio-abigen.md | 2 +- docs/04_upgrading/1.2-to-1.3.md | 4 +-- .../04_data-design-and-migration.md | 4 +-- .../05_securing_your_contract.md | 2 +- ...02_manually_write_an_ABI_file_explained.md | 6 ++-- .../10_native-tester-compilation.md | 2 +- ...ct.md => 11_debugging_a_smart_contract.md} | 2 +- .../01_compile-a-contract-via-cli.md | 6 ++-- .../03_compiling-contracts-with-cmake.md | 4 +-- .../how-to-define-a-secondary-index.md | 3 +- ...to-delete-data-from-a-multi-index-table.md | 3 +- ...to-insert-data-into-a-multi-index-table.md | 3 +- ...ti_index-table-based-on-secondary-index.md | 3 +- ...terate-and-retrieve-a-multi_index-table.md | 3 +- ...w-to-modify-data-in-a-multi-index-table.md | 3 +- ...to_restrict_access_to_an_action_by_user.md | 3 +- docs/08_troubleshooting.md | 28 +++++++++---------- docs/09_tutorials/02_abi-variants.md | 3 +- docs/index.md | 23 ++------------- 21 files changed, 48 insertions(+), 82 deletions(-) rename docs/05_best-practices/{11_debuggin_a_smart_contract.md => 11_debugging_a_smart_contract.md} (93%) diff --git a/README.md b/README.md index 83cdba2b8a..3cc3404b66 100644 --- a/README.md +++ b/README.md @@ -9,29 +9,10 @@ As of this release two new repositories are under the suite of tools provided by ## Important! EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. -## Concepts - -### Dispatcher and Notifications -[Dispatcher API reference](https://eosio.github.io/eosio.cdt/1.6.0/group__dispatcher.html) -[schemata:link to glossary] - -### Multi Index Table and RAM -[Multi Index Tables explained by example](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) -[schemata:link to glossary] - -### Smart Contract -[schemata:link to glossary] - -### Action -[schemata:link to glossary] - -### Transaction and Deferred Transaction -[schemata:link to glossary] - ## Binary Releases EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. -**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** +**If you have previously installed EOSIO.CDT, run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** ### Mac OS X Brew Install ```sh diff --git a/docs/02_installation.md b/docs/02_installation.md index 59f43e9c0a..193510a018 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -1,7 +1,7 @@ ## Binary Releases EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. -**If you have previously installed EOSIO.CDT, please run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** +**If you have previously installed EOSIO.CDT, run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** ### Mac OS X Brew Install ```sh diff --git a/docs/03_command-reference/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md index c8b9dcea27..a2a563f902 100644 --- a/docs/03_command-reference/eosio-abigen.md +++ b/docs/03_command-reference/eosio-abigen.md @@ -1,6 +1,6 @@ ## eosio-abigen tool -### This tool is deprecated, please use `eosio-cpp` for generation of your ABIs +### This tool is deprecated, use `eosio-cpp` for generation of your ABIs To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index f168999746..c5d254380c 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -203,7 +203,7 @@ typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; ``` If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. -For an example contract of ABI generation please see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with `eosio-abigen test.cpp --output=test.abi`. +For an example contract of ABI generation see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with `eosio-abigen test.cpp --output=test.abi`. ### Fixing an ABI or Writing an ABI Manually - The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually. @@ -216,7 +216,7 @@ For an example contract of ABI generation please see the file ./examples/abigen_ - For each Ricardian contract, the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - The option `-R` has been added to eosio-cpp and eosio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. -- To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. +- For exemplification see [hello.contracts.md](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/ricardian/hello.contracts.md). diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index 65d3ffdf8e..ec126b4250 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -17,10 +17,10 @@ If you don't mind losing the data from the initial table you can follow these tw If you want to keep the existing data there are two ways to do it: ### 2.1. Using binary extentions -To learn how to modify the structure using binary extensions please read this [tutorial](../09_tutorials/01_binary-extension.md). +To learn how to modify the structure using binary extensions read this [tutorial](../09_tutorials/01_binary-extension.md). ### 2.2. Using ABI variants -To learn how to modify the structure using ABI variants please read this [tutorial](../09_tutorials/02_abi-variants.md). +To learn how to modify the structure using ABI variants read this [tutorial](../09_tutorials/02_abi-variants.md). ### 2.3. Migrate the existing data to a second table diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md index 0148889147..2bcf2f39b8 100644 --- a/docs/05_best-practices/05_securing_your_contract.md +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -3,7 +3,7 @@ These are basic recommendations that should be the foundation of securing your s 1. The master git branch has the `has_auth`, `require_auth`, `require_auth2` and `require_recipient` methods available in the EOSIO library. They can be found in detail [here](https://eosio.github.io/eosio.cdt/1.6.0-rc1/group__action.html#function-requirerecipient) and implemented [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L144) (they end up calling the methods implemented in the `apply_context` class). -2. Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. You saw earlier how changing one parameter value in the multi-index `emplace` and `modify` methods changed the account that is billed for the RAM and CPU needed to execute that action. +2. Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. 3. Have a solid and comprehensive development process that includes security considerations from day one of the product planning and development. diff --git a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md index 803098b889..e2c10c7396 100644 --- a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -3,9 +3,9 @@ - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. ### Adding Ricardian Contracts and Clauses to ABI -- , the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. -- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. +- The ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. +- The Ricardian contracts should be housed in a file with the name `.contracts.md` and the clauses should be in a file named `.clauses.md`. - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - For each Ricardian clause, the header `

ClauseID

` should be used, as this directs the ABI generator to the clause id and the subsequent body. - The option `-R` has been added to [`eosio-cpp`](../../03_command-reference/eosio-cpp.md) and [`eosio-abigen`](../../03_command-reference/eosio-abigen.md) to add "resource" paths to search from, so you can place these files in any directory structure you like and use `-R` in the same vein as `-I` for include paths. - - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md. + - For exemplification see [hello.contracts.md](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/ricardian/hello.contracts.md). diff --git a/docs/05_best-practices/10_native-tester-compilation.md b/docs/05_best-practices/10_native-tester-compilation.md index 8ef328af7f..e677980021 100644 --- a/docs/05_best-practices/10_native-tester-compilation.md +++ b/docs/05_best-practices/10_native-tester-compilation.md @@ -88,7 +88,7 @@ int main(int argc, char** argv) { } ``` -Every `intrinsic` that is defined for eosio (prints, require_auth, etc.) is redefinable given the `intrinsics::set_intrinsics()` functions. These take a lambda whose arguments and return type should match that of the intrinsic you are trying to define. This gives the contract writer the flexibility to modify behavior to suit the unit test being written. A sister function `intrinsics::get_intrinsics()` will return the function object that currently defines the behavior for said intrinsic. This pattern can be used to mock functionality and allow for easier testing of smart contracts. For more information please see, either the `./tests` directory or `./examples/hello/tests/hello_test.cpp` for working examples. +Every `intrinsic` that is defined for eosio (prints, require_auth, etc.) is re-definable given the `intrinsics::set_intrinsics()` functions. These take a lambda whose arguments and return type should match that of the intrinsic you are trying to define. This gives the contract writer the flexibility to modify behavior to suit the unit test being written. A sister function `intrinsics::get_intrinsics()` will return the function object that currently defines the behavior for said intrinsic. This pattern can be used to mock functionality and allow for easier testing of smart contracts. For more information see, either the [tests](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/) directory or [hello_test.cpp](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/hello_test.cpp) for working examples. ### Compiling Native Code - Raw `eosio-cpp` to compile the test or program the only addition needed to the command line is to add the flag `-fnative` this will then generate native code instead of `wasm` code. diff --git a/docs/05_best-practices/11_debuggin_a_smart_contract.md b/docs/05_best-practices/11_debugging_a_smart_contract.md similarity index 93% rename from docs/05_best-practices/11_debuggin_a_smart_contract.md rename to docs/05_best-practices/11_debugging_a_smart_contract.md index a45a10aabc..7c03da1f91 100644 --- a/docs/05_best-practices/11_debuggin_a_smart_contract.md +++ b/docs/05_best-practices/11_debugging_a_smart_contract.md @@ -6,7 +6,7 @@ When you are creating your smart contract for the first time, it is recommended The concept is the same, so for the following guide, debugging on the private testnet will be covered. -If you haven't set up your own local nodeos, please follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. +If you haven't set up your own local nodeos, follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. ## Method The main method used to debug smart contract is **Caveman Debugging**. Printing is utilized to inspect the value of a variable and check the flow of the contract. Printing in smart contracts can be done through the Print API. The C++ API is a wrapper for C API and is the recommended API. diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index 6e527c2a67..c50c6155e6 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1,12 +1,10 @@ ## How to compile a contract via CLI ### Preconditions ---- -You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` +- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) -Follow these steps to compile your contract ---- +Follow these steps to compile your contract: 1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file 2. Now run following commands: diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index bac74f9bbe..70afbb5fd0 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -1,12 +1,10 @@ ## How to compile a smart contract with CMake ### Preconditions ---- -You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` +- You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) Follow these steps to compile your contract: ---- 1. Navigate to the hello folder in examples (./examples/hello), you should then see the ./src/hello.cpp file 2. Run following commands: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 4df568052d..3036e20b45 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,6 +1,7 @@ ## How to define a secondary index -### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index f017e930df..5ea7abf61c 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,6 +1,7 @@ ## How to delete data from a multi index table -### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To delete data from a multi index table follow the steps below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index e08fb2c8c1..ac5510fbe2 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,6 +1,7 @@ ## How to insert data into a multi index table -### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To insert data into a multi index table follow the following steps diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 71db17d652..400abb4156 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,7 @@ ## How to iterate and retreive a multi index table based on secondary index -### Preconditions It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). +### Preconditions +- It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index f8f63bc6b6..7aae513058 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,6 +1,7 @@ ## How to iterate and retrieve a multi index table -### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). For exemplification define the multi index contract definition like below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index e2547b25a0..af5f600c59 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,6 +1,7 @@ ## How to modify data in a multi index table -### Preconditions it is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). +### Preconditions +- It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To modify data in the multi index table defined in the above tutorial, you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index f0761d1053..a1a2754560 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,6 +1,7 @@ ## How to restrict access to an action by a user -### Preconditions It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. +### Preconditions +- It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. To restrict access to the `hi` action, you can do it in two ways: diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index 09caa37dc8..b3465e9ad2 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,6 +1,6 @@ ## Troubleshooting -1. __Problem__: When sending an action to the blockchain you get the error below +### When sending an action to the blockchain you get the error below ```{ "code":500, "message":"Internal Service Error", @@ -19,9 +19,9 @@ } } ``` -__Possbile solution__: Verify if you did not forget to set code for contract, is it possible that you only set the `abi` for the contract but not the code as well? +__Possible solution__: Verify if you did not forget to set code for contract, is it possible that you only set the `abi` for the contract but not the code as well? -2. __Problem__: When sending an action to the blockchain an error similar to the one below is encountered: +### When sending an action to the blockchain an error similar to the one below is encountered: ```sh Error 3015014: Pack data exception Error Details: @@ -33,14 +33,14 @@ cleos push action eostutorial1 get '[]' -p eostutorial1@active ``` The command above is one way of sending correctly `get` action with no parameters to the blockchain. -3. __Problem__: When sending an action to the blockchain an error similar to the one below is encountered: +### When sending an action to the blockchain an error similar to the one below is encountered: ```sh error 2019-09-25T07:38:14.859 thread-0 main.cpp:3449 main ] Failed with error: Assert Exception (10) !action_type.empty(): Unknown action action_name in contract eostutorial1 ``` __Possible solution__: Verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. -4. __Problem__: When deploying a contract code to the blockchain a similar error with the ones below is encountered: +### When deploying a contract code to the blockchain a similar error with the ones below is encountered: ```sh Error 3160010: No abi file found or @@ -48,11 +48,11 @@ Error 3160009: No wasm file found ``` __Possible solution__: Verify that `abi` and `wasm` files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. -5. __Problem__: Action triggers ram charge which cannot be initiated from a notification. +### Action triggers ram charge which cannot be initiated from a notification. __Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control -6. __Problem__: You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +### You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: ```sh Error 3050003: eosio_assert_message assertion failure Error Details: @@ -61,26 +61,26 @@ pending console output: ``` __Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -7. __Problem__: You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. +### You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. __Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -8. __Problem__: You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. +### You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. ```sh error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) Couldn't parse type_name ``` __Possible solution__: It is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -9. __Problem__: eosio-cpp process never completes. +### eosio-cpp process never completes. __Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) -10. __Problem__: You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. +### You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. -11. __Problem__: You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +### You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: ```sh Error 3050004: eosio_assert_code assertion failure Error Details: @@ -88,7 +88,7 @@ assertion failure with error code: 8000000000000000000 ``` __Possible solution__: If you are referencing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. -12. __Problem__: Print statements from smart contract code are not seen in the output. +### Print statements from smart contract code are not seen in the output. __Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iteration will be printed, nothing else after that, nothing from the second iteration onwards either. @@ -111,7 +111,7 @@ The below code will print all lines of the iteration separated by `'|'` char. } ``` -12. __Problem__: Print statements from smart contract code are not shown in the `expected order`. +### Print statements from smart contract code are not shown in the `expected order`. __Possible solution__: The key point here is the `expected order` and what you think it should be. Although the EOSIO is single threaded, when looking at your smart contract action code implementation, which let's say it has a series of `print` (either `print_f` or `printf`) statements, they might not necessarily be outputted in the order the `apparent` code workflow is. One example is when inline transactions are sent from your smart contract action code, and you expect to see the `print` statements from within the inline action code outputted before the `print` statements made after the inline action `send` statement. For better exemplification let's look at the code below: diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 50c2606cb6..9e99f1f912 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -102,7 +102,8 @@ Now you can deploy the contract and it will be backwards compatible with the pre ### Use variant when changing an already deployed multi index table -#### Preconditions The contract defined in the this section [here](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) will be used. It is assumed you deployed it and now you are going to change the table structure. +#### Preconditions +- It is assumed you deployed the contract defined in [this section](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) and now you are going to change its table structure. To change the existing table structure, you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: diff --git a/docs/index.md b/docs/index.md index e3d160b886..3dc341ead1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,27 +6,8 @@ EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate s ## New Introductions As of this release two new repositories are under the suite of tools provided by **EOSIO.CDT**. These are the [Ricardian Template Toolkit](https://github.com/eosio/ricardian-template-toolkit) and the [Ricardian Specification](https://github.com/eosio/ricardian-spec). The **Ricardian Template Toolkit** is a set of libraries to facilitate smart contract writers in crafting their Ricardian contracts. The Ricardian specification is the working specification for the above mentioned toolkit. Please note that both projects are **alpha** releases and are subject to change. -## Important! -EOSIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from EOSIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the [Upgrade guide from 1.2 to 1.3](./upgrading/1.2-to-1.3) section of this readme. - -## Concepts - -### Dispatcher and Notifications -[Dispatcher API reference](https://eosio.github.io/eosio.cdt/1.6.0/group__dispatcher.html) -[schemata:link to glossary] - -### Multi Index Table and RAM -[Multi Index Tables explained by example](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) -[schemata:link to glossary] - -### Smart Contract -[schemata:link to glossary] - -### Action -[schemata:link to glossary] - -### Transaction and Deferred Transaction -[schemata:link to glossary] +## Upgrading +There's been a round of braking changes, if you are upgrading please read the [Upgrade guide from 1.2 to 1.3](./04_upgrading/1.2-to-1.3.md) and [Upgrade guide from 1.5 to 1.6](./04_upgrading/1.5-to-1.6.md). ## Contributing From 2d772c784e2f0c0884e1ba091f2b5775fc07bba8 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 17 Oct 2019 17:16:08 +0800 Subject: [PATCH 078/659] change the example code to be consistent with the example codes from the other repos --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 3cc3404b66..9826b96c63 100644 --- a/README.md +++ b/README.md @@ -16,45 +16,45 @@ EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Li ### Mac OS X Brew Install ```sh -$ brew tap eosio/eosio.cdt -$ brew install eosio.cdt +brew tap eosio/eosio.cdt +brew install eosio.cdt ``` ### Mac OS X Brew Uninstall ```sh -$ brew remove eosio.cdt +brew remove eosio.cdt ``` ### Debian Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb -$ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb +sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb ``` ### Debian Package Uninstall ```sh -$ sudo apt remove eosio.cdt +sudo apt remove eosio.cdt ``` ### RPM Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm -$ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm +wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm +sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm ``` ### RPM Package Uninstall ```sh -$ sudo yum remove eosio.cdt +sudo yum remove eosio.cdt ``` ## Guided Installation or Building from Scratch ```sh -$ git clone --recursive https://github.com/eosio/eosio.cdt -$ cd eosio.cdt -$ mkdir build -$ cd build -$ cmake .. -$ make -j8 +git clone --recursive https://github.com/eosio/eosio.cdt +cd eosio.cdt +mkdir build +cd build +cmake .. +make -j8 ``` From here onward you can build your contracts code by simply exporting the `build` directory to your path, so you don't have to install globally (makes things cleaner). @@ -67,9 +67,9 @@ sudo make install ### Uninstall after manual installation ```sh -$ sudo rm -fr /usr/local/eosio.cdt -$ sudo rm -fr /usr/local/lib/cmake/eosio.cdt -$ sudo rm /usr/local/bin/eosio-* +sudo rm -fr /usr/local/eosio.cdt +sudo rm -fr /usr/local/lib/cmake/eosio.cdt +sudo rm /usr/local/bin/eosio-* ``` ## Installed Tools From 50b4b082d1149864f27595d24c630fcd50b56527 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 17 Oct 2019 09:44:37 -0400 Subject: [PATCH 079/659] changes for catalina --- .cicd/pipeline.yml | 68 ++++++++++++++++++++++++++++++++++++++ scripts/generate_bottle.sh | 14 ++++---- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 4ec15ffbee..4772bfdc37 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -69,6 +69,30 @@ steps: - "queue=mac-anka-large-node-fleet" skip: $SKIP_MOJAVE + - label: ":darwin: macOS 10.15 - Build" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && ./.cicd/build.sh" + - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" + plugins: + - chef/anka#v0.5.1: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.0_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-large-node-fleet" + skip: $SKIP_MOJAVE + + - wait - label: ":aws: Amazon_Linux 2 - Unit Tests" @@ -138,6 +162,29 @@ steps: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} + - label: ":darwin: macOS 10.15 - Unit Tests" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/tests.sh" + plugins: + - chef/anka#v0.5.1: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.0_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-large-node-fleet" + skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} + - wait: continue_on_failure: true @@ -203,6 +250,27 @@ steps: timeout: 10 skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} + - label: ":darwin: Catalina - Package Builder" + command: + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/package.sh" + plugins: + - chef/anka#v0.5.1: + no-volume: true + inherit-environment-vars: true + vm-name: 10.14.6_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-node-fleet" + timeout: 10 + skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} + - label: ":git: Git Submodule Regression Check" command: - "./.cicd/submodule-regression-checker.sh" diff --git a/scripts/generate_bottle.sh b/scripts/generate_bottle.sh index d93dc23190..12a1db9b1f 100644 --- a/scripts/generate_bottle.sh +++ b/scripts/generate_bottle.sh @@ -1,17 +1,15 @@ #! /bin/bash -VERS=`sw_vers -productVersion | awk '/10\.13\..*/{print $0}'` -if [[ -z "$VERS" ]]; -then - VERS=`sw_vers -productVersion | awk '/10\.14.*/{print $0}'` - if [[ -z "$VERS" ]]; - then +VERS=`sw_vers -productVersion | awk '/10\.14\..*/{print $0}'` +if [[ -z "$VERS" ]]; then + VERS=`sw_vers -productVersion | awk '/10\.15.*/{print $0}'` + if [[ -z $VERS ]]; then echo "Error, unsupported OS X version" exit -1 fi - MAC_VERSION="mojave" + MAC_VERSION="catalina" else - MAC_VERSION="high_sierra" + MAC_VERSION="mojave" fi NAME="${PROJECT}-${VERSION}.${MAC_VERSION}.bottle" From 8f793fd3e90de19582723b69bbb1f596a16708fd Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 17 Oct 2019 09:46:42 -0400 Subject: [PATCH 080/659] quick fix to version --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 4772bfdc37..8e6e428d74 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -261,7 +261,7 @@ steps: - chef/anka#v0.5.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.6_6C_14G_40G + vm-name: 10.15.0_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" always-pull: true debug: true From eab1b915589747d395ccedce73800e7c01e9ac84 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 17 Oct 2019 09:47:39 -0400 Subject: [PATCH 081/659] quick fix to version --- .cicd/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 8e6e428d74..bb88efec6e 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -69,7 +69,7 @@ steps: - "queue=mac-anka-large-node-fleet" skip: $SKIP_MOJAVE - - label: ":darwin: macOS 10.15 - Build" + - label: ":darwin: macOS 10.15 - Build" command: - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" - "git clone $BUILDKITE_REPO eosio.cdt" @@ -168,7 +168,7 @@ steps: - "git clone $BUILDKITE_REPO eosio.cdt" - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" - - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/tests.sh" plugins: - chef/anka#v0.5.1: From 618b3f8668e337eb74e6a5fda8953c20ac7d4238 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 17 Oct 2019 10:21:40 -0400 Subject: [PATCH 082/659] quick fix to SKIP --- .cicd/pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index bb88efec6e..897c3a4acf 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -90,7 +90,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: $SKIP_MOJAVE + skip: $SKIP_CATALINA - wait @@ -183,7 +183,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} + skip: ${SKIP_CATALINA}${SKIP_UNIT_TESTS} - wait: continue_on_failure: true @@ -269,7 +269,7 @@ steps: agents: - "queue=mac-anka-node-fleet" timeout: 10 - skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} + skip: ${SKIP_CATALINA}${SKIP_PACKAGE_BUILDER} - label: ":git: Git Submodule Regression Check" command: From 2e3a0c537cff8985add6e32715810d4fe8571017 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 17 Oct 2019 10:23:05 -0400 Subject: [PATCH 083/659] quick fix to SKIP --- .cicd/pipeline.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 897c3a4acf..c338a7a2a2 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -67,7 +67,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: $SKIP_MOJAVE + skip: $SKIP_MACOS_10_14 - label: ":darwin: macOS 10.15 - Build" command: @@ -90,7 +90,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: $SKIP_CATALINA + skip: $SKIP_MACOS_10_15 - wait @@ -160,7 +160,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} + skip: ${SKIP_MACOS_10_14}${SKIP_UNIT_TESTS} - label: ":darwin: macOS 10.15 - Unit Tests" command: @@ -183,7 +183,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_CATALINA}${SKIP_UNIT_TESTS} + skip: ${SKIP_MACOS_10_15}${SKIP_UNIT_TESTS} - wait: continue_on_failure: true @@ -248,7 +248,7 @@ steps: agents: - "queue=mac-anka-node-fleet" timeout: 10 - skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} + skip: ${SKIP_MACOS_10_14}${SKIP_PACKAGE_BUILDER} - label: ":darwin: Catalina - Package Builder" command: @@ -269,7 +269,7 @@ steps: agents: - "queue=mac-anka-node-fleet" timeout: 10 - skip: ${SKIP_CATALINA}${SKIP_PACKAGE_BUILDER} + skip: ${SKIP_MACOS_10_15}${SKIP_PACKAGE_BUILDER} - label: ":git: Git Submodule Regression Check" command: From 034d8e9b1b5ce9eca94ce86ee0d65742645dce88 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 10:14:17 -0400 Subject: [PATCH 084/659] Fix a segfault when "using" a variant. --- tools/include/eosio/abigen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 1cd33e636b..02fd768b65 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -237,7 +237,7 @@ namespace eosio { namespace cdt { void add_variant( const clang::QualType& t ) { abi_variant var; auto pt = llvm::dyn_cast(t.getTypePtr()); - auto tst = llvm::dyn_cast(pt->desugar().getTypePtr()); + auto tst = llvm::dyn_cast((pt) ? pt->desugar().getTypePtr() : t.getTypePtr()); var.name = get_type(t); for (int i=0; i < tst->getNumArgs(); ++i) { var.types.push_back(translate_type(get_template_argument( t, i ).getAsType())); From 3d7c9e963223b3ffe8cc9d332f3220bbd2da4cc1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 10:21:01 -0400 Subject: [PATCH 085/659] Add toolchain test for using a variant --- .../build-pass/using_std_variant.cpp | 30 +++++++++++++++++++ .../build-pass/using_std_variant.json | 10 +++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/toolchain/build-pass/using_std_variant.cpp create mode 100644 tests/toolchain/build-pass/using_std_variant.json diff --git a/tests/toolchain/build-pass/using_std_variant.cpp b/tests/toolchain/build-pass/using_std_variant.cpp new file mode 100644 index 0000000000..b3e5f159f5 --- /dev/null +++ b/tests/toolchain/build-pass/using_std_variant.cpp @@ -0,0 +1,30 @@ +/* + * Regression test for https://github.com/EOSIO/eosio.cdt/issues/558 + * + * Verifies that a class/function can be used from the std namespace + */ + +#include +#include +#include + +using std::variant; +using namespace eosio; + +class[[eosio::contract("hello")]] hello : public contract +{ +public: + using contract::contract; + + [[eosio::action]] void hi(name user) { + require_auth(user); + print("Hello, ", user); + } + + struct [[eosio::table]] greeting { + uint64_t id; + variant t; + uint64_t primary_key() const { return id; } + }; + typedef multi_index<"greeting"_n, greeting> greeting_index; +}; diff --git a/tests/toolchain/build-pass/using_std_variant.json b/tests/toolchain/build-pass/using_std_variant.json new file mode 100644 index 0000000000..b3598b0cf4 --- /dev/null +++ b/tests/toolchain/build-pass/using_std_variant.json @@ -0,0 +1,10 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} + From 7aee55a1fe60fbf2cd6095cd3096fb8a4e2a6644 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 10:28:34 -0400 Subject: [PATCH 086/659] Add toolchain tests to CICD --- .cicd/pipeline.yml | 69 ++++++++++++++++++++++++++++++++++++++++ .cicd/toolchain-tests.sh | 35 ++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100755 .cicd/toolchain-tests.sh diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 4ec15ffbee..5aa9f8015d 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -154,6 +154,75 @@ steps: - wait + - label: ":aws: Amazon_Linux 2 - Toolchain Tests" + command: + - "buildkite-agent artifact download build.tar.gz . --step ':aws: Amazon_Linux 2 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "./.cicd/toolchain-tests.sh" + env: + IMAGE_TAG: "amazonlinux-2" + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: ${SKIP_AMAZON_LINUX_2}${SKIP_TOOLCHAIN_TESTS} + + - label: ":centos: CentOS 7.6 - Toolchain Tests" + command: + - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.6 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "./.cicd/toolchain-tests.sh" + env: + IMAGE_TAG: "centos-7.6" + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: ${SKIP_CENTOS_7}${SKIP_TOOLCHAIN_TESTS} + + - label: ":ubuntu: Ubuntu 16.04 - Toolchain Tests" + command: + - "buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 16.04 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "./.cicd/toolchain-tests.sh" + env: + IMAGE_TAG: "ubuntu-16.04" + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: ${SKIP_UBUNTU_16}${SKIP_TOOLCHAIN_TESTS} + + - label: ":ubuntu: Ubuntu 18.04 - Toolchain Tests" + command: + - "buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 18.04 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "./.cicd/toolchain-tests.sh" + env: + IMAGE_TAG: "ubuntu-18.04" + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: ${SKIP_UBUNTU_18}${SKIP_TOOLCHAIN_TESTS} + + - label: ":darwin: macOS 10.14 - Toolchain Tests" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/toolchain-tests.sh" + plugins: + - chef/anka#v0.5.1: + no-volume: true + inherit-environment-vars: true + vm-name: 10.14.6_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-large-node-fleet" + skip: ${SKIP_MOJAVE}${SKIP_TOOLCHAIN_TESTS} + + - wait + - label: ":centos: Centos 7.6 - Package Builder" command: - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.6 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" diff --git a/.cicd/toolchain-tests.sh b/.cicd/toolchain-tests.sh new file mode 100755 index 0000000000..a369b1e68a --- /dev/null +++ b/.cicd/toolchain-tests.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -eo pipefail +. ./.cicd/helpers/general.sh + +mkdir -p $BUILD_DIR + +PRE_COMMANDS="cd $MOUNTED_DIR/build" +TEST="./tools/toolchain-tester/toolchain-tester ../tests/toolchain/" +COMMANDS="$PRE_COMMANDS && $TEST" + +if [[ $(uname) == 'Darwin' ]]; then + + # You can't use chained commands in execute + cd $BUILD_DIR + bash -c "$TEST" + +else # Linux + + ARGS=${ARGS:-"--rm --init -v $(pwd):$MOUNTED_DIR"} + + . $HELPERS_DIR/docker-hash.sh + + [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS -e CCACHE_DIR=/opt/.ccache" + + # Load BUILDKITE Environment Variables for use in docker run + if [[ -f $BUILDKITE_ENV_FILE ]]; then + evars="" + while read -r var; do + evars="$evars --env ${var%%=*}" + done < "$BUILDKITE_ENV_FILE" + fi + + eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" + +fi From ca81245c02571b379c260c0e11984a1e3d56013b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 11:38:20 -0400 Subject: [PATCH 087/659] Exit with proper code based on success/failure --- tools/toolchain-tester/main.py | 10 ++++++++-- tools/toolchain-tester/printer.py | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/toolchain-tester/main.py b/tools/toolchain-tester/main.py index c6d12fc801..44129530da 100644 --- a/tools/toolchain-tester/main.py +++ b/tools/toolchain-tester/main.py @@ -1,5 +1,6 @@ import argparse import os +import sys import tempfile from pathlib import Path @@ -75,9 +76,14 @@ def main(): end = timer() if args.format == "human": - print_test_results(test_results, end - start) + failures = print_test_results(test_results, end - start) else: - print_test_results_machine(test_results, end - start) + failures = print_test_results_machine(test_results, end - start) + + if failures: + sys.exit(1) + + sys.exit(0) def get_cdt_path() -> str: diff --git a/tools/toolchain-tester/printer.py b/tools/toolchain-tester/printer.py index b524b80464..c68ccf8345 100644 --- a/tools/toolchain-tester/printer.py +++ b/tools/toolchain-tester/printer.py @@ -25,7 +25,7 @@ def print_test_results( results: List[Tuple[Test, Optional[TestFailure]]], run_time: float -) -> None: +) -> List[TestFailure]: Printer.print("\n========= Results =========") failures = [] @@ -60,6 +60,8 @@ def print_test_results( Printer.print(f"\nTotal Test discovery and run time = {run_time:.2f} sec") + return failures + def print_test_results_machine( results: List[Tuple[Test, Optional[TestFailure]]], run_time: float From 6c02bcccae6257a9b226e6f89f0e064d80769694 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 12:55:20 -0400 Subject: [PATCH 088/659] Update docker images to have Python 3.7.4 --- .cicd/docker/centos-7.6.dockerfile | 17 +++++++++++++++-- .cicd/docker/ubuntu-16.04.dockerfile | 15 +++++++++++++-- .cicd/docker/ubuntu-18.04.dockerfile | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.cicd/docker/centos-7.6.dockerfile b/.cicd/docker/centos-7.6.dockerfile index f7baa808a5..76363842b9 100644 --- a/.cicd/docker/centos-7.6.dockerfile +++ b/.cicd/docker/centos-7.6.dockerfile @@ -6,7 +6,9 @@ RUN yum update -y && \ yum install -y python33.x86_64 git autoconf automake bzip2 \ libtool ocaml.x86_64 doxygen graphviz-devel.x86_64 \ libicu-devel.x86_64 bzip2.x86_64 bzip2-devel.x86_64 openssl-devel.x86_64 \ - gmp-devel.x86_64 python-devel.x86_64 gettext-devel.x86_64 gcc-c++.x86_64 perl + gmp-devel.x86_64 python-devel.x86_64 gettext-devel.x86_64 gcc-c++.x86_64 perl \ + libffi-devel.x86_64 + # build lcov RUN git clone https://github.com/linux-test-project/lcov.git && \ source /opt/rh/python33/enable && \ @@ -15,6 +17,7 @@ RUN git clone https://github.com/linux-test-project/lcov.git && \ make install && \ cd / && \ rm -rf lcov/ + # build cmake RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ source /opt/rh/python33/enable && \ @@ -25,4 +28,14 @@ RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ make -j$(nproc) && \ make install && \ cd .. && \ - rm -f cmake-3.10.2.tar.gz \ No newline at end of file + rm -f cmake-3.10.2.tar.gz + +# build Python 3.7.4 +RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ + source /opt/rh/devtoolset-7/enable && \ + tar xzf Python-3.7.4.tgz && \ + cd Python-3.7.4 && \ + ./configure --enable-optimizations && \ + make -j$(nproc) altinstall && \ + cd .. && \ + rm -f Python-3.7.4 && rm -f Python-3.7.4.tgz diff --git a/.cicd/docker/ubuntu-16.04.dockerfile b/.cicd/docker/ubuntu-16.04.dockerfile index 0bda1a4138..18645ea172 100644 --- a/.cicd/docker/ubuntu-16.04.dockerfile +++ b/.cicd/docker/ubuntu-16.04.dockerfile @@ -4,7 +4,9 @@ RUN apt-get update && apt-get upgrade -y && \ DEBIAN_FRONTEND=noninteractive apt-get install -y git clang-4.0 \ lldb-4.0 libclang-4.0-dev make automake libbz2-dev libssl-dev \ libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ - python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz + python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz \ + wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev + # install cmake RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ tar -xzf cmake-3.10.2.tar.gz && \ @@ -13,4 +15,13 @@ RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ make -j$(nproc) && \ make install && \ cd .. && \ - rm -f cmake-3.10.2.tar.gz \ No newline at end of file + rm -f cmake-3.10.2.tar.gz + +# install Python 3.7.4 +RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ + tar xzf Python-3.7.4.tgz && \ + cd Python-3.7.4 && \ + ./configure --enable-optimizations && \ + make -j$(nproc) altinstall && \ + cd .. && \ + rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tar.gz diff --git a/.cicd/docker/ubuntu-18.04.dockerfile b/.cicd/docker/ubuntu-18.04.dockerfile index 817636b8e2..01db7761f9 100644 --- a/.cicd/docker/ubuntu-18.04.dockerfile +++ b/.cicd/docker/ubuntu-18.04.dockerfile @@ -1,7 +1,18 @@ FROM ubuntu:18.04 # install dependencies + RUN apt-get update && apt-get upgrade -y && \ DEBIAN_FRONTEND=noninteractive apt-get install -y git clang-4.0 \ lldb-4.0 libclang-4.0-dev cmake make automake libbz2-dev libssl-dev \ - libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ - python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz \ No newline at end of file + libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ + python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz \ + libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev + +# install Python 3.7.4 +RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ + tar xzf Python-3.7.4.tgz && \ + cd Python-3.7.4 && \ + ./configure --enable-optimizations && \ + make -j$(nproc) altinstall && \ + cd .. && \ + rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tar.gz From 019691dbe0b552f0f01fcdd42cace5f3671886e0 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 12:55:44 -0400 Subject: [PATCH 089/659] Use /usr/bin/env to make sure we get the right Python --- tools/toolchain-tester/toolchain-tester | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/toolchain-tester/toolchain-tester b/tools/toolchain-tester/toolchain-tester index 1e61fff1dd..bd4477a3ec 100755 --- a/tools/toolchain-tester/toolchain-tester +++ b/tools/toolchain-tester/toolchain-tester @@ -1,3 +1,3 @@ #!/usr/bin/env bash REPO_ROOT=$(git rev-parse --show-toplevel) -python3 "${REPO_ROOT}/tools/toolchain-tester/main.py" "$@" +/usr/bin/env python3.7 "${REPO_ROOT}/tools/toolchain-tester/main.py" "$@" From c474055606f76b3aaf99f49319a5cf3ea2e6527e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 18 Oct 2019 13:16:07 -0400 Subject: [PATCH 090/659] Delete directory in Centos --- .cicd/docker/centos-7.6.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/docker/centos-7.6.dockerfile b/.cicd/docker/centos-7.6.dockerfile index 76363842b9..9911f68937 100644 --- a/.cicd/docker/centos-7.6.dockerfile +++ b/.cicd/docker/centos-7.6.dockerfile @@ -38,4 +38,4 @@ RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ ./configure --enable-optimizations && \ make -j$(nproc) altinstall && \ cd .. && \ - rm -f Python-3.7.4 && rm -f Python-3.7.4.tgz + rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tgz From 9605a3df933d02a5458a1d44b582036d8b4cfab6 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Mon, 21 Oct 2019 23:10:29 -0400 Subject: [PATCH 091/659] expose only-export option through eosio-cpp and eosio-ld --- tools/include/compiler_options.hpp.in | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 2792ee4248..755f8e457a 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -19,6 +19,10 @@ static llvm::cl::OptionCategory EosioLdToolCategory("ld options"); #endif /// begin ld options +static cl::opt only_export_opt( + "only-export", + cl::desc("Export only this symbol"), + cl::cat(LD_CAT)); static cl::opt no_abigen_opt( "no-abigen", cl::desc("Disable ABI file generation"), @@ -471,6 +475,9 @@ static void GetLdDefaults(std::vector& ldopts) { ldopts.emplace_back("-lrt -lsf"); if (fquery_opt || fquery_server_opt || fquery_client_opt) ldopts.emplace_back("-leosio_cmem"); + if (!only_export_opt.empty()) { + ldopts.emplace_back("--only-export \""+only_export_opt+"\""); + } } else { #ifdef __APPLE__ @@ -514,8 +521,8 @@ static Options CreateOptions(bool add_defaults=true) { GetLdDefaults(ldopts); #endif } - -#ifndef ONLY_LD + +#ifndef ONLY_LD if (fquery_opt) ldopts.emplace_back("-fquery"); if (fquery_server_opt) @@ -764,7 +771,7 @@ static Options CreateOptions(bool add_defaults=true) { ldopts.emplace_back("a.out"); } #else - if (inputs.size() == 1) { + if (inputs.size() == 1) { llvm::SmallString<256> fn = llvm::sys::path::filename(inputs[0]); llvm::sys::path::replace_extension(fn, ""); llvm::sys::path::replace_extension(fn, fnative_opt ? "" : ".wasm"); @@ -839,7 +846,7 @@ static Options CreateOptions(bool add_defaults=true) { if (fuse_main_opt) ldopts.emplace_back("-fuse-main"); #endif - + #ifndef ONLY_LD return {output_fn, inputs, link, abigen, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; #else From e8543dea421365d0b37b10390aa038c6333a1e4d Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 22 Oct 2019 10:53:03 -0400 Subject: [PATCH 092/659] Remove out-dated file to sync with develop --- libraries/eosiolib/multi_index.hpp | 1714 ---------------------------- 1 file changed, 1714 deletions(-) delete mode 100644 libraries/eosiolib/multi_index.hpp diff --git a/libraries/eosiolib/multi_index.hpp b/libraries/eosiolib/multi_index.hpp deleted file mode 100644 index a5c6db2289..0000000000 --- a/libraries/eosiolib/multi_index.hpp +++ /dev/null @@ -1,1714 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once - -#include "action.h" -#include "name.hpp" -#include "serialize.hpp" -#include "datastream.hpp" -#include "db.h" -#include "fixed_bytes.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#warning " is deprecated use " - -namespace eosio { - -constexpr static inline name same_payer{}; - -template -struct const_mem_fun -{ - typedef typename std::remove_reference::type result_type; - - template - - auto operator()(const ChainedPtr& x)const -> std::enable_if_t::value, Type> - { - return operator()(*x); - } - - Type operator()(const Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const std::reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type operator()(const std::reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -#define WRAP_SECONDARY_SIMPLE_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, &secondary );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, &secondary );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, &secondary, primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, &secondary, &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, &secondary, &primary );\ - }\ -}; - -#define WRAP_SECONDARY_ARRAY_TYPE(IDX, TYPE)\ -template<>\ -struct secondary_index_db_functions {\ - static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return db_##IDX##_next( iterator, primary ); }\ - static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return db_##IDX##_previous( iterator, primary ); }\ - static void db_idx_remove( int32_t iterator ) { db_##IDX##_remove( iterator ); }\ - static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return db_##IDX##_end( code, scope, table ); }\ - static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\ - return db_##IDX##_store( scope, table, payer, id, secondary.data(), TYPE::num_words() );\ - }\ - static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\ - db_##IDX##_update( iterator, payer, secondary.data(), TYPE::num_words() );\ - }\ - static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\ - return db_##IDX##_find_primary( code, scope, table, secondary.data(), TYPE::num_words(), primary );\ - }\ - static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_find_secondary( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_lowerbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ - static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\ - return db_##IDX##_upperbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary );\ - }\ -}; - -#define MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(TYPE)\ -template<>\ -struct secondary_key_traits {\ - static_assert( std::numeric_limits::is_specialized, "TYPE does not have specialized numeric_limits" );\ - static constexpr TYPE true_lowest() { return std::numeric_limits::lowest(); }\ -}; - -namespace _multi_index_detail { - - namespace hana = boost::hana; - - template - struct secondary_index_db_functions; - - template - struct secondary_key_traits; - - WRAP_SECONDARY_SIMPLE_TYPE(idx64, uint64_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint64_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx128, uint128_t) - MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(uint128_t) - - WRAP_SECONDARY_SIMPLE_TYPE(idx_double, double) - template<> - struct secondary_key_traits { - static constexpr double true_lowest() { return -std::numeric_limits::infinity(); } - }; - - WRAP_SECONDARY_SIMPLE_TYPE(idx_long_double, long double) - template<> - struct secondary_key_traits { - static constexpr long double true_lowest() { return -std::numeric_limits::infinity(); } - }; - - WRAP_SECONDARY_ARRAY_TYPE(idx256, eosio::fixed_bytes<32>) - template<> - struct secondary_key_traits> { - static constexpr eosio::fixed_bytes<32> true_lowest() { return eosio::fixed_bytes<32>(); } - }; - -} - -/** - * The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * @brief The indexed_by struct is used to instantiate the indices for the Multi-Index table. In EOSIO, up to 16 secondary indices can be specified. - * - * @tparam IndexName - is the name of the index. The name must be provided as an EOSIO base32 encoded 64-bit integer and must conform to the EOSIO naming requirements of a maximum of 13 characters, the first twelve from the lowercase characters a-z, digits 1-5, and ".", and if there is a 13th character, it is restricted to lowercase characters a-p and ".". - * @tparam Extractor - is a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type. It is recommended to use the `eosio::const_mem_fun` template, which is a type alias to the `boost::multi_index::const_mem_fun`. See the documentation for the Boost `const_mem_fun` key extractor for more details. - * - * Example: - * -* - * @code - * #include - * using namespace eosio; - * class mycontract: eosio::contract { - * struct record { - * uint64_t primary; - * uint128_t secondary; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary() const { return secondary; } - * }; - * public: - * mycontract(name receiver, name code, datastream ds):contract(receiver, code, ds){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index<"mytable"_n, record, - * indexed_by< "bysecondary"_n, const_mem_fun > > table( code, scope); - * } - * } - * EOSIO_DISPATCH( mycontract, (myaction) ) - * @endcode - */ -template -struct indexed_by { - enum constants { index_name = static_cast(IndexName) }; - typedef Extractor secondary_extractor_type; -}; - -/** - * @defgroup multi_index Multi Index Table - * @brief Defines EOSIO Multi Index Table - * @ingroup contracts - * - * @details EOSIO Multi-Index API provides a C++ interface to the EOSIO database. It is patterned after Boost Multi Index Container. - * EOSIO Multi-Index table requires exactly a uint64_t primary key. For the table to be able to retrieve the primary key, - * the object stored inside the table is required to have a const member function called primary_key() that returns uint64_t. - * EOSIO Multi-Index table also supports up to 16 secondary indices. The type of the secondary indices could be any of: - * - uint64_t - * - uint128_t - * - double - * - long double - * - eosio::checksum256 - * - * @tparam TableName - name of the table - * @tparam T - type of the data stored inside the table - * @tparam Indices - secondary indices for the table, up to 16 indices is supported here - * - * Example: - * - * @code - * #include - * using namespace eosio; - * class mycontract: contract { - * struct record { - * uint64_t primary; - * uint64_t secondary_1; - * uint128_t secondary_2; - * checksum256 secondary_3; - * double secondary_4; - * long double secondary_5; - * uint64_t primary_key() const { return primary; } - * uint64_t get_secondary_1() const { return secondary_1; } - * uint128_t get_secondary_2() const { return secondary_2; } - * checksum256 get_secondary_3() const { return secondary_3; } - * double get_secondary_4() const { return secondary_4; } - * long double get_secondary_5() const { return secondary_5; } - * }; - * public: - * mycontract(name receiver, name code, datastream ds):contract(receiver, code, ds){} - * void myaction() { - * auto code = _self; - * auto scope = _self; - * multi_index<"mytable"_n, record, - * indexed_by< "bysecondary1"_n, const_mem_fun >, - * indexed_by< "bysecondary2"_n, const_mem_fun >, - * indexed_by< "bysecondary3"_n, const_mem_fun >, - * indexed_by< "bysecondary4"_n, const_mem_fun >, - * indexed_by< "bysecondary5"_n, const_mem_fun > - * > table( code, scope); - * } - * } - * EOSIO_DISPATCH( mycontract, (myaction) ) - * @endcode - * @{ - */ - -template -class multi_index -{ - private: - - static_assert( sizeof...(Indices) <= 16, "multi_index only supports a maximum of 16 secondary indices" ); - - constexpr static bool validate_table_name( name n ) { - // Limit table names to 12 characters so that the last character (4 bits) can be used to distinguish between the secondary indices. - return n.length() < 13; //(n & 0x000000000000000FULL) == 0; - } - - constexpr static size_t max_stack_buffer_size = 512; - - static_assert( validate_table_name( name(TableName) ), "multi_index does not support table names with a length greater than 12"); - - name _code; - uint64_t _scope; - - mutable uint64_t _next_primary_key; - - enum next_primary_key_tags : uint64_t { - no_available_primary_key = static_cast(-2), // Must be the smallest uint64_t value compared to all other tags - unset_next_primary_key = static_cast(-1) - }; - - struct item : public T - { - template - item( const multi_index* idx, Constructor&& c ) - :__idx(idx){ - c(*this); - } - - const multi_index* __idx; - int32_t __primary_itr; - int32_t __iters[sizeof...(Indices)+(sizeof...(Indices)==0)]; - }; - - struct item_ptr - { - item_ptr(std::unique_ptr&& i, uint64_t pk, int32_t pitr) - : _item(std::move(i)), _primary_key(pk), _primary_itr(pitr) {} - - std::unique_ptr _item; - uint64_t _primary_key; - int32_t _primary_itr; - }; - - mutable std::vector _items_vector; - - template - struct index { - public: - typedef Extractor secondary_extractor_type; - typedef typename std::decay::type secondary_key_type; - - constexpr static bool validate_index_name( eosio::name n ) { - return n.value != 0 && n != eosio::name("primary"); // Primary is a reserve index name. - } - - static_assert( validate_index_name( name(IndexName) ), "invalid index name used in multi_index" ); - - enum constants { - table_name = static_cast(TableName), - index_name = static_cast(IndexName), - index_number = Number, - index_table_name = (static_cast(TableName) & 0xFFFFFFFFFFFFFFF0ULL) - | (Number & 0x000000000000000FULL) // Assuming no more than 16 secondary indices are allowed - }; - - constexpr static uint64_t name() { return index_table_name; } - constexpr static uint64_t number() { return Number; } - - struct const_iterator : public std::iterator { - public: - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int){ - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int){ - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - using namespace _multi_index_detail; - - eosio::check( _item != nullptr, "cannot increment end iterator" ); - - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - - uint64_t next_pk = 0; - auto next_itr = secondary_index_db_functions::db_idx_next( _item->__iters[Number], &next_pk ); - if( next_itr < 0 ) { - _item = nullptr; - return *this; - } - - const T& obj = *_idx->_multidx->find( next_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = next_itr; - _item = &mi; - - return *this; - } - - const_iterator& operator--() { - using namespace _multi_index_detail; - - uint64_t prev_pk = 0; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = secondary_index_db_functions::db_idx_end(_idx->get_code().value, _idx->get_scope(), _idx->name()); - eosio::check( ei != -1, "cannot decrement end iterator when the index is empty" ); - prev_itr = secondary_index_db_functions::db_idx_previous( ei , &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement end iterator when the index is empty" ); - } else { - if( _item->__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key); - auto& mi = const_cast( *_item ); - mi.__iters[Number] = idxitr; - } - prev_itr = secondary_index_db_functions::db_idx_previous( _item->__iters[Number], &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement iterator at beginning of index" ); - } - - const T& obj = *_idx->_multidx->find( prev_pk ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = prev_itr; - _item = &mi; - - return *this; - } - - const_iterator():_item(nullptr){} - private: - friend struct index; - const_iterator( const index* idx, const item* i = nullptr ) - : _idx(idx), _item(i) {} - - const index* _idx; - const item* _item; - }; /// struct multi_index::index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - const_iterator cbegin()const { - using namespace _multi_index_detail; - return lower_bound( secondary_key_traits::true_lowest() ); - } - const_iterator begin()const { return cbegin(); } - - const_iterator cend()const { return const_iterator( this ); } - const_iterator end()const { return cend(); } - - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - const_reverse_iterator rbegin()const { return crbegin(); } - - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - const_reverse_iterator rend()const { return crend(); } - - const_iterator find( secondary_key_type&& secondary )const { - return find( secondary ); - } - - const_iterator find( const secondary_key_type& secondary )const { - auto lb = lower_bound( secondary ); - auto e = cend(); - if( lb == e ) return e; - - if( secondary != secondary_extractor_type()(*lb) ) - return e; - return lb; - } - - const_iterator require_find( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return require_find( secondary, error_msg ); - } - - const_iterator require_find( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto lb = lower_bound( secondary ); - eosio::check( lb != cend(), error_msg ); - eosio::check( secondary == secondary_extractor_type()(*lb), error_msg ); - return lb; - } - - const T& get( secondary_key_type&& secondary, const char* error_msg = "unable to find secondary key" )const { - return get( secondary, error_msg ); - } - - // Gets the object with the smallest primary key in the case where the secondary key is not unique. - const T& get( const secondary_key_type& secondary, const char* error_msg = "unable to find secondary key" )const { - auto result = find( secondary ); - eosio::check( result != cend(), error_msg ); - return *result; - } - - const_iterator lower_bound( secondary_key_type&& secondary )const { - return lower_bound( secondary ); - } - const_iterator lower_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_lowerbound( get_code().value, get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator upper_bound( secondary_key_type&& secondary )const { - return upper_bound( secondary ); - } - const_iterator upper_bound( const secondary_key_type& secondary )const { - using namespace _multi_index_detail; - - uint64_t primary = 0; - secondary_key_type secondary_copy(secondary); - auto itr = secondary_index_db_functions::db_idx_upperbound( get_code().value, get_scope(), name(), secondary_copy, primary ); - if( itr < 0 ) return cend(); - - const T& obj = *_multidx->find( primary ); - auto& mi = const_cast( static_cast(obj) ); - mi.__iters[Number] = itr; - - return {this, &mi}; - } - - const_iterator iterator_to( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == _multidx, "object passed to iterator_to is not in multi_index" ); - - if( objitem.__iters[Number] == -1 ) { - secondary_key_type temp_secondary_key; - auto idxitr = secondary_index_db_functions::db_idx_find_primary(get_code().value, get_scope(), name(), objitem.primary_key(), temp_secondary_key); - auto& mi = const_cast( objitem ); - mi.__iters[Number] = idxitr; - } - - return {this, &objitem}; - } - - template - void modify( const_iterator itr, eosio::name payer, Lambda&& updater ) { - eosio::check( itr != cend(), "cannot pass end iterator to modify" ); - - _multidx->modify( *itr, payer, std::forward(updater) ); - } - - const_iterator erase( const_iterator itr ) { - eosio::check( itr != cend(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - _multidx->erase(obj); - - return itr; - } - - eosio::name get_code()const { return _multidx->get_code(); } - uint64_t get_scope()const { return _multidx->get_scope(); } - - static auto extract_secondary_key(const T& obj) { return secondary_extractor_type()(obj); } - - private: - friend class multi_index; - - index( typename std::conditional::type midx ) - :_multidx(midx){} - - typename std::conditional::type _multidx; - }; /// struct multi_index::index - - template - struct intc { enum e{ value = I }; operator uint64_t()const{ return I; } }; - - static constexpr auto transform_indices( ) { - using namespace _multi_index_detail; - - typedef decltype( hana::zip_shortest( - hana::make_tuple( intc<0>(), intc<1>(), intc<2>(), intc<3>(), intc<4>(), intc<5>(), - intc<6>(), intc<7>(), intc<8>(), intc<9>(), intc<10>(), intc<11>(), - intc<12>(), intc<13>(), intc<14>(), intc<15>() ), - hana::tuple() ) ) indices_input_type; - - return hana::transform( indices_input_type(), [&]( auto&& idx ){ - typedef typename std::decay(idx))>::type num_type; - typedef typename std::decay(idx))>::type idx_type; - return hana::make_tuple( hana::type_c(idx_type::index_name)), - typename idx_type::secondary_extractor_type, - num_type::e::value, false> >, - hana::type_c(idx_type::index_name)), - typename idx_type::secondary_extractor_type, - num_type::e::value, true> > ); - - }); - } - - typedef decltype( multi_index::transform_indices() ) indices_type; - - indices_type _indices; - - const item& load_object_by_primary_iterator( int32_t itr )const { - using namespace _multi_index_detail; - - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._primary_itr == itr; - }); - if( itr2 != _items_vector.rend() ) - return *itr2->_item; - - auto size = db_get_i64( itr, nullptr, 0 ); - eosio::check( size >= 0, "error reading iterator" ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size_t(size) ? malloc(size_t(size)) : alloca(size_t(size)); - - db_get_i64( itr, buffer, uint32_t(size) ); - - datastream ds( (char*)buffer, uint32_t(size) ); - - auto itm = std::make_unique( this, [&]( auto& i ) { - T& val = static_cast(i); - ds >> val; - - i.__primary_itr = itr; - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<1>(idx))::type index_type; - - i.__iters[ index_type::number() ] = -1; - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - if ( max_stack_buffer_size < size_t(size) ) { - free(buffer); - } - - return *ptr; - } /// load_object_by_primary_iterator - - public: - /** - * Constructs an instance of a Multi-Index table. - * @brief Constructs an instance of a Multi-Index table. - * - * @param code - Account that owns table - * @param scope - Scope identifier within the code hierarchy - * - * @pre code and scope member properties are initialized - * @post each secondary index table initialized - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * Notes - * The `eosio::multi_index` template has template parameters ``, where: - * - `TableName` is the name of the table, maximum 12 characters long, characters in the name from the set of lowercase letters, digits 1 to 5, and the "." (period) character and is converted to a eosio::raw - which wraps uint64_t; - * - `T` is the object type (i.e., row definition); - * - `Indices` is a list of up to 16 secondary indices. - * - Each must be a default constructable class or struct - * - Each must have a function call operator that takes a const reference to the table object type and returns either a secondary key type or a reference to a secondary key type - * - It is recommended to use the eosio::const_mem_fun template, which is a type alias to the boost::multi_index::const_mem_fun. See the documentation for the Boost const_mem_fun key extractor for more details. - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint64_t primary_key() const { return account_name; } - * }; - * public: - * addressbook(name self):contract(self) {} - * typedef eosio::multi_index< "address"_n, address > address_index; - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - multi_index( name code, uint64_t scope ) - :_code(code),_scope(scope),_next_primary_key(unset_next_primary_key) - {} - - /** - * Returns the `code` member property. - * - * @return Account name of the Code that owns the Primary Table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope - * eosio::check(addresses.get_code() == "dan"_n, "Codes don't match."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - name get_code()const { return _code; } - - /** - * Returns the `scope` member property. - * - * @return Scope id of the Scope within the Code of the Current Receiver under which the desired Primary Table instance can be found. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope - * eosio::check(addresses.get_code() == "dan"_n, "Scopes don't match"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - uint64_t get_scope()const { return _scope; } - - struct const_iterator : public std::iterator { - friend bool operator == ( const const_iterator& a, const const_iterator& b ) { - return a._item == b._item; - } - friend bool operator != ( const const_iterator& a, const const_iterator& b ) { - return a._item != b._item; - } - - const T& operator*()const { return *static_cast(_item); } - const T* operator->()const { return static_cast(_item); } - - const_iterator operator++(int) { - const_iterator result(*this); - ++(*this); - return result; - } - - const_iterator operator--(int) { - const_iterator result(*this); - --(*this); - return result; - } - - const_iterator& operator++() { - eosio::check( _item != nullptr, "cannot increment end iterator" ); - - uint64_t next_pk; - auto next_itr = db_next_i64( _item->__primary_itr, &next_pk ); - if( next_itr < 0 ) - _item = nullptr; - else - _item = &_multidx->load_object_by_primary_iterator( next_itr ); - return *this; - } - const_iterator& operator--() { - uint64_t prev_pk; - int32_t prev_itr = -1; - - if( !_item ) { - auto ei = db_end_i64(_multidx->get_code().value, _multidx->get_scope(), static_cast(TableName)); - eosio::check( ei != -1, "cannot decrement end iterator when the table is empty" ); - prev_itr = db_previous_i64( ei , &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement end iterator when the table is empty" ); - } else { - prev_itr = db_previous_i64( _item->__primary_itr, &prev_pk ); - eosio::check( prev_itr >= 0, "cannot decrement iterator at beginning of table" ); - } - - _item = &_multidx->load_object_by_primary_iterator( prev_itr ); - return *this; - } - - private: - const_iterator( const multi_index* mi, const item* i = nullptr ) - :_multidx(mi),_item(i){} - - const multi_index* _multidx; - const item* _item; - friend class multi_index; - }; /// struct multi_index::const_iterator - - typedef std::reverse_iterator const_reverse_iterator; - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.cbegin(), "Only address is not at front."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator cbegin()const { - return lower_bound(std::numeric_limits::lowest()); - } - - /** - * Returns an iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the object_type with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.begin(), "Only address is not at front."); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator begin()const { return cbegin(); } - - /** - * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. - * - * @return An iterator referring to the `past-the-end` element in the multi index container. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.cend(), "Address for account doesn't exist"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator cend()const { return const_iterator( this ); } - - /** - * Returns an iterator referring to the `past-the-end` element in the multi index container. The `past-the-end` element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced. - * - * @return An iterator referring to the `past-the-end` element in the multi index container. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account doesn't exist"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator end()const { return cend(); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crbegin(); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Last Record "); - * itr++; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect Second Last Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crbegin()const { return std::make_reverse_iterator(cend()); } - - /** - * Returns a reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * @return A reverse iterator pointing to the `object_type` with the highest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rbegin(); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Last Record "); - * itr++; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect Second Last Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rbegin()const { return crbegin(); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.crend(); - * itr--; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Record "); - * itr--; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator crend()const { return std::make_reverse_iterator(cbegin()); } - - /** - * Returns an iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * @return An iterator pointing to the `object_type` with the lowest primary key value in the Multi-Index table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * }); - * auto itr = addresses.rend(); - * itr--; - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Record "); - * itr--; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Record"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_reverse_iterator rend()const { return crend(); } - - /** - * Searches for the `object_type` with the lowest primary key that is greater than or equal to a given primary key. - * - * @param primary - Primary key that establishes the target value for the lower bound search. - * @return An iterator pointing to the `object_type` that has the lowest primary key that is greater than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * // This assumes the code from the get_index() example below. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.lower_bound(zipnumb); - * eosio::check(itr->account_name == name("brendan"), "Lock arf, Incorrect First Lower Bound Record "); - * itr++; - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Second Lower Bound Record"); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator lower_bound( uint64_t primary )const { - auto itr = db_lowerbound_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Searches for the `object_type` with the highest primary key that is less than or equal to a given primary key. - * - * @param primary - Primary key that establishes the target value for the upper bound search - * @return An iterator pointing to the `object_type` that has the highest primary key that is less than or equal to `primary`. If an object could not be found, it will return the `end` iterator. If the table does not exist** it will return `-1`. - * - * Example: - * - * @code - * // This assumes the code from the get_index() example below. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect First Upper Bound Record "); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator upper_bound( uint64_t primary )const { - auto itr = db_upperbound_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - const auto& obj = load_object_by_primary_iterator( itr ); - return {this, &obj}; - } - - /** - * Returns an available primary key. - * - * @return An available (unused) primary key value. - * - * Notes: - * Intended to be used in tables in which the primary keys of the table are strictly intended to be auto-incrementing, and thus will never be set to custom values by the contract. Violating this expectation could result in the table appearing to be full due to inability to allocate an available primary key. - * Ideally this method would only be used to determine the appropriate primary key to use within new objects added to a table in which the primary keys of the table are strictly intended from the beginning to be autoincrementing and thus will not ever be set to custom arbitrary values by the contract. Violating this agreement could result in the table appearing full when in reality there is plenty of space left. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(payer, [&](auto& address) { - * address.key = addresses.available_primary_key(); - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - uint64_t available_primary_key()const { - if( _next_primary_key == unset_next_primary_key ) { - // This is the first time available_primary_key() is called for this multi_index instance. - if( begin() == end() ) { // empty table - _next_primary_key = 0; - } else { - auto itr = --end(); // last row of table sorted by primary key - auto pk = itr->primary_key(); // largest primary key currently in table - if( pk >= no_available_primary_key ) // Reserve the tags - _next_primary_key = no_available_primary_key; - else - _next_primary_key = pk + 1; - } - } - - eosio::check( _next_primary_key < no_available_primary_key, "next primary key in table is at autoincrement limit"); - return _next_primary_key; - } - - /** - * Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * #include - * using namespace eosio; - * using namespace std; - * class addressbook: contract { - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * uint32_t zip = 0; - * uint64_t primary_key() const { return account_name; } - * uint64_t by_zip() const { return zip; } - * }; - * public: - * addressbook(name receiver, name code, datastream ds):contract(receiver, code, ds) {} - * typedef eosio::multi_index< name("address"), address, indexed_by< name("zip"), const_mem_fun > address_index; - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * uint32_t zipnumb = 93446; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.find(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect Record "); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index() { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(std::decay(in))::type>::type::index_name) == static_cast(IndexName)>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<0>(res.value()))::type(this); - } - - /** - * Returns an appropriately typed Secondary Index. - * - * @tparam IndexName - the ID of the desired secondary index - * - * @return An index of the appropriate type: Primitive 64-bit unsigned integer key (idx64), Primitive 128-bit unsigned integer key (idx128), 128-bit fixed-size lexicographical key (idx128), 256-bit fixed-size lexicographical key (idx256), Floating point key, Double precision floating point key, Long Double (quadruple) precision floating point key - * - * Example: - * - * @code - * // This assumes the code from the get_index() example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * uint32_t zipnumb = 93445; - * auto zip_index = addresses.get_index(); - * auto itr = zip_index.upper_bound(zipnumb); - * eosio::check(itr->account_name == name("dan"), "Lock arf, Incorrect First Upper Bound Record "); - * itr++; - * eosio::check(itr == zip_index.end(), "Lock arf, Incorrect End of Iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - auto get_index()const { - using namespace _multi_index_detail; - - auto res = hana::find_if( _indices, []( auto&& in ) { - return std::integral_constant(std::decay(in))::type>::type::index_name) == static_cast(IndexName)>(); - }); - - static_assert( res != hana::nothing, "name provided is not the name of any secondary index within multi_index" ); - - return typename decltype(+hana::at_c<1>(res.value()))::type(this); - } - - /** - * Returns an iterator to the given object in a Multi-Index table. - * - * @param obj - A reference to the desired object - * - * @return An iterator to the given object - * - * Example: - * - * @code - * // This assumes the code from the get_index() example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example below - * // add dan account to table - see emplace example below - * // add additional account - brendan - * - * addresses.emplace(payer, [&](auto& address) { - * address.account_name = "brendan"_n; - * address.first_name = "Brendan"; - * address.last_name = "Blumer"; - * address.street = "1 EOS Way"; - * address.city = "Hong Kong"; - * address.state = "HK"; - * address.zip = 93445; - * }); - * auto user = addresses.get("dan"_n); - * auto itr = address.find("dan"_n); - * eosio::check(iterator_to(user) == itr, "Invalid iterator"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator iterator_to( const T& obj )const { - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to iterator_to is not in multi_index" ); - return {this, &objitem}; - } - /** - * Adds a new object (i.e., row) to the table. - * - * @param payer - Account name of the payer for the Storage usage of the new object - * @param constructor - Lambda function that does an in-place initialization of the object to be created in the table - * - * @pre A multi index table has been instantiated - * @post A new object is created in the Multi-Index table, with a unique primary key (as specified in the object). The object is serialized and written to the table. If the table does not exist, it is created. - * @post Secondary indices are updated to refer to the newly added object. If the secondary index tables do not exist, they are created. - * @post The payer is charged for the storage usage of the new object and, if the table (and secondary index tables) must be created, for the overhead of the table creation. - * - * @return A primary key iterator to the newly created object - * - * Exception - The account is not authorized to write to the table. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * address_index addresses(_self, _self.value); // code, scope - * // add to table, first argument is account to bill for storage - * addresses.emplace(_self, [&](auto& address) { - * address.account_name = "dan"_n; - * address.first_name = "Daniel"; - * address.last_name = "Larimer"; - * address.street = "1 EOS Way"; - * address.city = "Blacksburg"; - * address.state = "VA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - const_iterator emplace( name payer, Lambda&& constructor ) { - using namespace _multi_index_detail; - - eosio::check( _code.value == current_receiver(), "cannot create objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto itm = std::make_unique( this, [&]( auto& i ){ - T& obj = static_cast(i); - constructor( obj ); - - size_t size = pack_size( obj ); - - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - auto pk = obj.primary_key(); - - i.__primary_itr = db_store_i64( _scope, static_cast(TableName), payer.value, pk, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free(buffer); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - i.__iters[index_type::number()] = secondary_index_db_functions::db_idx_store( _scope, index_type::name(), payer.value, obj.primary_key(), index_type::extract_secondary_key(obj) ); - }); - }); - - const item* ptr = itm.get(); - auto pk = itm->primary_key(); - auto pitr = itm->__primary_itr; - - _items_vector.emplace_back( std::move(itm), pk, pitr ); - - return {this, ptr}; - } - - /** - * Modifies an existing object in a table. - * - * @param itr - an iterator pointing to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre itr points to an existing element - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.modify( itr, account payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const_iterator itr, name payer, Lambda&& updater ) { - eosio::check( itr != end(), "cannot pass end iterator to modify" ); - - modify( *itr, payer, std::forward(updater) ); - } - - /** - * Modifies an existing object in a table. - * - * @param obj - a reference to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row - * @param updater - lambda function that updates the target object - * - * @pre obj is an existing object in the table - * @pre payer is a valid account that is authorized to execute the action and be billed for storage usage. - * - * @post The modified object is serialized, then replaces the existing object in the table. - * @post Secondary indices are updated; the primary key of the updated object is not changed. - * @post The payer is charged for the storage usage of the updated object. - * @post If payer is the same as the existing payer, payer only pays for the usage difference between existing and updated object (and is refunded if this difference is negative). - * @post If payer is different from the existing payer, the existing payer is refunded for the storage usage of the existing object. - * - * Exceptions: - * If called with an invalid precondition, execution is aborted. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.modify( *itr, payer, [&]( auto& address ) { - * address.city = "San Luis Obispo"; - * address.state = "CA"; - * }); - * eosio::check(itr->city == "San Luis Obispo", "Lock arf, Address not modified"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - template - void modify( const T& obj, name payer, Lambda&& updater ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to modify is not in multi_index" ); - auto& mutableitem = const_cast(objitem); - eosio::check( _code.value == current_receiver(), "cannot modify objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto secondary_keys = hana::transform( _indices, [&]( auto&& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - return index_type::extract_secondary_key( obj ); - }); - - auto pk = obj.primary_key(); - - auto& mutableobj = const_cast(obj); // Do not forget the auto& otherwise it would make a copy and thus not update at all. - updater( mutableobj ); - - eosio::check( pk == obj.primary_key(), "updater cannot change primary key when modifying an object" ); - - size_t size = pack_size( obj ); - //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions - void* buffer = max_stack_buffer_size < size ? malloc(size) : alloca(size); - - datastream ds( (char*)buffer, size ); - ds << obj; - - db_update_i64( objitem.__primary_itr, payer.value, buffer, size ); - - if ( max_stack_buffer_size < size ) { - free( buffer ); - } - - if( pk >= _next_primary_key ) - _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto secondary = index_type::extract_secondary_key( obj ); - if( memcmp( &hana::at_c(secondary_keys), &secondary, sizeof(secondary) ) != 0 ) { - auto indexitr = mutableitem.__iters[index_type::number()]; - - if( indexitr < 0 ) { - typename index_type::secondary_key_type temp_secondary_key; - indexitr = mutableitem.__iters[index_type::number()] - = secondary_index_db_functions::db_idx_find_primary( _code.value, _scope, index_type::name(), pk, temp_secondary_key ); - } - - secondary_index_db_functions::db_idx_update( indexitr, payer.value, secondary ); - } - }); - } - - /** - * Retrieves an existing object from a table using its primary key. - * - * @param primary - Primary key value of the object - * @return A constant reference to the object containing the specified primary key. - * - * Exception - No object matches the given key - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto user = addresses.get("dan"_n); - * eosio::check(user.first_name == "Daniel", "Couldn't get him."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const T& get( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto result = find( primary ); - eosio::check( result != cend(), error_msg ); - return *result; - } - - /** - * Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @return An iterator to the found object which has a primary key equal to `primary` OR the `end` iterator of the referenced table if an object with primary key `primary` is not found. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Couldn't get him."); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - const_iterator find( uint64_t primary )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code.value, _scope, static_cast(TableName), primary ); - if( itr < 0 ) return end(); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Search for an existing object in a table using its primary key. - * - * @param primary - Primary key value of the object - * @param error_msg - error message if an object with primary key `primary` is not found. - * @return An iterator to the found object which has a primary key equal to `primary` OR throws an exception if an object with primary key `primary` is not found. - */ - - const_iterator require_find( uint64_t primary, const char* error_msg = "unable to find key" )const { - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == primary; - }); - if( itr2 != _items_vector.rend() ) - return iterator_to(*(itr2->_item)); - - auto itr = db_find_i64( _code.value, _scope, static_cast(TableName), primary ); - eosio::check( itr >= 0, error_msg ); - - const item& i = load_object_by_primary_iterator( itr ); - return iterator_to(static_cast(i)); - } - - /** - * Remove an existing object from a table using its primary key. - * - * @param itr - An iterator pointing to the object to be removed - * - * @pre itr points to an existing element - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * @return For the signature with `const_iterator`, returns a pointer to the object following the removed object. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * // create reference to address_index - see emplace example - * // add dan account to table - see emplace example - * - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Address for account not found"); - * addresses.erase( itr ); - * eosio::check(itr != addresses.end(), "Everting lock arf, Address not erased properly"); - * } - * } - * EOSIO_ABI( addressbook, (myaction) ) - * @endcode - */ - const_iterator erase( const_iterator itr ) { - eosio::check( itr != end(), "cannot pass end iterator to erase" ); - - const auto& obj = *itr; - ++itr; - - erase(obj); - - return itr; - } - - /** - * Remove an existing object from a table using its primary key. - * - * @param obj - Object to be removed - * - * @pre obj is an existing object in the table - * @post The object is removed from the table and all associated storage is reclaimed. - * @post Secondary indices associated with the table are updated. - * @post The existing payer for storage usage of the object is refunded for the table and secondary indices usage of the removed object, and if the table and indices are removed, for the associated overhead. - * - * Exceptions: - * The object to be removed is not in the table. - * The action is not authorized to modify the table. - * The given iterator is invalid. - * - * Example: - * - * @code - * // This assumes the code from the constructor example. Replace myaction() {...} - * - * void myaction() { - * auto itr = addresses.find("dan"_n); - * eosio::check(itr != addresses.end(), "Record is not found"); - * addresses.erase(*itr); - * itr = addresses.find("dan"_n); - * eosio::check(itr == addresses.end(), "Record is not deleted"); - * } - * } - * EOSIO_DISPATCH( addressbook, (myaction) ) - * @endcode - */ - void erase( const T& obj ) { - using namespace _multi_index_detail; - - const auto& objitem = static_cast(obj); - eosio::check( objitem.__idx == this, "object passed to erase is not in multi_index" ); - eosio::check( _code.value == current_receiver(), "cannot erase objects in table of another contract" ); // Quick fix for mutating db using multi_index that shouldn't allow mutation. Real fix can come in RC2. - - auto pk = objitem.primary_key(); - auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](const item_ptr& ptr) { - return ptr._item->primary_key() == pk; - }); - - eosio::check( itr2 != _items_vector.rend(), "attempt to remove object that was not in multi_index" ); - - _items_vector.erase(--(itr2.base())); - - db_remove_i64( objitem.__primary_itr ); - - hana::for_each( _indices, [&]( auto& idx ) { - typedef typename decltype(+hana::at_c<0>(idx))::type index_type; - - auto i = objitem.__iters[index_type::number()]; - if( i < 0 ) { - typename index_type::secondary_key_type secondary; - i = secondary_index_db_functions::db_idx_find_primary( _code.value, _scope, index_type::name(), objitem.primary_key(), secondary ); - } - if( i >= 0 ) - secondary_index_db_functions::db_idx_remove( i ); - }); - } - -}; - /// @} -} /// eosio From 58c5e64903a45f167346ff65453db55770855995 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Wed, 23 Oct 2019 01:44:39 -0400 Subject: [PATCH 093/659] Make the option zero or more and hidden --- tools/include/compiler_options.hpp.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 755f8e457a..5e5057eadb 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -22,7 +22,9 @@ static llvm::cl::OptionCategory EosioLdToolCategory("ld options"); static cl::opt only_export_opt( "only-export", cl::desc("Export only this symbol"), - cl::cat(LD_CAT)); + cl::cat(LD_CAT), + cl::Hidden, + cl::ZeroOrMore); static cl::opt no_abigen_opt( "no-abigen", cl::desc("Disable ABI file generation"), From f43b26c56a2c47d83baf8a39945c322227617d12 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 24 Oct 2019 13:24:28 -0400 Subject: [PATCH 094/659] Port missing metrics. --- .cicd/tests.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.cicd/tests.sh b/.cicd/tests.sh index e0a68e452f..bada0427df 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -29,7 +29,28 @@ else # Linux evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi - + set +e eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" - +fi +# buildkite +if [[ "$BUILDKITE" == 'true' ]]; then + cd build + # upload artifacts + echo '+++ :arrow_up: Uploading Artifacts' + echo 'Compressing core dumps...' + [[ $((`ls -1 core.* 2>/dev/null | wc -l`)) != 0 ]] && tar czf core.tar.gz core.* || : # collect core dumps + echo 'Exporting xUnit XML' + mv -f ./Testing/$(ls ./Testing/ | grep '2' | tail -n 1)/Test.xml test-results.xml + echo 'Uploading artifacts' + [[ -f config.ini ]] && buildkite-agent artifact upload config.ini + [[ -f core.tar.gz ]] && buildkite-agent artifact upload core.tar.gz + [[ -f genesis.json ]] && buildkite-agent artifact upload genesis.json + [[ -f mongod.log ]] && buildkite-agent artifact upload mongod.log + buildkite-agent artifact upload test-results.xml + echo 'Done uploading artifacts.' +fi +# re-throw +if [[ "$EXIT_STATUS" != 0 ]]; then + echo "Failing due to non-zero exit status from ctest: $EXIT_STATUS" + exit $EXIT_STATUS fi \ No newline at end of file From 2e6eb7da339c1c875fe50bf85a4fa24bcb0e726d Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 24 Oct 2019 14:03:57 -0400 Subject: [PATCH 095/659] Set EXIT_STATUS --- .cicd/tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.cicd/tests.sh b/.cicd/tests.sh index bada0427df..d427fb10a3 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -31,6 +31,7 @@ else # Linux fi set +e eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" + EXIT_STATUS=$? fi # buildkite if [[ "$BUILDKITE" == 'true' ]]; then From 89f2c526bb8184a28a9cf9c09a3e8b1a40db9457 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 24 Oct 2019 14:37:29 -0400 Subject: [PATCH 096/659] EXIT_STATUS for Mac. Fix Mac test artifacts. --- .cicd/tests.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.cicd/tests.sh b/.cicd/tests.sh index d427fb10a3..f1317a6a14 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -12,8 +12,11 @@ if [[ $(uname) == 'Darwin' ]]; then # You can't use chained commands in execute cd $BUILD_DIR + set +e bash -c "$TEST" - + EXIT_STATUS=$? + cd $ROOT_DIR + else # Linux ARGS=${ARGS:-"--rm --init -v $(pwd):$MOUNTED_DIR"} From 891f58a49aceabaa6a2e4f858ca9ae21d08eb9e8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 24 Oct 2019 16:40:47 -0400 Subject: [PATCH 097/659] Remove Python versions --- .cicd/docker/amazonlinux-2.dockerfile | 4 ++-- .cicd/docker/centos-7.6.dockerfile | 25 ++++++++++++------------- .cicd/docker/ubuntu-16.04.dockerfile | 2 +- .cicd/docker/ubuntu-18.04.dockerfile | 2 +- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.cicd/docker/amazonlinux-2.dockerfile b/.cicd/docker/amazonlinux-2.dockerfile index 28a2f5a614..caf5c58472 100644 --- a/.cicd/docker/amazonlinux-2.dockerfile +++ b/.cicd/docker/amazonlinux-2.dockerfile @@ -3,7 +3,7 @@ FROM amazonlinux:2.0.20190508 RUN yum update -y && \ yum install -y git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make bzip2 \ bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 libstdc++.x86_64 \ - python.x86_64 python3-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64 perl + libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64 perl # build lcov RUN git clone https://github.com/linux-test-project/lcov.git && \ cd lcov && \ @@ -18,4 +18,4 @@ RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ make -j$(nproc) && \ make install && \ cd .. && \ - rm -f cmake-3.10.2.tar.gz \ No newline at end of file + rm -f cmake-3.10.2.tar.gz diff --git a/.cicd/docker/centos-7.6.dockerfile b/.cicd/docker/centos-7.6.dockerfile index 9911f68937..890b2c5d94 100644 --- a/.cicd/docker/centos-7.6.dockerfile +++ b/.cicd/docker/centos-7.6.dockerfile @@ -3,15 +3,24 @@ FROM centos:7.6.1810 RUN yum update -y && \ yum --enablerepo=extras install -y centos-release-scl && \ yum install -y devtoolset-7 && \ - yum install -y python33.x86_64 git autoconf automake bzip2 \ + yum install -y git autoconf automake bzip2 \ libtool ocaml.x86_64 doxygen graphviz-devel.x86_64 \ libicu-devel.x86_64 bzip2.x86_64 bzip2-devel.x86_64 openssl-devel.x86_64 \ - gmp-devel.x86_64 python-devel.x86_64 gettext-devel.x86_64 gcc-c++.x86_64 perl \ + gmp-devel.x86_64 gettext-devel.x86_64 gcc-c++.x86_64 perl \ libffi-devel.x86_64 +# build Python 3.7.4 +RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ + source /opt/rh/devtoolset-7/enable && \ + tar xzf Python-3.7.4.tgz && \ + cd Python-3.7.4 && \ + ./configure --enable-optimizations && \ + make -j$(nproc) altinstall && \ + cd .. && \ + rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tgz + # build lcov RUN git clone https://github.com/linux-test-project/lcov.git && \ - source /opt/rh/python33/enable && \ source /opt/rh/devtoolset-7/enable && \ cd lcov && \ make install && \ @@ -20,7 +29,6 @@ RUN git clone https://github.com/linux-test-project/lcov.git && \ # build cmake RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ - source /opt/rh/python33/enable && \ source /opt/rh/devtoolset-7/enable && \ tar -xzf cmake-3.10.2.tar.gz && \ cd cmake-3.10.2 && \ @@ -30,12 +38,3 @@ RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ cd .. && \ rm -f cmake-3.10.2.tar.gz -# build Python 3.7.4 -RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ - source /opt/rh/devtoolset-7/enable && \ - tar xzf Python-3.7.4.tgz && \ - cd Python-3.7.4 && \ - ./configure --enable-optimizations && \ - make -j$(nproc) altinstall && \ - cd .. && \ - rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tgz diff --git a/.cicd/docker/ubuntu-16.04.dockerfile b/.cicd/docker/ubuntu-16.04.dockerfile index 18645ea172..f049e4a387 100644 --- a/.cicd/docker/ubuntu-16.04.dockerfile +++ b/.cicd/docker/ubuntu-16.04.dockerfile @@ -4,7 +4,7 @@ RUN apt-get update && apt-get upgrade -y && \ DEBIAN_FRONTEND=noninteractive apt-get install -y git clang-4.0 \ lldb-4.0 libclang-4.0-dev make automake libbz2-dev libssl-dev \ libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ - python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz \ + autoconf libtool curl zlib1g-dev doxygen graphviz \ wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev # install cmake diff --git a/.cicd/docker/ubuntu-18.04.dockerfile b/.cicd/docker/ubuntu-18.04.dockerfile index 01db7761f9..71f3428bf7 100644 --- a/.cicd/docker/ubuntu-18.04.dockerfile +++ b/.cicd/docker/ubuntu-18.04.dockerfile @@ -5,7 +5,7 @@ RUN apt-get update && apt-get upgrade -y && \ DEBIAN_FRONTEND=noninteractive apt-get install -y git clang-4.0 \ lldb-4.0 libclang-4.0-dev cmake make automake libbz2-dev libssl-dev \ libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ - python3-dev autoconf libtool curl zlib1g-dev doxygen graphviz \ + autoconf libtool curl zlib1g-dev doxygen graphviz \ libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev # install Python 3.7.4 From 93e046f5461d2c31d29af4cb228fcb00cb812dc1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 24 Oct 2019 16:41:31 -0400 Subject: [PATCH 098/659] Run toolchain tests in parallel --- .cicd/pipeline.yml | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 5aa9f8015d..8504dfa6be 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -138,22 +138,6 @@ steps: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} - - wait: - continue_on_failure: true - - - label: ":bar_chart: Unit Tests Metrics" - command: | - echo '+++ :compression: Extracting Unit Tests Metrics Code' - tar -zxf .cicd/metrics/test-metrics.tar.gz - echo '+++ :javascript: Running test-metrics.js' - node --max-old-space-size=32768 test-metrics.js - agents: - queue: "automation-eos-builder-fleet" - timeout: 10 - soft_fail: true - - - wait - - label: ":aws: Amazon_Linux 2 - Toolchain Tests" command: - "buildkite-agent artifact download build.tar.gz . --step ':aws: Amazon_Linux 2 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" @@ -221,6 +205,20 @@ steps: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MOJAVE}${SKIP_TOOLCHAIN_TESTS} + - wait: + continue_on_failure: true + + - label: ":bar_chart: Unit Tests Metrics" + command: | + echo '+++ :compression: Extracting Unit Tests Metrics Code' + tar -zxf .cicd/metrics/test-metrics.tar.gz + echo '+++ :javascript: Running test-metrics.js' + node --max-old-space-size=32768 test-metrics.js + agents: + queue: "automation-eos-builder-fleet" + timeout: 10 + soft_fail: true + - wait - label: ":centos: Centos 7.6 - Package Builder" From c0c15a6e975cf34593b1f247fd1d9230522d4279 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 24 Oct 2019 16:41:43 -0400 Subject: [PATCH 099/659] Add toolchain tests to ctest --- tests/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1dd02ff0e7..3592e3e0c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,6 +39,9 @@ set_property(TEST time_tests PROPERTY LABELS unit_tests) add_test( varint_tests ${CMAKE_BINARY_DIR}/tests/unit/varint_tests ) set_property(TEST varint_tests PROPERTY LABELS unit_tests) +add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain ) +set_property(TEST toolchain_tests PROPERTY LABELS toolchain_tests) + if (eosio_FOUND AND EOSIO_RUN_INTEGRATION_TESTS) add_test(integration_tests ${CMAKE_BINARY_DIR}/tests/integration/integration_tests) set_property(TEST integration_tests PROPERTY LABELS integration_tests) From 965fc9e27ac593d71c162ff446fcf98e8f9b1b38 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 24 Oct 2019 17:05:02 -0400 Subject: [PATCH 100/659] Remove unneeded artifact uploads. --- .cicd/tests.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.cicd/tests.sh b/.cicd/tests.sh index f1317a6a14..41a4537b36 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -41,15 +41,9 @@ if [[ "$BUILDKITE" == 'true' ]]; then cd build # upload artifacts echo '+++ :arrow_up: Uploading Artifacts' - echo 'Compressing core dumps...' - [[ $((`ls -1 core.* 2>/dev/null | wc -l`)) != 0 ]] && tar czf core.tar.gz core.* || : # collect core dumps echo 'Exporting xUnit XML' mv -f ./Testing/$(ls ./Testing/ | grep '2' | tail -n 1)/Test.xml test-results.xml echo 'Uploading artifacts' - [[ -f config.ini ]] && buildkite-agent artifact upload config.ini - [[ -f core.tar.gz ]] && buildkite-agent artifact upload core.tar.gz - [[ -f genesis.json ]] && buildkite-agent artifact upload genesis.json - [[ -f mongod.log ]] && buildkite-agent artifact upload mongod.log buildkite-agent artifact upload test-results.xml echo 'Done uploading artifacts.' fi From ffbe1a3e7737c0ef1e0ef172076e2ae1fef4a5cd Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 25 Oct 2019 08:48:04 -0400 Subject: [PATCH 101/659] Fix accidental delete in Amazon Linux --- .cicd/docker/amazonlinux-2.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/docker/amazonlinux-2.dockerfile b/.cicd/docker/amazonlinux-2.dockerfile index caf5c58472..879f6b1d22 100644 --- a/.cicd/docker/amazonlinux-2.dockerfile +++ b/.cicd/docker/amazonlinux-2.dockerfile @@ -3,7 +3,7 @@ FROM amazonlinux:2.0.20190508 RUN yum update -y && \ yum install -y git gcc.x86_64 gcc-c++.x86_64 autoconf automake libtool make bzip2 \ bzip2-devel.x86_64 openssl-devel.x86_64 gmp-devel.x86_64 libstdc++.x86_64 \ - libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64 perl + python.x86_64 python3-devel.x86_64 libedit-devel.x86_64 doxygen.x86_64 graphviz.x86_64 perl # build lcov RUN git clone https://github.com/linux-test-project/lcov.git && \ cd lcov && \ From 25a6b12123453919a5ed96459090f5f5f5b5b9d2 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 25 Oct 2019 10:25:25 -0400 Subject: [PATCH 102/659] Move to EKS tester --- .cicd/pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 8504dfa6be..500ddc0a01 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -145,7 +145,7 @@ steps: env: IMAGE_TAG: "amazonlinux-2" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_AMAZON_LINUX_2}${SKIP_TOOLCHAIN_TESTS} @@ -156,7 +156,7 @@ steps: env: IMAGE_TAG: "centos-7.6" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_CENTOS_7}${SKIP_TOOLCHAIN_TESTS} @@ -167,7 +167,7 @@ steps: env: IMAGE_TAG: "ubuntu-16.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_UBUNTU_16}${SKIP_TOOLCHAIN_TESTS} @@ -178,7 +178,7 @@ steps: env: IMAGE_TAG: "ubuntu-18.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_UBUNTU_18}${SKIP_TOOLCHAIN_TESTS} From 890c57a66dc4f4df1175454f6c6f5d63aa7e2685 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Mon, 28 Oct 2019 16:48:17 -0400 Subject: [PATCH 103/659] Update libc --- libraries/libc/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc/musl b/libraries/libc/musl index 1fe3e67a0f..4b50059833 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 1fe3e67a0f98abac43f1a613fd294d0e2808476d +Subproject commit 4b5005983305cbf270e0c9e782774caf55d38149 From 9d85143cd827920953162d05206c4735976b6caa Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 31 Oct 2019 16:39:37 -0400 Subject: [PATCH 104/659] Revert "CI/CD support for Catalina" (#722) --- .cicd/pipeline.yml | 74 ++------------------------------------ scripts/generate_bottle.sh | 14 ++++---- 2 files changed, 11 insertions(+), 77 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index c338a7a2a2..4ec15ffbee 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -67,31 +67,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: $SKIP_MACOS_10_14 - - - label: ":darwin: macOS 10.15 - Build" - command: - - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" - - "git clone $BUILDKITE_REPO eosio.cdt" - - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" - - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" - - "cd eosio.cdt && ./.cicd/build.sh" - - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" - plugins: - - chef/anka#v0.5.1: - no-volume: true - inherit-environment-vars: true - vm-name: 10.15.0_6C_14G_40G - vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" - modify-cpu: 12 - modify-ram: 24 - always-pull: true - debug: true - wait-network: true - agents: - - "queue=mac-anka-large-node-fleet" - skip: $SKIP_MACOS_10_15 - + skip: $SKIP_MOJAVE - wait @@ -160,30 +136,7 @@ steps: wait-network: true agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MACOS_10_14}${SKIP_UNIT_TESTS} - - - label: ":darwin: macOS 10.15 - Unit Tests" - command: - - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" - - "git clone $BUILDKITE_REPO eosio.cdt" - - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" - - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" - - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" - - "cd eosio.cdt && ./.cicd/tests.sh" - plugins: - - chef/anka#v0.5.1: - no-volume: true - inherit-environment-vars: true - vm-name: 10.15.0_6C_14G_40G - vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" - modify-cpu: 12 - modify-ram: 24 - always-pull: true - debug: true - wait-network: true - agents: - - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MACOS_10_15}${SKIP_UNIT_TESTS} + skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} - wait: continue_on_failure: true @@ -248,28 +201,7 @@ steps: agents: - "queue=mac-anka-node-fleet" timeout: 10 - skip: ${SKIP_MACOS_10_14}${SKIP_PACKAGE_BUILDER} - - - label: ":darwin: Catalina - Package Builder" - command: - - "git clone $BUILDKITE_REPO eosio.cdt" - - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" - - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" - - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" - - "cd eosio.cdt && ./.cicd/package.sh" - plugins: - - chef/anka#v0.5.1: - no-volume: true - inherit-environment-vars: true - vm-name: 10.15.0_6C_14G_40G - vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" - always-pull: true - debug: true - wait-network: true - agents: - - "queue=mac-anka-node-fleet" - timeout: 10 - skip: ${SKIP_MACOS_10_15}${SKIP_PACKAGE_BUILDER} + skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} - label: ":git: Git Submodule Regression Check" command: diff --git a/scripts/generate_bottle.sh b/scripts/generate_bottle.sh index 12a1db9b1f..d93dc23190 100644 --- a/scripts/generate_bottle.sh +++ b/scripts/generate_bottle.sh @@ -1,15 +1,17 @@ #! /bin/bash -VERS=`sw_vers -productVersion | awk '/10\.14\..*/{print $0}'` -if [[ -z "$VERS" ]]; then - VERS=`sw_vers -productVersion | awk '/10\.15.*/{print $0}'` - if [[ -z $VERS ]]; then +VERS=`sw_vers -productVersion | awk '/10\.13\..*/{print $0}'` +if [[ -z "$VERS" ]]; +then + VERS=`sw_vers -productVersion | awk '/10\.14.*/{print $0}'` + if [[ -z "$VERS" ]]; + then echo "Error, unsupported OS X version" exit -1 fi - MAC_VERSION="catalina" -else MAC_VERSION="mojave" +else + MAC_VERSION="high_sierra" fi NAME="${PROJECT}-${VERSION}.${MAC_VERSION}.bottle" From edb3fd105c70a0990e7e515809a60fdf5b2d5d8b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 31 Oct 2019 17:03:33 -0400 Subject: [PATCH 105/659] Add debug support for native code. Need Release in libc/c++ due to linkage errors. --- libraries/libc++/CMakeLists.txt | 1 + libraries/libc/CMakeLists.txt | 1 + modules/LibrariesExternalProject.txt | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index b5b74e98cb..89318f251c 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -9,6 +9,7 @@ FOREACH(FN ${SRC_FILENAMES}) ENDFOREACH(FN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-everything") +set(CMAKE_BUILD_TYPE "Release") add_library(c++ ${SRC_FILES}) diff --git a/libraries/libc/CMakeLists.txt b/libraries/libc/CMakeLists.txt index 1fe21392ce..3806239e8a 100644 --- a/libraries/libc/CMakeLists.txt +++ b/libraries/libc/CMakeLists.txt @@ -17,6 +17,7 @@ file(GLOB THREAD_SOURCES "musl/src/thread/*.c") #only for __lock __unlock set(INTERNAL_SOURCES musl/src/internal/floatscan.c musl/src/internal/intscan.c musl/src/internal/shgetc.c musl/src/internal/libc.c) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-everything -allow-sse") +set(CMAKE_BUILD_TYPE "Release") file(GLOB HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/musl/include/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal/*.h" diff --git a/modules/LibrariesExternalProject.txt b/modules/LibrariesExternalProject.txt index d9298be3a2..07506528fd 100644 --- a/modules/LibrariesExternalProject.txt +++ b/modules/LibrariesExternalProject.txt @@ -6,7 +6,7 @@ ExternalProject_Add( EosioWasmLibraries SOURCE_DIR "${CMAKE_SOURCE_DIR}/libraries" BINARY_DIR "${CMAKE_BINARY_DIR}/libraries" - CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" From 2e07b16cf959cc0fdd156a13a30e39fde449a7cf Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 6 Nov 2019 14:01:01 -0500 Subject: [PATCH 106/659] Realloc should preserve the old memory contents. --- libraries/eosiolib/simple_malloc.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/simple_malloc.cpp b/libraries/eosiolib/simple_malloc.cpp index c91790d87a..4c626aeee2 100644 --- a/libraries/eosiolib/simple_malloc.cpp +++ b/libraries/eosiolib/simple_malloc.cpp @@ -75,7 +75,13 @@ void* calloc(size_t count, size_t size) { } void* realloc(void* ptr, size_t size) { - return eosio::_dsmalloc(size); + if (void* result = eosio::_dsmalloc(size)) { + // May read out of bounds, but that's okay, as the + // contents of the memory are undefined anyway. + memmove(result, ptr, size); + return result; + } + return nullptr; } void free(void* ptr) {} From 80423b5746719ab61d2e061d05310ec5f7f3cad0 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 6 Nov 2019 14:43:13 -0500 Subject: [PATCH 107/659] Allow toolchain_tests to work in out-of-tree builds. --- tests/CMakeLists.txt | 2 +- tools/toolchain-tester/CMakeLists.txt | 2 +- tools/toolchain-tester/toolchain-tester | 3 --- tools/toolchain-tester/toolchain-tester.in | 2 ++ 4 files changed, 4 insertions(+), 5 deletions(-) delete mode 100755 tools/toolchain-tester/toolchain-tester create mode 100755 tools/toolchain-tester/toolchain-tester.in diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3592e3e0c7..9094d77b7c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,7 +39,7 @@ set_property(TEST time_tests PROPERTY LABELS unit_tests) add_test( varint_tests ${CMAKE_BINARY_DIR}/tests/unit/varint_tests ) set_property(TEST varint_tests PROPERTY LABELS unit_tests) -add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain ) +add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain --cdt ${CMAKE_BINARY_DIR}/bin ) set_property(TEST toolchain_tests PROPERTY LABELS toolchain_tests) if (eosio_FOUND AND EOSIO_RUN_INTEGRATION_TESTS) diff --git a/tools/toolchain-tester/CMakeLists.txt b/tools/toolchain-tester/CMakeLists.txt index aadb128a1c..1916476aa7 100644 --- a/tools/toolchain-tester/CMakeLists.txt +++ b/tools/toolchain-tester/CMakeLists.txt @@ -1,4 +1,4 @@ project(toolchain-tester) cmake_minimum_required(VERSION 3.5) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/toolchain-tester ${CMAKE_BINARY_DIR}/ COPYONLY) +configure_file(toolchain-tester.in toolchain-tester ) diff --git a/tools/toolchain-tester/toolchain-tester b/tools/toolchain-tester/toolchain-tester deleted file mode 100755 index bd4477a3ec..0000000000 --- a/tools/toolchain-tester/toolchain-tester +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -REPO_ROOT=$(git rev-parse --show-toplevel) -/usr/bin/env python3.7 "${REPO_ROOT}/tools/toolchain-tester/main.py" "$@" diff --git a/tools/toolchain-tester/toolchain-tester.in b/tools/toolchain-tester/toolchain-tester.in new file mode 100755 index 0000000000..b59d6cdb5c --- /dev/null +++ b/tools/toolchain-tester/toolchain-tester.in @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +/usr/bin/env python3.7 "${CMAKE_CURRENT_SOURCE_DIR}/main.py" "$@" From 5d155fa3457fab0e6afe84444d69b5510567c3aa Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 6 Nov 2019 14:44:09 -0500 Subject: [PATCH 108/659] Align to 16 bytes. Fixes #131. --- libraries/eosiolib/simple_malloc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/simple_malloc.cpp b/libraries/eosiolib/simple_malloc.cpp index c91790d87a..e793a2c047 100644 --- a/libraries/eosiolib/simple_malloc.cpp +++ b/libraries/eosiolib/simple_malloc.cpp @@ -27,13 +27,13 @@ namespace eosio { dsmalloc() { volatile uintptr_t heap_base = 0; // linker places this at address 0 - heap = align(*(char**)heap_base, 8); + heap = align(*(char**)heap_base, 16); last_ptr = heap; next_page = CURRENT_MEMORY; } - char* operator()(size_t sz, uint8_t align_amt=8) { + char* operator()(size_t sz, uint8_t align_amt=16) { if (sz == 0) return NULL; From 9bd464223b36160e2520fe5db8af8f502f7846c3 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 6 Nov 2019 17:18:28 -0500 Subject: [PATCH 109/659] Update malloc tests --- tests/integration/CMakeLists.txt | 2 +- tests/integration/memory_tests.cpp | 6 +- tests/unit/test_contracts/malloc_tests.cpp | 134 +++++++++------------ 3 files changed, 61 insertions(+), 81 deletions(-) diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index d9ef0617a9..cdee032ff8 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required( VERSION 3.5 ) set(EOSIO_VERSION_MIN "1.4") -set(EOSIO_VERSION_SOFT_MAX "1.4") +set(EOSIO_VERSION_SOFT_MAX "2.0") #set(EOSIO_VERSION_HARD_MAX "") find_package(eosio) diff --git a/tests/integration/memory_tests.cpp b/tests/integration/memory_tests.cpp index dc80027f52..ec8acb0953 100644 --- a/tests/integration/memory_tests.cpp +++ b/tests/integration/memory_tests.cpp @@ -21,17 +21,13 @@ BOOST_AUTO_TEST_SUITE(memory_tests) BOOST_FIXTURE_TEST_CASE( malloc_tests, tester ) try { create_accounts( { N(test) } ); produce_block(); -/* set_code( N(test), contracts::malloc_tests_wasm() ); set_abi( N(test), contracts::malloc_tests_abi().data() ); produce_blocks(); - push_action(N(test), N(malloctest), N(test), {}); - push_action(N(test), N(mallocalot), N(test), {}); push_action(N(test), N(mallocpass), N(test), {}); - push_action(N(test), N(mallocpass2), N(test), {}); + push_action(N(test), N(mallocalign), N(test), {}); BOOST_CHECK_EXCEPTION( push_action(N(test), N(mallocfail), N(test), {}), eosio_assert_message_exception, eosio_assert_message_is("failed to allocate pages") ); - */ } FC_LOG_AND_RETHROW() } diff --git a/tests/unit/test_contracts/malloc_tests.cpp b/tests/unit/test_contracts/malloc_tests.cpp index bed9696815..25f4032c91 100644 --- a/tests/unit/test_contracts/malloc_tests.cpp +++ b/tests/unit/test_contracts/malloc_tests.cpp @@ -2,90 +2,74 @@ using namespace eosio; -// simple macro to add line info to string -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define X(STR) \ - STR " at line # " TOSTRING(__LINE__) - -CONTRACT malloc_tests : public contract{ +class [[eosio::contract]] malloc_tests : public contract{ public: using contract::contract; - inline char* align(char* ptr, uint8_t align_amt) { - return (char*)((((size_t)ptr) + align_amt-1) & ~(align_amt-1)); - } - - inline size_t align(size_t ptr, uint8_t align_amt) { - return (ptr + align_amt-1) & ~(align_amt-1); - } - - inline char* get_heap_base() { - - volatile uintptr_t address = 0; - volatile char* heap_base = align(*(char**)address, 8); - return (char*)heap_base; - } - static constexpr size_t max_heap = 33*1024*1024; - - ACTION mallocalot() { - char* ret = (char*)malloc(10); - char* last_ret = ret; - for (size_t i=0; i < ((max_heap-(64*1024))/align(10,8)); i++) { - last_ret = ret; - ret = (char*)malloc(10); - check(ret != last_ret, X("ret should not equal last_ret")); - check((size_t)ret%8 == 0, X("ret should be divisible by 8")); - check(ret == align(last_ret+10, 8), X("alloc(10) not as expected")); - } - } - ACTION mallocpass() { - malloc(max_heap-(64*1024)); - size_t diff = (64*1024)-(size_t)get_heap_base(); - malloc(diff-align(1,8)); + [[eosio::action]] + void mallocpass() { + // make sure that malloc allocates non-overlapping writable memory + volatile char * ptr0 = (char*)malloc(1); + *ptr0 = 0x11; + volatile short * ptr1 = (short*)malloc(sizeof(short)); + *ptr1 = 0x2222; + volatile int * ptr2 = (int*)malloc(sizeof(int)); + *ptr2 = 0x33333333; + volatile long long *ptr3 = (long long*)malloc(sizeof(long long)); + *ptr3 = 0x4444444444444444; + volatile __int128_t *ptr4 = (__int128_t*)malloc(sizeof(__int128_t)); + *ptr4 = ((__int128_t(0x5555555555555555) << 64) | 0x5555555555555555); + volatile __int128_t *ptr5 = (__int128_t*)malloc(sizeof(__int128_t)); + *ptr5 = ((__int128_t(0x6666666666666666) << 64) | 0x6666666666666666); + volatile __int128_t *ptr6 = (__int128_t*)malloc(sizeof(__int128_t) * 2); + ptr6[0] = ptr6[1] = ((__int128_t(0x7777777777777777) << 64) | 0x7777777777777777); + volatile __int128_t *ptr7 = (__int128_t*)malloc(sizeof(__int128_t) * 2); + ptr7[0] = ptr7[1] = ((__int128_t(0x8888888888888888) << 64) | 0x8888888888888888); + volatile long long *ptr8 = (long long*)malloc(sizeof(long long) * 3); + ptr8[0] = ptr8[1] = ptr8[2] = 0x9999999999999999; + volatile long long *ptr9 = (long long*)malloc(sizeof(long long) * 3); + ptr9[0] = ptr9[1] = ptr9[2] = 0xAAAAAAAAAAAAAAAA; + eosio::check(*ptr0 == 0x11, "wrong value for char"); + eosio::check(*ptr1 == 0x2222, "wrong value for short"); + eosio::check(*ptr2 == 0x33333333, "wrong value for int"); + eosio::check(*ptr3 == 0x4444444444444444, "wrong value for long long"); + eosio::check(*ptr4 == ((__int128_t(0x5555555555555555) << 64) | 0x5555555555555555), "wrong value for __int128 #1"); + eosio::check(*ptr5 == ((__int128_t(0x6666666666666666) << 64) | 0x6666666666666666), "wrong value for __int128 #2"); + eosio::check(ptr6[0] == ((__int128_t(0x7777777777777777) << 64) | 0x7777777777777777), "wrong value for __int128[2] #1"); + eosio::check(ptr6[1] == ((__int128_t(0x7777777777777777) << 64) | 0x7777777777777777), "wrong value for __int128[2] #1"); + eosio::check(ptr7[0] == ((__int128_t(0x8888888888888888) << 64) | 0x8888888888888888), "wrong value for __int128[2] #2"); + eosio::check(ptr7[1] == ((__int128_t(0x8888888888888888) << 64) | 0x8888888888888888), "wrong value for __int128[2] #2"); + eosio::check(ptr8[0] == 0x9999999999999999, "wrong value for long long[3] #1"); + eosio::check(ptr8[1] == 0x9999999999999999, "wrong value for long long[3] #1"); + eosio::check(ptr8[2] == 0x9999999999999999, "wrong value for long long[3] #1"); + eosio::check(ptr9[0] == 0xAAAAAAAAAAAAAAAA, "wrong value for long long[3] #2"); + eosio::check(ptr9[1] == 0xAAAAAAAAAAAAAAAA, "wrong value for long long[3] #2"); + eosio::check(ptr9[2] == 0xAAAAAAAAAAAAAAAA, "wrong value for long long[3] #2"); } - ACTION mallocpass2() { - char* ptr = (char*)malloc(max_heap-(64*1024)); - size_t diff = (64*1024)-(size_t)get_heap_base(); - malloc(diff-align(1,8)); - for (size_t i=0; i < (max_heap-diff); i++) { - ptr[i] = 'a'; - } - for (size_t i=0; i < (max_heap-diff); i++) { - eosio::check(ptr[i] == 'a', "should have written to memory"); - } - - } - - ACTION mallocfail() { - mallocpass(); + template + void malloc_align_test() { + eosio::check((uintptr_t)malloc(sizeof(T)) % alignof(T) == 0, "insufficient alignment"); malloc(1); + eosio::check((uintptr_t)malloc(sizeof(T)) % alignof(T) == 0, "insufficient alignment"); + } + [[eosio::action]] + void mallocalign() { + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test(); + malloc_align_test<__int128_t>(); } - ACTION malloctest() { - char* ptr1 = (char*)malloc(0); - check(ptr1 == nullptr, "should not have allocated a 0 char buf"); - - // 20 chars - 20 + 4(header) which is divisible by 8 - ptr1 = (char*)malloc(20); - check(ptr1 != nullptr, "should have allocated a 20 char buf"); - - // 20 chars allocated - char* ptr2 = (char*)malloc(20); - check(ptr2 != nullptr, "should have allocated another 20 char buf"); - check(ptr1 + 20 < ptr2, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) - - // 20 chars allocated - char* ptr3 = (char*)malloc(20); - check(ptr3 != nullptr, "should have allocated another 20 char buf"); - check(ptr2 + 20 < ptr3, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) - - // 20 chars allocated - char* ptr4 = (char*)malloc(20); - check(ptr4 != nullptr, "should have allocated another 20 char buf"); - check(ptr3 + 20 < ptr4, "20 char buf should have been created after ptr1"); // test specific to implementation (can remove for refactor) + [[eosio::action]] + void mallocfail() { + malloc(max_heap); } }; From 36491410ed287c72d09acae43fe8a2258531f0df Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 7 Nov 2019 09:39:45 -0500 Subject: [PATCH 110/659] Switch CI fleet. --- .cicd/pipeline.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 500ddc0a01..720db4e061 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -9,7 +9,7 @@ steps: env: IMAGE_TAG: "amazonlinux-2" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: ${TIMEOUT:-10} skip: $SKIP_AMAZON_LINUX_2 @@ -20,7 +20,7 @@ steps: env: IMAGE_TAG: "centos-7.6" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: ${TIMEOUT:-10} skip: $SKIP_CENTOS_7 @@ -31,7 +31,7 @@ steps: env: IMAGE_TAG: "ubuntu-16.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: ${TIMEOUT:-10} skip: $SKIP_UBUNTU_16 @@ -42,7 +42,7 @@ steps: env: IMAGE_TAG: "ubuntu-18.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: ${TIMEOUT:-10} skip: $SKIP_UBUNTU_18 @@ -78,7 +78,7 @@ steps: env: IMAGE_TAG: "amazonlinux-2" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_AMAZON_LINUX_2}${SKIP_UNIT_TESTS} @@ -89,7 +89,7 @@ steps: env: IMAGE_TAG: "centos-7.6" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_CENTOS_7}${SKIP_UNIT_TESTS} @@ -100,7 +100,7 @@ steps: env: IMAGE_TAG: "ubuntu-16.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_UBUNTU_16}${SKIP_UNIT_TESTS} @@ -111,7 +111,7 @@ steps: env: IMAGE_TAG: "ubuntu-18.04" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_UBUNTU_18}${SKIP_UNIT_TESTS} @@ -215,7 +215,7 @@ steps: echo '+++ :javascript: Running test-metrics.js' node --max-old-space-size=32768 test-metrics.js agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: 10 soft_fail: true @@ -231,7 +231,7 @@ steps: OS: "el7" # OS and PKGTYPE required for lambdas PKGTYPE: "rpm" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_CENTOS_7}${SKIP_PACKAGE_BUILDER} @@ -245,7 +245,7 @@ steps: OS: "ubuntu-18.04" # OS and PKGTYPE required for lambdas PKGTYPE: "deb" agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} skip: ${SKIP_UBUNTU_18}${SKIP_PACKAGE_BUILDER} From 02f5f4f60a1e3e090dbe1a585e076339b01dc3c1 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 7 Nov 2019 10:07:20 -0500 Subject: [PATCH 111/659] Fix capi declarations of functions with no arguments. --- libraries/eosiolib/capi/eosio/action.h | 6 +++--- libraries/eosiolib/capi/eosio/system.h | 4 ++-- libraries/eosiolib/capi/eosio/transaction.h | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/eosiolib/capi/eosio/action.h b/libraries/eosiolib/capi/eosio/action.h index abec96698b..92e82522ba 100644 --- a/libraries/eosiolib/capi/eosio/action.h +++ b/libraries/eosiolib/capi/eosio/action.h @@ -83,7 +83,7 @@ uint32_t read_action_data( void* msg, uint32_t len ); * @return the length of the current action's data field */ __attribute__((eosio_wasm_import)) -uint32_t action_data_size(); +uint32_t action_data_size( void ); /** * Add the specified account to set of accounts to be notified @@ -158,7 +158,7 @@ void send_context_free_inline(char *serialized_action, size_t size); * @return the time in microseconds from 1970 of the publication_time */ __attribute__((eosio_wasm_import)) -uint64_t publication_time(); +uint64_t publication_time( void ); /** * Get the current receiver of the action @@ -166,7 +166,7 @@ uint64_t publication_time(); * @return the account which specifies the current receiver of the action */ __attribute__((eosio_wasm_import)) -capi_name current_receiver(); +capi_name current_receiver( void ); #ifdef __cplusplus } diff --git a/libraries/eosiolib/capi/eosio/system.h b/libraries/eosiolib/capi/eosio/system.h index b7b7cb63a1..668bf56125 100644 --- a/libraries/eosiolib/capi/eosio/system.h +++ b/libraries/eosiolib/capi/eosio/system.h @@ -74,7 +74,7 @@ void eosio_exit( int32_t code ); * @return time in microseconds from 1970 of the current block */ __attribute__((eosio_wasm_import)) -uint64_t current_time(); +uint64_t current_time( void ); /** * Check if specified protocol feature has been activated @@ -91,7 +91,7 @@ bool is_feature_activated( const capi_checksum256* feature_digest ); * @return name of account that sent the current inline action (empty name if not called from inline action) */ __attribute__((eosio_wasm_import)) -capi_name get_sender(); +capi_name get_sender( void ); #ifdef __cplusplus } diff --git a/libraries/eosiolib/capi/eosio/transaction.h b/libraries/eosiolib/capi/eosio/transaction.h index d414b23eae..111b7b16a7 100644 --- a/libraries/eosiolib/capi/eosio/transaction.h +++ b/libraries/eosiolib/capi/eosio/transaction.h @@ -89,7 +89,7 @@ size_t read_transaction(char *buffer, size_t size); * @return size of the currently executing transaction */ __attribute__((eosio_wasm_import)) -size_t transaction_size(); +size_t transaction_size( void ); /** * Gets the block number used for TAPOS on the currently executing transaction. @@ -102,7 +102,7 @@ size_t transaction_size(); * @endcode */ __attribute__((eosio_wasm_import)) -int tapos_block_num(); +int tapos_block_num( void ); /** * Gets the block prefix used for TAPOS on the currently executing transaction. @@ -115,7 +115,7 @@ int tapos_block_num(); * @endcode */ __attribute__((eosio_wasm_import)) -int tapos_block_prefix(); +int tapos_block_prefix( void ); /** * Gets the expiration of the currently executing transaction. @@ -129,7 +129,7 @@ int tapos_block_prefix(); * @endcode */ __attribute__((eosio_wasm_import)) -uint32_t expiration(); +uint32_t expiration( void ); /** * Retrieves the indicated action from the active transaction. From 0d050e3ec177353ac3d772812879c5c78b026c23 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 7 Nov 2019 16:27:33 -0500 Subject: [PATCH 112/659] Forward arguments to subprocesses correctly. Fixes #531. --- tools/cc/eosio-cpp.cpp.in | 4 +- tools/include/compiler_options.hpp.in | 61 +++++++++++++++------------ tools/include/eosio/utils.hpp | 11 ++--- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index 90ed8151d3..8534701eb7 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -201,7 +201,7 @@ int main(int argc, const char **argv) { output = opts.output_fn.empty() ? "a.out" : opts.output_fn; } - new_opts.insert(new_opts.begin(), "-o "+output); + new_opts.insert(new_opts.begin(), {"-o", output}); outputs.push_back(output); if (llvm::sys::path::extension(input).equals(".c")) @@ -221,7 +221,7 @@ int main(int argc, const char **argv) { if (opts.link) { std::vector new_opts = opts.ld_options; for (auto input : outputs) { - new_opts.insert(new_opts.begin(), std::string(" ")+input+" "); + new_opts.insert(new_opts.begin(), input); } if (!eosio::cdt::environment::exec_subprogram("eosio-ld", new_opts)) { diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 5e5057eadb..789fd418bc 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -434,59 +434,64 @@ static void GetLdDefaults(std::vector& ldopts) { if (fquery_opt || fquery_server_opt || fquery_client_opt) { ldopts.emplace_back("--export-table"); ldopts.emplace_back("-other-model"); - ldopts.emplace_back("--only-export \"*:table\""); - ldopts.emplace_back("--only-export \"*:memory\""); + ldopts.insert(ldopts.end(), { "--only-export", "*:table" }); + ldopts.insert(ldopts.end(), { "--only-export", "*:memory" }); if (fuse_main_opt) { - ldopts.emplace_back("-e main"); - ldopts.emplace_back("--only-export \"main:function\""); + ldopts.insert(ldopts.end(), { "-e", "main" }); + ldopts.insert(ldopts.end(), { "--only-export", "main:function" } ); } else { - ldopts.emplace_back("-e initialize "); - ldopts.emplace_back("--only-export \"initialize:function\""); + ldopts.insert(ldopts.end(), { "-e", "initialize " } ); + ldopts.insert(ldopts.end(), { "--only-export", "initialize:function" } ); } if (fquery_server_opt) - ldopts.emplace_back("-export run_query "); + ldopts.insert(ldopts.end(), { "-export", "run_query " }); else { - ldopts.emplace_back("-export create_query_request "); - ldopts.emplace_back("-export decode_query_response "); - ldopts.emplace_back("-export describe_query_request "); - ldopts.emplace_back("-export describe_query_response "); + ldopts.insert(ldopts.end(), { "-export", "create_query_request " }); + ldopts.insert(ldopts.end(), { "-export", "decode_query_response " }); + ldopts.insert(ldopts.end(), { "-export", "describe_query_request " }); + ldopts.insert(ldopts.end(), { "-export", "describe_query_response " }); } if (fquery_server_opt) - ldopts.emplace_back("--only-export \"run_query:function\""); + ldopts.insert(ldopts.end(), { "--only-export", "run_query:function" }); else { - ldopts.emplace_back("--only-export \"create_query_request:function\""); - ldopts.emplace_back("--only-export \"decode_query_response:function\""); - ldopts.emplace_back("--only-export \"describe_query_request:function\""); - ldopts.emplace_back("--only-export \"describe_query_response:function\""); + ldopts.insert(ldopts.end(), { "--only-export", "create_query_request:function" }); + ldopts.insert(ldopts.end(), { "--only-export", "decode_query_response:function" }); + ldopts.insert(ldopts.end(), { "--only-export", "describe_query_request:function" }); + ldopts.insert(ldopts.end(), { "--only-export", "describe_query_response:function" }); } } else { if (fuse_main_opt) - ldopts.emplace_back("-e main"); + ldopts.insert(ldopts.end(), { "-e", "main" }); else - ldopts.emplace_back("-e apply"); - ldopts.emplace_back("--only-export \"apply:function\""); + ldopts.insert(ldopts.end(), { "-e", "apply" }); + ldopts.insert(ldopts.end(), { "--only-export", "apply:function" }); } - ldopts.emplace_back("-lc++ -lc -leosio"); + ldopts.emplace_back("-lc++"); + ldopts.emplace_back("-lc"); + ldopts.emplace_back("-leosio"); if (use_old_malloc_opt) ldopts.emplace_back("-leosio_malloc"); else ldopts.emplace_back("-leosio_dsm"); - if (use_rt_opt || fquery_opt || fquery_server_opt || fquery_client_opt) - ldopts.emplace_back("-lrt -lsf"); + if (use_rt_opt || fquery_opt || fquery_server_opt || fquery_client_opt) { + ldopts.emplace_back("-lrt"); + ldopts.emplace_back("-lsf"); + } if (fquery_opt || fquery_server_opt || fquery_client_opt) ldopts.emplace_back("-leosio_cmem"); if (!only_export_opt.empty()) { - ldopts.emplace_back("--only-export \""+only_export_opt+"\""); + ldopts.emplace_back("--only-export"); + ldopts.emplace_back(only_export_opt); } } else { #ifdef __APPLE__ - ldopts.emplace_back("-arch x86_64 -macosx_version_min 10.13 -framework Foundation -framework System"); + ldopts.insert(ldopts.end(), {"-arch", "x86_64", "-macosx_version_min", "10.13", "-framework", "Foundation", "-framework", "System"}); #endif ldopts.emplace_back("-static"); - ldopts.emplace_back("-lnative_c++ -lnative_c -lnative_eosio -lnative -lnative_rt"); + ldopts.insert(ldopts.end(), {"-lnative_c++", "-lnative_c", "-lnative_eosio", "-lnative", "-lnative_rt"}); } } #endif @@ -611,7 +616,7 @@ static Options CreateOptions(bool add_defaults=true) { copts.emplace_back("-fcolor-diagnostics"); } if (!MF_opt.empty()) { - copts.emplace_back("-MF "+MF_opt); + copts.insert(copts.end(), { "-MF", MF_opt }); } if (MD_opt) { copts.emplace_back("-MD"); @@ -778,10 +783,10 @@ static Options CreateOptions(bool add_defaults=true) { llvm::sys::path::replace_extension(fn, ""); llvm::sys::path::replace_extension(fn, fnative_opt ? "" : ".wasm"); output_fn = fn.str(); - ldopts.emplace_back("-o "+output_fn); + ldopts.emplace_back("-o"+output_fn); } else { output_fn = "a.out"; - ldopts.emplace_back("-o "+output_fn); + ldopts.emplace_back("-o"+output_fn); } #endif } diff --git a/tools/include/eosio/utils.hpp b/tools/include/eosio/utils.hpp index 27924caf19..ac83337a66 100644 --- a/tools/include/eosio/utils.hpp +++ b/tools/include/eosio/utils.hpp @@ -134,14 +134,15 @@ struct environment { return env_table; } static bool exec_subprogram(const std::string prog, std::vector options, bool root=false) { - std::stringstream args; - for (auto s : options) - args << s << " "; + std::vector args; + args.push_back(prog); + args.insert(args.end(), options.begin(), options.end()); std::string find_path = eosio::cdt::whereami::where(); if (root) find_path = "/usr/bin"; - if ( auto path = llvm::sys::findProgramByName(prog.c_str(), {find_path}) ) - std::system((*path+" "+args.str()).c_str()); + if ( auto path = llvm::sys::findProgramByName(prog.c_str(), {find_path}) ) { + return llvm::sys::ExecuteAndWait(*path, args, {}, {}, 0, 0, nullptr, nullptr) != -1; + } else return false; return true; From 3a067f6794c35fc67e821e321c7bc9c00b15cdab Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 7 Nov 2019 17:28:31 -0500 Subject: [PATCH 113/659] Fix -E. We shouldn't try to run ClangTool when -E is used. --- tools/cc/eosio-cpp.cpp.in | 33 ++++++++++++++------------- tools/include/compiler_options.hpp.in | 7 ++++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index 8534701eb7..3dc88f33d5 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -183,26 +183,27 @@ int main(int argc, const char **argv) { std::string tmp_file = std::string(res.c_str())+"/"+llvm::sys::path::filename(input).str(); std::string output; - generate(opts.comp_options, input, opts.abigen_contract, opts.abigen_resources, opts.abigen); + if (!opts.pp_only) { + generate(opts.comp_options, input, opts.abigen_contract, opts.abigen_resources, opts.abigen); - auto src = SmallString<64>(input); - llvm::sys::path::remove_filename(src); - std::string source_path = src.str().empty() ? "." : src.str(); - new_opts.insert(new_opts.begin(), "-I" + source_path); + auto src = SmallString<64>(input); + llvm::sys::path::remove_filename(src); + std::string source_path = src.str().empty() ? "." : src.str(); + new_opts.insert(new_opts.begin(), "-I" + source_path); - if (llvm::sys::fs::exists(tmp_file)) { - input = tmp_file; - } - output = tmp_file+".o"; + if (llvm::sys::fs::exists(tmp_file)) { + input = tmp_file; + } + output = tmp_file+".o"; - new_opts.insert(new_opts.begin(), input); - - if (!opts.link) { - output = opts.output_fn.empty() ? "a.out" : opts.output_fn; - } + if (!opts.link) { + output = opts.output_fn.empty() ? "a.out" : opts.output_fn; + } - new_opts.insert(new_opts.begin(), {"-o", output}); - outputs.push_back(output); + new_opts.insert(new_opts.begin(), {"-o", output}); + outputs.push_back(output); + } + new_opts.insert(new_opts.begin(), input); if (llvm::sys::path::extension(input).equals(".c")) new_opts.insert(new_opts.begin(), "-xc++"); diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 789fd418bc..2571297d5e 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -354,6 +354,7 @@ struct Options { std::vector inputs; bool link; bool abigen; + bool pp_only; std::string eosio_pp_dir; std::string abigen_output; std::string abigen_contract; @@ -511,8 +512,10 @@ static Options CreateOptions(bool add_defaults=true) { #ifdef ONLY_LD bool abigen = false; + bool pp_only = false; #else bool abigen = abigen_opt; + bool pp_only = E_opt; abigen_output = abigen_output_opt; debug = g_opt; #endif @@ -855,8 +858,8 @@ static Options CreateOptions(bool add_defaults=true) { #endif #ifndef ONLY_LD - return {output_fn, inputs, link, abigen, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; + return {output_fn, inputs, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; #else - return {output_fn, {}, link, abigen, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; + return {output_fn, {}, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; #endif } From 87263df591216e5e89a1406a4c99773dd142c25d Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 7 Nov 2019 17:59:56 -0500 Subject: [PATCH 114/659] Fix --emit-llvm, --emit-ir, and -S --- tools/cc/eosio-cpp.cpp.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index 3dc88f33d5..023e62ad9d 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -184,7 +184,12 @@ int main(int argc, const char **argv) { std::string output; if (!opts.pp_only) { - generate(opts.comp_options, input, opts.abigen_contract, opts.abigen_resources, opts.abigen); + auto tool_opts = opts.comp_options; + std::set non_tool_opts = { "-S", "-emit-llvm" }; + tool_opts.erase(std::remove_if(tool_opts.begin(), tool_opts.end(), + [&](const auto& opt){ return non_tool_opts.count(opt); }), + tool_opts.end()); + generate(tool_opts, input, opts.abigen_contract, opts.abigen_resources, opts.abigen); auto src = SmallString<64>(input); llvm::sys::path::remove_filename(src); From ece88ef5e025270ee4468198a2a50b491ed6a23e Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 8 Nov 2019 09:31:16 -0500 Subject: [PATCH 115/659] Fix -emit-ast --- tools/cc/eosio-cpp.cpp.in | 2 +- tools/include/compiler_options.hpp.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index 023e62ad9d..b87c0b3686 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -185,7 +185,7 @@ int main(int argc, const char **argv) { if (!opts.pp_only) { auto tool_opts = opts.comp_options; - std::set non_tool_opts = { "-S", "-emit-llvm" }; + std::set non_tool_opts = { "-S", "-emit-llvm", "-emit-ast" }; tool_opts.erase(std::remove_if(tool_opts.begin(), tool_opts.end(), [&](const auto& opt){ return non_tool_opts.count(opt); }), tool_opts.end()); diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 2571297d5e..bc477bb12e 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -600,6 +600,7 @@ static Options CreateOptions(bool add_defaults=true) { copts.emplace_back("-D"+define); } if (emit_ast_opt) { + link = false; copts.emplace_back("-emit-ast"); } if (emit_llvm_opt) { From 1d680a8a138bb5960d1142698c0c129b85829768 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 8 Nov 2019 10:01:59 -0500 Subject: [PATCH 116/659] Update eosio-cc and the linker options to handle the new subprocess argument behavior. --- tools/cc/eosio-cc.cpp.in | 4 ++-- tools/include/compiler_options.hpp.in | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cc/eosio-cc.cpp.in b/tools/cc/eosio-cc.cpp.in index 9674a4093e..1d8e220103 100644 --- a/tools/cc/eosio-cc.cpp.in +++ b/tools/cc/eosio-cc.cpp.in @@ -58,7 +58,7 @@ int main(int argc, const char **argv) { output = opts.output_fn.empty() ? "a.out" : opts.output_fn; } - new_opts.insert(new_opts.begin(), "-o "+output); + new_opts.insert(new_opts.begin(), "-o"+output); outputs.push_back(output); if (!eosio::cdt::environment::exec_subprogram("clang-7", new_opts)) { llvm::sys::fs::remove(tmp_file); @@ -71,7 +71,7 @@ int main(int argc, const char **argv) { if (opts.link) { std::vector new_opts = opts.ld_options; for (auto input : outputs) { - new_opts.insert(new_opts.begin(), std::string(" ")+input+" "); + new_opts.insert(new_opts.begin(), input); } if (!eosio::cdt::environment::exec_subprogram("eosio-ld", new_opts)) { for (auto input : outputs) { diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index bc477bb12e..2115984133 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -795,7 +795,8 @@ static Options CreateOptions(bool add_defaults=true) { #endif } else { - ldopts.emplace_back("-o "+o_opt); + ldopts.emplace_back("-o"); + ldopts.emplace_back(o_opt); output_fn = o_opt; } From 2e0e344b65c9e6f4afc4e7e846be93ff3d267a0b Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 8 Nov 2019 15:44:39 -0500 Subject: [PATCH 117/659] Adjust builtin macros for native OSX builds. --- libraries/libc/CMakeLists.txt | 3 +++ tools/include/compiler_options.hpp.in | 2 ++ 2 files changed, 5 insertions(+) diff --git a/libraries/libc/CMakeLists.txt b/libraries/libc/CMakeLists.txt index 1fe21392ce..f88c2b47d1 100644 --- a/libraries/libc/CMakeLists.txt +++ b/libraries/libc/CMakeLists.txt @@ -17,6 +17,9 @@ file(GLOB THREAD_SOURCES "musl/src/thread/*.c") #only for __lock __unlock set(INTERNAL_SOURCES musl/src/internal/floatscan.c musl/src/internal/intscan.c musl/src/internal/shgetc.c musl/src/internal/libc.c) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-everything -allow-sse") +if(__APPLE) + add_definitions(-D__APPLE__) +endif() file(GLOB HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/musl/include/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal/*.h" diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 2115984133..873be56bbb 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -398,9 +398,11 @@ static void GetCompDefaults(std::vector& copts) { copts.emplace_back("-fno-exceptions"); copts.emplace_back("-fno-rtti"); copts.emplace_back("-fmodules-ts"); + copts.emplace_back("-D_GNU_SOURCE=1"); #endif copts.emplace_back("-DBOOST_DISABLE_ASSERTS"); copts.emplace_back("-DBOOST_EXCEPTION_DISABLE"); + copts.emplace_back("-U__APPLE__"); if (!fnative_opt) { copts.emplace_back("-Xclang"); copts.emplace_back("-load"); From 1ed675a5d3b01bf9f0184371977d52241fad9265 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 8 Nov 2019 16:33:19 -0500 Subject: [PATCH 118/659] Switch libcxx to current eosio. --- libraries/libc++/libcxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index bfc1bddd18..d45faf798d 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit bfc1bddd181bb0b1a62610d526f01385a919d0cb +Subproject commit d45faf798dd6b56e322e89b0af8d120a33a34b4c From f847bd326f659eb28a5e05cc28ae3389fe5e8df8 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 8 Nov 2019 16:40:50 -0500 Subject: [PATCH 119/659] Update libc, since libcxx depends on it. --- libraries/libc/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc/musl b/libraries/libc/musl index 4b50059833..5c68a528ad 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 4b5005983305cbf270e0c9e782774caf55d38149 +Subproject commit 5c68a528ad29c364245d3b56eec7b4a375acd19b From dcb361cee237a6e4441aab7fbbd468a4600fec2f Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 12 Nov 2019 11:00:33 -0500 Subject: [PATCH 120/659] Make datastream operators more selective to avoid interference with std::[io]stream. Refs #186. --- libraries/eosiolib/core/eosio/datastream.hpp | 199 ++++++++++--------- 1 file changed, 105 insertions(+), 94 deletions(-) diff --git a/libraries/eosiolib/core/eosio/datastream.hpp b/libraries/eosiolib/core/eosio/datastream.hpp index 5526d2e6bf..acbdbf3b47 100644 --- a/libraries/eosiolib/core/eosio/datastream.hpp +++ b/libraries/eosiolib/core/eosio/datastream.hpp @@ -370,12 +370,12 @@ inline datastream& operator>>(datastream& ds, std::variant& - Reference to the datastream */ -template -DataStream& operator<<( DataStream& ds, const std::pair& t ) { +template +datastream& operator<<( datastream& ds, const std::pair& t ) { ds << std::get<0>(t); ds << std::get<1>(t); return ds; @@ -386,12 +386,12 @@ DataStream& operator<<( DataStream& ds, const std::pair& t ) { * * @param ds - The stream to read * @param t - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator>>( DataStream& ds, std::pair& t ) { +template +datastream& operator>>( datastream& ds, std::pair& t ) { T1 t1; T2 t2; ds >> t1; @@ -473,11 +473,11 @@ inline datastream& operator>>(datastream& ds, bool& d) { * * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::string& v ) { +template +datastream& operator << ( datastream& ds, const std::string& v ) { ds << unsigned_int( v.size() ); if (v.size()) ds.write(v.data(), v.size()); @@ -489,11 +489,11 @@ DataStream& operator << ( DataStream& ds, const std::string& v ) { * * @param ds - The stream to read * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::string& v ) { +template +datastream& operator >> ( datastream& ds, std::string& v ) { std::vector tmp; ds >> tmp; if( tmp.size() ) @@ -508,13 +508,13 @@ DataStream& operator >> ( DataStream& ds, std::string& v ) { * * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the array * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::array& v ) { +template +datastream& operator << ( datastream& ds, const std::array& v ) { for( const auto& i : v ) ds << i; return ds; @@ -527,13 +527,13 @@ DataStream& operator << ( DataStream& ds, const std::array& v ) { * @brief Deserialize a fixed size std::array * @param ds - The stream to read * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the array * @tparam N - Size of the array - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::array& v ) { +template +datastream& operator >> ( datastream& ds, std::array& v ) { for( auto& i : v ) ds >> i; return ds; @@ -568,6 +568,17 @@ namespace _datastream_detail { return std::is_arithmetic::value || std::is_enum::value; } + + /* + * Check if type T is a specialization of datastream + * + * @brief Check if type T is a datastream + * @tparam T - The type to be checked + */ + template + struct is_datastream { static constexpr bool value = false; }; + template + struct is_datastream> { static constexpr bool value = true; }; } /** @@ -575,13 +586,13 @@ namespace _datastream_detail { * * @brief Deserialize a a pointer * @param ds - The stream to read - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream * @post Throw an exception if it is a pointer */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T ) { +template()>* = nullptr> +datastream& operator >> ( datastream& ds, T ) { static_assert(!_datastream_detail::is_pointer(), "Pointers should not be serialized" ); return ds; } @@ -592,14 +603,14 @@ DataStream& operator >> ( DataStream& ds, T ) { * @brief Serialize a fixed size C array of non-primitive and non-pointer type * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template() && !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { +datastream& operator << ( datastream& ds, const T (&v)[N] ) { ds << unsigned_int( N ); for( uint32_t i = 0; i < N; ++i ) ds << v[i]; @@ -612,13 +623,13 @@ DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { * @brief Serialize a fixed size C array of primitive type * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the pointer - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template()>* = nullptr> -DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { +datastream& operator << ( datastream& ds, const T (&v)[N] ) { ds << unsigned_int( N ); ds.write((char*)&v[0], sizeof(v)); return ds; @@ -632,13 +643,13 @@ DataStream& operator << ( DataStream& ds, const T (&v)[N] ) { * @param v - The destination for deserialized value * @tparam T - Type of the object contained in the array * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template() && !_datastream_detail::is_pointer()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { +datastream& operator >> ( datastream& ds, T (&v)[N] ) { unsigned_int s; ds >> s; eosio::check( N == s.value, "T[] size and unpacked size don't match"); @@ -655,12 +666,12 @@ DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { * @param v - The destination for deserialized value * @tparam T - Type of the object contained in the array * @tparam N - Size of the array - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template()>* = nullptr> -DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { +datastream& operator >> ( datastream& ds, T (&v)[N] ) { unsigned_int s; ds >> s; eosio::check( N == s.value, "T[] size and unpacked size don't match"); @@ -674,11 +685,11 @@ DataStream& operator >> ( DataStream& ds, T (&v)[N] ) { * @brief Serialize a vector of char * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::vector& v ) { +template +datastream& operator << ( datastream& ds, const std::vector& v ) { ds << unsigned_int( v.size() ); ds.write( v.data(), v.size() ); return ds; @@ -690,12 +701,12 @@ DataStream& operator << ( DataStream& ds, const std::vector& v ) { * @brief Serialize a vector * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::vector& v ) { +template +datastream& operator << ( datastream& ds, const std::vector& v ) { ds << unsigned_int( v.size() ); for( const auto& i : v ) ds << i; @@ -708,11 +719,11 @@ DataStream& operator << ( DataStream& ds, const std::vector& v ) { * @brief Deserialize a vector of char * @param ds - The stream to read * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream - * @return DataStream& - Reference to the datastream + * @tparam Stream - Type of datastream buffer + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::vector& v ) { +template +datastream& operator >> ( datastream& ds, std::vector& v ) { unsigned_int s; ds >> s; v.resize( s.value ); @@ -726,12 +737,12 @@ DataStream& operator >> ( DataStream& ds, std::vector& v ) { * @brief Deserialize a vector * @param ds - The stream to read * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the vector - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::vector& v ) { +template +datastream& operator >> ( datastream& ds, std::vector& v ) { unsigned_int s; ds >> s; v.resize(s.value); @@ -746,12 +757,12 @@ DataStream& operator >> ( DataStream& ds, std::vector& v ) { * @brief Serialize a set * @param ds - The stream to write * @param s - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the set - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::set& s ) { +template +datastream& operator << ( datastream& ds, const std::set& s ) { ds << unsigned_int( s.size() ); for( const auto& i : s ) { ds << i; @@ -766,12 +777,12 @@ DataStream& operator << ( DataStream& ds, const std::set& s ) { * @brief Deserialize a set * @param ds - The stream to read * @param s - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the object contained in the set - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::set& s ) { +template +datastream& operator >> ( datastream& ds, std::set& s ) { s.clear(); unsigned_int sz; ds >> sz; @@ -789,13 +800,13 @@ DataStream& operator >> ( DataStream& ds, std::set& s ) { * @brief Serialize a map * @param ds - The stream to write * @param m - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam K - Type of the key contained in the map * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator << ( DataStream& ds, const std::map& m ) { +template +datastream& operator << ( datastream& ds, const std::map& m ) { ds << unsigned_int( m.size() ); for( const auto& i : m ) { ds << i.first << i.second; @@ -809,13 +820,13 @@ DataStream& operator << ( DataStream& ds, const std::map& m ) { * @brief Deserialize a map * @param ds - The stream to read * @param m - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam K - Type of the key contained in the map * @tparam V - Type of the value contained in the map - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator >> ( DataStream& ds, std::map& m ) { +template +datastream& operator >> ( datastream& ds, std::map& m ) { m.clear(); unsigned_int s; ds >> s; @@ -833,12 +844,12 @@ DataStream& operator >> ( DataStream& ds, std::map& m ) { * @brief Serialize a tuple * @param ds - The stream to write * @param t - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator<<( DataStream& ds, const std::tuple& t ) { +template +datastream& operator<<( datastream& ds, const std::tuple& t ) { boost::fusion::for_each( t, [&]( const auto& i ) { ds << i; }); @@ -851,12 +862,12 @@ DataStream& operator<<( DataStream& ds, const std::tuple& t ) { * @brief Deserialize a tuple * @param ds - The stream to read * @param t - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam Args - Type of the objects contained in the tuple - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template -DataStream& operator>>( DataStream& ds, std::tuple& t ) { +template +datastream& operator>>( datastream& ds, std::tuple& t ) { boost::fusion::for_each( t, [&]( auto& i ) { ds >> i; }); @@ -873,7 +884,7 @@ DataStream& operator>>( DataStream& ds, std::tuple& t ) { * @tparam T - Type of class * @return DataStream& - Reference to the datastream */ -template::value>* = nullptr> +template::value && _datastream_detail::is_datastream::value>* = nullptr> DataStream& operator<<( DataStream& ds, const T& v ) { boost::pfr::for_each_field(v, [&](const auto& field) { ds << field; @@ -891,7 +902,7 @@ DataStream& operator<<( DataStream& ds, const T& v ) { * @tparam T - Type of class * @return DataStream& - Reference to the datastream */ -template::value>* = nullptr> +template::value && _datastream_detail::is_datastream::value>* = nullptr> DataStream& operator>>( DataStream& ds, T& v ) { boost::pfr::for_each_field(v, [&](auto& field) { ds >> field; @@ -905,12 +916,12 @@ DataStream& operator>>( DataStream& ds, T& v ) { * @brief Serialize a primitive type * @param ds - The stream to write * @param v - The value to serialize - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template()>* = nullptr> -DataStream& operator<<( DataStream& ds, const T& v ) { +template()>* = nullptr> +datastream& operator<<( datastream& ds, const T& v ) { ds.write( (const char*)&v, sizeof(T) ); return ds; } @@ -921,12 +932,12 @@ DataStream& operator<<( DataStream& ds, const T& v ) { * @brief Deserialize a primitive type * @param ds - The stream to read * @param v - The destination for deserialized value - * @tparam DataStream - Type of datastream + * @tparam Stream - Type of datastream buffer * @tparam T - Type of the primitive type - * @return DataStream& - Reference to the datastream + * @return datastream& - Reference to the datastream */ -template()>* = nullptr> -DataStream& operator>>( DataStream& ds, T& v ) { +template()>* = nullptr> +datastream& operator>>( datastream& ds, T& v ) { ds.read( (char*)&v, sizeof(T) ); return ds; } From b4c6052943203f2284db0b664ae1864b73341f88 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 12 Nov 2019 11:13:00 -0500 Subject: [PATCH 121/659] Add time back, to fix link errors from strftime_l. --- libraries/libc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc/CMakeLists.txt b/libraries/libc/CMakeLists.txt index f88c2b47d1..b168c380a3 100644 --- a/libraries/libc/CMakeLists.txt +++ b/libraries/libc/CMakeLists.txt @@ -11,7 +11,7 @@ file(GLOB SEARCH_SOURCES "musl/src/search/*.c") file(GLOB STDIO_SOURCES "musl/src/stdio/*.c") file(GLOB STDLIB_SOURCES "musl/src/stdlib/*.c") file(GLOB STRING_SOURCES "musl/src/string/*.c") -#file(GLOB TIME_SOURCES "musl/src/time/*.c") +file(GLOB TIME_SOURCES "musl/src/time/*.c") file(GLOB THREAD_SOURCES "musl/src/thread/*.c") #only for __lock __unlock set(INTERNAL_SOURCES musl/src/internal/floatscan.c musl/src/internal/intscan.c musl/src/internal/shgetc.c musl/src/internal/libc.c) From 1d27ae0f519ab0cbfeef0e5874c27ac35d2bac93 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 12 Nov 2019 13:59:03 -0500 Subject: [PATCH 122/659] Add attributes for wasm imports in generated code. Fixes #477. --- tests/unit/test_contracts/CMakeLists.txt | 1 + tests/unit/test_contracts/minimal_tests.cpp | 8 ++++++++ tools/include/eosio/codegen.hpp | 3 +++ 3 files changed, 12 insertions(+) create mode 100644 tests/unit/test_contracts/minimal_tests.cpp diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 984ab3ca19..2079375e70 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -2,6 +2,7 @@ add_contract(malloc_tests malloc_tests malloc_tests.cpp) add_contract(malloc_tests old_malloc_tests malloc_tests.cpp) add_contract(simple_tests simple_tests simple_tests.cpp) add_contract(transfer_contract transfer_contract transfer.cpp) +add_contract(minimal_tests minimal_tests minimal_tests.cpp) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/simple_wrong.abi ${CMAKE_CURRENT_BINARY_DIR}/simple_wrong.abi COPYONLY ) diff --git a/tests/unit/test_contracts/minimal_tests.cpp b/tests/unit/test_contracts/minimal_tests.cpp new file mode 100644 index 0000000000..e652abdabd --- /dev/null +++ b/tests/unit/test_contracts/minimal_tests.cpp @@ -0,0 +1,8 @@ +// Verifies that the dispatching code is self-contained + +class [[eosio::contract]] minimal_tests { + public: + template + explicit constexpr minimal_tests(const N&, const N&, const DS&) {} + [[eosio::action]] void test1() {} +}; diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index c2f811afb2..aedc6c0145 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -237,7 +237,9 @@ namespace eosio { namespace cdt { ss << "#include \n"; } ss << "extern \"C\" {\n"; + ss << "__attribute__((eosio_wasm_import))\n"; ss << "uint32_t action_data_size();\n"; + ss << "__attribute__((eosio_wasm_import))\n"; ss << "uint32_t read_action_data(void*, uint32_t);\n"; ss << "__attribute__((weak, " << attr << "(\""; ss << get_str(decl); @@ -417,6 +419,7 @@ namespace eosio { namespace cdt { // generate apply stub with abi std::stringstream ss; ss << "extern \"C\" {\n"; + ss << "__attribute__((eosio_wasm_import))\n"; ss << "void eosio_assert_code(uint32_t, uint64_t);"; ss << "\t__attribute__((weak, eosio_wasm_entry, eosio_wasm_abi("; std::string abi = cg.abi; From a302ee4bf302c19f6e46323d7aac206e57262dea Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 13 Nov 2019 11:05:09 -0500 Subject: [PATCH 123/659] Detect failure from subprocesses correctly. Fixes #725. --- tools/include/eosio/utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/eosio/utils.hpp b/tools/include/eosio/utils.hpp index ac83337a66..7ec624a093 100644 --- a/tools/include/eosio/utils.hpp +++ b/tools/include/eosio/utils.hpp @@ -141,7 +141,7 @@ struct environment { if (root) find_path = "/usr/bin"; if ( auto path = llvm::sys::findProgramByName(prog.c_str(), {find_path}) ) { - return llvm::sys::ExecuteAndWait(*path, args, {}, {}, 0, 0, nullptr, nullptr) != -1; + return llvm::sys::ExecuteAndWait(*path, args, {}, {}, 0, 0, nullptr, nullptr) == 0; } else return false; From 0c5d7c92ed725a0026006806583a94f1e86d5926 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 13 Nov 2019 11:16:47 -0500 Subject: [PATCH 124/659] Add missing source, so that unordered_map can link. Fixes #685. --- libraries/libc++/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index b5b74e98cb..bf74e6c465 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -1,5 +1,5 @@ SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp condition_variable.cpp functional.cpp - future.cpp ios.cpp iostream.cpp locale.cpp memory.cpp mutex.cpp new.cpp optional.cpp + future.cpp hash.cpp ios.cpp iostream.cpp locale.cpp memory.cpp mutex.cpp new.cpp optional.cpp regex.cpp stdexcept.cpp string.cpp strstream.cpp system_error.cpp exception.cpp typeinfo.cpp utility.cpp valarray.cpp variant.cpp vector.cpp eosio.cpp) From 151cd139f09a05797f9a58f3bf08c71e34dea700 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 18 Nov 2019 11:53:36 +0200 Subject: [PATCH 125/659] Remove accidentally checked in file. --- examples_v2/hello/include/hello.hpp | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 examples_v2/hello/include/hello.hpp diff --git a/examples_v2/hello/include/hello.hpp b/examples_v2/hello/include/hello.hpp deleted file mode 100644 index a456255361..0000000000 --- a/examples_v2/hello/include/hello.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -using namespace eosio; - -class [[eosio::contract]] hello : public contract { - public: - using contract::contract; - - [[eosio::action]] void hi( name nm ); - [[eosio::action]] void check( name nm ); - - using hi_action = action_wrapper<"hi"_n, &hello::hi>; - using check_action = action_wrapper<"check"_n, &hello::check>; -}; From 3306af7f500715ae007ad0fcfa2725f60b17eaf5 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 21 Nov 2019 13:31:59 +0200 Subject: [PATCH 126/659] Fix headers --- docs/02_installation.md | 23 +++++---- docs/03_command-reference/eosio-abidiff.md | 4 +- docs/03_command-reference/eosio-abigen.md | 6 ++- docs/03_command-reference/eosio-cc.md | 4 +- docs/03_command-reference/eosio-cpp.md | 4 +- docs/03_command-reference/eosio-init.md | 4 +- docs/03_command-reference/eosio-ld.md | 4 +- docs/04_upgrading/1.2-to-1.3.md | 50 ++++++++++--------- docs/04_upgrading/1.5-to-1.6.md | 18 ++++--- .../05_best-practices/03_resource-planning.md | 4 +- .../04_data-design-and-migration.md | 4 +- .../05_securing_your_contract.md | 5 +- docs/05_best-practices/07_error_handling.md | 4 +- ...abi-code-generator-attributes-explained.md | 17 ++++--- ...02_manually_write_an_ABI_file_explained.md | 7 ++- .../09_deferred_transactions.md | 4 +- .../10_native-tester-compilation.md | 11 ++-- .../11_debugging_a_smart_contract.md | 16 +++--- ...ry-extension.md => 12_binary-extension.md} | 4 +- .../01_compile-a-contract-via-cli.md | 6 ++- .../01_compile/02_how-to-configure-cmake.md | 10 ++-- .../03_compiling-contracts-with-cmake.md | 6 ++- .../how-to-define-a-primary-index.md | 4 +- .../how-to-define-a-secondary-index.md | 6 ++- .../how-to-define-a-singleton.md | 4 +- ...to-delete-data-from-a-multi-index-table.md | 6 ++- ...to-insert-data-into-a-multi-index-table.md | 6 ++- .../how-to-instantiate-a-multi-index-table.md | 4 +- ...ti_index-table-based-on-secondary-index.md | 6 ++- ...terate-and-retrieve-a-multi_index-table.md | 6 ++- ...w-to-modify-data-in-a-multi-index-table.md | 6 ++- ...4_how_to_create_and_use_action_wrappers.md | 4 +- ...to_restrict_access_to_an_action_by_user.md | 6 ++- docs/08_troubleshooting.md | 30 +++++------ docs/09_tutorials/01_binary-extension.md | 4 +- docs/09_tutorials/02_abi-variants.md | 10 ++-- docs/index.md | 1 + 37 files changed, 198 insertions(+), 120 deletions(-) rename docs/05_best-practices/{binary-extension.md => 12_binary-extension.md} (99%) diff --git a/docs/02_installation.md b/docs/02_installation.md index 193510a018..680d8addbe 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -1,42 +1,45 @@ -## Binary Releases +--- +content_title: Binary Releases +--- + EOSIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages. **If you have previously installed EOSIO.CDT, run the `uninstall` script (it is in the directory where you cloned EOSIO.CDT) before downloading and using the binary releases.** -### Mac OS X Brew Install +## Mac OS X Brew Install ```sh $ brew tap eosio/eosio.cdt $ brew install eosio.cdt ``` -### Mac OS X Brew Uninstall +## Mac OS X Brew Uninstall ```sh $ brew remove eosio.cdt ``` -### Debian Package Install +## Debian Package Install ```sh $ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb $ sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb ``` -### Debian Package Uninstall +## Debian Package Uninstall ```sh $ sudo apt remove eosio.cdt ``` -### RPM Package Install +## RPM Package Install ```sh $ wget https://github.com/eosio/eosio.cdt/releases/download/v1.6.3/eosio.cdt-1.6.3-1.el7.x86_64.rpm $ sudo yum install ./eosio.cdt-1.6.3-1.el7.x86_64.rpm ``` -### RPM Package Uninstall +## RPM Package Uninstall ```sh $ sudo yum remove eosio.cdt ``` -## Guided Installation or Building from Scratch +# Guided Installation or Building from Scratch ```sh $ git clone --recursive https://github.com/eosio/eosio.cdt $ cd eosio.cdt @@ -53,7 +56,7 @@ Or you can install globally by running this command sudo make install ``` -### Uninstall after manual installation +## Uninstall after manual installation ```sh $ sudo rm -fr /usr/local/eosio.cdt @@ -62,7 +65,7 @@ $ sudo rm /usr/local/bin/eosio-* ``` -## Installed Tools +# Installed Tools --- * eosio-cpp * eosio-cc diff --git a/docs/03_command-reference/eosio-abidiff.md b/docs/03_command-reference/eosio-abidiff.md index adba0081f1..29dd8a34be 100644 --- a/docs/03_command-reference/eosio-abidiff.md +++ b/docs/03_command-reference/eosio-abidiff.md @@ -1,4 +1,6 @@ -## eosio-abidiff tool +--- +content_title: eosio-abidiff tool +--- The eosio-abidiff tool is used to diff two ABI files to flag and output differences. To report differences with ```eosio-abidiff```, you only need to pass the two ABI file names as command line arguments. diff --git a/docs/03_command-reference/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md index a2a563f902..35ea5849ba 100644 --- a/docs/03_command-reference/eosio-abigen.md +++ b/docs/03_command-reference/eosio-abigen.md @@ -1,6 +1,8 @@ -## eosio-abigen tool +--- +content_title: eosio-abigen tool +--- -### This tool is deprecated, use `eosio-cpp` for generation of your ABIs +## This tool is deprecated, use `eosio-cpp` for generation of your ABIs To generate an ABI with ```eosio-abigen```, only requires that you give the main '.cpp' file to compile and the output filename `--output` and generating against the contract name `--contract`. diff --git a/docs/03_command-reference/eosio-cc.md b/docs/03_command-reference/eosio-cc.md index 003e129210..11b08050d3 100644 --- a/docs/03_command-reference/eosio-cc.md +++ b/docs/03_command-reference/eosio-cc.md @@ -1,4 +1,6 @@ -## eosio-cc tool +--- +content_title: eosio-cc tool +--- To manually compile the source code, use `eosio-cc` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. diff --git a/docs/03_command-reference/eosio-cpp.md b/docs/03_command-reference/eosio-cpp.md index c4cdc74e09..27b9053abd 100644 --- a/docs/03_command-reference/eosio-cpp.md +++ b/docs/03_command-reference/eosio-cpp.md @@ -1,4 +1,6 @@ -## eosio-cpp tool +--- +content_title: eosio-cpp tool +--- To manually compile the source code, use `eosio-cpp` and `eosio-ld` as if it were __clang__ and __lld__. All the includes and options specific to EOSIO and CDT are baked in. diff --git a/docs/03_command-reference/eosio-init.md b/docs/03_command-reference/eosio-init.md index 0702b09585..fb6dd99039 100644 --- a/docs/03_command-reference/eosio-init.md +++ b/docs/03_command-reference/eosio-init.md @@ -1,4 +1,6 @@ -## eosio-init tool +--- +content_title: eosio-init tool +--- This tool is used to generate a skeleton smart contract and directory structure. To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. diff --git a/docs/03_command-reference/eosio-ld.md b/docs/03_command-reference/eosio-ld.md index 07bad1e2af..0e4e8f74ae 100644 --- a/docs/03_command-reference/eosio-ld.md +++ b/docs/03_command-reference/eosio-ld.md @@ -1,4 +1,6 @@ -## eosio-ld tool +--- +content_title: eosio-ld tool +--- The eosio-ld tool is a the custom web assembly linker for EOSIO platform smart contracts. diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index c5d254380c..3d5b66a0ef 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -1,6 +1,8 @@ -## Version 1.3 +--- +content_title: Version 1.3 +--- -### eosiolib C API +## eosiolib C API - Removed the following typedefs to `uint64_t`: - `account_name` - `permission_name` @@ -22,7 +24,7 @@ - `signature` -> `capi_signature` - Removed the non-existent intrinsics declarations `require_write_lock` and `require_read_lock`. -### eosiolib C++ API +## eosiolib C++ API - Removed eosiolib/vector.hpp: - Removed alias `eosio::vector` and typedef `bytes`. - Going forward contract writers should include `` from the STL and use `std::vector` instead of bytes. @@ -31,14 +33,14 @@ - Removed eosiolib/core_symbol.hpp. The contract writer should explicitly specify the symbol. - Added eosiolib/name.hpp. -#### eosiolib/types.hpp +### eosiolib/types.hpp - Moved the typedef `eosio::extensions_types` to eosiolib/transaction.hpp. - Removed comparison functions for `checksum` structs. - Removal of `eosio::char_to_symbol`, `eosio::string_to_name`, `eosio::name_suffix` functions - Removal of the `N` macro. The `""_n` operator or the `name` constructor should be used as a type safe replacement. Example: `N(foo)` -> `"foo"_n`, or `N(foo)` -> `name("foo")`. - Moved `eosio::name` struct definition and `""_n` operator to eosiolib/name.hpp. -#### eosiolib/name.hpp +### eosiolib/name.hpp - Removed implicit and explicit conversions to `uint64_t`. - Added `enum class` `eosio::name::raw` which is implicitly converted from an `eosio::name` (used for template non-type parameters). - Added `bool` conversion operator for conditionally testing if a name is empty. @@ -46,7 +48,7 @@ - Added `constexpr` methods `eosio::name::length` and `eosio::name::suffix`. - Added equivalence, inverted equivalence and less than operators to `eosio::name`. -#### eosiolib/symbol.hpp +### eosiolib/symbol.hpp - Removed `eosio::symbol_type` struct and replaced with `eosio::symbol` class. - Added struct `eosio::symbol_code`: - Added two `constexpr` constructors that take either a raw `uint64_t` or an `std::string_view`. @@ -65,41 +67,41 @@ - Added `constexpr` methods `get_symbol` and `get_contract`. - Made existing comparison operators `constexpr`. -#### eosiolib/asset.hpp +### eosiolib/asset.hpp - The main constructor now requires a `int64_t` (quantity) and `eosio::symbol` explicitly. - The default constructor no longer initializes the instance to a valid zero quantity asset with a symbol equivalent to "core symbol". Instead the default constructed `eosio::asset` is a bit representation of all zeros (which will cause `is_valid` to fail) so that check is bypassed to allow for `multi_index` and `datastream` to work. - Old contracts that use `eosio::asset()` should be changed to either use the core symbol of the specific chain they are targeting i.e. `eosio::asset(0, symbol(symbol_code("SYS"),4))`. To reduce writing `symbol(symbol_code("SYS"),4)` over and over, a `constexpr` function to return the symbol or `constexpr` global variable should be used. -#### eosiolib/contract.hpp +### eosiolib/contract.hpp - The constructor for `eosio::contract` now takes an `eosio::name` for the receiver, an `eosio::name` for the code, and a `eosio::datastream` for the datastream used for the contract. The last argument is for manually unpacking an action, see the section on `eosio::ignore` for a more indepth usage. -#### eosiolib/dispatcher.hpp +### eosiolib/dispatcher.hpp - Renamed the macro `EOSIO_ABI` to `EOSIO_DISPATCH` as this is more descriptive of what this macro actually does. - Modified the definition of `EOSIO_DISPATCH` to work with the new constructor for `eosio::contract`. -#### eosiolib/multi_index.hpp +### eosiolib/multi_index.hpp - The first template parameter for `indexed_by` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The first template parameter for `multi_index` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The constructor now takes an `eosio::name` type for the code (replacing `uint64_t`). Scope is still `uint64_t`. - Various other replacements of `uint64_t` to `eosio::name`. -#### eosiolib/singleton.hpp +### eosiolib/singleton.hpp - The first template parameter for `eosio::singleton` now requires the argument be convertible to `eosio::name::raw` (replacing `uint64_t`). - The constructor now takes an `eosio::name` type for the code. - In the methods `get_or_create` and `set`, the argument `bill_to_account` is now of type `eosio::name` (replacing `uint64_t`). -#### eosiolib/action.hpp +### eosiolib/action.hpp - Added C++ function `eosio::require_auth`. - Added C++ function `eosio::has_auth`. - Added C++ function `eosio::is_account`. - Redefined `eosio::permission_level` to use `eosio::name` in place of `uint64_t`. - Removed the macro `ACTION`. (The identifier `ACTION` has been reused for another macro described below in the Macros section.) -#### eosiolib/permission.hpp +### eosiolib/permission.hpp - The optional provided_keys argument of the function `eosio::check_transaction_authorization` is now of the type `std::set` rather than the type `std::set`. C++ contract code should most likely be using the `eosio::public_key` struct (defined in "eosiolib/public_key.hpp") if they need to deal with EOSIO-compatible public keys rather than the `capi_public_key` struct (now renamed from its original name of `::public_key`) from the eosiolib C API. Note that existing contract code that just referred to the type `public_key` without namespace qualification may have accidentally been using the `capi_public_key` struct and therefore should ideally be modified to use the `eosio::public_key` C++ type. - The `account` and `permission` arguments of `eosio::check_permission_authorization` are both `eosio::name` now instead of `uint64_t`. -#### eosiolib/ignore.hpp +### eosiolib/ignore.hpp - Added new type `ignore`: - This type acts as a placeholder for actions that don't want to deserialize their fields but want the types to be reflected in the ABI. ``` @@ -108,25 +110,25 @@ - Added new type `ignore_wrapper`: - This allows for calling `SEND_INLINE_ACTION` with `ignore_wrapper(some_value)` against an action with an `ignore` of matching types. -### Macros +## Macros - Added `ACTION` macro which is simply a shortcut for `[[eosio::action]] void`. - Added `TABLE` macro which is simply a shortcut for `struct [[eosio::table]]`. - Added `CONTRACT` macro which is simply a shortcut for `class [[eosio::contract]]`. -### CMake +## CMake - Added `eosio.cdt-config.cmake` to allow for `find_package(eosio.cdt)`. See eosio.cdt/examples/hello or eosio.cdt/examples/template for an example. - Added new macro `add_contract`. This new contract takes a contract name, cmake target, then any normal arguments you would give to `add_executable`. See eosio.cdt/examples/hello or eosio.cdt/examples/template. - New version checking mechanism is included. See eosio.contracts/CMakeLists.txt to see this in use. -### libc +## libc - Replaced `printf`, `sprintf`, and `snprintf` with new minimal variants. This allows contracts to use these functions without causing stack overflow issues. -### libcxx +## libcxx - Removed `sstream` with the intent to return this after more has been done. - Added `__cxa_pure_virtual` to allow for pure virtual methods in contract classes. - `std::to_string` now works without the issues of stack overflows. -### attributes +## attributes - Added `[[eosio::ignore]]` attribute to flag a type as being ignored by the deserializer. This attribute is primarily only used for internal use within eosiolib. - Added `[[eosio::contract]]` attribute. This new attribute is used to mark a contract class as "contract" with the name being either the C++ name of the class or a user specified name (i.e. `[[eosio::contract("somecontract")]]`). This attribute can also be used in conjunction with the `eosio::action` and `eosio::table` attributes for tables that you would like to define outside of the `eosio::contract` class. This is used in conjunction with either the raw `eosio-cpp` option `--contract `, `-o .wasm` or with CMake `add_contract`. It acts as a filter enabling contract developers to include a header file with attributes from another contract (e.g. eosio.token) while generating an ABI devoid of those actions and tables. ```c++ @@ -153,13 +155,13 @@ ``` The above code will produce the tables `testtaba` and `testtabb` in your ABI. Example: `eosio-cpp -abigen test.cpp -o test.wasm` will mark this compilation and ABI generation for the `eosio::contract` `test`. The same thing can be done with `eosio-cpp -abigen test.cpp -o test_contract.wasm --contract test` or with the CMake command `add_contract( test, test_contract, test.cpp )`. Either of the previous two approaches will produce a test_contract.wasm and test_contract.abi generated under the context of the contract name of `test`. -### Boost +## Boost - Boost is now part of the library. No more external dependence on Boost and all system inclusion are within it's `sysroot`. (Boost will be removed in a future release.) -## ABI generator attributes +# ABI generator attributes Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark ```actions``` and ```tables```. -#### [[eosio::action]] +### [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): ```c++ @@ -205,12 +207,12 @@ If you don't want to use the multi-index you can explicitly specify the name in For an example contract of ABI generation see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with `eosio-abigen test.cpp --output=test.abi`. -### Fixing an ABI or Writing an ABI Manually +## Fixing an ABI or Writing an ABI Manually - The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually. - The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. -### Adding Ricardian Contracts and Clauses to ABI +## Adding Ricardian Contracts and Clauses to ABI - As of EOSIO.CDT v1.4.0, the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. - The Ricardian contract should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md. - For each Ricardian contract, the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. diff --git a/docs/04_upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md index a870b8bec0..4181b6d877 100644 --- a/docs/04_upgrading/1.5-to-1.6.md +++ b/docs/04_upgrading/1.5-to-1.6.md @@ -1,7 +1,9 @@ -## Version 1.6 +--- +content_title: Version 1.6 +--- -### eosiolib -#### Partitioning +## eosiolib +### Partitioning In `eosio.cdt` v1.6.0, `eosiolib` will now be partitioned into 3 groups. These allow for finer grained allowance for particular modes of compilation. - CAPI - Contracts @@ -13,7 +15,7 @@ In `eosio.cdt` v1.6.0, `eosiolib` will now be partitioned into 3 groups. These a To access these new partitioned header files, use `` instead of ``. Please note that all the old header files are still available at the old `eosiolib` directory, but these are deprecated and will be removed in v1.7.0. Also, once you change one header file from `eosiolib` to `eosio` you will need to do so for all other occurrences at that point, because of some conflicts with the auto generated dispatcher. -### eosiolib C API +## eosiolib C API - `action.h` - `chain.h` - `crypto.h` @@ -27,7 +29,7 @@ To access these new partitioned header files, use `` inst This entire API is now only available to C developers (i.e. using `eosio-cc`), and all internal uses in `Core` and `Contracts` have been guarded behind the namespace `eosio::internal_use_do_not_use`. -### eosiolib Contracts API +## eosiolib Contracts API - `action.hpp` - added C++ wrappers for - `publication_time` -> `time_point publication_time()` @@ -80,7 +82,7 @@ This entire API is now only available to C developers (i.e. using `eosio-cc`), a - `expiration` - `get_context_free_data` -#### eosiolib Core API +### eosiolib Core API - `asset.hpp` - no changes - `binary_extension.hpp` @@ -119,10 +121,10 @@ This entire API is now only available to C developers (i.e. using `eosio-cc`), a - `varint.hpp` - no changes -### Auto Code Generation +## Auto Code Generation There is no more need to add the `EOSIO_DISPATCH` macro to your smart contracts. The compiler/linker will now automatically generate a dispatcher for you the proper `eosio::contract`, `eosio::action` and `eosio::on_notify` attributes are used. Of course, if you don't have these attributes then you will still need to either use the old macro or hand write the `apply` function yourself. -#### How the auto dispatcher will work +### How the auto dispatcher will work Given that you have marked your classes with the `eosio::contract` macro and any sub-contracts with the macro with the same given name (i.e. `eosio::contract("")`) then any actions and notify handlers that are contained within these will be dispatchable by your smart contract. This will allow for aggregate patterns for smart contract development and better separation of concerns. In addition to actions and notification handlers, two new "hooks" are available. diff --git a/docs/05_best-practices/03_resource-planning.md b/docs/05_best-practices/03_resource-planning.md index 1ba7fb6f62..4b3b70e44f 100644 --- a/docs/05_best-practices/03_resource-planning.md +++ b/docs/05_best-practices/03_resource-planning.md @@ -1,4 +1,6 @@ -## Resource planning +--- +content_title: Resource planning +--- How much RAM do I need? This is not an easy question to answer, and there's really no perfect answer for it. You need to find out by measuring your contracts' actions and by planning accordingly based on your predictions on how fast and how much your blockchain application will grow. If your blockchain application growth is requiring more storage capacity you'll need to buy more RAM. If it requires more actions to be executed in the 3 day window (the staking time) you need to stake more tokens for CPU bandwidth. If your blockchain application growth means more actions will be stored on the blockchain then you also will need to expand your NET bandwidth maximum limit by staking more tokens for NET bandwidth. diff --git a/docs/05_best-practices/04_data-design-and-migration.md b/docs/05_best-practices/04_data-design-and-migration.md index ec126b4250..5d847064a9 100644 --- a/docs/05_best-practices/04_data-design-and-migration.md +++ b/docs/05_best-practices/04_data-design-and-migration.md @@ -1,4 +1,6 @@ -# Data design and migration +--- +content_title: Data design and migration +--- EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below you will find a few possible approaches which you can consider when you design your smart contract data and its migration. diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md index 2bcf2f39b8..122e5c52d7 100644 --- a/docs/05_best-practices/05_securing_your_contract.md +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -1,4 +1,7 @@ -## Securing your contract +--- +content_title: Securing your contract +--- + These are basic recommendations that should be the foundation of securing your smart contract: 1. The master git branch has the `has_auth`, `require_auth`, `require_auth2` and `require_recipient` methods available in the EOSIO library. They can be found in detail [here](https://eosio.github.io/eosio.cdt/1.6.0-rc1/group__action.html#function-requirerecipient) and implemented [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L144) (they end up calling the methods implemented in the `apply_context` class). diff --git a/docs/05_best-practices/07_error_handling.md b/docs/05_best-practices/07_error_handling.md index 162977af7d..8f323e6e48 100644 --- a/docs/05_best-practices/07_error_handling.md +++ b/docs/05_best-practices/07_error_handling.md @@ -1,4 +1,6 @@ -## Error handling +--- +content_title: Error handling +--- Contracts are able to use `uint64_t` error codes as an alternative (and cheaper) means of signaling error conditions as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. They assume that the contract develop respects the following restrictions: diff --git a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md index 937f18cab4..cf2864d8dc 100644 --- a/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md +++ b/docs/05_best-practices/08_abi/01_abi-code-generator-attributes-explained.md @@ -1,7 +1,10 @@ -## ABI/Code generator attributes explained +--- +content_title: ABI/Code generator attributes explained +--- + The new ABI generator tool uses C++11 or GNU style attributes to mark `actions` and `tables`. -### [[eosio::action]] +## [[eosio::action]] This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation): ```cpp @@ -30,7 +33,7 @@ struct __attribute__((eosio_action)) testa { If your action name is not a valid [EOSIO name](https://developers.eos.io/eosio-cpp/docs/naming-conventions) you can explicitly specify the name in the attribute ```c++ [[eosio::action("")]]``` -### [[eosio::table]] +## [[eosio::table]] Example (two ways to declare a table for ABI generation): ```cpp struct [[eosio::table]] testtable { @@ -48,7 +51,7 @@ typedef eosio::multi_index<"tablename"_n, testtable> testtable_t; If you don't want to use the multi-index you can explicitly specify the name in the attribute ```c++ [[eosio::table("")]]```. -### [[eosio::contract("ANY_NAME_YOU_LIKE")]] +## [[eosio::contract("ANY_NAME_YOU_LIKE")]] ```cpp class [[eosio::contract("ANY_NAME_YOU_LIKE")]] test_contract : public eosio::contract { }; @@ -56,7 +59,7 @@ class [[eosio::contract("ANY_NAME_YOU_LIKE")]] test_contract : public eosio::con The code above will mark this `class` as being an `EOSIO` contract, this allows for namespacing of contracts, i.e. you can include headers like `eosio::token` and not have `eosio::token`'s actions/tables wind up in you ABI or generated dispatcher. -### [[eosio::on_notify("VALID_EOSIO_ACCOUNT_NAME::VALID_EOSIO_ACTION_NAME")]] +## [[eosio::on_notify("VALID_EOSIO_ACCOUNT_NAME::VALID_EOSIO_ACTION_NAME")]] ```cpp [[eosio::on_notify("eosio.token::transfer")]] void on_token_transfer(name from, name to, assert quantity, std::string memo) { @@ -69,7 +72,7 @@ void on_any_transfer(name from, name to, assert quantity, std::string memo) { } ``` -### [[eosio::wasm_entry]] +## [[eosio::wasm_entry]] ```cpp [[eosio::wasm_entry]] void some_function(...) { @@ -79,7 +82,7 @@ void some_function(...) { The code above will mark an arbitrary function as an entry point, which will then wrap the function with global constructors (ctors) and global destructors (dtors). This will allow for the eosio.cdt toolchain to produce WASM binaries for other ecosystems. -### [[eosio::wasm_import]] +## [[eosio::wasm_import]] ```cpp extern "C" { __attribute__((eosio_wasm_import)) diff --git a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md index e2c10c7396..c97a45726a 100644 --- a/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md +++ b/docs/05_best-practices/08_abi/02_manually_write_an_ABI_file_explained.md @@ -1,8 +1,11 @@ -## Manually write, or fix, an ABI file +--- +content_title: Manually write, or fix, an ABI file +--- + - Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. - Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. -### Adding Ricardian Contracts and Clauses to ABI +## Adding Ricardian Contracts and Clauses to ABI - The ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. - The Ricardian contracts should be housed in a file with the name `.contracts.md` and the clauses should be in a file named `.clauses.md`. - For each Ricardian contract the header `

ActionName

` should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md index 0989b6372c..63ca63c2aa 100644 --- a/docs/05_best-practices/09_deferred_transactions.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -1,4 +1,6 @@ -## Deferred transactions +--- +content_title: Deferred transactions +--- Deferred communication conceptually takes the form of action notifications sent to a peer transaction. Deferred actions get scheduled to run, at best, at a later time, at the producer's discretion. There is no guarantee that a deferred action will be executed. diff --git a/docs/05_best-practices/10_native-tester-compilation.md b/docs/05_best-practices/10_native-tester-compilation.md index e677980021..c1dc48e348 100644 --- a/docs/05_best-practices/10_native-tester-compilation.md +++ b/docs/05_best-practices/10_native-tester-compilation.md @@ -1,7 +1,10 @@ -## How to use native tester/compilation +--- +content_title: How to use native tester/compilation +--- + As of v1.5.0 native compilation can be performed and a new set of libraries to facilitate native testing and native "scratch pad" compilation. [`eosio-cc`](../03_command-reference/eosio-cc.md), [`eosio-cpp`](../03_command-reference/eosio-cpp.md) and [`eosio-ld`](../03_command-reference/eosio-ld.md) now support building "smart contracts" and unit tests natively for quick tests to help facilitate faster development \(note the default implementations of eosio `intrinsics` are currently asserts that state they are unavailable, these are user definable.\) -### Getting Started +## Getting Started Once you have your smart contract written then a test source file can be written. `hello.hpp` @@ -90,12 +93,12 @@ int main(int argc, char** argv) { Every `intrinsic` that is defined for eosio (prints, require_auth, etc.) is re-definable given the `intrinsics::set_intrinsics()` functions. These take a lambda whose arguments and return type should match that of the intrinsic you are trying to define. This gives the contract writer the flexibility to modify behavior to suit the unit test being written. A sister function `intrinsics::get_intrinsics()` will return the function object that currently defines the behavior for said intrinsic. This pattern can be used to mock functionality and allow for easier testing of smart contracts. For more information see, either the [tests](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/) directory or [hello_test.cpp](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/tests/hello_test.cpp) for working examples. -### Compiling Native Code +## Compiling Native Code - Raw `eosio-cpp` to compile the test or program the only addition needed to the command line is to add the flag `-fnative` this will then generate native code instead of `wasm` code. - Via CMake - `add_native_library` and `add_native_executable` CMake macros have been added (these are a drop in replacement for add_library and add_executable). -### Eosio.CDT Native Tester API +## Eosio.CDT Native Tester API - CHECK_ASSERT(...) : This macro will check whether a particular assert has occured and flag the tests as failed but allow the rest of the tests to run. - This is called either by - `CHECK_ASSERT("", [](){ whatever_function(); })` diff --git a/docs/05_best-practices/11_debugging_a_smart_contract.md b/docs/05_best-practices/11_debugging_a_smart_contract.md index 7c03da1f91..2debfd3f4b 100644 --- a/docs/05_best-practices/11_debugging_a_smart_contract.md +++ b/docs/05_best-practices/11_debugging_a_smart_contract.md @@ -1,4 +1,6 @@ -## Debugging a smart contract +--- +content_title: Debugging a smart contract +--- In order to be able to debug your smart contract, you will need to setup a local nodeos node. This local nodeos node can be run as separate private testnet or as an extension of a public testnet. This local node also needs to be run with the contracts-console option on, either `--contracts-console` via the command line or `contracts-console = true` via the config.ini and/or by setting up logging on your running nodeos node and checking the output logs. See below for details on logging. @@ -8,10 +10,10 @@ The concept is the same, so for the following guide, debugging on the private te If you haven't set up your own local nodeos, follow the [setup guide](https://developers.eos.io/eosio-home/docs/getting-the-software). By default, your local nodeos will just run in a private testnet unless you modify the config.ini file to connect with public testnet (or official testnet) nodes. -## Method +# Method The main method used to debug smart contract is **Caveman Debugging**. Printing is utilized to inspect the value of a variable and check the flow of the contract. Printing in smart contracts can be done through the Print API. The C++ API is a wrapper for C API and is the recommended API. -## Print +# Print Print C API supports the following data type that you can print: - prints - a null terminated char array (string) - prints_l - any char array (string) with given size @@ -31,10 +33,10 @@ The Print C++ API wraps some of the above C API by overriding the print() functi - base32 string encoded as 64-bit unsigned integer - struct that has print() method -## Example +# Example Here's an example contract for debugging -### debug.hpp +## debug.hpp ```cpp namespace debug { @@ -48,7 +50,7 @@ namespace debug { }; } ``` -### debug.cpp +## debug.cpp ```cpp #include @@ -74,7 +76,7 @@ extern "C" { } } // extern "C" ``` -### debug.abi +## debug.abi ```json { diff --git a/docs/05_best-practices/binary-extension.md b/docs/05_best-practices/12_binary-extension.md similarity index 99% rename from docs/05_best-practices/binary-extension.md rename to docs/05_best-practices/12_binary-extension.md index 3f3d09d674..c7783641ac 100644 --- a/docs/05_best-practices/binary-extension.md +++ b/docs/05_best-practices/12_binary-extension.md @@ -1,4 +1,6 @@ -## eosio::binary_extension +--- +content_title: The eosio::binary_extension type +--- Let's fully explain what the `eosio::binary_extension` type is, what it does, and why we need it for contract upgrades in certain situations. diff --git a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md index c50c6155e6..060efe3869 100644 --- a/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md +++ b/docs/06_how-to-guides/01_compile/01_compile-a-contract-via-cli.md @@ -1,6 +1,8 @@ -## How to compile a contract via CLI +--- +content_title: How to compile a contract via CLI +--- -### Preconditions +## Preconditions - You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) diff --git a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md index 8811abf5d1..22549b473c 100644 --- a/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md +++ b/docs/06_how-to-guides/01_compile/02_how-to-configure-cmake.md @@ -1,8 +1,10 @@ -## How to configure CMake +--- +content_title: How to configure CMake +--- -### CMake Configuration +## CMake Configuration -#### Automatic generation of CMake configuration +### Automatic generation of CMake configuration To compile an EOSIO smart contract with CMake, you'll need a CMake file. To use the new `eosio-init` tool to generate the directory structure stub .hpp/.cpp files and the cmake configuration files follow these steps: @@ -16,7 +18,7 @@ To compile an EOSIO smart contract with CMake, you'll need a CMake file. To use At this point, you'll have the `test_contract.abi` and `test_contract.wasm` files in `~/test_contract/test_contract`. These files are ready to be deployed. -#### Manual generation of CMake configuration +### Manual generation of CMake configuration To create manually the cmake configuration, the template `CMakeLists.txt` in the examples folder is a good boilerplate for manual usage. diff --git a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md index 70afbb5fd0..54bd0814d6 100644 --- a/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md +++ b/docs/06_how-to-guides/01_compile/03_compiling-contracts-with-cmake.md @@ -1,6 +1,8 @@ -## How to compile a smart contract with CMake +--- +content_title: How to compile a smart contract with CMake +--- -### Preconditions +## Preconditions - You have the source of your contract saved in one of your local folders, e.g. `./examples/hello` For details on how to create your first contract follow [this tutorial here](https://developers.eos.io/eosio-home/docs/your-first-contract) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md index dc1eb6265d..edebe2c726 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-primary-index.md @@ -1,4 +1,6 @@ -## How to define a primary index +--- +content_title: How to define a primary index +--- A primary key is required when defining a multi index table structure. See the following example: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md index 3036e20b45..a0aaae5329 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-secondary-index.md @@ -1,6 +1,8 @@ -## How to define a secondary index +--- +content_title: How to define a secondary index +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). The steps below show how to add a secondary index to the existing multi index table. diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index ce861a6103..4729372b53 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -1,4 +1,6 @@ -## How to define a singleton +--- +content_title: How to define a singleton +--- To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`, follow the steps below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md index 5ea7abf61c..f1079c7aec 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-delete-data-from-a-multi-index-table.md @@ -1,6 +1,8 @@ -## How to delete data from a multi index table +--- +content_title: How to delete data from a multi index table +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To delete data from a multi index table follow the steps below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md index ac5510fbe2..81df3702d9 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-insert-data-into-a-multi-index-table.md @@ -1,6 +1,8 @@ -## How to insert data into a multi index table +--- +content_title: How to insert data into a multi index table +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To insert data into a multi index table follow the following steps diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index c1c2d33877..9a33cf0abb 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -1,4 +1,6 @@ -## How to instantiate a multi index table +--- +content_title: How to instantiate a multi index table +--- 1. Include the `eosio.hpp` header and declare the `eosio` namespace usage ``` diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md index 400abb4156..f2363f4477 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table-based-on-secondary-index.md @@ -1,6 +1,8 @@ -## How to iterate and retreive a multi index table based on secondary index +--- +content_title: How to iterate and retrieve a multi index table based on secondary index +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table defined with a primary index and a secondary index, if not you can find an example [here](./how-to-define-a-secondary-index.md). You'll start with this example below which shows the definition of a `multi_index_example` contract class which has defined a multi index table with two indexes, a mandatory primary one and a secondary one: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md index 7aae513058..188f50e1f7 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-iterate-and-retrieve-a-multi_index-table.md @@ -1,6 +1,8 @@ -## How to iterate and retrieve a multi index table +--- +content_title: How to iterate and retrieve a multi index table +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). For exemplification define the multi index contract definition like below: diff --git a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md index af5f600c59..c3be46ea60 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-modify-data-in-a-multi-index-table.md @@ -1,6 +1,8 @@ -## How to modify data in a multi index table +--- +content_title: How to modify data in a multi index table +--- -### Preconditions +## Preconditions - It is assumed you already have a multi index table instance defined along with its mandatory primary index, otherwise take a look at the section [How to instantiate a multi index table](./how-to-instantiate-a-multi-index-table.md). To modify data in the multi index table defined in the above tutorial, you will implement an action `mod` which it will receive as parameter the `user` which is the key of the row you want to modify and the `value` param which is the value to update with the row. diff --git a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md index e6f354f770..f717d9a960 100644 --- a/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md +++ b/docs/06_how-to-guides/04_how_to_create_and_use_action_wrappers.md @@ -1,4 +1,6 @@ -## How to create and use action wrappers +--- +content_title: How to create and use action wrappers +--- 1. Start with a contract `multi_index_example` which has an action `mod` defined like below in file `multi_index_example.hpp`; the action modifies the integer value `n` stored for row with key `user`. ```cpp diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index a1a2754560..4ec1229724 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,6 +1,8 @@ -## How to restrict access to an action by a user +--- +content_title: How to restrict access to an action by a user +--- -### Preconditions +## Preconditions - It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. To restrict access to the `hi` action, you can do it in two ways: diff --git a/docs/08_troubleshooting.md b/docs/08_troubleshooting.md index b3465e9ad2..b41d979018 100644 --- a/docs/08_troubleshooting.md +++ b/docs/08_troubleshooting.md @@ -1,6 +1,8 @@ -## Troubleshooting +--- +content_title: Troubleshooting +--- -### When sending an action to the blockchain you get the error below +## When sending an action to the blockchain you get the error below ```{ "code":500, "message":"Internal Service Error", @@ -21,7 +23,7 @@ ``` __Possible solution__: Verify if you did not forget to set code for contract, is it possible that you only set the `abi` for the contract but not the code as well? -### When sending an action to the blockchain an error similar to the one below is encountered: +## When sending an action to the blockchain an error similar to the one below is encountered: ```sh Error 3015014: Pack data exception Error Details: @@ -33,14 +35,14 @@ cleos push action eostutorial1 get '[]' -p eostutorial1@active ``` The command above is one way of sending correctly `get` action with no parameters to the blockchain. -### When sending an action to the blockchain an error similar to the one below is encountered: +## When sending an action to the blockchain an error similar to the one below is encountered: ```sh error 2019-09-25T07:38:14.859 thread-0 main.cpp:3449 main ] Failed with error: Assert Exception (10) !action_type.empty(): Unknown action action_name in contract eostutorial1 ``` __Possible solution__: Verify if the action attribute `[[eosio::action]]` is used when defining and/or declaring the action `action_name` for the contract. -### When deploying a contract code to the blockchain a similar error with the ones below is encountered: +## When deploying a contract code to the blockchain a similar error with the ones below is encountered: ```sh Error 3160010: No abi file found or @@ -48,11 +50,11 @@ Error 3160009: No wasm file found ``` __Possible solution__: Verify that `abi` and `wasm` files exist in the directory specified in the `cleos set contract` command, and that their names match the directory name. -### Action triggers ram charge which cannot be initiated from a notification. +## Action triggers ram charge which cannot be initiated from a notification. __Possible solution__: The reason for this error is because the notification action doesn't have authorization to buy the needed RAM. In the context of multi index tables, there’s a table payer and a row payer. Only the contract can modify rows. The contract can create rows with a payer that didn’t authorize the action if the total amount of ram charged that payer doesn’t increase (e.g. delete a row and add another with the same payer). The table payer can’t change until the last row is deleted. For the purposes of billing, a table is identified by the tuple `contract, scope, table`. When you create a row for a `contract, scope, table` tuple that doesn’t exist, you create a table with the same payer. This can outlive the original row which created it, if other rows were created with that combination and this prevents the original payer from getting their ram back. Secondary indexes throw in more complexity since they use the lower 4 bits of the table name, producing additional `contract, scope, table` tuples combinations. Key takeaway: payer is about billing, not access control -### You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: +## You successfully re-deployed the contract code, but when you query the table you get the custom message that you coded when the table is not initialized (doesn't exist), or the system error message below in case you do not have code that checks first if table exist: ```sh Error 3050003: eosio_assert_message assertion failure Error Details: @@ -61,26 +63,26 @@ pending console output: ``` __Possible solution__: It is possible that you changed the table name? That is the first, of `eosio::name` type, parameter which you passed to the `eosio::template` type alias definition. Or did you change the table structure definition at all? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -### You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. +## You successfully re-deployed the contract code, but when you query the table you get the fields of the row values swapped, that is, it appears the values stored in table rows are the same only that they are swapped between fields/columns. __Possible solution__: It is possible that you changed the order of the fields the table struct definition? If you change the order of the table struct definition, if the swapped fields have the same type you will see the data in the fields correctly, however if the types of the fields are different the results could be of something undefined. If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -### You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. +## You successfully re-deployed the contract code, but when you query the table you get a parse error, like the one below, or the returned data seems to be garbage. ```sh error 2019-09-26T07:05:54.825 thread-0 main.cpp:3449 main ] Failed with error: Parse Error (4) Couldn't parse type_name ``` __Possible solution__: It is possible that you changed the type of the fields for the table struct definition? If you need to change the table structure definition there are some limitations and a couple of ways to do it which are explained in the [Data Design and Migration](./05_best-practices/04_data-design-and-migration.md) section. -### eosio-cpp process never completes. +## eosio-cpp process never completes. __Possible solution__: make sure you have at least 2 cores on the host that executes the eosio-cpp (e.g. docker container, VM, local sub-system) -### You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. +## You can not find the `now()` time function, or the result of the `current_time_point` functions are not what you expected them to be. __Possible solution__: The `now()` function has been replaced by `current_time_point().sec_since_epoch()`, it returns the time in microseconds from 1970 of the `current block` as a time_point. There's also available `current_block_time()` which returns the time in microseconds from 1970 of the `current block` as a `block_timestamp`. Be aware that for time base functions, the assumption is when you call something like `now()` or `current_time()` you will get the exact now/current time, however that is not the case with EOSIO, you get __the block time__, and only ever get __the block time__ from the available `sec_since_epoch()` or `current_block_time()` no matter how many times you call it. -### You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: +## You successfully re-deployed the contract code, but when you broadcast one of the contracts methods to the blockchain you get below error message: ```sh Error 3050004: eosio_assert_code assertion failure Error Details: @@ -88,7 +90,7 @@ assertion failure with error code: 8000000000000000000 ``` __Possible solution__: If you are referencing a smart contract from another smart contract and each of them have at least one action with the same name you will experience the above error when sending to the blockchain one of those actions, so what you have to do is to make sure the action names between those two contracts are not common. -### Print statements from smart contract code are not seen in the output. +## Print statements from smart contract code are not seen in the output. __Possible solution__: There are a few reasons print statements do not show up in the output. One reason could be because an error occurs, in which case the whole transaction is rolled back and the print statements output is replaced by the error that occurs instead; Another reason is if you are in a loop, iterating through a table's rows for example and for each row you have a print statement that prints also the new line char at the `'\n'` only the chars before the new line char from the first iteration will be printed, nothing else after that, nothing from the second iteration onwards either. @@ -111,7 +113,7 @@ The below code will print all lines of the iteration separated by `'|'` char. } ``` -### Print statements from smart contract code are not shown in the `expected order`. +## Print statements from smart contract code are not shown in the `expected order`. __Possible solution__: The key point here is the `expected order` and what you think it should be. Although the EOSIO is single threaded, when looking at your smart contract action code implementation, which let's say it has a series of `print` (either `print_f` or `printf`) statements, they might not necessarily be outputted in the order the `apparent` code workflow is. One example is when inline transactions are sent from your smart contract action code, and you expect to see the `print` statements from within the inline action code outputted before the `print` statements made after the inline action `send` statement. For better exemplification let's look at the code below: diff --git a/docs/09_tutorials/01_binary-extension.md b/docs/09_tutorials/01_binary-extension.md index b48f8cb80b..c149089790 100644 --- a/docs/09_tutorials/01_binary-extension.md +++ b/docs/09_tutorials/01_binary-extension.md @@ -1,4 +1,6 @@ -# eosio::binary_extension +--- +content_title: eosio::binary_extension +--- You can find the implementation of `eosio::binary_extension` in the `eosio.cdt` repository in [binary_extension.hpp](https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/binary_extension.hpp). diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 9e99f1f912..51430b4b08 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -1,9 +1,11 @@ -## ABI variants +--- +content_title: ABI variants +--- ABI variants give the flexibility of using more than one type for a defined variable or data member. In EOSIO, the variants make use of the standard template library `variant` which was introduced in C++ 17. An instance of `std::variant` at any given time either holds a value of one of its alternative types, or in the case of error - no value. Because of this trait, variants can be used to build the multi index table structure with flexibility. Used in conjunction with ABI extensions, it allows for modification of the structure of an exiting multi index table, a.k.a. table. -### Use variant when building the multi index table the first time +## Use variant when building the multi index table the first time To define a `variant` for your table structure one example is shown below @@ -100,9 +102,9 @@ class [[eosio::contract]] multi_index_example : public contract { Now you can deploy the contract and it will be backwards compatible with the previous existing multi index table. -### Use variant when changing an already deployed multi index table +## Use variant when changing an already deployed multi index table -#### Preconditions +### Preconditions - It is assumed you deployed the contract defined in [this section](../06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md) and now you are going to change its table structure. To change the existing table structure, you will use the `std::variant` in conjunction with ABI extensions; you can read a tutorial on abi extensions [here](./01_binary-extension.md). You will add another field to the table called `variant_field` which can store either of the following data `int8_t`, `int16_t`, and `int32_t`. You can do it by adding below data member to the table structure: diff --git a/docs/index.md b/docs/index.md index 3dc341ead1..ba66b91f59 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,5 @@ # EOSIO.CDT (Contract Development Toolkit) + ## Version : 1.7.0 EOSIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate smart contract development for the EOSIO platform. In addition to being a general purpose WebAssembly toolchain, [EOSIO](https://github.com/eosio/eos) specific optimizations are available to support building EOSIO smart contracts. This new toolchain is built around [Clang 7](https://github.com/eosio/llvm), which means that EOSIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are incomplete or not available. From d0fc6e0cdf6d47fcc36c6384050886f6cb763983 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 21 Nov 2019 16:49:55 -0500 Subject: [PATCH 127/659] Track ricardian file dependencies. add_dependencies does not for for ordinary files. Fixes #455. Fixes #309. --- modules/EosioCDTMacros.cmake.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/EosioCDTMacros.cmake.in b/modules/EosioCDTMacros.cmake.in index f4e439de8c..41d52c4c82 100644 --- a/modules/EosioCDTMacros.cmake.in +++ b/modules/EosioCDTMacros.cmake.in @@ -5,11 +5,14 @@ if (NOT EOSIO_WASM_OLD_BEHAVIOR STREQUAL "On") get_target_property(BINOUTPUT ${TARGET} BINARY_DIR) target_compile_options( ${TARGET} PUBLIC -abigen_output=${BINOUTPUT}/${TARGET}.abi ) target_compile_options( ${TARGET} PUBLIC -contract ${CONTRACT_NAME} ) + file(GLOB contracts ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.contracts.md ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.clauses.md) + set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) endmacro() macro (target_ricardian_directory TARGET DIR) target_compile_options( ${TARGET} PUBLIC -R${DIR} ) file(GLOB contracts ${DIR}/*.contracts.md ${DIR}/*.clauses.md) - add_dependencies( ${TARGET} ${contracts} ) + get_target_property(contract_sources ${TARGET} SOURCES) + set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) endmacro() else() @@ -19,11 +22,14 @@ else() get_target_property(BINOUTPUT ${TARGET}.wasm BINARY_DIR) target_compile_options( ${TARGET}.wasm PUBLIC -abigen_output=${BINOUTPUT}/${TARGET}.abi ) target_compile_options( ${TARGET}.wasm PUBLIC -contract ${CONTRACT_NAME} ) + file(GLOB contracts ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.contracts.md ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.clauses.md) + set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) endmacro() macro (target_ricardian_directory TARGET DIR) target_compile_options( ${TARGET}.wasm PUBLIC -R${DIR} ) file(GLOB contracts ${DIR}/*.contracts.md ${DIR}/*.clauses.md) - add_dependencies( ${TARGET}.wasm ${contracts} ) + get_target_property(contract_sources ${TARGET}.wasm SOURCES) + set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) endmacro() endif() From 7373d79c2824b93ea6ec3097f23f46e0dc92d80c Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 22 Nov 2019 09:07:47 -0500 Subject: [PATCH 128/659] Fix build errors when there isn't a ricardian contract. --- modules/EosioCDTMacros.cmake.in | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/EosioCDTMacros.cmake.in b/modules/EosioCDTMacros.cmake.in index 41d52c4c82..40449d4dce 100644 --- a/modules/EosioCDTMacros.cmake.in +++ b/modules/EosioCDTMacros.cmake.in @@ -6,13 +6,17 @@ if (NOT EOSIO_WASM_OLD_BEHAVIOR STREQUAL "On") target_compile_options( ${TARGET} PUBLIC -abigen_output=${BINOUTPUT}/${TARGET}.abi ) target_compile_options( ${TARGET} PUBLIC -contract ${CONTRACT_NAME} ) file(GLOB contracts ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.contracts.md ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.clauses.md) - set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) + if(contracts) + set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) + endif() endmacro() macro (target_ricardian_directory TARGET DIR) target_compile_options( ${TARGET} PUBLIC -R${DIR} ) file(GLOB contracts ${DIR}/*.contracts.md ${DIR}/*.clauses.md) get_target_property(contract_sources ${TARGET} SOURCES) - set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) + if(contracts) + set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) + endif() endmacro() else() @@ -23,13 +27,17 @@ else() target_compile_options( ${TARGET}.wasm PUBLIC -abigen_output=${BINOUTPUT}/${TARGET}.abi ) target_compile_options( ${TARGET}.wasm PUBLIC -contract ${CONTRACT_NAME} ) file(GLOB contracts ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.contracts.md ${CMAKE_CURRENT_SOURCE_DIR}/${CONTRACT_NAME}.clauses.md) - set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) + if(contracts) + set_source_files_properties(${ARGN} PROPERTIES OBJECT_DEPENDS ${contracts}) + endif() endmacro() macro (target_ricardian_directory TARGET DIR) target_compile_options( ${TARGET}.wasm PUBLIC -R${DIR} ) file(GLOB contracts ${DIR}/*.contracts.md ${DIR}/*.clauses.md) get_target_property(contract_sources ${TARGET}.wasm SOURCES) - set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) + if(contracts) + set_source_files_properties(${contract_sources} PROPERTIES OBJECT_DEPENDS ${contracts}) + endif() endmacro() endif() From 93a2f5e6951bf49aab97185a1cb68905da418ec8 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Mon, 25 Nov 2019 10:33:19 -0500 Subject: [PATCH 129/659] Fix C++isms in the C api. --- libraries/eosiolib/capi/eosio/crypto.h | 20 +++--- libraries/eosiolib/capi/eosio/privileged.h | 2 +- libraries/eosiolib/capi/eosio/system.h | 2 +- libraries/eosiolib/capi/eosio/transaction.h | 4 +- libraries/native/intrinsics.cpp | 4 +- tests/integration/capi_tests.cpp | 29 ++++++++ tests/integration/contracts.hpp.in | 3 + tests/unit/test_contracts/CMakeLists.txt | 3 + tests/unit/test_contracts/capi/action.c | 16 +++++ tests/unit/test_contracts/capi/capi.c | 24 +++++++ tests/unit/test_contracts/capi/capi_tests.abi | 22 ++++++ tests/unit/test_contracts/capi/chain.c | 6 ++ tests/unit/test_contracts/capi/crypto.c | 15 ++++ tests/unit/test_contracts/capi/db.c | 70 +++++++++++++++++++ tests/unit/test_contracts/capi/permission.c | 9 +++ tests/unit/test_contracts/capi/print.c | 16 +++++ tests/unit/test_contracts/capi/privileged.c | 14 ++++ tests/unit/test_contracts/capi/system.c | 12 ++++ tests/unit/test_contracts/capi/transaction.c | 14 ++++ 19 files changed, 269 insertions(+), 16 deletions(-) create mode 100644 tests/integration/capi_tests.cpp create mode 100644 tests/unit/test_contracts/capi/action.c create mode 100644 tests/unit/test_contracts/capi/capi.c create mode 100644 tests/unit/test_contracts/capi/capi_tests.abi create mode 100644 tests/unit/test_contracts/capi/chain.c create mode 100644 tests/unit/test_contracts/capi/crypto.c create mode 100644 tests/unit/test_contracts/capi/db.c create mode 100644 tests/unit/test_contracts/capi/permission.c create mode 100644 tests/unit/test_contracts/capi/print.c create mode 100644 tests/unit/test_contracts/capi/privileged.c create mode 100644 tests/unit/test_contracts/capi/system.c create mode 100644 tests/unit/test_contracts/capi/transaction.c diff --git a/libraries/eosiolib/capi/eosio/crypto.h b/libraries/eosiolib/capi/eosio/crypto.h index e5d1ad0b8e..6f60fbe7d8 100644 --- a/libraries/eosiolib/capi/eosio/crypto.h +++ b/libraries/eosiolib/capi/eosio/crypto.h @@ -38,7 +38,7 @@ extern "C" { * @endcode */ __attribute__((eosio_wasm_import)) -void assert_sha256( const char* data, uint32_t length, const capi_checksum256* hash ); +void assert_sha256( const char* data, uint32_t length, const struct capi_checksum256* hash ); /** * Tests if the sha1 hash generated from data matches the provided checksum. @@ -63,7 +63,7 @@ void assert_sha256( const char* data, uint32_t length, const capi_checksum256* h * @endcode */ __attribute__((eosio_wasm_import)) -void assert_sha1( const char* data, uint32_t length, const capi_checksum160* hash ); +void assert_sha1( const char* data, uint32_t length, const struct capi_checksum160* hash ); /** * Tests if the sha512 hash generated from data matches the provided checksum. @@ -88,7 +88,7 @@ void assert_sha1( const char* data, uint32_t length, const capi_checksum160* has * @endcode */ __attribute__((eosio_wasm_import)) -void assert_sha512( const char* data, uint32_t length, const capi_checksum512* hash ); +void assert_sha512( const char* data, uint32_t length, const struct capi_checksum512* hash ); /** * Tests if the ripemod160 hash generated from data matches the provided checksum. @@ -112,7 +112,7 @@ void assert_sha512( const char* data, uint32_t length, const capi_checksum512* h * @endcode */ __attribute__((eosio_wasm_import)) -void assert_ripemd160( const char* data, uint32_t length, const capi_checksum160* hash ); +void assert_ripemd160( const char* data, uint32_t length, const struct capi_checksum160* hash ); /** * Hashes `data` using `sha256` and stores result in memory pointed to by hash. @@ -130,7 +130,7 @@ void assert_ripemd160( const char* data, uint32_t length, const capi_checksum160 * @endcode */ __attribute__((eosio_wasm_import)) -void sha256( const char* data, uint32_t length, capi_checksum256* hash ); +void sha256( const char* data, uint32_t length, struct capi_checksum256* hash ); /** * Hashes `data` using `sha1` and stores result in memory pointed to by hash. @@ -148,7 +148,7 @@ void sha256( const char* data, uint32_t length, capi_checksum256* hash ); * @endcode */ __attribute__((eosio_wasm_import)) -void sha1( const char* data, uint32_t length, capi_checksum160* hash ); +void sha1( const char* data, uint32_t length, struct capi_checksum160* hash ); /** * Hashes `data` using `sha512` and stores result in memory pointed to by hash. @@ -166,7 +166,7 @@ void sha1( const char* data, uint32_t length, capi_checksum160* hash ); * @endcode */ __attribute__((eosio_wasm_import)) -void sha512( const char* data, uint32_t length, capi_checksum512* hash ); +void sha512( const char* data, uint32_t length, struct capi_checksum512* hash ); /** * Hashes `data` using `ripemod160` and stores result in memory pointed to by hash. @@ -184,7 +184,7 @@ void sha512( const char* data, uint32_t length, capi_checksum512* hash ); * @endcode */ __attribute__((eosio_wasm_import)) -void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ); +void ripemd160( const char* data, uint32_t length, struct capi_checksum160* hash ); /** * Calculates the public key used for a given signature and hash used to create a message. @@ -202,7 +202,7 @@ void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ); * @endcode */ __attribute__((eosio_wasm_import)) -int recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); +int recover_key( const struct capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ); /** * Tests a given public key with the generated key from digest and the signature. @@ -230,7 +230,7 @@ int recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, * @endcode */ __attribute__((eosio_wasm_import)) -void assert_recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); +void assert_recover_key( const struct capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ); #ifdef __cplusplus } diff --git a/libraries/eosiolib/capi/eosio/privileged.h b/libraries/eosiolib/capi/eosio/privileged.h index 523bf436a3..780cafdf9c 100644 --- a/libraries/eosiolib/capi/eosio/privileged.h +++ b/libraries/eosiolib/capi/eosio/privileged.h @@ -111,7 +111,7 @@ uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ); * @param feature_digest - digest of the protocol feature to pre-activate */ __attribute__((eosio_wasm_import)) -void preactivate_feature( const capi_checksum256* feature_digest ); +void preactivate_feature( const struct capi_checksum256* feature_digest ); #ifdef __cplusplus } diff --git a/libraries/eosiolib/capi/eosio/system.h b/libraries/eosiolib/capi/eosio/system.h index 668bf56125..76c342f9d5 100644 --- a/libraries/eosiolib/capi/eosio/system.h +++ b/libraries/eosiolib/capi/eosio/system.h @@ -83,7 +83,7 @@ uint64_t current_time( void ); * @return true if the specified protocol feature has been activated, false otherwise */ __attribute__((eosio_wasm_import)) -bool is_feature_activated( const capi_checksum256* feature_digest ); +bool is_feature_activated( const struct capi_checksum256* feature_digest ); /** * Return name of account that sent current inline action diff --git a/libraries/eosiolib/capi/eosio/transaction.h b/libraries/eosiolib/capi/eosio/transaction.h index 111b7b16a7..3fce87fb2c 100644 --- a/libraries/eosiolib/capi/eosio/transaction.h +++ b/libraries/eosiolib/capi/eosio/transaction.h @@ -47,7 +47,7 @@ extern "C" { * @param replace_existing - f this is `0` then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction */ __attribute__((eosio_wasm_import)) -void send_deferred(const uint128_t& sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing = 0); +void send_deferred(const uint128_t* sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing); /** * Cancels a deferred transaction. @@ -69,7 +69,7 @@ void send_deferred(const uint128_t& sender_id, capi_name payer, const char *seri * @endcode */ __attribute__((eosio_wasm_import)) -int cancel_deferred(const uint128_t& sender_id); +int cancel_deferred(const uint128_t* sender_id); /** * Access a copy of the currently executing transaction. diff --git a/libraries/native/intrinsics.cpp b/libraries/native/intrinsics.cpp index e023fbd736..2c89196c80 100644 --- a/libraries/native/intrinsics.cpp +++ b/libraries/native/intrinsics.cpp @@ -331,10 +331,10 @@ extern "C" { void send_context_free_inline(char *serialized_action, size_t size) { return intrinsics::get().call(serialized_action, size); } - void send_deferred(const uint128_t& sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing) { + void send_deferred(const uint128_t* sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing) { return intrinsics::get().call(sender_id, payer, serialized_transaction, size, replace_existing); } - int cancel_deferred(const uint128_t& sender_id) { + int cancel_deferred(const uint128_t* sender_id) { return intrinsics::get().call(sender_id); } int get_context_free_data( uint32_t index, char* buff, size_t size ) { diff --git a/tests/integration/capi_tests.cpp b/tests/integration/capi_tests.cpp new file mode 100644 index 0000000000..3efd52cf28 --- /dev/null +++ b/tests/integration/capi_tests.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +#include + +#include + +#include + +using namespace eosio; +using namespace eosio::testing; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +BOOST_AUTO_TEST_SUITE(capi_tests) + +BOOST_FIXTURE_TEST_CASE( capi_tests, tester ) try { + create_accounts( { N(test) } ); + produce_block(); + set_code( N(test), contracts::capi_tests_wasm() ); + set_abi( N(test), contracts::capi_tests_abi().data() ); + produce_blocks(); + + push_action(N(test), N(act), N(test), {}); +} FC_LOG_AND_RETHROW() } diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 149db3b926..8d0f140bbc 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -16,6 +16,9 @@ struct contracts { static std::vector transfer_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/transfer_contract.wasm"); } static std::vector transfer_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/transfer_contract.abi"); } + static std::vector capi_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.wasm"); } + static std::vector capi_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.abi"); } + }; }} //ns eosio::testing diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 2079375e70..d5582ac3d0 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -3,7 +3,10 @@ add_contract(malloc_tests old_malloc_tests malloc_tests.cpp) add_contract(simple_tests simple_tests simple_tests.cpp) add_contract(transfer_contract transfer_contract transfer.cpp) add_contract(minimal_tests minimal_tests minimal_tests.cpp) +add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c + capi/print.c capi/privileged.c capi/system.c capi/transaction.c) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/simple_wrong.abi ${CMAKE_CURRENT_BINARY_DIR}/simple_wrong.abi COPYONLY ) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/capi/capi_tests.abi ${CMAKE_CURRENT_BINARY_DIR}/capi_tests.abi COPYONLY ) target_link_libraries(old_malloc_tests PUBLIC --use-freeing-malloc) diff --git a/tests/unit/test_contracts/capi/action.c b/tests/unit/test_contracts/capi/action.c new file mode 100644 index 0000000000..43fdded202 --- /dev/null +++ b/tests/unit/test_contracts/capi/action.c @@ -0,0 +1,16 @@ +#include +#include + +void test_action( void ) { + read_action_data(NULL, 0); + action_data_size(); + require_recipient(0); + require_auth(0); + has_auth(0); + require_auth2(0, 0); + is_account(0); + send_inline(NULL, 0); + send_context_free_inline(NULL, 0); + publication_time(); + current_receiver(); +} diff --git a/tests/unit/test_contracts/capi/capi.c b/tests/unit/test_contracts/capi/capi.c new file mode 100644 index 0000000000..d235e43cd8 --- /dev/null +++ b/tests/unit/test_contracts/capi/capi.c @@ -0,0 +1,24 @@ +#include + +void test_action( void ); +void test_chain( void ); +void test_crypto( void ); +void test_db( void ); +void test_permission( void ); +void test_print( void ); +void test_privileged( void ); +void test_system( void ); +void test_transaction( void ); + +void apply( uint64_t a, uint64_t b, uint64_t c ) { + if(a != 0xed234054a367196eull) return; // random value that should not be used + test_action(); + test_chain(); + test_crypto(); + test_db(); + test_permission(); + test_print(); + test_privileged(); + test_system(); + test_transaction(); +} diff --git a/tests/unit/test_contracts/capi/capi_tests.abi b/tests/unit/test_contracts/capi/capi_tests.abi new file mode 100644 index 0000000000..af470081c2 --- /dev/null +++ b/tests/unit/test_contracts/capi/capi_tests.abi @@ -0,0 +1,22 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "act", + "base": "", + "fields": [] + } + ], + "actions": [ + { + "name": "act", + "type": "act", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [] +} \ No newline at end of file diff --git a/tests/unit/test_contracts/capi/chain.c b/tests/unit/test_contracts/capi/chain.c new file mode 100644 index 0000000000..ed18f245d0 --- /dev/null +++ b/tests/unit/test_contracts/capi/chain.c @@ -0,0 +1,6 @@ +#include +#include + +void test_chain( void ) { + get_active_producers(NULL, 0); +} diff --git a/tests/unit/test_contracts/capi/crypto.c b/tests/unit/test_contracts/capi/crypto.c new file mode 100644 index 0000000000..cbe7784c9b --- /dev/null +++ b/tests/unit/test_contracts/capi/crypto.c @@ -0,0 +1,15 @@ +#include +#include + +void test_crypto( void ) { + assert_sha256( NULL, 0, NULL ); + assert_sha1( NULL, 0, NULL ); + assert_sha512( NULL, 0, NULL ); + assert_ripemd160( NULL, 0, NULL ); + sha256( NULL, 0 , NULL ); + sha1( NULL, 0, NULL ); + sha512( NULL, 0, NULL ); + ripemd160( NULL, 0, NULL ); + recover_key( NULL, NULL, 0, NULL, 0 ); + assert_recover_key( NULL, NULL, 0, NULL, 0 ); +} diff --git a/tests/unit/test_contracts/capi/db.c b/tests/unit/test_contracts/capi/db.c new file mode 100644 index 0000000000..49705c13b0 --- /dev/null +++ b/tests/unit/test_contracts/capi/db.c @@ -0,0 +1,70 @@ +#include +#include + +void test_db( void ) { + db_store_i64(0, 0, 0, 0, NULL, 0); + db_update_i64(0, 0, NULL, 0); + db_remove_i64(0); + db_get_i64(0, NULL, 0); + db_next_i64(0, NULL); + db_previous_i64(0, NULL); + db_find_i64(0, 0, 0, 0); + db_lowerbound_i64(0, 0, 0, 0); + db_upperbound_i64(0, 0, 0, 0); + db_end_i64(0, 0, 0); + + db_idx64_store(0, 0, 0, 0, NULL); + db_idx64_update(0, 0, NULL); + db_idx64_remove(0); + db_idx64_next(0, NULL); + db_idx64_previous(0, NULL); + db_idx64_find_primary(0, 0, 0, NULL, 0); + db_idx64_find_secondary(0, 0, 0, NULL, NULL); + db_idx64_lowerbound(0, 0, 0, NULL, NULL); + db_idx64_upperbound(0, 0, 0, NULL, NULL); + db_idx64_end(0, 0, 0); + + db_idx128_store(0, 0, 0, 0, NULL); + db_idx128_update(0, 0, NULL); + db_idx128_remove(0); + db_idx128_next(0, NULL); + db_idx128_previous(0, NULL); + db_idx128_find_primary(0, 0, 0, NULL, 0); + db_idx128_find_secondary(0, 0, 0, NULL, NULL); + db_idx128_lowerbound(0, 0, 0, NULL, NULL); + db_idx128_upperbound(0, 0, 0, NULL, NULL); + db_idx128_end(0, 0, 0); + + db_idx256_store(0, 0, 0, 0, NULL, 0); + db_idx256_update(0, 0, NULL, 0); + db_idx256_remove(0); + db_idx256_next(0, NULL); + db_idx256_previous(0, NULL); + db_idx256_find_primary(0, 0, 0, NULL, 0, 0); + db_idx256_find_secondary(0, 0, 0, NULL,0, NULL); + db_idx256_lowerbound(0, 0, 0, NULL, 0, NULL); + db_idx256_upperbound(0, 0, 0, NULL, 0, NULL); + db_idx256_end(0, 0, 0); + + db_idx_double_store(0, 0, 0, 0, NULL); + db_idx_double_update(0, 0, NULL); + db_idx_double_remove(0); + db_idx_double_next(0, NULL); + db_idx_double_previous(0, NULL); + db_idx_double_find_primary(0, 0, 0, NULL, 0); + db_idx_double_find_secondary(0, 0, 0, NULL, NULL); + db_idx_double_lowerbound(0, 0, 0, NULL, NULL); + db_idx_double_upperbound(0, 0, 0, NULL, NULL); + db_idx_double_end(0, 0, 0); + + db_idx_long_double_store(0, 0, 0, 0, NULL); + db_idx_long_double_update(0, 0, NULL); + db_idx_long_double_remove(0); + db_idx_long_double_next(0, NULL); + db_idx_long_double_previous(0, NULL); + db_idx_long_double_find_primary(0, 0, 0, NULL, 0); + db_idx_long_double_find_secondary(0, 0, 0, NULL, NULL); + db_idx_long_double_lowerbound(0, 0, 0, NULL, NULL); + db_idx_long_double_upperbound(0, 0, 0, NULL, NULL); + db_idx_long_double_end(0, 0, 0); +} diff --git a/tests/unit/test_contracts/capi/permission.c b/tests/unit/test_contracts/capi/permission.c new file mode 100644 index 0000000000..027dee33c3 --- /dev/null +++ b/tests/unit/test_contracts/capi/permission.c @@ -0,0 +1,9 @@ +#include +#include + +void test_permission( void ) { + check_transaction_authorization(NULL, 0, NULL, 0, NULL, 0); + check_permission_authorization(0, 0, NULL, 0, NULL, 0, 0); + get_permission_last_used(0, 0); + get_account_creation_time(0); +} diff --git a/tests/unit/test_contracts/capi/print.c b/tests/unit/test_contracts/capi/print.c new file mode 100644 index 0000000000..da137ecd4b --- /dev/null +++ b/tests/unit/test_contracts/capi/print.c @@ -0,0 +1,16 @@ +#include +#include + +void test_print( void ) { + prints(NULL); + prints_l(NULL, 0); + printi(0); + printui(0); + printi128(NULL); + printui128(NULL); + printsf(0.0f); + printdf(0.0); + printqf(NULL); + printn(0); + printhex(NULL, 0); +} diff --git a/tests/unit/test_contracts/capi/privileged.c b/tests/unit/test_contracts/capi/privileged.c new file mode 100644 index 0000000000..e4ea864c52 --- /dev/null +++ b/tests/unit/test_contracts/capi/privileged.c @@ -0,0 +1,14 @@ +#include +#include + +void test_privileged( void ) { + get_resource_limits(0, NULL, NULL, NULL); + set_resource_limits(0, 0, 0, 0); + set_proposed_producers(NULL, 0); + set_proposed_producers_ex(0, NULL, 0); + is_privileged(0); + set_privileged(0, 0); + set_blockchain_parameters_packed(NULL, 0); + get_blockchain_parameters_packed(NULL, 0); + preactivate_feature(NULL); +} diff --git a/tests/unit/test_contracts/capi/system.c b/tests/unit/test_contracts/capi/system.c new file mode 100644 index 0000000000..21b4622e7d --- /dev/null +++ b/tests/unit/test_contracts/capi/system.c @@ -0,0 +1,12 @@ +#include +#include + +void test_system( void ) { + eosio_assert(0, NULL); + eosio_assert_message(0, NULL, 0); + eosio_assert_code(0, 0); + eosio_exit(0); + current_time(); + is_feature_activated(NULL); + get_sender(); +} diff --git a/tests/unit/test_contracts/capi/transaction.c b/tests/unit/test_contracts/capi/transaction.c new file mode 100644 index 0000000000..21d14f3f35 --- /dev/null +++ b/tests/unit/test_contracts/capi/transaction.c @@ -0,0 +1,14 @@ +#include +#include + +void test_transaction( void ) { + send_deferred(NULL, 0, NULL, 0, 0); + cancel_deferred(NULL); + read_transaction(NULL, 0); + transaction_size(); + tapos_block_num(); + tapos_block_prefix(); + expiration(); + get_action(0, 0, NULL, 0); + get_context_free_data(0, NULL, 0); +} From 45e8d505075446495a6a0bbe1a4460b601f3a05c Mon Sep 17 00:00:00 2001 From: dskvr Date: Mon, 2 Dec 2019 23:17:54 +0100 Subject: [PATCH 130/659] remove --- when not relateed to frontmatter --- docs/02_installation.md | 2 -- docs/03_command-reference/eosio-abidiff.md | 1 - docs/03_command-reference/eosio-abigen.md | 1 - docs/03_command-reference/eosio-init.md | 1 - docs/03_command-reference/eosio-ld.md | 2 +- docs/04_upgrading/1.2-to-1.3.md | 1 - docs/04_upgrading/1.5-to-1.6.md | 5 ++--- 7 files changed, 3 insertions(+), 10 deletions(-) diff --git a/docs/02_installation.md b/docs/02_installation.md index 680d8addbe..8b93611ec8 100644 --- a/docs/02_installation.md +++ b/docs/02_installation.md @@ -66,7 +66,6 @@ $ sudo rm /usr/local/bin/eosio-* # Installed Tools ---- * eosio-cpp * eosio-cc * eosio-ld @@ -88,5 +87,4 @@ eosio-readelf License ----- [MIT](../LICENSE) diff --git a/docs/03_command-reference/eosio-abidiff.md b/docs/03_command-reference/eosio-abidiff.md index 29dd8a34be..92f155739f 100644 --- a/docs/03_command-reference/eosio-abidiff.md +++ b/docs/03_command-reference/eosio-abidiff.md @@ -11,7 +11,6 @@ $ eosio-abidiff hello.abi old_hello.abi ``` This will generate dump the report output to the console. ---- ``` OVERVIEW: eosio-abidiff USAGE: eosio-abidiff [options] ... ... diff --git a/docs/03_command-reference/eosio-abigen.md b/docs/03_command-reference/eosio-abigen.md index 35ea5849ba..3650985d91 100644 --- a/docs/03_command-reference/eosio-abigen.md +++ b/docs/03_command-reference/eosio-abigen.md @@ -13,7 +13,6 @@ $ eosio-abigen hello.cpp --contract=hello --output=hello.abi This will generate one file: * The generated ABI file (hello.abi) ---- ``` USAGE: eosio-abigen [options] [... ] diff --git a/docs/03_command-reference/eosio-init.md b/docs/03_command-reference/eosio-init.md index fb6dd99039..271f28de5e 100644 --- a/docs/03_command-reference/eosio-init.md +++ b/docs/03_command-reference/eosio-init.md @@ -11,7 +11,6 @@ $ eosio-abigen hello.cpp --contract=hello --output=hello.abi This will generate one file: * The generated ABI file (hello.abi) ---- ``` USAGE: eosio-init [options] diff --git a/docs/03_command-reference/eosio-ld.md b/docs/03_command-reference/eosio-ld.md index 0e4e8f74ae..21b28fe974 100644 --- a/docs/03_command-reference/eosio-ld.md +++ b/docs/03_command-reference/eosio-ld.md @@ -4,7 +4,7 @@ content_title: eosio-ld tool The eosio-ld tool is a the custom web assembly linker for EOSIO platform smart contracts. ---- + ``` USAGE: eosio-ld [options] ... diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index 3d5b66a0ef..835d79a75c 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -223,5 +223,4 @@ For an example contract of ABI generation see the file ./examples/abigen_test/te License ----- [MIT](../../LICENSE) diff --git a/docs/04_upgrading/1.5-to-1.6.md b/docs/04_upgrading/1.5-to-1.6.md index 4181b6d877..5571d8bde6 100644 --- a/docs/04_upgrading/1.5-to-1.6.md +++ b/docs/04_upgrading/1.5-to-1.6.md @@ -9,7 +9,7 @@ In `eosio.cdt` v1.6.0, `eosiolib` will now be partitioned into 3 groups. These a - Contracts - Core - The `CAPI` will only be available to contract writers using `eosio-cc` and purely for `C` smart contracts. - - The `Contracts` will be available to `eosio-cpp` for smart contract writing. + - The `Contracts` will be available to `eosio-cpp` for smart contract writing. - `Core` will be available to `eosio-cpp` for any of the modes (present and future). - `eosio-cpp` in `fnative` mode will have access to all of these groups. @@ -125,7 +125,7 @@ This entire API is now only available to C developers (i.e. using `eosio-cc`), a There is no more need to add the `EOSIO_DISPATCH` macro to your smart contracts. The compiler/linker will now automatically generate a dispatcher for you the proper `eosio::contract`, `eosio::action` and `eosio::on_notify` attributes are used. Of course, if you don't have these attributes then you will still need to either use the old macro or hand write the `apply` function yourself. ### How the auto dispatcher will work -Given that you have marked your classes with the `eosio::contract` macro and any sub-contracts with the macro with the same given name (i.e. `eosio::contract("")`) then any actions and notify handlers that are contained within these will be dispatchable by your smart contract. This will allow for aggregate patterns for smart contract development and better separation of concerns. +Given that you have marked your classes with the `eosio::contract` macro and any sub-contracts with the macro with the same given name (i.e. `eosio::contract("")`) then any actions and notify handlers that are contained within these will be dispatchable by your smart contract. This will allow for aggregate patterns for smart contract development and better separation of concerns. In addition to actions and notification handlers, two new "hooks" are available. - `bool pre_dispatch(name self, name first_receiver, name action)` @@ -142,5 +142,4 @@ If the dispatcher is in notification handling mode and if your contract receives For a real world example of this new style of contract in use see `tests/unit/test_contracts/simple_test.cpp`. License ----- [MIT](../../LICENSE) From 896356be7822c1b75686b4b262804b5d83ee6808 Mon Sep 17 00:00:00 2001 From: dskvr Date: Mon, 2 Dec 2019 23:30:17 +0100 Subject: [PATCH 131/659] Migrate write ABI file guide, add link, add docs.json --- docs/04_upgrading/1.2-to-1.3.md | 2 +- .../05_how-to-write-an-abi-file.md | 524 ++++++++++++++++++ 2 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 docs/06_how-to-guides/05_how-to-write-an-abi-file.md diff --git a/docs/04_upgrading/1.2-to-1.3.md b/docs/04_upgrading/1.2-to-1.3.md index 835d79a75c..c0afd1a339 100644 --- a/docs/04_upgrading/1.2-to-1.3.md +++ b/docs/04_upgrading/1.2-to-1.3.md @@ -210,7 +210,7 @@ For an example contract of ABI generation see the file ./examples/abigen_test/te ## Fixing an ABI or Writing an ABI Manually - The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually. - The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generator's type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer. -- Please refer to [developers.eos.io "How to Write an ABI File"](https://developers.eos.io/eosio-cpp/docs/how-to-write-an-abi) to learn about the different sections of an ABI. +- Read ["How to Write an ABI File"](../06_how-to-guides/05_how-to-write-an-abi-file.md) to learn about the different sections of an ABI. ## Adding Ricardian Contracts and Clauses to ABI - As of EOSIO.CDT v1.4.0, the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause. diff --git a/docs/06_how-to-guides/05_how-to-write-an-abi-file.md b/docs/06_how-to-guides/05_how-to-write-an-abi-file.md new file mode 100644 index 0000000000..cd88c30875 --- /dev/null +++ b/docs/06_how-to-guides/05_how-to-write-an-abi-file.md @@ -0,0 +1,524 @@ +--- +content_title: How to Write an ABI File +--- + + +[[warning]] +| As of v1.2.0, the eosio.wasmsdk was decoupled from the core repository. This change has introduced an eosio-cpp regression where the legacy eosio-abigen is no longer bundled with eosio-cpp. Until a new ABI generator is introduced, you will need to hand-write your ABI files. + +## Introduction +The Application Binary Interface (ABI) is a JSON-based description on how to convert user actions between their JSON and Binary representations. The ABI also describes how to convert the database state to/from JSON. Once you have described your contract via an ABI then developers and users will be able to interact with your contract seamlessly via JSON. + +This tutorial will use the [eosio.token](https://github.com/EOSIO/eosio.contracts/tree/master/eosio.token) contract as an example. *eosio.token contract does not cover every possible permutation of an ABI definition. +## +To make things easy, we will start with an empty ABI. + +```text + +{ + "version": "eosio::abi/1.0", + "types": [], + "structs": [], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "abi_extensions": [], + "___comment" : "" +} +``` + +## Types +An ABI enables any client or interface to interpret and even generate an GUI for you contract. For this to work in a consistent manner, we'll need to describe the custom types that are used as a parameter in any public action or struct that we would like to describe in the ABI. +[[info]] +|Built-in Types +EOSIO implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with EOSIO's built-ins, they are defined [here](https://github.com/EOSIO/eos/blob/master/libraries/chain/abi_serializer.cpp#L65-L103) +Using **eosio.token** as an example, the only type that requires a description in the ABI file is `account_name`. The ABI uses "new_type_name" to describe explicit types, in this case `account_name`, and `account_name` is an alias of `name` type. + +So in the ABI file we'll add the following object + +```json +{ + "new_type_name": "account_name", + "type": "name" + } +``` +Our ABI now looks like this: + +```json +{ + "version": "eosio::abi/1.0", + "types": [{ + "new_type_name": "account_name", + "type": "name" + }], + "structs": [], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "abi_extensions": [] +} +``` + +## Structs +We now need to describe the structs of the token contract. By looking at eosio.token.hpp, we can quickly determine which structs are utilized by public actions. This is particularly important for when we describe our actions in the the ABI file in the next step. + +A struct's object definition in JSON looks like the following: + +```json +{ + "name": "issue", //The name + "base": "", //Inheritance, parent struct + "fields": [] //Array of field objects describing the struct's fields. + } +``` + + +```json +{ + "name":"", // The field's name + "type":"" // The field's type +} +``` +Looking through the `eosio.token` contract, we see a number of structs that require definition. Please note, not all of the structs are explicitly defined, some correspond to an actions' parameters. Here's a list of structs that require an ABI description for the `eosio.token` contract: + +## Implicit Structs + +The following structs are implicit in that a struct was never explicitly defined in the contract. Looking at the [create](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L24) action, you'll find two parameters, `issuer` of type `account_name ` and `maximum_supply` of type `asset`. For brevity this tutorial won't break down every struct, but applying the same logic, you will end up with the following: + +### [create](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L24) + +```json +{ + "name": "create", + "base": "", + "fields": [ + { + "name":"issuer", + "type":"account_name" + }, + { + "name":"maximum_supply", + "type":"asset" + } + ] +} +``` +### [issue](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L27) + +```json +{ + "name": "issue", + "base": "", + "fields": [ + { + "name":"to", + "type":"account_name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [retire](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L29) + +```json +{ + "name": "retire", + "base": "", + "fields": [ + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [transfer](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L31-L34) + +```json +{ + "name": "transfer", + "base": "", + "fields": [ + { + "name":"from", + "type":"account_name" + }, + { + "name":"to", + "type":"account_name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [close](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L36) + +```json +{ + "name": "close", + "base": "", + "fields": [ + { + "name":"owner", + "type":"account_name" + }, + { + "name":"symbol", + "type":"symbol" + } + ] + } +``` +## Explicit Structs +These structs are explicitly defined, as they are a requirement to instantiate a multi-index table. Describing them is no different than defining the implicit structs as demonstrated above. + +### [account](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L43-L47) + +```json +{ + "name": "account", + "base": "", + "fields": [ + { + "name":"balance", + "type":"asset" + } + ] +} +``` +### [currency_stats](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L49-L55) + +```json +{ + "name": "currency_stats", + "base": "", + "fields": [ + { + "name":"supply", + "type":"asset" + }, + { + "name":"max_supply", + "type":"asset" + }, + { + "name":"issuer", + "type":"account_name" + } + ] +} +``` + +## Actions +An action's JSON object definition looks like the following: + +```json +{ + "name": "transfer", //The name of the action as defined in the contract + "type": "transfer", //The name of the implicit struct as described in the ABI + "ricardian_contract": "" //An optional ricardian clause to associate to this action describing its intended functionality. +} +``` +Next, we'll describe the actions of the `eosio.token` contract by aggregating all the public functions describe in the `eosio.token` contract's [header file](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L24-L36). We'll then describe each action's *type* to their previously described struct. In most situations, the function name and the struct name will be equal, but are not required to be equal. + +Below is a list of actions that link to their source code with example JSON provided for how each action would be described. + +## [create](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L24-L25) + +```json +{ + "name": "create", + "type": "create", + "ricardian_contract": "" +} +``` +## [issue](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L27) + +```json +{ + "name": "issue", + "type": "issue", + "ricardian_contract": "" +} +``` +## [retire](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L31-L34) + +```json +{ + "name": "retire", + "type": "retire", + "ricardian_contract": "" +} +``` +## [transfer](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L31-L34) + +```json +{ + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" +} +``` +## [close](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L36) + +```json +{ + "name": "close", + "type": "close", + "ricardian_contract": "" +} +``` +You will notice we previously described all of these in the "structs" array of the ABI definition. +## Tables +Finally, we need to describe our tables. Here's a table's JSON object definition: + +```json +{ + "name": "", //The name of the table, determined during instantiation. + "type": "", //The table's corresponding struct + "index_type": "", //The type of primary index of this table + "key_names" : [], //An array of key names, length must equal length of key_types member + "key_types" : [] //An array of key types that correspond to key names array member, length of array must equal length of key names array. +} +``` +The eosio.token contract instantiates two tables, [accounts](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L57) and [stat](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L58). + +The accounts table is an i64 index, based on the [`account` struct](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L43-L47), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L46) and it's key been arbitrarily named "currency". + +Here's how the accounts table would be described in the ABI + +```text +{ + "name": "accounts", + "type": "account", // Corresponds to previously defined struct + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] +} +``` +The stat table is an i64 index, based on the [`currenct_stats` struct](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L49-L55), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/eosio.token/include/eosio.token/eosio.token.hpp#L54) and it's key been arbitrarily named "currency" + +Here's how the stat table would be described in the ABI + +```text +{ + "name": "stat", + "type": "currency_stats", + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] +} +``` +You'll notice the above tables have the same "key name." Naming your keys similar names is symbolic in that it can potentially suggest a subjective relationship. As with this implementation, implying that any given value can be used to query different tables. +## Putting it all Together +Finally, once all the pieces are strewn together, we have ourselves a ABI file that accurately describes the `eosio.token` contract. + +```json +{ + "version": "eosio::abi/1.0", + "types": [ + { + "new_type_name": "account_name", + "type": "name" + } + ], + "structs": [ + { + "name": "create", + "base": "", + "fields": [ + { + "name":"issuer", + "type":"account_name" + }, + { + "name":"maximum_supply", + "type":"asset" + } + ] + }, + { + "name": "issue", + "base": "", + "fields": [ + { + "name":"to", + "type":"account_name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "retire", + "base": "", + "fields": [ + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "close", + "base": "", + "fields": [ + { + "name":"owner", + "type":"account_name" + }, + { + "name":"symbol", + "type":"symbol" + } + ] + }, + { + "name": "transfer", + "base": "", + "fields": [ + { + "name":"from", + "type":"account_name" + }, + { + "name":"to", + "type":"account_name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "account", + "base": "", + "fields": [ + { + "name":"balance", + "type":"asset" + } + ] + }, + { + "name": "currency_stats", + "base": "", + "fields": [ + { + "name":"supply", + "type":"asset" + }, + { + "name":"max_supply", + "type":"asset" + }, + { + "name":"issuer", + "type":"account_name" + } + ] + } + ], + "actions": [ + { + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" + }, + { + "name": "issue", + "type": "issue", + "ricardian_contract": "" + }, + { + "name": "retire", + "type": "retire", + "ricardian_contract": "" + }, + { + "name": "create", + "type": "create", + "ricardian_contract": "" + }, + { + "name": "close", + "type": "close", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "accounts", + "type": "account", + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] + }, + { + "name": "stat", + "type": "currency_stats", + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] + } + ], + "ricardian_clauses": [], + "abi_extensions": [] +} +``` + +## Cases not Covered by Token Contract +## Vectors +When describing a vector in your ABI file, simply append the type with `[]`, so if you need to describe a vector of permission levels, you would describe it like so: `permission_level[]` + +## Struct Base +It's a rarely used property worth mentioning. You can use **base** ABI struct property to reference another struct for inheritance, as long as that struct is also described in the same ABI file. Base will do nothing or potentially throw an error if your smart contract logic does not support inheritance. + +You can see an example of base in use in the system contract [source code](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/include/eosio.system/eosio.system.hpp#L46) and [ABI](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/abi/eosio.system.abi#L262) +## Extra ABI Properties Not Covered Here +A few properties of the ABI specification were skipped here for brevity, however, there is a pending ABI specification that will outline every property of the ABI in its entirety. + +## Ricardian Clauses +Ricardian clauses describe the intended outcome of a particular actions. It may also be utilized to establish terms between the sender and the contract. + +## ABI Extensions +A generic "future proofing" layer that allows old clients to skip the parsing of "chunks" of extension data. For now, this property is unused. In the future each extension would have its own "chunk" in that vector so that older clients skip it and newer clients that understand how to interpret it. +## Maintenance +Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases failure to update your ABI file will not produce any error. +## Troubleshooting +## Table returns no rows + +Check that your table is accurately described in the <> file. For example, If you use `cleos` to add a table on a contract with a malformed <> definition and then get rows from that table, you will recieve an empty result. `cleos` will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its <> File. From d89d5750609d6fb02236510ae54df5f7a81233f0 Mon Sep 17 00:00:00 2001 From: dskvr Date: Mon, 2 Dec 2019 23:45:14 +0100 Subject: [PATCH 132/659] add docs.json --- docs.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs.json diff --git a/docs.json b/docs.json new file mode 100644 index 0000000000..63282bf690 --- /dev/null +++ b/docs.json @@ -0,0 +1,23 @@ +{ + "name": "eosio.cdt", + "generators": [ + { + "name": "collate_markdown", + "options": { + "docs_dir": "docs" + } + }, + { + "name": "doxygen_to_xml", + "options": { + "INPUT": "libraries/eosiolib", + "EXCLUDE": "libraries/eosiolib/memory.h libraries/eosiolib/memory.hpp libraries/eosiolib/action.h libraries/eosiolib/permission.h libraries/eosiolib/privileged.h libraries/eosiolib/print.h libraries/eosiolib/system.h", + "EXCLUDE_PATTERNS": "*.cpp *.c *.h" + } + }, + { + "name": "doxybook", + "options": {} + } + ] +} From 24ff895dde9715c7c3de7b7468df8fd2da1cbfbf Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 13 Dec 2019 16:00:27 -0500 Subject: [PATCH 133/659] update uint64_t error code ranges --- docs/05_best-practices/07_error_handling.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/05_best-practices/07_error_handling.md b/docs/05_best-practices/07_error_handling.md index 8f323e6e48..cc54a013f6 100644 --- a/docs/05_best-practices/07_error_handling.md +++ b/docs/05_best-practices/07_error_handling.md @@ -2,12 +2,14 @@ content_title: Error handling --- -Contracts are able to use `uint64_t` error codes as an alternative (and cheaper) means of signaling error conditions as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. They assume that the contract develop respects the following restrictions: +Contracts can use `uint64_t` error codes as an alternative (and shorter) means of signaling error conditions, as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. The contract developer must be aware of the following ranges and restrictions: -1. 0 (inclusive) to 5,000,000,000,000,000,000 (exclusive): Available for contract developers to use to signal errors specific to their contracts. +1. 0 to 4,999,999,999,999,999,999: Available for contract developers to assign error codes specific to their contracts. -2. 5,000,000,000,000,000,000 (inclusive) to 8,000,000,000,000,000,000 (exclusive): Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). +2. 5,000,000,000,000,000,000 to 7,999,999,999,999,999,999: Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). -3. 8,000,000,000,000,000,000 (inclusive) to 10,000,000,000,000,000,000 (exclusive): Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. +3. 8,000,000,000,000,000,000 to 9,999,999,999,999,999,999: Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. -4. 10,000,000,000,000,000,000 (inclusive) to 18,446,744,073,709,551,615 (inclusive): Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. \ No newline at end of file +4. 10,000,000,000,000,000,000 to 18,446,744,073,709,551,615: Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. + +Therefore, contract developers should only reserve error codes from the first range above (0 to 4,999,999,999,999,999,999) to use in their contracts. From f3e055ba5922802823abd2a962268dfa6a1441d1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 13 Dec 2019 16:13:28 -0500 Subject: [PATCH 134/659] Add new intrinsic set_action_return_value --- libraries/eosiolib/capi/eosio/action.h | 10 ++++++++++ libraries/eosiolib/contracts/eosio/action.hpp | 15 +++++++++++++++ libraries/native/intrinsics.cpp | 3 +++ libraries/native/native/eosio/intrinsics_def.hpp | 3 ++- tests/unit/test_contracts/capi/action.c | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/capi/eosio/action.h b/libraries/eosiolib/capi/eosio/action.h index 92e82522ba..741c268c95 100644 --- a/libraries/eosiolib/capi/eosio/action.h +++ b/libraries/eosiolib/capi/eosio/action.h @@ -168,6 +168,16 @@ uint64_t publication_time( void ); __attribute__((eosio_wasm_import)) capi_name current_receiver( void ); +/** + * Set the action return value which will be included in the action_receipt + * @brief Set the action return value + * @param return_value - serialized return value + * @param size - size of serialized return value in bytes + * @pre `return_value` is a valid pointer to an array at least `size` bytes long + */ +__attribute__((eosio_wasm_import)) +void set_action_return_value(char *return_value, size_t size); + #ifdef __cplusplus } #endif diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index 85ca78edb4..cd464f619e 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -52,6 +52,9 @@ namespace eosio { __attribute__((eosio_wasm_import)) uint64_t current_receiver(); + + __attribute__((eosio_wasm_import)) + void set_action_return_value(char *return_value, size_t size); } }; @@ -150,6 +153,18 @@ namespace eosio { return name{internal_use_do_not_use::current_receiver()}; } + /** + * Set the action return value which will be included in action_receipt + * @ingroup action + * @tparam T type of return value + * @param v the return value to set + */ + template + inline void set_action_return_value( const T& v ) { + const auto packed_value = pack( v ); + internal_use_do_not_use::set_action_return_value( &packed_value[0], packed_value.size() ); + } + /** * Copy up to length bytes of current action data to the specified location * diff --git a/libraries/native/intrinsics.cpp b/libraries/native/intrinsics.cpp index 2c89196c80..d70bf28a8c 100644 --- a/libraries/native/intrinsics.cpp +++ b/libraries/native/intrinsics.cpp @@ -292,6 +292,9 @@ extern "C" { capi_name current_receiver() { return intrinsics::get().call(); } + void set_action_return_value( char* rv, size_t len ) { + intrinsics::get().call(rv, len); + } void require_recipient( capi_name name ) { return intrinsics::get().call(name); } diff --git a/libraries/native/native/eosio/intrinsics_def.hpp b/libraries/native/native/eosio/intrinsics_def.hpp index 9166d1f2a4..d800111886 100644 --- a/libraries/native/native/eosio/intrinsics_def.hpp +++ b/libraries/native/native/eosio/intrinsics_def.hpp @@ -157,7 +157,8 @@ intrinsic_macro(send_context_free_inline) \ intrinsic_macro(send_deferred) \ intrinsic_macro(cancel_deferred) \ intrinsic_macro(get_context_free_data) \ -intrinsic_macro(get_sender) +intrinsic_macro(get_sender) \ +intrinsic_macro(set_action_return_value) #define CREATE_ENUM(name) \ name, diff --git a/tests/unit/test_contracts/capi/action.c b/tests/unit/test_contracts/capi/action.c index 43fdded202..63824f2bff 100644 --- a/tests/unit/test_contracts/capi/action.c +++ b/tests/unit/test_contracts/capi/action.c @@ -13,4 +13,5 @@ void test_action( void ) { send_context_free_inline(NULL, 0); publication_time(); current_receiver(); + set_action_return_value(NULL, 0); } From 7da6c06bddb82b2db2ce2926fc2df5a4b687eaf3 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Sat, 14 Dec 2019 22:35:02 -0500 Subject: [PATCH 135/659] wrap error code ranges in latex --- docs/05_best-practices/07_error_handling.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/05_best-practices/07_error_handling.md b/docs/05_best-practices/07_error_handling.md index cc54a013f6..549a21ce59 100644 --- a/docs/05_best-practices/07_error_handling.md +++ b/docs/05_best-practices/07_error_handling.md @@ -2,14 +2,18 @@ content_title: Error handling --- -Contracts can use `uint64_t` error codes as an alternative (and shorter) means of signaling error conditions, as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. The contract developer must be aware of the following ranges and restrictions: +Contracts can use `uint64_t` error codes as an alternative (and shorter) means of signaling error conditions, as opposed to string error messages. However, EOSIO and EOSIO.CDT reserve certain ranges of the `uint64_t` value space for their own purposes. Contract developers must be aware of the following ranges and restrictions: -1. 0 to 4,999,999,999,999,999,999: Available for contract developers to assign error codes specific to their contracts. +1. $0 - 4,999,999,999,999,999,999$: +Available for contract developers to assign error codes specific to their contracts. -2. 5,000,000,000,000,000,000 to 7,999,999,999,999,999,999: Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). +2. $5,000,000,000,000,000,000 - 7,999,999,999,999,999,999$: +Reserved for the EOSIO.CDT compiler to allocate as appropriate. Although the WASM code generated by the EOSIO.CDT compiler may use error code values that were automatically generated from within this range, the error codes in this range are meant to have meaning specific to the particular compiled contract (the meaning would typically be conveyed through the mapping between the error code value and strings in the associated generated ABI file). -3. 8,000,000,000,000,000,000 to 9,999,999,999,999,999,999: Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. +3. $8,000,000,000,000,000,000 - 9,999,999,999,999,999,999$: +Reserved for the EOSIO.CDT compiler to allocate as appropriate. The error codes in this range are not specific to any contract but rather are used to convey general runtime error conditions associated with the generated code by EOSIO.CDT. -4. 10,000,000,000,000,000,000 to 18,446,744,073,709,551,615: Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. +4. $10,000,000,000,000,000,000 - 18,446,744,073,709,551,615$: +Reserved for EOSIO to represent system-level error conditions. EOSIO will actually enforce this by restricting the ability for `eosio_assert_code` to be used to fail with error code values used within this range. -Therefore, contract developers should only reserve error codes from the first range above (0 to 4,999,999,999,999,999,999) to use in their contracts. +Therefore, contract developers should only reserve error codes from the first range above to use in their contracts. From 06162dfd5f0eb0bd2f531faf6638d92c41de2430 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Wed, 18 Dec 2019 17:31:09 -0500 Subject: [PATCH 136/659] fix for extended_symbol --- libraries/eosiolib/core/eosio/symbol.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/eosiolib/core/eosio/symbol.hpp b/libraries/eosiolib/core/eosio/symbol.hpp index 631a9272f1..e02c86ad07 100644 --- a/libraries/eosiolib/core/eosio/symbol.hpp +++ b/libraries/eosiolib/core/eosio/symbol.hpp @@ -393,14 +393,14 @@ namespace eosio { * @param sym - The symbol * @param con - The name of the contract */ - constexpr extended_symbol( symbol sym, name con ) : symbol(sym), contract(con) {} + constexpr extended_symbol( symbol s, name con ) : sym(s), contract(con) {} /** * Returns the symbol in the extended_contract * * @return symbol */ - constexpr symbol get_symbol() const { return symbol; } + constexpr symbol get_symbol() const { return sym; } /** * Returns the name of the contract in the extended_symbol @@ -415,7 +415,7 @@ namespace eosio { * @brief %Print the extended symbol */ void print( bool show_precision = true )const { - symbol.print( show_precision ); + sym.print( show_precision ); ::eosio::print("@", contract); } @@ -425,7 +425,7 @@ namespace eosio { * @return boolean - true if both provided extended_symbols are the same */ friend constexpr bool operator == ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) == std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) == std::tie( b.sym, b.contract ); } /** @@ -434,7 +434,7 @@ namespace eosio { * @return boolean - true if both provided extended_symbols are not the same */ friend constexpr bool operator != ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) != std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) != std::tie( b.sym, b.contract ); } /** @@ -443,13 +443,13 @@ namespace eosio { * @return boolean - true if extended_symbol `a` is less than `b` */ friend constexpr bool operator < ( const extended_symbol& a, const extended_symbol& b ) { - return std::tie( a.symbol, a.contract ) < std::tie( b.symbol, b.contract ); + return std::tie( a.sym, a.contract ) < std::tie( b.sym, b.contract ); } private: - symbol symbol; ///< the symbol + symbol sym; ///< the symbol name contract; ///< the token contract hosting the symbol - EOSLIB_SERIALIZE( extended_symbol, (symbol)(contract) ) + EOSLIB_SERIALIZE( extended_symbol, (sym)(contract) ) }; } From aa82f01ea6c3f2fa0280bc4194ffd7d4f719babc Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Thu, 2 Jan 2020 05:37:29 +0000 Subject: [PATCH 137/659] Remove redundant install from CMakeLists.txt --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b84284295..e59580995c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,6 @@ set(CDT_ROOT_DIR ${CDT_INSTALL_PREFIX}) configure_file(${CMAKE_SOURCE_DIR}/modules/eosio.cdt-config.cmake ${CMAKE_BINARY_DIR}/modules/eosio.cdt-config.cmake @ONLY) configure_file(${CMAKE_SOURCE_DIR}/modules/EosioCDTMacros.cmake.in ${CMAKE_BINARY_DIR}/modules/EosioCDTMacros.cmake @ONLY) configure_file(${CMAKE_SOURCE_DIR}/modules/EosioWasmToolchain.cmake.in ${CMAKE_BINARY_DIR}/modules/EosioWasmToolchain.cmake @ONLY) -install(FILES ${CMAKE_BINARY_DIR}/modules/EosioCDTMacros.cmake DESTINATION ${CDT_INSTALL_PREFIX}/lib/cmake/eosio.cdt) set(CDT_ROOT_DIR "_PREFIX_") configure_file(${CMAKE_SOURCE_DIR}/modules/EosioCDTMacros.cmake.in ${CMAKE_BINARY_DIR}/modules/EosioCDTMacrosPackage.cmake @ONLY) From 0ba0eb7a9966de158b94abd5c23f8426fdcc6184 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 3 Jan 2020 14:07:59 -0500 Subject: [PATCH 138/659] don't use a const vector<> for action return value pack() The CAPI for action return value takes a non-const char*, so it's a compile error to pass a const char* from a const vector<> here --- libraries/eosiolib/contracts/eosio/action.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index cd464f619e..44d81e233d 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -161,7 +161,7 @@ namespace eosio { */ template inline void set_action_return_value( const T& v ) { - const auto packed_value = pack( v ); + auto packed_value = pack( v ); internal_use_do_not_use::set_action_return_value( &packed_value[0], packed_value.size() ); } From 7c70c0e528db5a100ce82cd371aa712c53da48aa Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 9 Jan 2020 10:49:00 -0500 Subject: [PATCH 139/659] Fix integration test hierarchy. --- tests/integration/CMakeLists.txt | 17 ++++++++++++++++- tests/integration/capi_tests.cpp | 4 +++- tests/integration/codegen_tests.cpp | 4 +++- tests/integration/memory_tests.cpp | 4 +++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index cdee032ff8..ca553d507b 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -30,4 +30,19 @@ include_directories(${CMAKE_BINARY_DIR}) file(GLOB INT_TESTS "*.cpp" "*.hpp") -add_eosio_test( integration_tests ${INT_TESTS} ) +add_eosio_test_executable( integration_tests ${INT_TESTS} ) + +foreach(TEST_SUITE ${INT_TESTS}) # create an independent target for each test suite + execute_process(COMMAND bash -c "grep -E 'BOOST_AUTO_TEST_SUITE\\s*[(]' ${TEST_SUITE} | grep -vE '//.*BOOST_AUTO_TEST_SUITE\\s*[(]' | cut -d ')' -f 1 | cut -d '(' -f 2" OUTPUT_VARIABLE SUITE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE) # get the test suite name from the *.cpp file + if (NOT "" STREQUAL "${SUITE_NAME}") # ignore empty lines + execute_process(COMMAND bash -c "echo ${SUITE_NAME} | sed -e 's/s$//' | sed -e 's/_test$//'" OUTPUT_VARIABLE TRIMMED_SUITE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE) # trim "_test" or "_tests" from the end of ${SUITE_NAME} + # to run unit_test with all log from blockchain displayed, put "--verbose" after "--", i.e. "unit_test -- --verbose" + add_test(NAME ${TRIMMED_SUITE_NAME}_integration_test COMMAND integration_tests --run_test=${SUITE_NAME} --report_level=detailed --color_output) + # build list of tests to run during coverage testing + if(ctest_tests) + string(APPEND ctest_tests "|") + endif() + string(APPEND ctest_tests ${TRIMMED_SUITE_NAME}_unit_test_$RUNTIME) + endif() +endforeach(TEST_SUITE) +set(ctest_tests "'${ctest_tests}' -j8") # surround test list string in apostrophies diff --git a/tests/integration/capi_tests.cpp b/tests/integration/capi_tests.cpp index 3efd52cf28..632042352b 100644 --- a/tests/integration/capi_tests.cpp +++ b/tests/integration/capi_tests.cpp @@ -26,4 +26,6 @@ BOOST_FIXTURE_TEST_CASE( capi_tests, tester ) try { produce_blocks(); push_action(N(test), N(act), N(test), {}); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/codegen_tests.cpp b/tests/integration/codegen_tests.cpp index 118c6aa924..6591306fa4 100644 --- a/tests/integration/codegen_tests.cpp +++ b/tests/integration/codegen_tests.cpp @@ -92,4 +92,6 @@ BOOST_FIXTURE_TEST_CASE( simple_eosio_tests, tester ) try { ("arg0", 33) ("arg1", "some string")); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/memory_tests.cpp b/tests/integration/memory_tests.cpp index ec8acb0953..cb25067173 100644 --- a/tests/integration/memory_tests.cpp +++ b/tests/integration/memory_tests.cpp @@ -30,4 +30,6 @@ BOOST_FIXTURE_TEST_CASE( malloc_tests, tester ) try { BOOST_CHECK_EXCEPTION( push_action(N(test), N(mallocfail), N(test), {}), eosio_assert_message_exception, eosio_assert_message_is("failed to allocate pages") ); -} FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() From 0fe369e3d4e02f0e4928b75bb95c6122f4f1eb29 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 9 Jan 2020 10:59:51 -0500 Subject: [PATCH 140/659] Fix copy pasta --- tests/integration/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index ca553d507b..816b4ad62b 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -42,7 +42,7 @@ foreach(TEST_SUITE ${INT_TESTS}) # create an independent target for each test su if(ctest_tests) string(APPEND ctest_tests "|") endif() - string(APPEND ctest_tests ${TRIMMED_SUITE_NAME}_unit_test_$RUNTIME) + string(APPEND ctest_tests ${TRIMMED_SUITE_NAME}_integration_test) endif() endforeach(TEST_SUITE) set(ctest_tests "'${ctest_tests}' -j8") # surround test list string in apostrophies From 249fecadc4ce67959b690ff56ddd4c18539519a3 Mon Sep 17 00:00:00 2001 From: johndebord Date: Thu, 9 Jan 2020 13:54:18 -0500 Subject: [PATCH 141/659] Allow interoperability between `binary_extension` and types with only an explicit default constructor --- libraries/eosiolib/core/eosio/binary_extension.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/core/eosio/binary_extension.hpp b/libraries/eosiolib/core/eosio/binary_extension.hpp index d44ed3276a..2cb2813952 100644 --- a/libraries/eosiolib/core/eosio/binary_extension.hpp +++ b/libraries/eosiolib/core/eosio/binary_extension.hpp @@ -103,12 +103,12 @@ namespace eosio { } constexpr T value_or()& { if (!_has_value) - return {}; + return T{}; return _get(); } constexpr T value_or()const& { if (!_has_value) - return {}; + return T{}; return _get(); } From 38b5285fe0c21051363cddc507888c6cced09499 Mon Sep 17 00:00:00 2001 From: John DeBord Date: Thu, 9 Jan 2020 15:41:44 -0500 Subject: [PATCH 142/659] Switch brackets to parenthesis --- libraries/eosiolib/core/eosio/binary_extension.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/core/eosio/binary_extension.hpp b/libraries/eosiolib/core/eosio/binary_extension.hpp index 2cb2813952..ac59569e43 100644 --- a/libraries/eosiolib/core/eosio/binary_extension.hpp +++ b/libraries/eosiolib/core/eosio/binary_extension.hpp @@ -103,12 +103,12 @@ namespace eosio { } constexpr T value_or()& { if (!_has_value) - return T{}; + return T(); return _get(); } constexpr T value_or()const& { if (!_has_value) - return T{}; + return T(); return _get(); } From bd8b80c5f667685ec9d4b2ef59be774644754815 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 10 Jan 2020 09:33:08 -0500 Subject: [PATCH 143/659] Fix extra spaces in options for wasm-ql --- tools/include/compiler_options.hpp.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 873be56bbb..25a4630581 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -444,16 +444,16 @@ static void GetLdDefaults(std::vector& ldopts) { ldopts.insert(ldopts.end(), { "--only-export", "main:function" } ); } else { - ldopts.insert(ldopts.end(), { "-e", "initialize " } ); + ldopts.insert(ldopts.end(), { "-e", "initialize" } ); ldopts.insert(ldopts.end(), { "--only-export", "initialize:function" } ); } if (fquery_server_opt) - ldopts.insert(ldopts.end(), { "-export", "run_query " }); + ldopts.insert(ldopts.end(), { "-export", "run_query" }); else { - ldopts.insert(ldopts.end(), { "-export", "create_query_request " }); - ldopts.insert(ldopts.end(), { "-export", "decode_query_response " }); - ldopts.insert(ldopts.end(), { "-export", "describe_query_request " }); - ldopts.insert(ldopts.end(), { "-export", "describe_query_response " }); + ldopts.insert(ldopts.end(), { "-export", "create_query_request" }); + ldopts.insert(ldopts.end(), { "-export", "decode_query_response" }); + ldopts.insert(ldopts.end(), { "-export", "describe_query_request" }); + ldopts.insert(ldopts.end(), { "-export", "describe_query_response" }); } if (fquery_server_opt) ldopts.insert(ldopts.end(), { "--only-export", "run_query:function" }); From 15b83b7b8d06ab08c2f42a94d6fa9e20df5a7acd Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 9 Jan 2020 19:16:21 -0500 Subject: [PATCH 144/659] added macros --- modules/ToolsExternalProject.txt | 2 +- tools/include/compiler_options.hpp.in | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index 7bb6ccab41..de3bcfdf2f 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_PATCH=${VERSION_PATCH} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 873be56bbb..7cd3a32310 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -369,6 +369,11 @@ struct Options { static void GetCompDefaults(std::vector& copts) { const char* eosio_apply_suff = "${CMAKE_SHARED_LIBRARY_SUFFIX}"; std::string apply_lib; + // add the define for whether this is compiling with CDT and version macros + copts.emplace_back("-D__eosio_cdt__"); + copts.emplace_back(std::string("-D__eosio_cdt_major__=")+"${VERSION_MAJOR}"); + copts.emplace_back(std::string("-D__eosio_cdt_minor__=")+"${VERSION_MINOR}"); + copts.emplace_back(std::string("-D__eosio_cdt_patchlevel__=")+"${VERSION_PATCH}"); if (!fnative_opt) { copts.emplace_back("--target=wasm32"); copts.emplace_back("-ffreestanding"); @@ -387,6 +392,7 @@ static void GetCompDefaults(std::vector& copts) { if (!fasm_opt) { copts.emplace_back("-fno-builtin"); copts.emplace_back("-mstackrealign"); + copts.emplace_back("-D__eosio_cdt_native__"); copts.emplace_back("-DEOSIO_NATIVE"); copts.emplace_back("-DLLP64"); } From 299d6c452c8b90c7960bc060258720a9d3777529 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 10 Jan 2020 11:14:12 -0500 Subject: [PATCH 145/659] Propagate CMAKE_CXX_COMPILER to "external" projects so it isn't just ignored. --- modules/ClangExternalProject.txt | 2 +- modules/TestsExternalProject.txt | 2 +- modules/ToolsExternalProject.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ClangExternalProject.txt b/modules/ClangExternalProject.txt index eef039d957..bae1364483 100644 --- a/modules/ClangExternalProject.txt +++ b/modules/ClangExternalProject.txt @@ -4,7 +4,7 @@ include(GNUInstallDirs) ExternalProject_Add( EosioClang - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools SOURCE_DIR "${CMAKE_SOURCE_DIR}/eosio_llvm" BINARY_DIR "${CMAKE_BINARY_DIR}/eosio_llvm" diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index b82ed22b60..f7bdcc9639 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -34,7 +34,7 @@ if (EOSIO_RUN_INTEGRATION_TESTS) EosioIntegrationTests SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/integration" BINARY_DIR "${CMAKE_BINARY_DIR}/tests/integration" - CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT} + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index 7bb6ccab41..cb87f438d4 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" From 0d0ff9ec1a60fae787165074ebb128e1741cb75f Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 10 Jan 2020 11:27:58 -0500 Subject: [PATCH 146/659] CMAKE_C_COMPILER too. --- modules/ClangExternalProject.txt | 2 +- modules/TestsExternalProject.txt | 2 +- modules/ToolsExternalProject.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ClangExternalProject.txt b/modules/ClangExternalProject.txt index bae1364483..f3d0cd01f1 100644 --- a/modules/ClangExternalProject.txt +++ b/modules/ClangExternalProject.txt @@ -4,7 +4,7 @@ include(GNUInstallDirs) ExternalProject_Add( EosioClang - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools SOURCE_DIR "${CMAKE_SOURCE_DIR}/eosio_llvm" BINARY_DIR "${CMAKE_BINARY_DIR}/eosio_llvm" diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index f7bdcc9639..c33d1b6e8f 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -34,7 +34,7 @@ if (EOSIO_RUN_INTEGRATION_TESTS) EosioIntegrationTests SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/integration" BINARY_DIR "${CMAKE_BINARY_DIR}/tests/integration" - CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT} + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index cb87f438d4..a22b53bb5e 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=Release -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" From 09d5953997ad4558ee41cdbd1604e89be88f068e Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Mon, 20 Jan 2020 21:40:41 -0500 Subject: [PATCH 147/659] [Develop] Switching to using the EOSIO fork of anka-buildkite-plugin for security reasonsDevelop use forked anka plugin (#789) * EOSIO/anka for anka plugin now that we have approval to manage a fork in EOSIO * remove file --- .cicd/pipeline.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 720db4e061..c1c7c09df7 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -55,8 +55,9 @@ steps: - "cd eosio.cdt && ./.cicd/build.sh" - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" plugins: - - chef/anka#v0.5.1: + - EOSIO/anka#v0.5.7: no-volume: true + pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -124,8 +125,9 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/tests.sh" plugins: - - chef/anka#v0.5.1: + - EOSIO/anka#v0.5.7: no-volume: true + pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -191,8 +193,9 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/toolchain-tests.sh" plugins: - - chef/anka#v0.5.1: + - EOSIO/anka#v0.5.7: no-volume: true + pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -257,8 +260,9 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/package.sh" plugins: - - chef/anka#v0.5.1: + - EOSIO/anka#v0.5.7: no-volume: true + pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" From f0d5c07d2951a6697b92f4d604ee6c4ee22d8720 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 23 Jan 2020 16:22:38 -0500 Subject: [PATCH 148/659] fixed issue with copy assignment and move assignment --- .../eosiolib/core/eosio/binary_extension.hpp | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/core/eosio/binary_extension.hpp b/libraries/eosiolib/core/eosio/binary_extension.hpp index ac59569e43..5ddd687cc4 100644 --- a/libraries/eosiolib/core/eosio/binary_extension.hpp +++ b/libraries/eosiolib/core/eosio/binary_extension.hpp @@ -40,8 +40,6 @@ namespace eosio { ::new (&_data) T(std::forward(args)...); } - ~binary_extension() { reset(); } - constexpr binary_extension( const binary_extension& other ) :_has_value(other._has_value) { @@ -57,6 +55,32 @@ namespace eosio { } } + /// @cond INTERNAL + ~binary_extension() { reset(); } + + /// @cond INTERNAL + constexpr binary_extension& operator = (const binary_extension& other) { + if (has_value()) + reset(); + + if (other.has_value()) { + ::new (&_data) T(*other); + _has_value = true; + } + return *this; + } + + /// @cond INTERNAL + constexpr binary_extension& operator = (binary_extension&& other) { + if (has_value()) + reset(); + + if (other.has_value()) { + ::new (&_data) T(*other); + _has_value = true; + other._has_value = false; + } + } /** test if container is holding a value */ constexpr explicit operator bool()const { return _has_value; } /** test if container is holding a value */ From f344026681da23bddbfc7902798068968fd9e7dc Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 23 Jan 2020 19:05:41 -0500 Subject: [PATCH 149/659] added tests --- tests/unit/binary_extension_tests.cpp | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/unit/binary_extension_tests.cpp b/tests/unit/binary_extension_tests.cpp index 9d4ffc0a30..0fb3ac8d49 100644 --- a/tests/unit/binary_extension_tests.cpp +++ b/tests/unit/binary_extension_tests.cpp @@ -5,6 +5,7 @@ #include #include +#include using std::in_place; using std::move; @@ -219,6 +220,40 @@ EOSIO_TEST_BEGIN(binary_extension_test) CHECK_EQUAL( be_str_reset.has_value(), true ) be_str_reset.reset(); CHECK_EQUAL( be_str_reset.has_value(), false ) + +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(binary_extension_assignment_test) + // Regression for PR #792 + { + binary_extension be('a'); + binary_extension be_copy(be); + binary_extension be_copy_assign = be; + + CHECK_EQUAL(be.has_value(), true); + CHECK_EQUAL(be.value(), 'a'); + + CHECK_EQUAL(be_copy.has_value(), true); + CHECK_EQUAL(be.value(), be_copy.value()); + + CHECK_EQUAL(be_copy_assign.has_value(), true); + CHECK_EQUAL(be.value(), be_copy_assign.value()); + + binary_extension be2('a'); + binary_extension be_move(std::move(be)); + + CHECK_EQUAL(be2.has_value(), true); + CHECK_EQUAL(be.has_value(), false); + CHECK_EQUAL(be2.value(), be_move.value()); + + binary_extension be3('a'); + binary_extension be_move_assign = std::move(be2); + + CHECK_EQUAL(be3.has_value(), true); + CHECK_EQUAL(be2.has_value(), false); + CHECK_EQUAL(be3.value(), be_move_assign.value()); + } + EOSIO_TEST_END int main(int argc, char* argv[]) { @@ -229,5 +264,6 @@ int main(int argc, char* argv[]) { silence_output(!verbose); EOSIO_TEST(binary_extension_test); + EOSIO_TEST(binary_extension_assignment_test); return has_failed(); } From 08e1b6c131496586547adec4acd2576b56376126 Mon Sep 17 00:00:00 2001 From: johndebord Date: Fri, 24 Jan 2020 11:23:46 -0500 Subject: [PATCH 150/659] Patch bin ext assignment operator to `return *this` --- libraries/eosiolib/core/eosio/binary_extension.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/eosiolib/core/eosio/binary_extension.hpp b/libraries/eosiolib/core/eosio/binary_extension.hpp index 5ddd687cc4..44b51af222 100644 --- a/libraries/eosiolib/core/eosio/binary_extension.hpp +++ b/libraries/eosiolib/core/eosio/binary_extension.hpp @@ -80,6 +80,7 @@ namespace eosio { _has_value = true; other._has_value = false; } + return *this; } /** test if container is holding a value */ constexpr explicit operator bool()const { return _has_value; } From 3e4322e4dc160ed07bcda43f0bc4ad8ddae45c83 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 3 Dec 2019 11:16:48 -0500 Subject: [PATCH 151/659] gitignore vim files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3febf9557f..3e70b2dfa5 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ __pycache__/ # Editor Files .vscode/ +*.vim From 56b7ec761c763590902983fb313652f73450461b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 3 Dec 2019 12:40:18 -0500 Subject: [PATCH 152/659] Key Value Table support for a single (primary) index. --- libraries/eosiolib/contracts/eosio/eosio.hpp | 1 + .../eosiolib/contracts/eosio/key_value.hpp | 458 ++++++++++++++++++ 2 files changed, 459 insertions(+) create mode 100644 libraries/eosiolib/contracts/eosio/key_value.hpp diff --git a/libraries/eosiolib/contracts/eosio/eosio.hpp b/libraries/eosiolib/contracts/eosio/eosio.hpp index 1208ffd5e1..b4fcca066b 100644 --- a/libraries/eosiolib/contracts/eosio/eosio.hpp +++ b/libraries/eosiolib/contracts/eosio/eosio.hpp @@ -5,6 +5,7 @@ #pragma once #include "action.hpp" #include "../../core/eosio/print.hpp" +#include "key_value.hpp" #include "multi_index.hpp" #include "dispatcher.hpp" #include "contract.hpp" diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp new file mode 100644 index 0000000000..943ecd62b0 --- /dev/null +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -0,0 +1,458 @@ +#pragma once +#include "../../core/eosio/datastream.hpp" +#include "../../core/eosio/name.hpp" +#include "../../core/eosio/print.hpp" + +#include + +namespace eosio { + namespace internal_use_do_not_use { + extern "C" { + __attribute__((eosio_wasm_import)) + void kv_erase(uint64_t db, uint64_t contract, const char* key, uint32_t key_size); + + __attribute__((eosio_wasm_import)) + void kv_set(uint64_t db, uint64_t contract, const char* key, uint32_t key_size, const char* value, uint32_t value_size); + + __attribute__((eosio_wasm_import)) + bool kv_get(uint64_t db, uint64_t contract, const char* key, uint32_t key_size, uint32_t& value_size); + + __attribute__((eosio_wasm_import)) + uint32_t kv_get_data(uint64_t db, uint32_t offset, char* data, uint32_t data_size); + + __attribute__((eosio_wasm_import)) + uint32_t kv_it_create(uint64_t db, uint64_t contract, const char* prefix, uint32_t size); + + __attribute__((eosio_wasm_import)) + void kv_it_destroy(uint32_t itr); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_status(uint32_t itr); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_compare(uint32_t itr_a, uint32_t itr_b); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_key_compare(uint32_t itr, const char* key, uint32_t size); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_move_to_end(uint32_t itr); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_next(uint32_t itr); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_prev(uint32_t itr); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_lower_bound(uint32_t itr, const char* key, uint32_t size); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_key(uint32_t itr, uint32_t offset, char* dest, uint32_t size, uint32_t& actual_size); + + __attribute__((eosio_wasm_import)) + int32_t kv_it_value(uint32_t itr, uint32_t offset, char* dest, uint32_t size, uint32_t& actual_size); + } + } + +using key_type = std::pair; + +template +class kv_table { + constexpr static size_t max_stack_buffer_size = 512; + constexpr static uint64_t db = eosio::name{"eosio.kvram"}.value; + + enum class kv_it_stat { + iterator_ok = 0, // Iterator is positioned at a key-value pair + iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased + iterator_end = -2, // Iterator is out-of-bounds + }; + + struct iterator { + uint32_t itr; + kv_it_stat itr_stat; + + size_t data_size; + + iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat): contract_name{contract_name}, itr{itr}, itr_stat{itr_stat} {} + iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size): contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size} {} + + const T value() { + #if 0 + uint32_t actual_size; + uint32_t offset = 0; // TODO: How to use offset/is it needed? + + // TODO + key_type _key = key(); + size_t key_size = pack_size(_key); + void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); + datastream key_ds((char*)key_buffer, key_size); + key_ds << _key; + // TODO + + uint32_t value_size; + internal_use_do_not_use::kv_get(db, contract_name.value, (const char*)key_buffer, key_size, value_size); + + size_t data_size = size_t(value_size); + #endif + uint32_t actual_size; + uint32_t offset = 0; // TODO: How to use offset/is it needed? + + void* buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); + eosio::print_f("data_size %\n", data_size); + internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, data_size, actual_size); + datastream ds((char*)buffer, actual_size); + + T val; + ds >> val; + + /*if (max_stack_buffer_size < key_size) { + free(key_buffer); + }*/ + + if (max_stack_buffer_size < data_size) { + free(buffer); + } + return val; + } + + const key_type key() { + #if 0 + uint32_t copy_size; + + size_t key_size = sizeof(K); + void* buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); + internal_use_do_not_use::kv_it_key(itr, 0, (char*)buffer, key_size, copy_size); + + datastream ds((char*)buffer, copy_size); + + K key; + ds >> key; + + if (max_stack_buffer_size < key_size) { + free(buffer); + } + #endif + + auto key = std::make_pair(size_t(0), ""); + + return key; + } + + + iterator& operator++() { + eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); + itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); + return *this; + } + + iterator operator++(int) { + iterator copy(*this); + ++(*this); + return copy; + } + + iterator& operator--() { + itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); + eosio::check(itr_stat != kv_it_stat::iterator_end, "incremented past the beginning"); + return *this; + } + + iterator operator--(int) { + iterator copy(*this); + --(*this); + return copy; + } + + bool operator==(iterator b) { + if (itr_stat == kv_it_stat::iterator_end) { + return b.itr_stat == kv_it_stat::iterator_end; + } + if (b.itr_stat == kv_it_stat::iterator_end) { + return false; + } + return key() == b.key(); + } + + bool operator!=(iterator b) { + if (itr_stat == kv_it_stat::iterator_end) { + return b.itr_stat != kv_it_stat::iterator_end; + } + if (b.itr_stat == kv_it_stat::iterator_end) { + return true; + } + return key() != b.key(); + } + + private: + eosio::name contract_name; + }; + +public: + struct index { + eosio::name name; + key_type (T::*key_function)() const; + + eosio::name contract_name; + + index() = default; + + index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} + + template + iterator find(K key) { + uint32_t value_size; + + #if 0 + // size_t key_size = pack_size(key); + // void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); + // datastream key_ds((char*)key_buffer, key_size); + // key_ds << key; + #endif + eosio::print_f("\nfind: %\n", key); + auto [key_size, _key] = make_key(key); + eosio::print_f("key_size: %\n", key_size); + eosio::print_f("key: "); + eosio::printhex(_key.data(), key_size); + eosio::print_f("\n"); + + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (char*)_key.data(), key_size, value_size); + if (!success) { + eosio::print_f(" returning end??\n"); + return end(); + } + + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); + + kv_it_stat itr_stat = static_cast(internal_use_do_not_use::kv_it_lower_bound(itr, (const char*) _key.data(), key_size)); + auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, (const char*)_key.data(), key_size); + + /*if (max_stack_buffer_size < key_size) { + free(key_buffer); + }*/ + + eosio::check(cmp == 0, "This key does not exist in this iterator"); + + eosio::print_f("value_size %\n", value_size); + + return {contract_name, itr, itr_stat, value_size}; + } + + /* + void erase(K key) { + size_t key_size = pack_size(key); + void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); + datastream key_ds((char*)key_buffer, key_size); + key_ds << key; + + eosio::check(find(key) != end(), "cannot erase key that does not exist"); + + internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)key_buffer, key_size); + + if (max_stack_buffer_size < key_size) { + free(key_buffer); + } + } + */ + + iterator end() { + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); + int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); + + return {contract_name, itr, static_cast(itr_stat)}; + } + + iterator begin() { + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); + + return {contract_name, itr, static_cast(itr_stat)}; + } + + std::vector range(key_type b, key_type e) { + if (b == e) { + std::vector t; + t.push_back(find(b).value()); + return t; + } + auto begin_itr = find(b); + auto end_itr = find(e); + eosio::check(begin_itr != end(), "beginning of range is not in table"); + eosio::check(end_itr != end(), "end of range is not in table"); + + std::vector return_values; + + return_values.push_back(begin_itr.value()); + + iterator itr = begin_itr; + while(itr != end_itr){ + itr++; + return_values.push_back(itr.value()); + } + + return return_values; + } + + key_type get_key(T& t) { + return (t.*key_function)(); + } + }; + + kv_table() = default; + + template + void setup_indices(I index, Indices... indices) { + secondary_indices.push_back(index); + setup_indices(indices...); + } + + template + void setup_indices(I index) { + secondary_indices.push_back(index); + } + + template + void init(eosio::name contract, eosio::name table, index* primary, Indices... indices) { + contract_name = contract; + table_name = table; + + primary_index = primary; + primary_index->contract_name = contract; + setup_indices(indices...); + } + + void upsert(T value) { + auto [key_size, key] = value.primary_key(); + + eosio::print_f("upsert: %\n", value.n1); + eosio::print_f("key_size: %\n", key_size); + eosio::print_f("key: "); + eosio::printhex(key.data(), key_size); + eosio::print_f("\n"); + + size_t data_size = pack_size(value); + void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); + datastream data_ds((char*)data_buffer, data_size); + data_ds << value; + + internal_use_do_not_use::kv_set(db, contract_name.value, (const char*)key.data(), key_size, (const char*)data_buffer, data_size); + + for (auto& idx : secondary_indices) { + auto [skey_size, skey] = idx->get_key(value); + eosio::print_f(" skey_size: %\n", skey_size); + eosio::print_f(" skey: "); + eosio::printhex(skey.data(), skey_size); + eosio::print_f("\n"); + + internal_use_do_not_use::kv_set(db, contract_name.value, (const char*)skey.data(), skey_size, (const char*)key.data(), key_size); + } + + if (max_stack_buffer_size < data_size) { + free(data_buffer); + } + } + + template + void erase(K key) { + size_t key_size = pack_size(key); + void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); + datastream key_ds((char*)key_buffer, key_size); + key_ds << key; + + internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)key_buffer, key_size); + + /* TODO: + * Loop through all of the indexes + * delete with secondary index keys + * (may need to get struct first to use key methods) + */ + + if (max_stack_buffer_size < key_size) { + free(key_buffer); + } + } + + +private: + eosio::name contract_name; + eosio::name table_name; + + index* primary_index; + std::vector secondary_indices; +}; + + +/* +Key transformations +The key-value store could provide a lexicographical ordering of uint8_t on the keys. The contract can create an ordering on top by transforming its keys. Example transforms: + + uint?_t: Convert to big-endian + int?_t: Invert the MSB then convert to big-endian + strings: Convert 0x00 to (0x00, 0x01). Append (0x00, 0x00) to the end. This transform allows arbitrary-length strings. + case-insensitive strings: Convert to upper-case, then apply the above transform. Assumes ASCII. + floating-point: + There's some bit manipulations, followed by an endian conversion + limitations: + Positive 0 and Negative 0 map to the same value + NaN's and inf's end up with an unusual ordering + struct or tuple: transform each field in order. Concatenate results. +*/ +template +T swap_endian(T u) { + static_assert (CHAR_BIT == 8, "CHAR_BIT != 8"); + + union + { + T u; + unsigned char u8[sizeof(T)]; + } source, dest; + + source.u = u; + + for (size_t k = 0; k < sizeof(T); k++) + dest.u8[k] = source.u8[sizeof(T) - k - 1]; + + return dest.u; +} + +template +key_type make_key(T t, Ts... ts) { + auto A = make_key(t); + auto B = make_key(ts...); + return {0, ""}; +} +template<> +key_type make_key(std::string str) { + constexpr static size_t max_stack_buffer_size = 512; + size_t data_size = pack_size(str) + 3; + void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); + datastream data_ds((char*)data_buffer, data_size); + data_ds << str; + ((char*)data_buffer)[data_size - 3] = 0x01; + ((char*)data_buffer)[data_size - 2] = 0x00; + ((char*)data_buffer)[data_size - 1] = 0x00; + std::string s{(char*)data_buffer}; + if (max_stack_buffer_size < data_size) { + free(data_buffer); + } + return {data_size, s}; +} +template<> +key_type make_key(eosio::name n) { + constexpr static size_t max_stack_buffer_size = 512; + auto big_endian = swap_endian(n.value); + + size_t data_size = pack_size(big_endian); + void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); + datastream data_ds((char*)data_buffer, data_size); + data_ds << big_endian; + + std::string s{(char*)data_buffer}; + if (max_stack_buffer_size < data_size) { + free(data_buffer); + } + return {data_size, s}; +} + + +} // eosio From fa5f0d4c6a5402292b6b0a6c2eb88575d96e1074 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 12 Dec 2019 17:03:53 -0500 Subject: [PATCH 153/659] Key Value Table support for multiple indices. --- .../eosiolib/contracts/eosio/key_value.hpp | 578 ++++++++++-------- 1 file changed, 314 insertions(+), 264 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 943ecd62b0..571ad60179 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -3,6 +3,8 @@ #include "../../core/eosio/name.hpp" #include "../../core/eosio/print.hpp" +#include +#include #include namespace eosio { @@ -55,146 +57,290 @@ namespace eosio { } } -using key_type = std::pair; +struct key_type { + size_t size; + std::string buffer; -template -class kv_table { + bool operator==(key_type k){ + return size == k.size && buffer == k.buffer; + } + bool operator!=(key_type k){ + return !(size == k.size && buffer == k.buffer); + } +}; + +namespace _key_value_detail { constexpr static size_t max_stack_buffer_size = 512; - constexpr static uint64_t db = eosio::name{"eosio.kvram"}.value; +} - enum class kv_it_stat { - iterator_ok = 0, // Iterator is positioned at a key-value pair - iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased - iterator_end = -2, // Iterator is out-of-bounds - }; +/* +Key transformations +The key-value store could provide a lexicographical ordering of uint8_t on the keys. The contract can create an ordering on top by transforming its keys. Example transforms: + + [x] - uint?_t: Convert to big-endian + [x] - int?_t: Invert the MSB then convert to big-endian + [x] - strings: Convert 0x00 to (0x00, 0x01). Append (0x00, 0x00) to the end. This transform allows arbitrary-length strings. + [x] - case-insensitive strings: Convert to upper-case, then apply the above transform. Assumes ASCII. + [ ] - floating-point: + There's some bit manipulations, followed by an endian conversion + limitations: + Positive 0 and Negative 0 map to the same value + NaN's and inf's end up with an unusual ordering + [ ] - struct or tuple: transform each field in order. Concatenate results. (use tuples for composite keys) +*/ - struct iterator { - uint32_t itr; - kv_it_stat itr_stat; +template +inline T swap_endian(T u) { + static_assert (CHAR_BIT == 8, "CHAR_BIT != 8"); + + union + { + T u; + unsigned char u8[sizeof(T)]; + } source, dest; - size_t data_size; + source.u = u; - iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat): contract_name{contract_name}, itr{itr}, itr_stat{itr_stat} {} - iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size): contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size} {} + for (size_t k = 0; k < sizeof(T); k++) { + dest.u8[k] = source.u8[sizeof(T) - k - 1]; + } - const T value() { - #if 0 - uint32_t actual_size; - uint32_t offset = 0; // TODO: How to use offset/is it needed? + return dest.u; +} - // TODO - key_type _key = key(); - size_t key_size = pack_size(_key); - void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); - datastream key_ds((char*)key_buffer, key_size); - key_ds << _key; - // TODO +inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { + using namespace _key_value_detail; - uint32_t value_size; - internal_use_do_not_use::kv_get(db, contract_name.value, (const char*)key_buffer, key_size, value_size); + auto bige_table = swap_endian(table_name.value); + auto bige_index = swap_endian(index_name.value); - size_t data_size = size_t(value_size); - #endif - uint32_t actual_size; - uint32_t offset = 0; // TODO: How to use offset/is it needed? + size_t size_64 = sizeof(index_name); - void* buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); - eosio::print_f("data_size %\n", data_size); - internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, data_size, actual_size); - datastream ds((char*)buffer, actual_size); + size_t buffer_size = (2 * size_64) + sizeof(status); + void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - T val; - ds >> val; + memcpy(buffer, &status, sizeof(status)); + memcpy(((char*)buffer) + sizeof(status), &bige_table, size_64); + memcpy(((char*)buffer) + sizeof(status) + size_64, &bige_index, size_64); - /*if (max_stack_buffer_size < key_size) { - free(key_buffer); - }*/ + std::string s((char*)buffer, buffer_size); - if (max_stack_buffer_size < data_size) { - free(buffer); - } - return val; - } + if (buffer_size > _key_value_detail::max_stack_buffer_size) { + free(buffer); + } - const key_type key() { - #if 0 - uint32_t copy_size; + return {buffer_size, s}; +} - size_t key_size = sizeof(K); - void* buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); - internal_use_do_not_use::kv_it_key(itr, 0, (char*)buffer, key_size, copy_size); +inline key_type table_key(key_type prefix, key_type key) { + using namespace _key_value_detail; - datastream ds((char*)buffer, copy_size); + size_t buffer_size = key.size + prefix.size; + void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - K key; - ds >> key; + memcpy(buffer, prefix.buffer.data(), prefix.size); + memcpy(((char*)buffer) + prefix.size, key.buffer.data(), key.size); - if (max_stack_buffer_size < key_size) { - free(buffer); - } - #endif + std::string s((char*)buffer, buffer_size); - auto key = std::make_pair(size_t(0), ""); + if (buffer_size > _key_value_detail::max_stack_buffer_size) { + free(buffer); + } - return key; - } + return {buffer_size, s}; +} +template +inline I flip_msb(I val) { + constexpr static size_t BITS = sizeof(I) * 8; + return val ^ (static_cast(1) << (BITS - 1)); +} - iterator& operator++() { - eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); - itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); - return *this; - } +template +inline key_type make_key(I val) { + using namespace _key_value_detail; - iterator operator++(int) { - iterator copy(*this); - ++(*this); - return copy; - } + if (std::is_signed::value) { + val = flip_msb(val); + } - iterator& operator--() { - itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); - eosio::check(itr_stat != kv_it_stat::iterator_end, "incremented past the beginning"); - return *this; - } + auto big_endian = swap_endian(val); - iterator operator--(int) { - iterator copy(*this); - --(*this); - return copy; - } + size_t data_size = pack_size(big_endian); + void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - bool operator==(iterator b) { - if (itr_stat == kv_it_stat::iterator_end) { - return b.itr_stat == kv_it_stat::iterator_end; + datastream data_ds((char*)data_buffer, data_size); + data_ds << big_endian; + + std::string s((char*)data_buffer, data_size); + + if (data_size > _key_value_detail::max_stack_buffer_size) { + free(data_buffer); + } + return {data_size, s}; +} + +inline key_type make_key(std::string val, bool case_insensitive=false) { + using namespace _key_value_detail; + + if (case_insensitive) { + std::transform(val.begin(), val.end(), val.begin(), [](unsigned char c) -> unsigned char { return std::toupper(c); }); + } + + size_t data_size = pack_size(val) + 3; + void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + + datastream data_ds((char*)data_buffer, data_size); + data_ds << val; + + ((char*)data_buffer)[data_size - 3] = 0x01; + ((char*)data_buffer)[data_size - 2] = 0x00; + ((char*)data_buffer)[data_size - 1] = 0x00; + + std::string s((char*)data_buffer, data_size); + + if (data_size > _key_value_detail::max_stack_buffer_size) { + free(data_buffer); + } + return {data_size, s}; +} + +inline key_type make_key(const char * str, bool case_insensitive=false) { + return make_key(std::string{str}, case_insensitive); +} + +inline key_type make_key(eosio::name n) { + return make_key(n.value); +} + +template +class kv_table { + + enum class kv_it_stat { + iterator_ok = 0, // Iterator is positioned at a key-value pair + iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased + iterator_end = -2, // Iterator is out-of-bounds + }; + +public: + class index { + class iterator { + public: + iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size, index* idx) : + contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size}, idx{idx} {} + + T value() { + using namespace _key_value_detail; + eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); + eosio::check(data_size > 0, "Cannot read a value of size 0"); + + uint32_t actual_value_size; + uint32_t offset = 0; + + void* buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, data_size, actual_value_size); + + eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); + + if (idx->name == idx->tbl->primary_index->name) { + datastream ds((char*)buffer, actual_value_size); + + T val; + ds >> val; + if (data_size > _key_value_detail::max_stack_buffer_size) { + free(buffer); + } + return val; + } else { + uint32_t actual_data_size; + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (const char*)buffer, actual_value_size, actual_data_size); + eosio::check(success, "failure getting primary key"); + + void* pk_buffer = actual_data_size > _key_value_detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db, 0, (char*)pk_buffer, actual_data_size); + + eosio::check(copy_size > 0, "failure getting primary index data"); + + datastream ds((char*)pk_buffer, copy_size); + + T val; + ds >> val; + + if (actual_data_size > _key_value_detail::max_stack_buffer_size) { + free(pk_buffer); + } + if (data_size > _key_value_detail::max_stack_buffer_size) { + free(buffer); + } + return val; + } } - if (b.itr_stat == kv_it_stat::iterator_end) { - return false; + + iterator& operator++() { + eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); + itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); + return *this; } - return key() == b.key(); - } - bool operator!=(iterator b) { - if (itr_stat == kv_it_stat::iterator_end) { - return b.itr_stat != kv_it_stat::iterator_end; + iterator operator++(int) { + iterator copy(*this); + ++(*this); + return copy; } - if (b.itr_stat == kv_it_stat::iterator_end) { - return true; + + iterator& operator--() { + itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); + eosio::check(itr_stat != kv_it_stat::iterator_end, "incremented past the beginning"); + return *this; + } + + iterator operator--(int) { + iterator copy(*this); + --(*this); + return copy; + } + + bool operator==(iterator b) { + if (itr_stat == kv_it_stat::iterator_end) { + return b.itr_stat == kv_it_stat::iterator_end; + } + if (b.itr_stat == kv_it_stat::iterator_end) { + return false; + } + return key() == b.key(); + } + + bool operator!=(iterator b) { + if (itr_stat == kv_it_stat::iterator_end) { + return b.itr_stat != kv_it_stat::iterator_end; + } + if (b.itr_stat == kv_it_stat::iterator_end) { + return true; + } + return key() != b.key(); } - return key() != b.key(); - } private: - eosio::name contract_name; - }; + eosio::name contract_name; + index* idx; -public: - struct index { - eosio::name name; - key_type (T::*key_function)() const; + size_t data_size; + + uint32_t itr; + kv_it_stat itr_stat; + key_type key() { + return idx->get_key(value()); + } + }; + + public: + eosio::name name; + eosio::name table_name; eosio::name contract_name; + kv_table* tbl; + index() = default; index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} @@ -203,82 +349,65 @@ class kv_table { iterator find(K key) { uint32_t value_size; - #if 0 - // size_t key_size = pack_size(key); - // void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); - // datastream key_ds((char*)key_buffer, key_size); - // key_ds << key; - #endif - eosio::print_f("\nfind: %\n", key); - auto [key_size, _key] = make_key(key); - eosio::print_f("key_size: %\n", key_size); - eosio::print_f("key: "); - eosio::printhex(_key.data(), key_size); - eosio::print_f("\n"); - - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (char*)_key.data(), key_size, value_size); + auto prefix = make_prefix(table_name, name); + auto t_key = table_key(prefix, make_key(key)); + + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.buffer.data(), t_key.size, value_size); if (!success) { - eosio::print_f(" returning end??\n"); return end(); } - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); - - kv_it_stat itr_stat = static_cast(internal_use_do_not_use::kv_it_lower_bound(itr, (const char*) _key.data(), key_size)); - auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, (const char*)_key.data(), key_size); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); - /*if (max_stack_buffer_size < key_size) { - free(key_buffer); - }*/ + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.buffer.data(), t_key.size); + auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.buffer.data(), t_key.size); eosio::check(cmp == 0, "This key does not exist in this iterator"); - eosio::print_f("value_size %\n", value_size); - - return {contract_name, itr, itr_stat, value_size}; + return {contract_name, itr, static_cast(itr_stat), value_size, this}; } - /* - void erase(K key) { - size_t key_size = pack_size(key); - void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); - datastream key_ds((char*)key_buffer, key_size); - key_ds << key; - - eosio::check(find(key) != end(), "cannot erase key that does not exist"); - - internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)key_buffer, key_size); - - if (max_stack_buffer_size < key_size) { - free(key_buffer); - } - } - */ - iterator end() { - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); + auto prefix = make_prefix(table_name, name); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); - return {contract_name, itr, static_cast(itr_stat)}; + return {contract_name, itr, static_cast(itr_stat), 0, this}; } iterator begin() { - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, "", 0); + using namespace _key_value_detail; + + auto prefix = make_prefix(table_name, name); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - return {contract_name, itr, static_cast(itr_stat)}; + uint32_t value_size; + uint64_t buffer_size = 1024*1024; // TODO: + void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); + internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, buffer_size, value_size); + + if (buffer_size > _key_value_detail::max_stack_buffer_size) { + free(buffer); + } + + return {contract_name, itr, static_cast(itr_stat), value_size, this}; } - std::vector range(key_type b, key_type e) { - if (b == e) { + template + std::vector range(K begin, K end) { + eosio::check(begin <= end, "Beginning of range should be less than or equal to end"); + + if (begin == end) { std::vector t; - t.push_back(find(b).value()); + t.push_back(find(begin).value()); return t; } - auto begin_itr = find(b); - auto end_itr = find(e); - eosio::check(begin_itr != end(), "beginning of range is not in table"); - eosio::check(end_itr != end(), "end of range is not in table"); + + auto begin_itr = find(begin); + auto end_itr = find(end); + eosio::check(begin_itr != this->end(), "beginning of range is not in table"); + eosio::check(end_itr != this->end(), "end of range is not in table"); std::vector return_values; @@ -293,21 +422,29 @@ class kv_table { return return_values; } - key_type get_key(T& t) { + key_type get_key(T t) { return (t.*key_function)(); } - }; - kv_table() = default; + private: + key_type (T::*key_function)() const; + }; template void setup_indices(I index, Indices... indices) { + index->contract_name = contract_name; + index->table_name = table_name; + index->tbl = this; + secondary_indices.push_back(index); setup_indices(indices...); } template void setup_indices(I index) { + index->contract_name = contract_name; + index->table_name = table_name; + index->tbl = this; secondary_indices.push_back(index); } @@ -318,61 +455,49 @@ class kv_table { primary_index = primary; primary_index->contract_name = contract; - setup_indices(indices...); + primary_index->table_name = table; + primary_index->tbl = this; + + if constexpr (sizeof...(indices) > 0) { + setup_indices(indices...); + } } void upsert(T value) { - auto [key_size, key] = value.primary_key(); + using namespace _key_value_detail; - eosio::print_f("upsert: %\n", value.n1); - eosio::print_f("key_size: %\n", key_size); - eosio::print_f("key: "); - eosio::printhex(key.data(), key_size); - eosio::print_f("\n"); + auto t_key = table_key(make_prefix(table_name, primary_index->name), value.primary_key()); size_t data_size = pack_size(value); - void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); + void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); datastream data_ds((char*)data_buffer, data_size); data_ds << value; - internal_use_do_not_use::kv_set(db, contract_name.value, (const char*)key.data(), key_size, (const char*)data_buffer, data_size); + internal_use_do_not_use::kv_set(db, contract_name.value, t_key.buffer.data(), t_key.size, (const char*)data_buffer, data_size); for (auto& idx : secondary_indices) { - auto [skey_size, skey] = idx->get_key(value); - eosio::print_f(" skey_size: %\n", skey_size); - eosio::print_f(" skey: "); - eosio::printhex(skey.data(), skey_size); - eosio::print_f("\n"); - - internal_use_do_not_use::kv_set(db, contract_name.value, (const char*)skey.data(), skey_size, (const char*)key.data(), key_size); + auto st_key = table_key(make_prefix(table_name, idx->name), idx->get_key(value)); + internal_use_do_not_use::kv_set(db, contract_name.value, st_key.buffer.data(), st_key.size, t_key.buffer.data(), t_key.size); } - if (max_stack_buffer_size < data_size) { + if (data_size > _key_value_detail::max_stack_buffer_size) { free(data_buffer); } } template void erase(K key) { - size_t key_size = pack_size(key); - void* key_buffer = max_stack_buffer_size < key_size ? malloc(key_size) : alloca(key_size); - datastream key_ds((char*)key_buffer, key_size); - key_ds << key; - - internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)key_buffer, key_size); + T val = primary_index->find(key).value(); - /* TODO: - * Loop through all of the indexes - * delete with secondary index keys - * (may need to get struct first to use key methods) - */ + auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); + internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)k.buffer.data(), k.size); - if (max_stack_buffer_size < key_size) { - free(key_buffer); + for (auto& idx : secondary_indices) { + auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(val)); + internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)skey.buffer.data(), skey.size); } } - private: eosio::name contract_name; eosio::name table_name; @@ -380,79 +505,4 @@ class kv_table { index* primary_index; std::vector secondary_indices; }; - - -/* -Key transformations -The key-value store could provide a lexicographical ordering of uint8_t on the keys. The contract can create an ordering on top by transforming its keys. Example transforms: - - uint?_t: Convert to big-endian - int?_t: Invert the MSB then convert to big-endian - strings: Convert 0x00 to (0x00, 0x01). Append (0x00, 0x00) to the end. This transform allows arbitrary-length strings. - case-insensitive strings: Convert to upper-case, then apply the above transform. Assumes ASCII. - floating-point: - There's some bit manipulations, followed by an endian conversion - limitations: - Positive 0 and Negative 0 map to the same value - NaN's and inf's end up with an unusual ordering - struct or tuple: transform each field in order. Concatenate results. -*/ -template -T swap_endian(T u) { - static_assert (CHAR_BIT == 8, "CHAR_BIT != 8"); - - union - { - T u; - unsigned char u8[sizeof(T)]; - } source, dest; - - source.u = u; - - for (size_t k = 0; k < sizeof(T); k++) - dest.u8[k] = source.u8[sizeof(T) - k - 1]; - - return dest.u; -} - -template -key_type make_key(T t, Ts... ts) { - auto A = make_key(t); - auto B = make_key(ts...); - return {0, ""}; -} -template<> -key_type make_key(std::string str) { - constexpr static size_t max_stack_buffer_size = 512; - size_t data_size = pack_size(str) + 3; - void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); - datastream data_ds((char*)data_buffer, data_size); - data_ds << str; - ((char*)data_buffer)[data_size - 3] = 0x01; - ((char*)data_buffer)[data_size - 2] = 0x00; - ((char*)data_buffer)[data_size - 1] = 0x00; - std::string s{(char*)data_buffer}; - if (max_stack_buffer_size < data_size) { - free(data_buffer); - } - return {data_size, s}; -} -template<> -key_type make_key(eosio::name n) { - constexpr static size_t max_stack_buffer_size = 512; - auto big_endian = swap_endian(n.value); - - size_t data_size = pack_size(big_endian); - void* data_buffer = max_stack_buffer_size < data_size ? malloc(data_size) : alloca(data_size); - datastream data_ds((char*)data_buffer, data_size); - data_ds << big_endian; - - std::string s{(char*)data_buffer}; - if (max_stack_buffer_size < data_size) { - free(data_buffer); - } - return {data_size, s}; -} - - } // eosio From 5f3307b7f38be46da8961efd45a87c380534dce3 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 18 Dec 2019 16:46:43 -0500 Subject: [PATCH 154/659] Add integration tests for kv store --- .../eosiolib/contracts/eosio/key_value.hpp | 1 + tests/integration/contracts.hpp.in | 5 + tests/integration/kv_tests.cpp | 97 +++++++++ tests/unit/test_contracts/CMakeLists.txt | 2 + .../kv_multiple_indices_tests.cpp | 193 ++++++++++++++++++ .../test_contracts/kv_single_index_tests.cpp | 184 +++++++++++++++++ 6 files changed, 482 insertions(+) create mode 100644 tests/integration/kv_tests.cpp create mode 100644 tests/unit/test_contracts/kv_multiple_indices_tests.cpp create mode 100644 tests/unit/test_contracts/kv_single_index_tests.cpp diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 571ad60179..7e17ce14c0 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -231,6 +231,7 @@ class kv_table { T value() { using namespace _key_value_detail; + eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); eosio::check(data_size > 0, "Cannot read a value of size 0"); diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 8d0f140bbc..9bf98f3703 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -19,6 +19,11 @@ struct contracts { static std::vector capi_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.wasm"); } static std::vector capi_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.abi"); } + static std::vector kv_single_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_single_index_tests.wasm"); } + static std::vector kv_single_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_single_index_tests.abi"); } + + static std::vector kv_multi_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_multiple_indices_tests.wasm"); } + static std::vector kv_multi_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_multiple_indices_tests.abi"); } }; }} //ns eosio::testing diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp new file mode 100644 index 0000000000..dac9eb7735 --- /dev/null +++ b/tests/integration/kv_tests.cpp @@ -0,0 +1,97 @@ +#include +#include +#include + +#include + +using namespace eosio; +using namespace eosio::testing; + +BOOST_AUTO_TEST_SUITE(key_value_tests) + +BOOST_FIXTURE_TEST_CASE(single_tests_find, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(find), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(finderror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Cannot read end iterator")); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(single_tests_iteration, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(iteration), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(range), N(kvtest), {}); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Beginning of range should be less than or equal to end")); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(erase), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +// Multi +// ----- +BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(find), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(iteration), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(range), N(kvtest), {}); +} FC_LOG_AND_RETHROW() +} diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index d5582ac3d0..3effd52b87 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -3,6 +3,8 @@ add_contract(malloc_tests old_malloc_tests malloc_tests.cpp) add_contract(simple_tests simple_tests simple_tests.cpp) add_contract(transfer_contract transfer_contract transfer.cpp) add_contract(minimal_tests minimal_tests minimal_tests.cpp) +add_contract(kv_single_index_tests kv_single_index_tests kv_single_index_tests.cpp) +add_contract(kv_multiple_indices_tests kv_multiple_indices_tests kv_multiple_indices_tests.cpp) add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c capi/print.c capi/privileged.c capi/system.c capi/transaction.c) diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp new file mode 100644 index 0000000000..e20b69f3dd --- /dev/null +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -0,0 +1,193 @@ +#include + +struct my_struct { + eosio::name n1; + eosio::name n2; + std::string foo; + uint64_t bar; + int32_t baz; + + auto primary_key() const { return eosio::make_key(n1); } + auto foo_key() const { return eosio::make_key(foo); } + auto bar_key() const { return eosio::make_key(bar); } + auto baz_key() const { return eosio::make_key(baz); } + + bool operator==(const my_struct b) const { + return n1 == b.n1 && + n2 == b.n2 && + foo == b.foo && + bar == b.bar && + baz == b.baz; + } +}; + +struct my_table : eosio::kv_table { + eosio::kv_table::index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; + eosio::kv_table::index foo_index{eosio::name{"foo"}, &my_struct::foo_key}; + eosio::kv_table::index bar_index{eosio::name{"bar"}, &my_struct::bar_key}; + eosio::kv_table::index baz_index{eosio::name{"baz"}, &my_struct::baz_key}; + + my_table() { + init(eosio::name{"kvtest"}, eosio::name{"table"}, &primary_index, &foo_index, &bar_index, &baz_index); + } +}; + +class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { +public: + using contract::contract; + my_struct s{ + .n1 = "bob"_n, + .n2 = "alice"_n, + .foo = "a", + .bar = 5, + .baz = 0 + }; + my_struct s2{ + .n1 = "alice"_n, + .n2 = "bob"_n, + .foo = "c", + .bar = 4, + .baz = -1 + }; + my_struct s3{ + .n1 = "john"_n, + .n2 = "joe"_n, + .foo = "e", + .bar = 3, + .baz = -2 + }; + my_struct s4{ + .n1 = "joe"_n, + .n2 = "john"_n, + .foo = "g", + .bar = 2, + .baz = 1 + }; + my_struct s5{ + .n1 = "billy"_n, + .n2 = "vincent"_n, + .foo = "i", + .bar = 1, + .baz = 2 + }; + + [[eosio::action]] + void setup() { + my_table t; + + t.upsert(s); + t.upsert(s2); + t.upsert(s3); + t.upsert(s4); + t.upsert(s5); + } + + [[eosio::action]] + void find() { + my_table t; + + auto itr = t.primary_index.find("bob"_n); + auto val = itr.value(); + eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); + eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); + + itr = t.foo_index.find("c"); + val = itr.value(); + eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); + eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); + + itr = t.bar_index.find((uint64_t)1); + val = itr.value(); + eosio::check(val.n1 == "billy"_n, "Got the wrong n1"); + eosio::check(val.n2 == "vincent"_n, "Got the wrong n2"); + + itr = t.baz_index.find(0); + val = itr.value(); + eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); + + itr = t.baz_index.find(-1); + val = itr.value(); + eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); + + itr = t.baz_index.find(2); + val = itr.value(); + eosio::check(val.n1 == "billy"_n, "Got the wrong n1"); + + itr = t.baz_index.find(1); + val = itr.value(); + eosio::check(val.n1 == "joe"_n, "Got the wrong n1"); + + itr = t.baz_index.find(-2); + val = itr.value(); + eosio::check(val.n1 == "john"_n, "Got the wrong n1"); + } + + [[eosio::action]] + void iteration() { + my_table t; + + auto begin_itr = t.foo_index.begin(); + auto end_itr = t.foo_index.end(); + + // operator++ + // ---------- + auto itr = t.foo_index.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "a", "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "c", "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "e", "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "g", "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "i", "Got the wrong value"); + itr++; + eosio::check(itr == end_itr, "Should be the end"); + + // operator-- + // ---------- + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr == begin_itr, "Should be the beginning"); + + // operator int32_t + // ---------------- + itr = t.baz_index.begin(); + eosio::check(itr.value().baz == -2, "bad 1"); + itr++; + eosio::check(itr.value().baz == -1, "bad 2"); + itr++; + eosio::check(itr.value().baz == 0, "bad 3"); + itr++; + eosio::check(itr.value().baz == 1, "bad 4"); + itr++; + eosio::check(itr.value().baz == 2, "bad 5"); + } + + [[eosio::action]] + void range() { + my_table t; + + std::vector expected{s5, s4, s3}; + uint64_t b = 1; + uint64_t e = 3; + auto vals = t.bar_index.range(b, e); + eosio::check(vals == expected, "range did not return expected vector"); + + expected = {s3}; + vals = t.bar_index.range(e, e); + eosio::check(vals == expected, "range did not return expected vector"); + } +}; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp new file mode 100644 index 0000000000..46a29c31ba --- /dev/null +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -0,0 +1,184 @@ +#include + +struct my_struct { + eosio::name n1; + eosio::name n2; + std::string foo; + std::string bar; + + auto primary_key() const { return eosio::make_key(n1); } + + bool operator==(const my_struct b) const { + return n1 == b.n1 && + n2 == b.n2 && + foo == b.foo && + bar == b.bar; + } +}; + +struct my_table : eosio::kv_table { + eosio::kv_table::index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; + + my_table() { + init(eosio::name{"kvtest"}, eosio::name{"table"}, &primary_index); + } +}; + +class [[eosio::contract]] kv_single_index_tests : public eosio::contract { +public: + using contract::contract; + + my_struct s{ + .n1 = "bob"_n, + .n2 = "alice"_n, + .foo = "a", + .bar = "b" + }; + my_struct s2{ + .n1 = "alice"_n, + .n2 = "bob"_n, + .foo = "c", + .bar = "d" + }; + my_struct s3{ + .n1 = "john"_n, + .n2 = "joe"_n, + .foo = "e", + .bar = "f" + }; + my_struct s4{ + .n1 = "joe"_n, + .n2 = "john"_n, + .foo = "g", + .bar = "h" + }; + my_struct s5{ + .n1 = "billy"_n, + .n2 = "vincent"_n, + .foo = "i", + .bar = "j" + }; + + [[eosio::action]] + void setup() { + my_table t; + + t.upsert(s3); + t.upsert(s); + t.upsert(s4); + t.upsert(s2); + t.upsert(s5); + } + + [[eosio::action]] + void find() { + my_table t; + auto end_itr = t.primary_index.end(); + + auto itr = t.primary_index.find("bob"_n); + auto val = itr.value(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); + eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); + + itr = t.primary_index.find("joe"_n); + val = itr.value(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(val.n1 == "joe"_n, "Got the wrong n1"); + eosio::check(val.n2 == "john"_n, "Got the wrong n2"); + + itr = t.primary_index.find("alice"_n); + val = itr.value(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); + eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); + + itr = t.primary_index.find("john"_n); + val = itr.value(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(val.n1 == "john"_n, "Got the wrong n1"); + eosio::check(val.n2 == "joe"_n, "Got the wrong n2"); + } + + [[eosio::action]] + void finderror() { + my_table t; + auto itr = t.primary_index.find("larry"_n); + auto val = itr.value(); + } + + [[eosio::action]] + void iteration() { + my_table t; + auto begin_itr = t.primary_index.begin(); + auto end_itr = t.primary_index.end(); + + // operator++ + // ---------- + auto itr = t.primary_index.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().n1 == "alice"_n, "Got the wrong beginning"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().n1 == "billy"_n, "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().n1 == "bob"_n, "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().n1 == "joe"_n, "Got the wrong value"); + itr++; + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().n1 == "john"_n, "Got the wrong value"); + itr++; + eosio::check(itr == end_itr, "Should be the end"); + + // operator-- + // ---------- + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr != begin_itr, "Should not be the beginning"); + itr--; + eosio::check(itr == begin_itr, "Should be the beginning"); + } + + [[eosio::action]] + void range() { + my_table t; + + std::vector expected{s, s4, s3}; + auto vals = t.primary_index.range("bob"_n, "john"_n); + eosio::check(vals == expected, "range did not return expected vector"); + + expected = {s}; + vals = t.primary_index.range("bob"_n, "bob"_n); + eosio::check(vals == expected, "range did not return expected vector"); + } + + [[eosio::action]] + void rangeerror() { + my_table t; + std::vector expected = {s4, s3, s2}; + auto vals = t.primary_index.range("joe"_n, "alice"_n); + eosio::check(vals == expected, "range did not return expected vector"); + } + + [[eosio::action]] + void erase() { + my_table t; + auto end_itr = t.primary_index.end(); + + t.erase("joe"_n); + auto itr = t.primary_index.find("joe"_n); + eosio::check(itr == end_itr, "key was not properly deleted"); + + std::vector expected = {s, s3}; + auto vals = t.primary_index.range("bob"_n, "john"_n); + eosio::check(vals == expected, "range did not return expected vector"); + } +}; From ef64518a8f7ba6f9fdcc39d77b12f4a3f004fd6c Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 2 Jan 2020 16:36:57 -0500 Subject: [PATCH 155/659] Code Review feedback and cleanup. --- .../eosiolib/contracts/eosio/key_value.hpp | 153 ++++++------- tests/integration/kv_tests.cpp | 22 ++ .../kv_multiple_indices_tests.cpp | 201 +++++++++++------- .../test_contracts/kv_single_index_tests.cpp | 36 ++-- 4 files changed, 237 insertions(+), 175 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 7e17ce14c0..ed5d9f4fd5 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -61,22 +61,21 @@ struct key_type { size_t size; std::string buffer; - bool operator==(key_type k){ - return size == k.size && buffer == k.buffer; + bool operator==(const key_type& k) const { + return std::tie(size, buffer) == std::tie(k.size, k.buffer); } - bool operator!=(key_type k){ - return !(size == k.size && buffer == k.buffer); + bool operator!=(const key_type& k) const { + return !(*this == k); } }; -namespace _key_value_detail { +namespace detail { constexpr static size_t max_stack_buffer_size = 512; } /* Key transformations The key-value store could provide a lexicographical ordering of uint8_t on the keys. The contract can create an ordering on top by transforming its keys. Example transforms: - [x] - uint?_t: Convert to big-endian [x] - int?_t: Invert the MSB then convert to big-endian [x] - strings: Convert 0x00 to (0x00, 0x01). Append (0x00, 0x00) to the end. This transform allows arbitrary-length strings. @@ -109,7 +108,7 @@ inline T swap_endian(T u) { } inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { - using namespace _key_value_detail; + using namespace detail; auto bige_table = swap_endian(table_name.value); auto bige_index = swap_endian(index_name.value); @@ -117,7 +116,7 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint size_t size_64 = sizeof(index_name); size_t buffer_size = (2 * size_64) + sizeof(status); - void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); + void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); memcpy(buffer, &status, sizeof(status)); memcpy(((char*)buffer) + sizeof(status), &bige_table, size_64); @@ -125,25 +124,25 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint std::string s((char*)buffer, buffer_size); - if (buffer_size > _key_value_detail::max_stack_buffer_size) { + if (buffer_size > detail::max_stack_buffer_size) { free(buffer); } return {buffer_size, s}; } -inline key_type table_key(key_type prefix, key_type key) { - using namespace _key_value_detail; +inline key_type table_key(const key_type& prefix, const key_type& key) { + using namespace detail; size_t buffer_size = key.size + prefix.size; - void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); + void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); memcpy(buffer, prefix.buffer.data(), prefix.size); memcpy(((char*)buffer) + prefix.size, key.buffer.data(), key.size); std::string s((char*)buffer, buffer_size); - if (buffer_size > _key_value_detail::max_stack_buffer_size) { + if (buffer_size > detail::max_stack_buffer_size) { free(buffer); } @@ -158,7 +157,7 @@ inline I flip_msb(I val) { template inline key_type make_key(I val) { - using namespace _key_value_detail; + using namespace detail; if (std::is_signed::value) { val = flip_msb(val); @@ -167,45 +166,48 @@ inline key_type make_key(I val) { auto big_endian = swap_endian(val); size_t data_size = pack_size(big_endian); - void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); datastream data_ds((char*)data_buffer, data_size); data_ds << big_endian; std::string s((char*)data_buffer, data_size); - if (data_size > _key_value_detail::max_stack_buffer_size) { + if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } return {data_size, s}; } -inline key_type make_key(std::string val, bool case_insensitive=false) { - using namespace _key_value_detail; +inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { + using namespace detail; + + size_t data_size = size + 3; + void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); if (case_insensitive) { - std::transform(val.begin(), val.end(), val.begin(), [](unsigned char c) -> unsigned char { return std::toupper(c); }); + std::transform(str, str + size, (char*)data_buffer, [](unsigned char c) -> unsigned char { return std::toupper(c); }); + } else { + memcpy(data_buffer, str, size); } - size_t data_size = pack_size(val) + 3; - void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - - datastream data_ds((char*)data_buffer, data_size); - data_ds << val; - ((char*)data_buffer)[data_size - 3] = 0x01; ((char*)data_buffer)[data_size - 2] = 0x00; ((char*)data_buffer)[data_size - 1] = 0x00; std::string s((char*)data_buffer, data_size); - if (data_size > _key_value_detail::max_stack_buffer_size) { + if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } return {data_size, s}; } -inline key_type make_key(const char * str, bool case_insensitive=false) { +inline key_type make_key(const std::string& val, bool case_insensitive=false) { + return make_key(val.data(), val.size(), case_insensitive); +} + +inline key_type make_key(const char* str, bool case_insensitive=false) { return make_key(std::string{str}, case_insensitive); } @@ -213,7 +215,7 @@ inline key_type make_key(eosio::name n) { return make_key(n.value); } -template +template class kv_table { enum class kv_it_stat { @@ -223,14 +225,14 @@ class kv_table { }; public: - class index { + class kv_index { class iterator { public: - iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size, index* idx) : + iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size, kv_index* idx) : contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size}, idx{idx} {} - T value() { - using namespace _key_value_detail; + T value() const { + using namespace detail; eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); eosio::check(data_size > 0, "Cannot read a value of size 0"); @@ -238,7 +240,7 @@ class kv_table { uint32_t actual_value_size; uint32_t offset = 0; - void* buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + void* buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, data_size, actual_value_size); eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); @@ -248,7 +250,7 @@ class kv_table { T val; ds >> val; - if (data_size > _key_value_detail::max_stack_buffer_size) { + if (data_size > detail::max_stack_buffer_size) { free(buffer); } return val; @@ -257,7 +259,7 @@ class kv_table { auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (const char*)buffer, actual_value_size, actual_data_size); eosio::check(success, "failure getting primary key"); - void* pk_buffer = actual_data_size > _key_value_detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); + void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); auto copy_size = internal_use_do_not_use::kv_get_data(db, 0, (char*)pk_buffer, actual_data_size); eosio::check(copy_size > 0, "failure getting primary index data"); @@ -267,10 +269,10 @@ class kv_table { T val; ds >> val; - if (actual_data_size > _key_value_detail::max_stack_buffer_size) { + if (actual_data_size > detail::max_stack_buffer_size) { free(pk_buffer); } - if (data_size > _key_value_detail::max_stack_buffer_size) { + if (data_size > detail::max_stack_buffer_size) { free(buffer); } return val; @@ -283,25 +285,13 @@ class kv_table { return *this; } - iterator operator++(int) { - iterator copy(*this); - ++(*this); - return copy; - } - iterator& operator--() { itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); eosio::check(itr_stat != kv_it_stat::iterator_end, "incremented past the beginning"); return *this; } - iterator operator--(int) { - iterator copy(*this); - --(*this); - return copy; - } - - bool operator==(iterator b) { + bool operator==(const iterator& b) const { if (itr_stat == kv_it_stat::iterator_end) { return b.itr_stat == kv_it_stat::iterator_end; } @@ -311,26 +301,24 @@ class kv_table { return key() == b.key(); } - bool operator!=(iterator b) { - if (itr_stat == kv_it_stat::iterator_end) { - return b.itr_stat != kv_it_stat::iterator_end; - } - if (b.itr_stat == kv_it_stat::iterator_end) { - return true; - } - return key() != b.key(); + bool operator!=(const iterator& b) const { + return !(*this == b); + } + + bool operator<(const iterator& b) const { + return itr < b.itr; } private: eosio::name contract_name; - index* idx; + const kv_index* idx; size_t data_size; uint32_t itr; kv_it_stat itr_stat; - key_type key() { + key_type key() const { return idx->get_key(value()); } }; @@ -342,9 +330,9 @@ class kv_table { kv_table* tbl; - index() = default; + kv_index() = default; - index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} + kv_index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} template iterator find(K key) { @@ -377,20 +365,15 @@ class kv_table { } iterator begin() { - using namespace _key_value_detail; + using namespace detail; auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); uint32_t value_size; - uint64_t buffer_size = 1024*1024; // TODO: - void* buffer = buffer_size > _key_value_detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, buffer_size, value_size); - - if (buffer_size > _key_value_detail::max_stack_buffer_size) { - free(buffer); - } + char* buffer; + internal_use_do_not_use::kv_it_value(itr, 0, buffer, 0, value_size); return {contract_name, itr, static_cast(itr_stat), value_size, this}; } @@ -415,15 +398,15 @@ class kv_table { return_values.push_back(begin_itr.value()); iterator itr = begin_itr; - while(itr != end_itr){ - itr++; + while(itr != end_itr) { + ++itr; return_values.push_back(itr.value()); } return return_values; } - key_type get_key(T t) { + key_type get_key(T t) const { return (t.*key_function)(); } @@ -450,13 +433,12 @@ class kv_table { } template - void init(eosio::name contract, eosio::name table, index* primary, Indices... indices) { + void init(eosio::name contract, kv_index* primary, Indices... indices) { contract_name = contract; - table_name = table; primary_index = primary; primary_index->contract_name = contract; - primary_index->table_name = table; + primary_index->table_name = table_name; primary_index->tbl = this; if constexpr (sizeof...(indices) > 0) { @@ -464,13 +446,13 @@ class kv_table { } } - void upsert(T value) { - using namespace _key_value_detail; + void put(const T& value) { + using namespace detail; - auto t_key = table_key(make_prefix(table_name, primary_index->name), value.primary_key()); + auto t_key = table_key(make_prefix(table_name, primary_index->name), primary_index->get_key(value)); size_t data_size = pack_size(value); - void* data_buffer = data_size > _key_value_detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); datastream data_ds((char*)data_buffer, data_size); data_ds << value; @@ -481,7 +463,7 @@ class kv_table { internal_use_do_not_use::kv_set(db, contract_name.value, st_key.buffer.data(), st_key.size, t_key.buffer.data(), t_key.size); } - if (data_size > _key_value_detail::max_stack_buffer_size) { + if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } } @@ -500,10 +482,13 @@ class kv_table { } private: + constexpr static uint64_t db = static_cast(DbName); + constexpr static eosio::name table_name = static_cast(TableName); + eosio::name contract_name; - eosio::name table_name; - index* primary_index; - std::vector secondary_indices; + kv_index* primary_index; + std::vector secondary_indices; + }; } // eosio diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index dac9eb7735..703af208e6 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -73,6 +73,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { push_action(N(kvtest), N(find), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_find_i128, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(findi), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { create_accounts( { N(kvtest) } ); produce_block(); @@ -84,6 +95,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_iteration_insensitive, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(iterationi), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index e20b69f3dd..8ec5195f35 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -1,34 +1,38 @@ #include struct my_struct { - eosio::name n1; - eosio::name n2; + eosio::name primary_key; std::string foo; uint64_t bar; int32_t baz; + uint128_t i128; - auto primary_key() const { return eosio::make_key(n1); } + auto pk() const { return eosio::make_key(primary_key); } auto foo_key() const { return eosio::make_key(foo); } auto bar_key() const { return eosio::make_key(bar); } auto baz_key() const { return eosio::make_key(baz); } + auto foo_i_key() const { return eosio::make_key(foo, true); } + auto i128_key() const { return eosio::make_key(i128); } bool operator==(const my_struct b) const { - return n1 == b.n1 && - n2 == b.n2 && + return primary_key == b.primary_key && foo == b.foo && bar == b.bar && - baz == b.baz; + baz == b.baz && + i128 == b.i128; } }; -struct my_table : eosio::kv_table { - eosio::kv_table::index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; - eosio::kv_table::index foo_index{eosio::name{"foo"}, &my_struct::foo_key}; - eosio::kv_table::index bar_index{eosio::name{"bar"}, &my_struct::bar_key}; - eosio::kv_table::index baz_index{eosio::name{"baz"}, &my_struct::baz_key}; +struct my_table : eosio::kv_table { + kv_index primary_index{eosio::name{"primary"}, &my_struct::pk}; + kv_index foo_index{eosio::name{"foo"}, &my_struct::foo_key}; + kv_index bar_index{eosio::name{"bar"}, &my_struct::bar_key}; + kv_index baz_index{eosio::name{"baz"}, &my_struct::baz_key}; + kv_index ifoo_index{eosio::name{"ifoo"}, &my_struct::foo_i_key}; + kv_index i128_index{eosio::name{"ia"}, &my_struct::i128_key}; my_table() { - init(eosio::name{"kvtest"}, eosio::name{"table"}, &primary_index, &foo_index, &bar_index, &baz_index); + init(eosio::name{"kvtest"}, &primary_index, &foo_index, &bar_index, &baz_index, &ifoo_index, &i128_index); } }; @@ -36,50 +40,50 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; my_struct s{ - .n1 = "bob"_n, - .n2 = "alice"_n, + .primary_key = "bob"_n, .foo = "a", .bar = 5, - .baz = 0 + .baz = 0, + .i128 = (static_cast(1) << 127) - 5 }; my_struct s2{ - .n1 = "alice"_n, - .n2 = "bob"_n, - .foo = "c", + .primary_key = "alice"_n, + .foo = "C", .bar = 4, - .baz = -1 + .baz = -1, + .i128 = (static_cast(1) << 127) - 4 }; my_struct s3{ - .n1 = "john"_n, - .n2 = "joe"_n, + .primary_key = "john"_n, .foo = "e", .bar = 3, - .baz = -2 + .baz = -2, + .i128 = (static_cast(1) << 127) - 3 }; my_struct s4{ - .n1 = "joe"_n, - .n2 = "john"_n, + .primary_key = "joe"_n, .foo = "g", .bar = 2, - .baz = 1 + .baz = 1, + .i128 = (static_cast(1) << 127) - 2 }; my_struct s5{ - .n1 = "billy"_n, - .n2 = "vincent"_n, - .foo = "i", + .primary_key = "billy"_n, + .foo = "I", .bar = 1, - .baz = 2 + .baz = 2, + .i128 = (static_cast(1) << 127) - 1 }; [[eosio::action]] void setup() { my_table t; - t.upsert(s); - t.upsert(s2); - t.upsert(s3); - t.upsert(s4); - t.upsert(s5); + t.put(s); + t.put(s2); + t.put(s3); + t.put(s4); + t.put(s5); } [[eosio::action]] @@ -88,38 +92,56 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { auto itr = t.primary_index.find("bob"_n); auto val = itr.value(); - eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); - eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); + eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.foo_index.find("c"); + itr = t.foo_index.find("C"); val = itr.value(); - eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); - eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); + eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); itr = t.bar_index.find((uint64_t)1); val = itr.value(); - eosio::check(val.n1 == "billy"_n, "Got the wrong n1"); - eosio::check(val.n2 == "vincent"_n, "Got the wrong n2"); + eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); itr = t.baz_index.find(0); val = itr.value(); - eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); itr = t.baz_index.find(-1); val = itr.value(); - eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); itr = t.baz_index.find(2); val = itr.value(); - eosio::check(val.n1 == "billy"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); itr = t.baz_index.find(1); val = itr.value(); - eosio::check(val.n1 == "joe"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); itr = t.baz_index.find(-2); val = itr.value(); - eosio::check(val.n1 == "john"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); + } + + [[eosio::action]] + void findi() { + my_table t; + + auto end_itr = t.i128_index.end(); + + auto itr = t.i128_index.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().i128 == s.i128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().i128 == s2.i128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().i128 == s3.i128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().i128 == s4.i128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().i128 == s5.i128, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); } [[eosio::action]] @@ -129,51 +151,84 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { auto begin_itr = t.foo_index.begin(); auto end_itr = t.foo_index.end(); - // operator++ + // operator++ (case sensitive string) // ---------- auto itr = t.foo_index.begin(); eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "C", "Got the wrong value"); + ++itr; + eosio::check(itr.value().foo == "I", "Got the wrong value"); + ++itr; eosio::check(itr.value().foo == "a", "Got the wrong value"); - itr++; - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().foo == "c", "Got the wrong value"); - itr++; - eosio::check(itr != end_itr, "Should not be the end"); + ++itr; eosio::check(itr.value().foo == "e", "Got the wrong value"); - itr++; - eosio::check(itr != end_itr, "Should not be the end"); + ++itr; eosio::check(itr.value().foo == "g", "Got the wrong value"); - itr++; - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().foo == "i", "Got the wrong value"); - itr++; + ++itr; eosio::check(itr == end_itr, "Should be the end"); - // operator-- + // operator-- (case sensitive string) // ---------- - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr == begin_itr, "Should be the beginning"); // operator int32_t // ---------------- itr = t.baz_index.begin(); - eosio::check(itr.value().baz == -2, "bad 1"); - itr++; - eosio::check(itr.value().baz == -1, "bad 2"); - itr++; - eosio::check(itr.value().baz == 0, "bad 3"); - itr++; - eosio::check(itr.value().baz == 1, "bad 4"); - itr++; - eosio::check(itr.value().baz == 2, "bad 5"); + eosio::check(itr.value().baz == -2, "Got the wrong value"); + ++itr; + eosio::check(itr.value().baz == -1, "Got the wrong value"); + ++itr; + eosio::check(itr.value().baz == 0, "Got the wrong value"); + ++itr; + eosio::check(itr.value().baz == 1, "Got the wrong value"); + ++itr; + eosio::check(itr.value().baz == 2, "Got the wrong value"); + } + + [[eosio::action]] + void iterationi() { + my_table t; + + auto begin_itr = t.ifoo_index.begin(); + auto end_itr = t.ifoo_index.end(); + + // operator++ (case insensitive string) + // ---------- + auto itr = t.ifoo_index.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().foo == "a", "Got the wrong value"); + ++itr; + eosio::check(itr.value().foo == "C", "Got the wrong value"); + ++itr; + eosio::check(itr.value().foo == "e", "Got the wrong value"); + ++itr; + eosio::check(itr.value().foo == "g", "Got the wrong value"); + ++itr; + eosio::check(itr.value().foo == "I", "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + + // operator-- (case sensitive string) + // ---------- + --itr; + eosio::check(itr != begin_itr, "Should not be the beginning"); + --itr; + eosio::check(itr != begin_itr, "Should not be the beginning"); + --itr; + eosio::check(itr != begin_itr, "Should not be the beginning"); + --itr; + eosio::check(itr != begin_itr, "Should not be the beginning"); + --itr; + eosio::check(itr == begin_itr, "Should be the beginning"); } [[eosio::action]] diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 46a29c31ba..930c6732f3 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -16,11 +16,11 @@ struct my_struct { } }; -struct my_table : eosio::kv_table { - eosio::kv_table::index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; +struct my_table : eosio::kv_table { + kv_index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; my_table() { - init(eosio::name{"kvtest"}, eosio::name{"table"}, &primary_index); + init(eosio::name{"kvtest"}, &primary_index); } }; @@ -63,11 +63,11 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { void setup() { my_table t; - t.upsert(s3); - t.upsert(s); - t.upsert(s4); - t.upsert(s2); - t.upsert(s5); + t.put(s3); + t.put(s); + t.put(s4); + t.put(s2); + t.put(s5); } [[eosio::action]] @@ -118,32 +118,32 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto itr = t.primary_index.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "alice"_n, "Got the wrong beginning"); - itr++; + ++itr; eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "billy"_n, "Got the wrong value"); - itr++; + ++itr; eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "bob"_n, "Got the wrong value"); - itr++; + ++itr; eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "joe"_n, "Got the wrong value"); - itr++; + ++itr; eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "john"_n, "Got the wrong value"); - itr++; + ++itr; eosio::check(itr == end_itr, "Should be the end"); // operator-- // ---------- - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr != begin_itr, "Should not be the beginning"); - itr--; + --itr; eosio::check(itr == begin_itr, "Should be the beginning"); } From a9e2d47ff3be0c0877339a779cba70b619932467 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 7 Jan 2020 17:07:10 -0500 Subject: [PATCH 156/659] Reflection and member variables/functions --- .../eosiolib/contracts/eosio/key_value.hpp | 107 ++++++++++-------- libraries/eosiolib/core/eosio/utility.hpp | 40 +++++++ .../kv_multiple_indices_tests.cpp | 58 +++++----- .../test_contracts/kv_single_index_tests.cpp | 36 +++--- 4 files changed, 147 insertions(+), 94 deletions(-) create mode 100644 libraries/eosiolib/core/eosio/utility.hpp diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index ed5d9f4fd5..2c7b813f94 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -2,6 +2,7 @@ #include "../../core/eosio/datastream.hpp" #include "../../core/eosio/name.hpp" #include "../../core/eosio/print.hpp" +#include "../../core/eosio/utility.hpp" #include #include @@ -88,25 +89,6 @@ The key-value store could provide a lexicographical ordering of uint8_t on the k [ ] - struct or tuple: transform each field in order. Concatenate results. (use tuples for composite keys) */ -template -inline T swap_endian(T u) { - static_assert (CHAR_BIT == 8, "CHAR_BIT != 8"); - - union - { - T u; - unsigned char u8[sizeof(T)]; - } source, dest; - - source.u = u; - - for (size_t k = 0; k < sizeof(T); k++) { - dest.u8[k] = source.u8[sizeof(T) - k - 1]; - } - - return dest.u; -} - inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { using namespace detail; @@ -332,6 +314,13 @@ class kv_table { kv_index() = default; + template + kv_index(eosio::name name, KF T::*key_field): name{name} { + key_field_function = [=](const T& t) { + return make_key(std::invoke(key_field, t)); + }; + } + kv_index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} template @@ -406,44 +395,43 @@ class kv_table { return return_values; } - key_type get_key(T t) const { - return (t.*key_function)(); + key_type get_key(const T& t) const { + if (key_function) { + return std::invoke(key_function, t); + } else { + return key_field_function(t); + } } private: - key_type (T::*key_function)() const; + key_type (T::*key_function)() const = nullptr; + std::function key_field_function; }; - template - void setup_indices(I index, Indices... indices) { - index->contract_name = contract_name; - index->table_name = table_name; - index->tbl = this; - - secondary_indices.push_back(index); - setup_indices(indices...); - } - - template - void setup_indices(I index) { - index->contract_name = contract_name; - index->table_name = table_name; - index->tbl = this; - secondary_indices.push_back(index); - } - - template - void init(eosio::name contract, kv_index* primary, Indices... indices) { + template + void init(eosio::name contract, Indices indices) { contract_name = contract; - primary_index = primary; - primary_index->contract_name = contract; + auto& primary = get<0>(*indices); + + primary_index = &primary; + primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; - if constexpr (sizeof...(indices) > 0) { - setup_indices(indices...); - } + for_each_field(*indices, [&](auto& idx) { + if (idx.name != primary.name) { + kv_index* si = &idx; + si->contract_name = contract_name; + si->table_name = table_name; + si->tbl = this; + secondary_indices.push_back(si); + } + }); + + // Makes sure the indexes are run in the correct order. + // This is mainly useful for debugging, this probably could be deleted. + std::reverse(std::begin(secondary_indices), std::end(secondary_indices)); } void put(const T& value) { @@ -490,5 +478,30 @@ class kv_table { kv_index* primary_index; std::vector secondary_indices; + template + constexpr static auto& get(U& u) { + constexpr size_t kv_index_size = sizeof(kv_index); + static_assert(sizeof(U) % kv_index_size == 0); + kv_index* indices = (kv_index*)(&u); + return indices[I]; + } + + template + constexpr static void for_each_field(U& u, F&& f) { + f(get(u)); + if constexpr (S <= 0) { + return; + } else { + for_each_field(u, f); + } + } + + template + constexpr static void for_each_field(U& u, F&& f) { + constexpr size_t kv_index_size = sizeof(kv_index); + static_assert(sizeof(U) % kv_index_size == 0); + constexpr size_t num_elems = (sizeof(U) / sizeof(kv_index)) - 1; + for_each_field(u, f); + } }; } // eosio diff --git a/libraries/eosiolib/core/eosio/utility.hpp b/libraries/eosiolib/core/eosio/utility.hpp new file mode 100644 index 0000000000..92fc1c6518 --- /dev/null +++ b/libraries/eosiolib/core/eosio/utility.hpp @@ -0,0 +1,40 @@ +#pragma once + +namespace eosio { + /* utility function to swap the endianness of a variable */ + template + inline T swap_endian(T val) { + static_assert(sizeof(T) <= 16); + if constexpr (sizeof(T) == 1) + return val; + else if constexpr (sizeof(T) == 2) + return (val << 8) |(val >> 8); + else if constexpr (sizeof(T) == 4) { + union i32_swap { + T value; + uint32_t ui; + i32_swap(T v) : value(v) { ui = __builtin_bswap32(ui); } + }; + return i32_swap(val).value; + } else if constexpr (sizeof(T) == 8) { + union i64_swap { + T value; + uint64_t ui; + i64_swap(T v) : value(v) { ui = __builtin_bswap64(ui); } + }; + return i64_swap(val).value; + } else { + union i128_swap { + uint64_t high; + uint64_t low; + T value; + i128_swap(const T& val) : value(val) { + uint64_t tmp = high; + high = __builtin_bswap64(low); + low = __builtin_bswap64(tmp); + } + }; + return i128_swap(val).value; + } + } +} diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 8ec5195f35..3accf410c8 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -7,10 +7,6 @@ struct my_struct { int32_t baz; uint128_t i128; - auto pk() const { return eosio::make_key(primary_key); } - auto foo_key() const { return eosio::make_key(foo); } - auto bar_key() const { return eosio::make_key(bar); } - auto baz_key() const { return eosio::make_key(baz); } auto foo_i_key() const { return eosio::make_key(foo, true); } auto i128_key() const { return eosio::make_key(i128); } @@ -24,15 +20,17 @@ struct my_struct { }; struct my_table : eosio::kv_table { - kv_index primary_index{eosio::name{"primary"}, &my_struct::pk}; - kv_index foo_index{eosio::name{"foo"}, &my_struct::foo_key}; - kv_index bar_index{eosio::name{"bar"}, &my_struct::bar_key}; - kv_index baz_index{eosio::name{"baz"}, &my_struct::baz_key}; - kv_index ifoo_index{eosio::name{"ifoo"}, &my_struct::foo_i_key}; - kv_index i128_index{eosio::name{"ia"}, &my_struct::i128_key}; + struct { + kv_index primary{eosio::name{"primary"}, &my_struct::primary_key}; + kv_index foo{eosio::name{"foo"}, &my_struct::foo}; + kv_index bar{eosio::name{"bar"}, &my_struct::bar}; + kv_index baz{eosio::name{"baz"}, &my_struct::baz}; + kv_index i128{eosio::name{"ia"}, &my_struct::i128}; + kv_index ifoo{eosio::name{"ifoo"}, &my_struct::foo_i_key}; + } index; my_table() { - init(eosio::name{"kvtest"}, &primary_index, &foo_index, &bar_index, &baz_index, &ifoo_index, &i128_index); + init(eosio::name{"kvtest"}, &index); } }; @@ -90,35 +88,35 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { void find() { my_table t; - auto itr = t.primary_index.find("bob"_n); + auto itr = t.index.primary.find("bob"_n); auto val = itr.value(); eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.foo_index.find("C"); + itr = t.index.foo.find("C"); val = itr.value(); eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); - itr = t.bar_index.find((uint64_t)1); + itr = t.index.bar.find((uint64_t)1); val = itr.value(); eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - itr = t.baz_index.find(0); + itr = t.index.baz.find(0); val = itr.value(); eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.baz_index.find(-1); + itr = t.index.baz.find(-1); val = itr.value(); eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); - itr = t.baz_index.find(2); + itr = t.index.baz.find(2); val = itr.value(); eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - itr = t.baz_index.find(1); + itr = t.index.baz.find(1); val = itr.value(); eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); - itr = t.baz_index.find(-2); + itr = t.index.baz.find(-2); val = itr.value(); eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); } @@ -127,9 +125,9 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { void findi() { my_table t; - auto end_itr = t.i128_index.end(); + auto end_itr = t.index.i128.end(); - auto itr = t.i128_index.begin(); + auto itr = t.index.i128.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().i128 == s.i128, "Got the wrong value"); ++itr; @@ -148,12 +146,12 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { void iteration() { my_table t; - auto begin_itr = t.foo_index.begin(); - auto end_itr = t.foo_index.end(); + auto begin_itr = t.index.foo.begin(); + auto end_itr = t.index.foo.end(); // operator++ (case sensitive string) // ---------- - auto itr = t.foo_index.begin(); + auto itr = t.index.foo.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().foo == "C", "Got the wrong value"); ++itr; @@ -182,7 +180,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { // operator int32_t // ---------------- - itr = t.baz_index.begin(); + itr = t.index.baz.begin(); eosio::check(itr.value().baz == -2, "Got the wrong value"); ++itr; eosio::check(itr.value().baz == -1, "Got the wrong value"); @@ -198,12 +196,12 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { void iterationi() { my_table t; - auto begin_itr = t.ifoo_index.begin(); - auto end_itr = t.ifoo_index.end(); + auto begin_itr = t.index.ifoo.begin(); + auto end_itr = t.index.ifoo.end(); // operator++ (case insensitive string) // ---------- - auto itr = t.ifoo_index.begin(); + auto itr = t.index.ifoo.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().foo == "a", "Got the wrong value"); ++itr; @@ -238,11 +236,11 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { std::vector expected{s5, s4, s3}; uint64_t b = 1; uint64_t e = 3; - auto vals = t.bar_index.range(b, e); + auto vals = t.index.bar.range(b, e); eosio::check(vals == expected, "range did not return expected vector"); expected = {s3}; - vals = t.bar_index.range(e, e); + vals = t.index.bar.range(e, e); eosio::check(vals == expected, "range did not return expected vector"); } }; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 930c6732f3..b38fd9dbbf 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -17,10 +17,12 @@ struct my_struct { }; struct my_table : eosio::kv_table { - kv_index primary_index{eosio::name{"primary"}, &my_struct::primary_key}; + struct { + kv_index primary{eosio::name{"primary"}, &my_struct::primary_key}; + } index; my_table() { - init(eosio::name{"kvtest"}, &primary_index); + init(eosio::name{"kvtest"}, &index); } }; @@ -73,27 +75,27 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void find() { my_table t; - auto end_itr = t.primary_index.end(); + auto end_itr = t.index.primary.end(); - auto itr = t.primary_index.find("bob"_n); + auto itr = t.index.primary.find("bob"_n); auto val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); - itr = t.primary_index.find("joe"_n); + itr = t.index.primary.find("joe"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.n1 == "joe"_n, "Got the wrong n1"); eosio::check(val.n2 == "john"_n, "Got the wrong n2"); - itr = t.primary_index.find("alice"_n); + itr = t.index.primary.find("alice"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); - itr = t.primary_index.find("john"_n); + itr = t.index.primary.find("john"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.n1 == "john"_n, "Got the wrong n1"); @@ -103,19 +105,19 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void finderror() { my_table t; - auto itr = t.primary_index.find("larry"_n); + auto itr = t.index.primary.find("larry"_n); auto val = itr.value(); } [[eosio::action]] void iteration() { my_table t; - auto begin_itr = t.primary_index.begin(); - auto end_itr = t.primary_index.end(); + auto begin_itr = t.index.primary.begin(); + auto end_itr = t.index.primary.end(); // operator++ // ---------- - auto itr = t.primary_index.begin(); + auto itr = t.index.primary.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().n1 == "alice"_n, "Got the wrong beginning"); ++itr; @@ -152,11 +154,11 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { my_table t; std::vector expected{s, s4, s3}; - auto vals = t.primary_index.range("bob"_n, "john"_n); + auto vals = t.index.primary.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); expected = {s}; - vals = t.primary_index.range("bob"_n, "bob"_n); + vals = t.index.primary.range("bob"_n, "bob"_n); eosio::check(vals == expected, "range did not return expected vector"); } @@ -164,21 +166,21 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { void rangeerror() { my_table t; std::vector expected = {s4, s3, s2}; - auto vals = t.primary_index.range("joe"_n, "alice"_n); + auto vals = t.index.primary.range("joe"_n, "alice"_n); eosio::check(vals == expected, "range did not return expected vector"); } [[eosio::action]] void erase() { my_table t; - auto end_itr = t.primary_index.end(); + auto end_itr = t.index.primary.end(); t.erase("joe"_n); - auto itr = t.primary_index.find("joe"_n); + auto itr = t.index.primary.find("joe"_n); eosio::check(itr == end_itr, "key was not properly deleted"); std::vector expected = {s, s3}; - auto vals = t.primary_index.range("bob"_n, "john"_n); + auto vals = t.index.primary.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } }; From 6d484910c48d1c0172706c14212ee9c874a59943 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 15 Jan 2020 13:53:36 -0500 Subject: [PATCH 157/659] Fix missing test end. --- tests/integration/kv_tests.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 703af208e6..df2780b6a3 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -116,4 +116,5 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(range), N(kvtest), {}); } FC_LOG_AND_RETHROW() -} + +BOOST_AUTO_TEST_SUITE_END() From 4efa63065e19aecb49bf396fbfe5642b35ccf6a0 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 9 Jan 2020 17:08:28 -0500 Subject: [PATCH 158/659] Add floating point support to make_key. --- .../eosiolib/contracts/eosio/key_value.hpp | 64 ++++++++++++++----- tests/integration/kv_tests.cpp | 11 ++++ .../kv_multiple_indices_tests.cpp | 37 +++++++++-- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 2c7b813f94..67f08bde85 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -74,21 +74,6 @@ namespace detail { constexpr static size_t max_stack_buffer_size = 512; } -/* -Key transformations -The key-value store could provide a lexicographical ordering of uint8_t on the keys. The contract can create an ordering on top by transforming its keys. Example transforms: - [x] - uint?_t: Convert to big-endian - [x] - int?_t: Invert the MSB then convert to big-endian - [x] - strings: Convert 0x00 to (0x00, 0x01). Append (0x00, 0x00) to the end. This transform allows arbitrary-length strings. - [x] - case-insensitive strings: Convert to upper-case, then apply the above transform. Assumes ASCII. - [ ] - floating-point: - There's some bit manipulations, followed by an endian conversion - limitations: - Positive 0 and Negative 0 map to the same value - NaN's and inf's end up with an unusual ordering - [ ] - struct or tuple: transform each field in order. Concatenate results. (use tuples for composite keys) -*/ - inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { using namespace detail; @@ -133,11 +118,19 @@ inline key_type table_key(const key_type& prefix, const key_type& key) { template inline I flip_msb(I val) { - constexpr static size_t BITS = sizeof(I) * 8; - return val ^ (static_cast(1) << (BITS - 1)); + constexpr static size_t bits = sizeof(I) * 8; + return val ^ (static_cast(1) << (bits - 1)); } template +inline I get_msb(I val) { + constexpr static size_t bits = sizeof(I) * 8; + constexpr static I mask = static_cast(0x08) << (bits - 4); + I masked = val & mask; + return masked >> (bits - 1); +} + +template ::value, int> = 0> inline key_type make_key(I val) { using namespace detail; @@ -161,6 +154,43 @@ inline key_type make_key(I val) { return {data_size, s}; } +template +inline key_type make_floating_key(F val) { + auto* ival = reinterpret_cast(&val); + I bit_val; + auto msb = get_msb(*ival); + if (msb) { + // invert all the bits + bit_val = ~(*ival); + } else { + // invert just msb + bit_val = flip_msb(*ival); + } + + auto big_endian = swap_endian(bit_val); + + char* bytes = reinterpret_cast(&big_endian); + constexpr size_t size = sizeof(big_endian); + std::string s(bytes, size); + return {size, s}; +} + +template ::value, int> = 0> +inline key_type make_key(F val) { + static_assert(sizeof(F) != sizeof(long double), "long doubles are currently not supported by make_key"); + + if (val == -0) { + val = +0; + } + + if (sizeof(F) == sizeof(float)) { + return make_floating_key(val); + } + else { + return make_floating_key(val); + } +} + inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { using namespace detail; diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index df2780b6a3..8b6e72dc57 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -84,6 +84,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_find_i128, tester) try { push_action(N(kvtest), N(findi), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_find_float, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(findf), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 3accf410c8..ec3857e1d8 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -6,6 +6,7 @@ struct my_struct { uint64_t bar; int32_t baz; uint128_t i128; + float test_float; auto foo_i_key() const { return eosio::make_key(foo, true); } auto i128_key() const { return eosio::make_key(i128); } @@ -27,6 +28,7 @@ struct my_table : eosio::kv_table { kv_index baz{eosio::name{"baz"}, &my_struct::baz}; kv_index i128{eosio::name{"ia"}, &my_struct::i128}; kv_index ifoo{eosio::name{"ifoo"}, &my_struct::foo_i_key}; + kv_index flt{eosio::name{"float"}, &my_struct::test_float}; } index; my_table() { @@ -42,35 +44,40 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .foo = "a", .bar = 5, .baz = 0, - .i128 = (static_cast(1) << 127) - 5 + .i128 = (static_cast(1) << 127) - 5, + .test_float = 4.2574 }; my_struct s2{ .primary_key = "alice"_n, .foo = "C", .bar = 4, .baz = -1, - .i128 = (static_cast(1) << 127) - 4 + .i128 = (static_cast(1) << 127) - 4, + .test_float = 5.2574 }; my_struct s3{ .primary_key = "john"_n, .foo = "e", .bar = 3, .baz = -2, - .i128 = (static_cast(1) << 127) - 3 + .i128 = (static_cast(1) << 127) - 3, + .test_float = 187234 }; my_struct s4{ .primary_key = "joe"_n, .foo = "g", .bar = 2, .baz = 1, - .i128 = (static_cast(1) << 127) - 2 + .i128 = (static_cast(1) << 127) - 2, + .test_float = 0 }; my_struct s5{ .primary_key = "billy"_n, .foo = "I", .bar = 1, .baz = 2, - .i128 = (static_cast(1) << 127) - 1 + .i128 = (static_cast(1) << 127) - 1, + .test_float = -4.2574 }; [[eosio::action]] @@ -142,6 +149,26 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(itr == end_itr, "Should be the end"); } + [[eosio::action]] + void findf() { + my_table t; + auto end_itr = t.index.flt.end(); + + auto itr = t.index.flt.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().test_float == s5.test_float, "Got the wrong value"); + ++itr; + eosio::check(itr.value().test_float == s4.test_float, "Got the wrong value"); + ++itr; + eosio::check(itr.value().test_float == s.test_float, "Got the wrong value"); + ++itr; + eosio::check(itr.value().test_float == s2.test_float, "Got the wrong value"); + ++itr; + eosio::check(itr.value().test_float == s3.test_float, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + [[eosio::action]] void iteration() { my_table t; From c3da79103d06493dfd18fa977cf1a571f4cde4ca Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 13 Jan 2020 10:44:15 -0500 Subject: [PATCH 159/659] Add make_key support for structs. --- .../eosiolib/contracts/eosio/key_value.hpp | 28 +++++++++++++ tests/integration/kv_tests.cpp | 11 +++++ .../kv_multiple_indices_tests.cpp | 41 ++++++++++++++++--- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 67f08bde85..61704f9d08 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -8,6 +8,8 @@ #include #include +#include + namespace eosio { namespace internal_use_do_not_use { extern "C" { @@ -191,6 +193,32 @@ inline key_type make_key(F val) { } } +template ::value, int> = 0> +inline key_type make_key(S val) { + size_t data_size = 0; + size_t pos = 0; + void* data_buffer; + + boost::pfr::for_each_field(val, [&](auto& field) { + data_size += pack_size(field); + }); + + data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + + boost::pfr::for_each_field(val, [&](auto& field) { + auto kt = make_key(field); + memcpy((char*)data_buffer + pos, kt.buffer.data(), kt.size); + pos += kt.size; + }); + + std::string s((char*)data_buffer, data_size); + + if (data_size > detail::max_stack_buffer_size) { + free(data_buffer); + } + return {data_size, s}; +} + inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { using namespace detail; diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 8b6e72dc57..5e75c2e3c6 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -95,6 +95,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_find_float, tester) try { push_action(N(kvtest), N(findf), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_find_struct, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(finds), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index ec3857e1d8..9f0c8f022c 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -8,6 +8,11 @@ struct my_struct { uint128_t i128; float test_float; + struct { + uint16_t a; + uint16_t b; + } tstruct; + auto foo_i_key() const { return eosio::make_key(foo, true); } auto i128_key() const { return eosio::make_key(i128); } @@ -29,6 +34,7 @@ struct my_table : eosio::kv_table { kv_index i128{eosio::name{"ia"}, &my_struct::i128}; kv_index ifoo{eosio::name{"ifoo"}, &my_struct::foo_i_key}; kv_index flt{eosio::name{"float"}, &my_struct::test_float}; + kv_index tstruct{eosio::name{"struct"}, &my_struct::tstruct}; } index; my_table() { @@ -45,7 +51,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .bar = 5, .baz = 0, .i128 = (static_cast(1) << 127) - 5, - .test_float = 4.2574 + .test_float = 4.2574, + .tstruct = { 1, 2 } }; my_struct s2{ .primary_key = "alice"_n, @@ -53,7 +60,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .bar = 4, .baz = -1, .i128 = (static_cast(1) << 127) - 4, - .test_float = 5.2574 + .test_float = 5.2574, + .tstruct = { 5, 6 } }; my_struct s3{ .primary_key = "john"_n, @@ -61,7 +69,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .bar = 3, .baz = -2, .i128 = (static_cast(1) << 127) - 3, - .test_float = 187234 + .test_float = 187234, + .tstruct = { 3, 4 } }; my_struct s4{ .primary_key = "joe"_n, @@ -69,7 +78,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .bar = 2, .baz = 1, .i128 = (static_cast(1) << 127) - 2, - .test_float = 0 + .test_float = 0, + .tstruct = { 7, 8 } }; my_struct s5{ .primary_key = "billy"_n, @@ -77,7 +87,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .bar = 1, .baz = 2, .i128 = (static_cast(1) << 127) - 1, - .test_float = -4.2574 + .test_float = -4.2574, + .tstruct = { 9, 10 } }; [[eosio::action]] @@ -169,6 +180,26 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(itr == end_itr, "Should be the end"); } + [[eosio::action]] + void finds() { + my_table t; + auto end_itr = t.index.tstruct.end(); + + auto itr = t.index.tstruct.begin(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tstruct.a == s.tstruct.a, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct.a == s3.tstruct.a, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct.a == s2.tstruct.a, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct.a == s4.tstruct.a, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct.a == s5.tstruct.a, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + [[eosio::action]] void iteration() { my_table t; From 27a18b0fbf6a1c6fd0635696fa9f43a238388066 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 14 Jan 2020 13:51:05 -0500 Subject: [PATCH 160/659] Separate out tests that are focused on make_key specifically. --- tests/integration/contracts.hpp.in | 3 + tests/integration/kv_make_key_tests.cpp | 53 ++++ tests/unit/test_contracts/CMakeLists.txt | 1 + .../unit/test_contracts/kv_make_key_tests.cpp | 244 ++++++++++++++++++ 4 files changed, 301 insertions(+) create mode 100644 tests/integration/kv_make_key_tests.cpp create mode 100644 tests/unit/test_contracts/kv_make_key_tests.cpp diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 9bf98f3703..de9ba019a0 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -24,6 +24,9 @@ struct contracts { static std::vector kv_multi_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_multiple_indices_tests.wasm"); } static std::vector kv_multi_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_multiple_indices_tests.abi"); } + + static std::vector kv_make_key_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.wasm"); } + static std::vector kv_make_key_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.abi"); } }; }} //ns eosio::testing diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp new file mode 100644 index 0000000000..525d419f62 --- /dev/null +++ b/tests/integration/kv_make_key_tests.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#include + +using namespace eosio; +using namespace eosio::testing; + +BOOST_AUTO_TEST_SUITE(key_value_make_key_tests) + +void make_key_test(name test_name) { + tester t; + + t.create_accounts( { N(kvtest) } ); + t.produce_block(); + t.set_code( N(kvtest), contracts::kv_make_key_tests_wasm() ); + t.set_abi( N(kvtest), contracts::kv_make_key_tests_abi().data() ); + t.produce_blocks(); + + t.push_action(N(kvtest), N(setup), N(kvtest), {}); + t.push_action(N(kvtest), test_name, N(kvtest), {}); +} + +BOOST_AUTO_TEST_CASE(makekeyname) try { + make_key_test(N(makekeyname)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeystr) try { + make_key_test(N(makekeystr)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeyuill) try { + make_key_test(N(makekeyuill)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeyil) try { + make_key_test(N(makekeyil)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeyilll) try { + make_key_test(N(makekeyil)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeyflt) try { + make_key_test(N(makekeyflt)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_CASE(makekeystct) try { + make_key_test(N(makekeystct)); +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 3effd52b87..2c1355f3cf 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -5,6 +5,7 @@ add_contract(transfer_contract transfer_contract transfer.cpp) add_contract(minimal_tests minimal_tests minimal_tests.cpp) add_contract(kv_single_index_tests kv_single_index_tests kv_single_index_tests.cpp) add_contract(kv_multiple_indices_tests kv_multiple_indices_tests kv_multiple_indices_tests.cpp) +add_contract(kv_make_key_tests kv_make_key_tests kv_make_key_tests.cpp) add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c capi/print.c capi/privileged.c capi/system.c capi/transaction.c) diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp new file mode 100644 index 0000000000..fa8bc3b983 --- /dev/null +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -0,0 +1,244 @@ +#include + +struct testing_struct { + uint16_t a; + uint16_t b; + + bool operator==(testing_struct rhs){ + return a == rhs.a && b == rhs.b; + } +}; + +struct my_struct { + eosio::name tname; + std::string tstring; + uint64_t tui64; + int32_t ti32; + uint128_t ti128; + float tfloat; + testing_struct tstruct; +}; + +struct my_table : eosio::kv_table { + struct { + kv_index tname{eosio::name{"a"}, &my_struct::tname}; + kv_index tstring{eosio::name{"b"}, &my_struct::tstring}; + kv_index tui64{eosio::name{"c"}, &my_struct::tui64}; + kv_index ti32{eosio::name{"d"}, &my_struct::ti32}; + kv_index ti128{eosio::name{"e"}, &my_struct::ti128}; + kv_index tfloat{eosio::name{"f"}, &my_struct::tfloat}; + kv_index tstruct{eosio::name{"g"}, &my_struct::tstruct}; + } index; + + my_table() { + init(eosio::name{"kvtest"}, &index); + } +}; + +class [[eosio::contract]] kv_make_key_tests : public eosio::contract { +public: + using contract::contract; + my_struct s1{ + .tname = "bob"_n, + .tstring = "a", + .tui64 = 5, + .ti32 = 0, + .ti128 = (static_cast(1) << 127) - 5, + .tfloat = 4.2574, + .tstruct = { 1, 2 } + }; + my_struct s2{ + .tname = "alice"_n, + .tstring = "C", + .tui64 = 4, + .ti32 = -1, + .ti128 = (static_cast(1) << 127) - 4, + .tfloat = 5.2574, + .tstruct = { 5, 6 } + }; + my_struct s3{ + .tname = "john"_n, + .tstring = "e", + .tui64 = 3, + .ti32 = -2, + .ti128 = (static_cast(1) << 127) - 3, + .tfloat = 187234, + .tstruct = { 3, 4 } + }; + my_struct s4{ + .tname = "joe"_n, + .tstring = "g", + .tui64 = 2, + .ti32 = 1, + .ti128 = (static_cast(1) << 127) - 2, + .tfloat = 0, + .tstruct = { 7, 8 } + }; + my_struct s5{ + .tname = "billy"_n, + .tstring = "I", + .tui64 = 1, + .ti32 = 2, + .ti128 = (static_cast(1) << 127) - 1, + .tfloat = -4.2574, + .tstruct = { 9, 10 } + }; + + [[eosio::action]] + void setup() { + my_table t; + + t.put(s1); + t.put(s2); + t.put(s3); + t.put(s4); + t.put(s5); + } + + [[eosio::action]] + void makekeyname() { + my_table t; + + auto end_itr = t.index.tname.end(); + auto itr = t.index.tname.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tname == s2.tname, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tname == s5.tname, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tname == s1.tname, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tname == s4.tname, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tname == s3.tname, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeystr() { + my_table t; + + auto end_itr = t.index.tstring.end(); + auto itr = t.index.tstring.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tstring == s2.tstring, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstring == s5.tstring, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstring == s1.tstring, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstring == s3.tstring, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstring == s4.tstring, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeyuill() { + my_table t; + + auto end_itr = t.index.tui64.end(); + auto itr = t.index.tui64.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tui64 == s5.tui64, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tui64 == s4.tui64, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tui64 == s3.tui64, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tui64 == s2.tui64, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tui64 == s1.tui64, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeyil() { + my_table t; + + auto end_itr = t.index.ti32.end(); + auto itr = t.index.ti32.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().ti32 == s3.ti32, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti32 == s2.ti32, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti32 == s1.ti32, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti32 == s4.ti32, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti32 == s5.ti32, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeyilll() { + my_table t; + + auto end_itr = t.index.ti128.end(); + auto itr = t.index.ti128.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().ti128 == s1.ti128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti128 == s2.ti128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti128 == s3.ti128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti128 == s4.ti128, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ti128 == s5.ti128, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeyflt() { + my_table t; + + auto end_itr = t.index.tfloat.end(); + auto itr = t.index.tfloat.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tfloat == s5.tfloat, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tfloat == s4.tfloat, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tfloat == s1.tfloat, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tfloat == s2.tfloat, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tfloat == s3.tfloat, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + + [[eosio::action]] + void makekeystct() { + my_table t; + + auto end_itr = t.index.tstruct.end(); + auto itr = t.index.tstruct.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().tstruct == s1.tstruct, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct == s3.tstruct, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct == s2.tstruct, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct == s4.tstruct, "Got the wrong value"); + ++itr; + eosio::check(itr.value().tstruct == s5.tstruct, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } +}; From d26142dbfa5e1c298066a1181a64f70b9a1549c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 16 Jan 2020 13:03:41 -0500 Subject: [PATCH 161/659] Add make_key tuple support. --- .../eosiolib/contracts/eosio/key_value.hpp | 74 +++++++++++++------ tests/integration/kv_make_key_tests.cpp | 4 + .../unit/test_contracts/kv_make_key_tests.cpp | 38 ++++++++-- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 61704f9d08..7691d3563d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -193,6 +193,42 @@ inline key_type make_key(F val) { } } +inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { + using namespace detail; + + size_t data_size = size + 3; + void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + + if (case_insensitive) { + std::transform(str, str + size, (char*)data_buffer, [](unsigned char c) -> unsigned char { return std::toupper(c); }); + } else { + memcpy(data_buffer, str, size); + } + + ((char*)data_buffer)[data_size - 3] = 0x01; + ((char*)data_buffer)[data_size - 2] = 0x00; + ((char*)data_buffer)[data_size - 1] = 0x00; + + std::string s((char*)data_buffer, data_size); + + if (data_size > detail::max_stack_buffer_size) { + free(data_buffer); + } + return {data_size, s}; +} + +inline key_type make_key(const std::string& val, bool case_insensitive=false) { + return make_key(val.data(), val.size(), case_insensitive); +} + +inline key_type make_key(const char* str, bool case_insensitive=false) { + return make_key(std::string{str}, case_insensitive); +} + +inline key_type make_key(eosio::name n) { + return make_key(n.value); +} + template ::value, int> = 0> inline key_type make_key(S val) { size_t data_size = 0; @@ -219,21 +255,23 @@ inline key_type make_key(S val) { return {data_size, s}; } -inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { - using namespace detail; +template +inline key_type make_key(std::tuple val) { + size_t data_size = 0; + size_t pos = 0; + void* data_buffer; - size_t data_size = size + 3; - void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + boost::fusion::for_each(val, [&](auto& field) { + data_size += pack_size(field); + }); - if (case_insensitive) { - std::transform(str, str + size, (char*)data_buffer, [](unsigned char c) -> unsigned char { return std::toupper(c); }); - } else { - memcpy(data_buffer, str, size); - } + data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - ((char*)data_buffer)[data_size - 3] = 0x01; - ((char*)data_buffer)[data_size - 2] = 0x00; - ((char*)data_buffer)[data_size - 1] = 0x00; + boost::fusion::for_each(val, [&](auto& field) { + auto kt = make_key(field); + memcpy((char*)data_buffer + pos, kt.buffer.data(), kt.size); + pos += kt.size; + }); std::string s((char*)data_buffer, data_size); @@ -243,18 +281,6 @@ inline key_type make_key(const char* str, size_t size, bool case_insensitive=fal return {data_size, s}; } -inline key_type make_key(const std::string& val, bool case_insensitive=false) { - return make_key(val.data(), val.size(), case_insensitive); -} - -inline key_type make_key(const char* str, bool case_insensitive=false) { - return make_key(std::string{str}, case_insensitive); -} - -inline key_type make_key(eosio::name n) { - return make_key(n.value); -} - template class kv_table { diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp index 525d419f62..f0d5e1d41b 100644 --- a/tests/integration/kv_make_key_tests.cpp +++ b/tests/integration/kv_make_key_tests.cpp @@ -50,4 +50,8 @@ BOOST_AUTO_TEST_CASE(makekeystct) try { make_key_test(N(makekeystct)); } FC_LOG_AND_RETHROW() +BOOST_AUTO_TEST_CASE(makekeytup) try { + make_key_test(N(makekeytup)); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index fa8bc3b983..ece48c28c7 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -17,6 +17,7 @@ struct my_struct { uint128_t ti128; float tfloat; testing_struct tstruct; + std::tuple ttuple; }; struct my_table : eosio::kv_table { @@ -28,6 +29,7 @@ struct my_table : eosio::kv_table { kv_index ti128{eosio::name{"e"}, &my_struct::ti128}; kv_index tfloat{eosio::name{"f"}, &my_struct::tfloat}; kv_index tstruct{eosio::name{"g"}, &my_struct::tstruct}; + kv_index ttuple{eosio::name{"h"}, &my_struct::ttuple}; } index; my_table() { @@ -45,7 +47,8 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti32 = 0, .ti128 = (static_cast(1) << 127) - 5, .tfloat = 4.2574, - .tstruct = { 1, 2 } + .tstruct = { 1, 2 }, + .ttuple = { 100, 32.43, "abc"} }; my_struct s2{ .tname = "alice"_n, @@ -54,7 +57,8 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti32 = -1, .ti128 = (static_cast(1) << 127) - 4, .tfloat = 5.2574, - .tstruct = { 5, 6 } + .tstruct = { 5, 6 }, + .ttuple = { 100, 32.44, "def"} }; my_struct s3{ .tname = "john"_n, @@ -63,7 +67,8 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti32 = -2, .ti128 = (static_cast(1) << 127) - 3, .tfloat = 187234, - .tstruct = { 3, 4 } + .tstruct = { 3, 4 }, + .ttuple = { 100, 33.43, "abc"} }; my_struct s4{ .tname = "joe"_n, @@ -72,7 +77,8 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti32 = 1, .ti128 = (static_cast(1) << 127) - 2, .tfloat = 0, - .tstruct = { 7, 8 } + .tstruct = { 7, 8 }, + .ttuple = { 101, 32.43, "abc"} }; my_struct s5{ .tname = "billy"_n, @@ -81,7 +87,8 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti32 = 2, .ti128 = (static_cast(1) << 127) - 1, .tfloat = -4.2574, - .tstruct = { 9, 10 } + .tstruct = { 9, 10 }, + .ttuple = { 101, 34.43, "abc"} }; [[eosio::action]] @@ -241,4 +248,25 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { ++itr; eosio::check(itr == end_itr, "Should be the end"); } + + [[eosio::action]] + void makekeytup() { + my_table t; + + auto end_itr = t.index.ttuple.end(); + auto itr = t.index.ttuple.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().ttuple == s1.ttuple, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ttuple == s2.ttuple, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ttuple == s3.ttuple, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ttuple == s4.ttuple, "Got the wrong value"); + ++itr; + eosio::check(itr.value().ttuple == s5.ttuple, "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } }; From 8edd482518defd73df4a48ffe63aeb14ce1ae5e6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 21 Jan 2020 14:11:50 -0500 Subject: [PATCH 162/659] Add DEFINE_TABLE macro --- .../eosiolib/contracts/eosio/key_value.hpp | 62 ++++++++++++- .../unit/test_contracts/kv_make_key_tests.cpp | 44 ++++------ .../kv_multiple_indices_tests.cpp | 50 +++++------ .../test_contracts/kv_single_index_tests.cpp | 88 ++++++++----------- 4 files changed, 139 insertions(+), 105 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 7691d3563d..cb05d9e36d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -8,8 +8,58 @@ #include #include +#include +#include #include +#define EOSIO_CDT_KV_INDEX_nullptr + +#define EOSIO_CDT_KV_INDEX_TEST() 1 +#define EOSIO_CDT_KV_INDEX_TEST_EOSIO_CDT_KV_INDEX_TEST 0, +#define EOSIO_CDT_KV_INDEX_TEST_1 1, ignore +#define EOSIO_CDT_EXPAND(x) x +#define EOSIO_CDT_CAT2(x, y) x ## y +#define EOSIO_CDT_CAT(x, y) EOSIO_CDT_CAT2(x, y) +#define EOSIO_CDT_APPLY(f, args) f args +#define EOSIO_CDT_FIX_KV_INDEX_TYPE_0(index_name) kv_index +#define EOSIO_CDT_FIX_KV_INDEX_TYPE_1(index_name) null_kv_index +#define EOSIO_CDT_FIX_KV_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_FIX_KV_INDEX_TYPE_ ## iskeyword + +#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_0(value_class, index_name) {&value_class::index_name} +#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_1(value_class, index_name) +#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT(iskeyword, garbage) EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_ ## iskeyword + +#define EOSIO_CDT_KV_INDEX_TYPE(index_name) \ + EOSIO_CDT_APPLY(EOSIO_CDT_FIX_KV_INDEX_TYPE, \ + (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(index_name) + +#define EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name) \ + EOSIO_CDT_APPLY(EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT, \ + (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(value_class, index_name) + + +#define CREATE_KV_INDEX(r, value_class, index_name) \ + EOSIO_CDT_KV_INDEX_TYPE(index_name) index_name EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); + +#define LIST_INDICES(value_class, ...) \ + BOOST_PP_SEQ_FOR_EACH(CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) + +#define TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ + eosio::kv_table + +#define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ + struct table_class : TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ + struct { \ + LIST_INDICES(value_class, __VA_ARGS__) \ + } index; \ + \ + table_class(eosio::name contract_name) { \ + init(contract_name, &index); \ + } \ + }; + namespace eosio { namespace internal_use_do_not_use { extern "C" { @@ -281,7 +331,7 @@ inline key_type make_key(std::tuple val) { return {data_size, s}; } -template +template class kv_table { enum class kv_it_stat { @@ -399,13 +449,13 @@ class kv_table { kv_index() = default; template - kv_index(eosio::name name, KF T::*key_field): name{name} { + kv_index(KF T::*key_field) { key_field_function = [=](const T& t) { return make_key(std::invoke(key_field, t)); }; } - kv_index(eosio::name name, key_type (T::*key_function)() const): name{name}, key_function{key_function} {} + kv_index(key_type (T::*key_function)() const): key_function{key_function} {} template iterator find(K key) { @@ -495,21 +545,27 @@ class kv_table { template void init(eosio::name contract, Indices indices) { contract_name = contract; + uint64_t index_name = 1; auto& primary = get<0>(*indices); primary_index = &primary; + primary_index->name = eosio::name{index_name}; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; + ++index_name; + for_each_field(*indices, [&](auto& idx) { if (idx.name != primary.name) { kv_index* si = &idx; + si->name = eosio::name{index_name}; si->contract_name = contract_name; si->table_name = table_name; si->tbl = this; secondary_indices.push_back(si); + ++index_name; } }); diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index ece48c28c7..67e7c3fef0 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -20,22 +20,16 @@ struct my_struct { std::tuple ttuple; }; -struct my_table : eosio::kv_table { - struct { - kv_index tname{eosio::name{"a"}, &my_struct::tname}; - kv_index tstring{eosio::name{"b"}, &my_struct::tstring}; - kv_index tui64{eosio::name{"c"}, &my_struct::tui64}; - kv_index ti32{eosio::name{"d"}, &my_struct::ti32}; - kv_index ti128{eosio::name{"e"}, &my_struct::ti128}; - kv_index tfloat{eosio::name{"f"}, &my_struct::tfloat}; - kv_index tstruct{eosio::name{"g"}, &my_struct::tstruct}; - kv_index ttuple{eosio::name{"h"}, &my_struct::ttuple}; - } index; - - my_table() { - init(eosio::name{"kvtest"}, &index); - } -}; +DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + tname, + tstring, + tui64, + ti32, + ti128, + tfloat, + tstruct, + ttuple +) class [[eosio::contract]] kv_make_key_tests : public eosio::contract { public: @@ -93,7 +87,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t; + my_table t{"kvtest"_n}; t.put(s1); t.put(s2); @@ -104,7 +98,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyname() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tname.end(); auto itr = t.index.tname.begin(); @@ -125,7 +119,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeystr() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tstring.end(); auto itr = t.index.tstring.begin(); @@ -146,7 +140,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyuill() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tui64.end(); auto itr = t.index.tui64.begin(); @@ -167,7 +161,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyil() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.ti32.end(); auto itr = t.index.ti32.begin(); @@ -188,7 +182,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyilll() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.ti128.end(); auto itr = t.index.ti128.begin(); @@ -209,7 +203,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyflt() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tfloat.end(); auto itr = t.index.tfloat.begin(); @@ -230,7 +224,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeystct() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tstruct.end(); auto itr = t.index.tstruct.begin(); @@ -251,7 +245,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeytup() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.ttuple.end(); auto itr = t.index.ttuple.begin(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 9f0c8f022c..752ac5a61b 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -13,7 +13,7 @@ struct my_struct { uint16_t b; } tstruct; - auto foo_i_key() const { return eosio::make_key(foo, true); } + auto ifoo() const { return eosio::make_key(foo, true); } auto i128_key() const { return eosio::make_key(i128); } bool operator==(const my_struct b) const { @@ -25,22 +25,16 @@ struct my_struct { } }; -struct my_table : eosio::kv_table { - struct { - kv_index primary{eosio::name{"primary"}, &my_struct::primary_key}; - kv_index foo{eosio::name{"foo"}, &my_struct::foo}; - kv_index bar{eosio::name{"bar"}, &my_struct::bar}; - kv_index baz{eosio::name{"baz"}, &my_struct::baz}; - kv_index i128{eosio::name{"ia"}, &my_struct::i128}; - kv_index ifoo{eosio::name{"ifoo"}, &my_struct::foo_i_key}; - kv_index flt{eosio::name{"float"}, &my_struct::test_float}; - kv_index tstruct{eosio::name{"struct"}, &my_struct::tstruct}; - } index; - - my_table() { - init(eosio::name{"kvtest"}, &index); - } -}; +DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + primary_key, + foo, + bar, + baz, + i128, + test_float, + tstruct, + ifoo +) class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: @@ -93,7 +87,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t; + my_table t{"kvtest"_n}; t.put(s); t.put(s2); @@ -104,9 +98,9 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t; + my_table t{"kvtest"_n}; - auto itr = t.index.primary.find("bob"_n); + auto itr = t.index.primary_key.find("bob"_n); auto val = itr.value(); eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); @@ -141,7 +135,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void findi() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.i128.end(); @@ -162,10 +156,10 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void findf() { - my_table t; - auto end_itr = t.index.flt.end(); + my_table t{"kvtest"_n}; + auto end_itr = t.index.test_float.end(); - auto itr = t.index.flt.begin(); + auto itr = t.index.test_float.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().test_float == s5.test_float, "Got the wrong value"); ++itr; @@ -182,7 +176,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void finds() { - my_table t; + my_table t{"kvtest"_n}; auto end_itr = t.index.tstruct.end(); auto itr = t.index.tstruct.begin(); @@ -202,7 +196,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void iteration() { - my_table t; + my_table t{"kvtest"_n}; auto begin_itr = t.index.foo.begin(); auto end_itr = t.index.foo.end(); @@ -252,7 +246,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void iterationi() { - my_table t; + my_table t{"kvtest"_n}; auto begin_itr = t.index.ifoo.begin(); auto end_itr = t.index.ifoo.end(); @@ -289,7 +283,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void range() { - my_table t; + my_table t{"kvtest"_n}; std::vector expected{s5, s4, s3}; uint64_t b = 1; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index b38fd9dbbf..787c369905 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -1,61 +1,51 @@ #include struct my_struct { - eosio::name n1; + eosio::name primary_key; eosio::name n2; std::string foo; std::string bar; - auto primary_key() const { return eosio::make_key(n1); } - bool operator==(const my_struct b) const { - return n1 == b.n1 && + return primary_key == b.primary_key && n2 == b.n2 && foo == b.foo && bar == b.bar; } }; -struct my_table : eosio::kv_table { - struct { - kv_index primary{eosio::name{"primary"}, &my_struct::primary_key}; - } index; - - my_table() { - init(eosio::name{"kvtest"}, &index); - } -}; +DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) class [[eosio::contract]] kv_single_index_tests : public eosio::contract { public: using contract::contract; my_struct s{ - .n1 = "bob"_n, + .primary_key = "bob"_n, .n2 = "alice"_n, .foo = "a", .bar = "b" }; my_struct s2{ - .n1 = "alice"_n, + .primary_key = "alice"_n, .n2 = "bob"_n, .foo = "c", .bar = "d" }; my_struct s3{ - .n1 = "john"_n, + .primary_key = "john"_n, .n2 = "joe"_n, .foo = "e", .bar = "f" }; my_struct s4{ - .n1 = "joe"_n, + .primary_key = "joe"_n, .n2 = "john"_n, .foo = "g", .bar = "h" }; my_struct s5{ - .n1 = "billy"_n, + .primary_key = "billy"_n, .n2 = "vincent"_n, .foo = "i", .bar = "j" @@ -63,7 +53,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t; + my_table t{"kvtest"_n}; t.put(s3); t.put(s); @@ -74,64 +64,64 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t; - auto end_itr = t.index.primary.end(); + my_table t{"kvtest"_n}; + auto end_itr = t.index.primary_key.end(); - auto itr = t.index.primary.find("bob"_n); + auto itr = t.index.primary_key.find("bob"_n); auto val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.n1 == "bob"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); - itr = t.index.primary.find("joe"_n); + itr = t.index.primary_key.find("joe"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.n1 == "joe"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); eosio::check(val.n2 == "john"_n, "Got the wrong n2"); - itr = t.index.primary.find("alice"_n); + itr = t.index.primary_key.find("alice"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.n1 == "alice"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); - itr = t.index.primary.find("john"_n); + itr = t.index.primary_key.find("john"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.n1 == "john"_n, "Got the wrong n1"); + eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); eosio::check(val.n2 == "joe"_n, "Got the wrong n2"); } [[eosio::action]] void finderror() { - my_table t; - auto itr = t.index.primary.find("larry"_n); + my_table t{"kvtest"_n}; + auto itr = t.index.primary_key.find("larry"_n); auto val = itr.value(); } [[eosio::action]] void iteration() { - my_table t; - auto begin_itr = t.index.primary.begin(); - auto end_itr = t.index.primary.end(); + my_table t{"kvtest"_n}; + auto begin_itr = t.index.primary_key.begin(); + auto end_itr = t.index.primary_key.end(); // operator++ // ---------- - auto itr = t.index.primary.begin(); + auto itr = t.index.primary_key.begin(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().n1 == "alice"_n, "Got the wrong beginning"); + eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong beginning"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().n1 == "billy"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong value"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().n1 == "bob"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong value"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().n1 == "joe"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong value"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().n1 == "john"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "john"_n, "Got the wrong value"); ++itr; eosio::check(itr == end_itr, "Should be the end"); @@ -151,36 +141,36 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void range() { - my_table t; + my_table t{"kvtest"_n}; std::vector expected{s, s4, s3}; - auto vals = t.index.primary.range("bob"_n, "john"_n); + auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); expected = {s}; - vals = t.index.primary.range("bob"_n, "bob"_n); + vals = t.index.primary_key.range("bob"_n, "bob"_n); eosio::check(vals == expected, "range did not return expected vector"); } [[eosio::action]] void rangeerror() { - my_table t; + my_table t{"kvtest"_n}; std::vector expected = {s4, s3, s2}; - auto vals = t.index.primary.range("joe"_n, "alice"_n); + auto vals = t.index.primary_key.range("joe"_n, "alice"_n); eosio::check(vals == expected, "range did not return expected vector"); } [[eosio::action]] void erase() { - my_table t; - auto end_itr = t.index.primary.end(); + my_table t{"kvtest"_n}; + auto end_itr = t.index.primary_key.end(); t.erase("joe"_n); - auto itr = t.index.primary.find("joe"_n); + auto itr = t.index.primary_key.find("joe"_n); eosio::check(itr == end_itr, "key was not properly deleted"); std::vector expected = {s, s3}; - auto vals = t.index.primary.range("bob"_n, "john"_n); + auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } }; From ced830e10ef94d2047b20310d5116506afd2207e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 21 Jan 2020 14:49:21 -0500 Subject: [PATCH 163/659] Add better api for case insensitive strings --- .../eosiolib/contracts/eosio/key_value.hpp | 5 +++ tests/integration/kv_make_key_tests.cpp | 4 ++ tests/integration/kv_tests.cpp | 11 ----- .../unit/test_contracts/kv_make_key_tests.cpp | 26 ++++++++++- .../kv_multiple_indices_tests.cpp | 43 +------------------ 5 files changed, 35 insertions(+), 54 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index cb05d9e36d..727627a8c2 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -331,6 +331,11 @@ inline key_type make_key(std::tuple val) { return {data_size, s}; } +inline key_type make_insensitive(const std::string& val) { + return make_key(val, true); +} + + template class kv_table { diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp index f0d5e1d41b..31ea9b7fe4 100644 --- a/tests/integration/kv_make_key_tests.cpp +++ b/tests/integration/kv_make_key_tests.cpp @@ -30,6 +30,10 @@ BOOST_AUTO_TEST_CASE(makekeystr) try { make_key_test(N(makekeystr)); } FC_LOG_AND_RETHROW() +BOOST_AUTO_TEST_CASE(makekeyistr) try { + make_key_test(N(makekeyistr)); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_CASE(makekeyuill) try { make_key_test(N(makekeyuill)); } FC_LOG_AND_RETHROW() diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 5e75c2e3c6..aca2af2ffa 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -117,17 +117,6 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_iteration_insensitive, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(iterationi), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index 67e7c3fef0..a7e462613d 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -18,6 +18,8 @@ struct my_struct { float tfloat; testing_struct tstruct; std::tuple ttuple; + + auto itstring() const { return eosio::make_insensitive(tstring); } }; DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", @@ -28,7 +30,8 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", ti128, tfloat, tstruct, - ttuple + ttuple, + itstring ) class [[eosio::contract]] kv_make_key_tests : public eosio::contract { @@ -138,6 +141,27 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { eosio::check(itr == end_itr, "Should be the end"); } + [[eosio::action]] + void makekeyistr() { + my_table t{"kvtest"_n}; + + auto end_itr = t.index.itstring.end(); + auto itr = t.index.itstring.begin(); + + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().itstring() == s1.itstring(), "Got the wrong value"); + ++itr; + eosio::check(itr.value().itstring() == s2.itstring(), "Got the wrong value"); + ++itr; + eosio::check(itr.value().itstring() == s3.itstring(), "Got the wrong value"); + ++itr; + eosio::check(itr.value().itstring() == s4.itstring(), "Got the wrong value"); + ++itr; + eosio::check(itr.value().itstring() == s5.itstring(), "Got the wrong value"); + ++itr; + eosio::check(itr == end_itr, "Should be the end"); + } + [[eosio::action]] void makekeyuill() { my_table t{"kvtest"_n}; diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 752ac5a61b..2ecadec098 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -13,9 +13,6 @@ struct my_struct { uint16_t b; } tstruct; - auto ifoo() const { return eosio::make_key(foo, true); } - auto i128_key() const { return eosio::make_key(i128); } - bool operator==(const my_struct b) const { return primary_key == b.primary_key && foo == b.foo && @@ -32,8 +29,7 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", baz, i128, test_float, - tstruct, - ifoo + tstruct ) class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { @@ -244,43 +240,6 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(itr.value().baz == 2, "Got the wrong value"); } - [[eosio::action]] - void iterationi() { - my_table t{"kvtest"_n}; - - auto begin_itr = t.index.ifoo.begin(); - auto end_itr = t.index.ifoo.end(); - - // operator++ (case insensitive string) - // ---------- - auto itr = t.index.ifoo.begin(); - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().foo == "a", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "C", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "e", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "g", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "I", "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); - - // operator-- (case sensitive string) - // ---------- - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr == begin_itr, "Should be the beginning"); - } - [[eosio::action]] void range() { my_table t{"kvtest"_n}; From 4c448ad4ba826663b2ef31311d6076c56a7223f8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 21 Jan 2020 14:59:29 -0500 Subject: [PATCH 164/659] Cleanup kv_index constructor --- .../eosiolib/contracts/eosio/key_value.hpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 727627a8c2..5e5672fe8a 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -454,14 +454,12 @@ class kv_table { kv_index() = default; template - kv_index(KF T::*key_field) { - key_field_function = [=](const T& t) { - return make_key(std::invoke(key_field, t)); + kv_index(KF&& kf) { + key_function = [=](const T& t) { + return make_key(std::invoke(kf, &t)); }; } - kv_index(key_type (T::*key_function)() const): key_function{key_function} {} - template iterator find(K key) { uint32_t value_size; @@ -534,17 +532,10 @@ class kv_table { return return_values; } - key_type get_key(const T& t) const { - if (key_function) { - return std::invoke(key_function, t); - } else { - return key_field_function(t); - } - } + key_type get_key(const T& inst) const { return key_function(inst); } private: - key_type (T::*key_function)() const = nullptr; - std::function key_field_function; + std::function key_function; }; template From 430ba6eb6229bd4896d2b37bf68d99cdc8aa1371 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 21 Jan 2020 17:17:25 -0500 Subject: [PATCH 165/659] Cleanup and more tests --- .../eosiolib/contracts/eosio/key_value.hpp | 24 ++++------- tests/integration/kv_tests.cpp | 21 +++++++++- .../test_contracts/kv_single_index_tests.cpp | 42 +++++++++++++++++-- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 5e5672fe8a..cd25fc10ba 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -192,18 +192,10 @@ inline key_type make_key(I val) { auto big_endian = swap_endian(val); - size_t data_size = pack_size(big_endian); - void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - - datastream data_ds((char*)data_buffer, data_size); - data_ds << big_endian; - - std::string s((char*)data_buffer, data_size); - - if (data_size > detail::max_stack_buffer_size) { - free(data_buffer); - } - return {data_size, s}; + char* bytes = reinterpret_cast(&big_endian); + constexpr size_t size = sizeof(big_endian); + std::string s(bytes, size); + return {size, s}; } template @@ -491,8 +483,6 @@ class kv_table { } iterator begin() { - using namespace detail; - auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); @@ -594,7 +584,11 @@ class kv_table { template void erase(K key) { - T val = primary_index->find(key).value(); + auto primary_itr = primary_index->find(key); + + eosio::check(primary_itr != primary_index->end(), "Attempted to erase non-existent key"); + + T val = primary_itr.value(); auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)k.buffer.data(), k.size); diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index aca2af2ffa..ac5dad97e1 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -33,6 +33,14 @@ BOOST_FIXTURE_TEST_CASE(single_tests_iteration, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(iteration), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(itrerror1), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("cannot increment end iterator")); + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(itrerror2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("incremented past the beginning")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { @@ -44,9 +52,16 @@ BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(range), N(kvtest), {}); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror), N(kvtest), {}), + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror1), N(kvtest), {}), eosio_assert_message_exception, eosio_assert_message_is("Beginning of range should be less than or equal to end")); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("beginning of range is not in table")); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror3), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("end of range is not in table")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { @@ -58,6 +73,10 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(erase), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(eraseerror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Attempted to erase non-existent key")); } FC_LOG_AND_RETHROW() // Multi diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 787c369905..6ee8037d21 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -90,6 +90,12 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); eosio::check(val.n2 == "joe"_n, "Got the wrong n2"); + + itr = t.index.primary_key.find("billy"_n); + val = itr.value(); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); + eosio::check(val.n2 == "vincent"_n, "Got the wrong n2"); } [[eosio::action]] @@ -139,6 +145,20 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { eosio::check(itr == begin_itr, "Should be the beginning"); } + [[eosio::action]] + void itrerror1() { + my_table t{"kvtest"_n}; + auto end_itr = t.index.primary_key.end(); + ++end_itr; + } + + [[eosio::action]] + void itrerror2() { + my_table t{"kvtest"_n}; + auto begin_itr = t.index.primary_key.begin(); + --begin_itr; + } + [[eosio::action]] void range() { my_table t{"kvtest"_n}; @@ -153,11 +173,21 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { } [[eosio::action]] - void rangeerror() { + void rangeerror1() { my_table t{"kvtest"_n}; - std::vector expected = {s4, s3, s2}; auto vals = t.index.primary_key.range("joe"_n, "alice"_n); - eosio::check(vals == expected, "range did not return expected vector"); + } + + [[eosio::action]] + void rangeerror2() { + my_table t{"kvtest"_n}; + auto vals = t.index.primary_key.range("chris"_n, "joe"_n); + } + + [[eosio::action]] + void rangeerror3() { + my_table t{"kvtest"_n}; + auto vals = t.index.primary_key.range("alice"_n, "chris"_n); } [[eosio::action]] @@ -173,4 +203,10 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } + + [[eosio::action]] + void eraseerror() { + my_table t{"kvtest"_n}; + t.erase("chris"_n); + } }; From c2c334a102c4b96cd0b097f0552cb97d28b23619 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 22 Jan 2020 11:43:32 -0500 Subject: [PATCH 166/659] Add operators that use kv_it_compare and update range accordingly --- .../eosiolib/contracts/eosio/key_value.hpp | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index cd25fc10ba..6251617c5e 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -405,13 +405,8 @@ class kv_table { } bool operator==(const iterator& b) const { - if (itr_stat == kv_it_stat::iterator_end) { - return b.itr_stat == kv_it_stat::iterator_end; - } - if (b.itr_stat == kv_it_stat::iterator_end) { - return false; - } - return key() == b.key(); + auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); + return cmp == 0; } bool operator!=(const iterator& b) const { @@ -419,7 +414,23 @@ class kv_table { } bool operator<(const iterator& b) const { - return itr < b.itr; + auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); + return cmp == -1; + } + + bool operator<=(const iterator& b) const { + auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); + return cmp <= 0; + } + + bool operator>(const iterator& b) const { + auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); + return cmp == 1; + } + + bool operator>=(const iterator& b) const { + auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); + return cmp >= 0; } private: @@ -488,14 +499,21 @@ class kv_table { int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); uint32_t value_size; - char* buffer; - internal_use_do_not_use::kv_it_value(itr, 0, buffer, 0, value_size); + + // kv_it_value is just used to get the value_size + void* buffer = alloca(1); + internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); return {contract_name, itr, static_cast(itr_stat), value_size, this}; } template std::vector range(K begin, K end) { + auto begin_itr = find(begin); + auto end_itr = find(end); + eosio::check(begin_itr != this->end(), "beginning of range is not in table"); + eosio::check(end_itr != this->end(), "end of range is not in table"); + eosio::check(begin <= end, "Beginning of range should be less than or equal to end"); if (begin == end) { @@ -504,13 +522,7 @@ class kv_table { return t; } - auto begin_itr = find(begin); - auto end_itr = find(end); - eosio::check(begin_itr != this->end(), "beginning of range is not in table"); - eosio::check(end_itr != this->end(), "end of range is not in table"); - std::vector return_values; - return_values.push_back(begin_itr.value()); iterator itr = begin_itr; From b5c0137d127d9d3c58a4bb8e219e06a47ac4a9c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 22 Jan 2020 13:59:31 -0500 Subject: [PATCH 167/659] Add additional tests and reduce redundancy --- tests/integration/kv_tests.cpp | 46 +--- .../kv_multiple_indices_tests.cpp | 253 ++++++------------ .../test_contracts/kv_single_index_tests.cpp | 38 +-- 3 files changed, 84 insertions(+), 253 deletions(-) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index ac5dad97e1..5cea8c9136 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -90,39 +90,10 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(find), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - -BOOST_FIXTURE_TEST_CASE(multi_tests_find_i128, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(findi), N(kvtest), {}); -} FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_find_float, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(findf), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - -BOOST_FIXTURE_TEST_CASE(multi_tests_find_struct, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(finds), N(kvtest), {}); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(finderror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Cannot read end iterator")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { @@ -136,15 +107,4 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(range), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 2ecadec098..c01531492b 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -4,88 +4,54 @@ struct my_struct { eosio::name primary_key; std::string foo; uint64_t bar; - int32_t baz; - uint128_t i128; - float test_float; - - struct { - uint16_t a; - uint16_t b; - } tstruct; bool operator==(const my_struct b) const { return primary_key == b.primary_key && foo == b.foo && - bar == b.bar && - baz == b.baz && - i128 == b.i128; + bar == b.bar; } }; DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key, foo, - bar, - baz, - i128, - test_float, - tstruct + bar ) class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; - my_struct s{ + my_struct s1{ .primary_key = "bob"_n, .foo = "a", - .bar = 5, - .baz = 0, - .i128 = (static_cast(1) << 127) - 5, - .test_float = 4.2574, - .tstruct = { 1, 2 } + .bar = 5 }; my_struct s2{ .primary_key = "alice"_n, .foo = "C", - .bar = 4, - .baz = -1, - .i128 = (static_cast(1) << 127) - 4, - .test_float = 5.2574, - .tstruct = { 5, 6 } + .bar = 4 }; my_struct s3{ .primary_key = "john"_n, .foo = "e", - .bar = 3, - .baz = -2, - .i128 = (static_cast(1) << 127) - 3, - .test_float = 187234, - .tstruct = { 3, 4 } + .bar = 3 }; my_struct s4{ .primary_key = "joe"_n, .foo = "g", - .bar = 2, - .baz = 1, - .i128 = (static_cast(1) << 127) - 2, - .test_float = 0, - .tstruct = { 7, 8 } + .bar = 2 }; my_struct s5{ .primary_key = "billy"_n, .foo = "I", - .bar = 1, - .baz = 2, - .i128 = (static_cast(1) << 127) - 1, - .test_float = -4.2574, - .tstruct = { 9, 10 } + .bar = 1 }; [[eosio::action]] void setup() { my_table t{"kvtest"_n}; - t.put(s); + t.put(s1); t.put(s2); t.put(s3); t.put(s4); @@ -107,151 +73,82 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { itr = t.index.bar.find((uint64_t)1); val = itr.value(); eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - - itr = t.index.baz.find(0); - val = itr.value(); - eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - - itr = t.index.baz.find(-1); - val = itr.value(); - eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); - - itr = t.index.baz.find(2); - val = itr.value(); - eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - - itr = t.index.baz.find(1); - val = itr.value(); - eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); - - itr = t.index.baz.find(-2); - val = itr.value(); - eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); } [[eosio::action]] - void findi() { + void finderror() { my_table t{"kvtest"_n}; - auto end_itr = t.index.i128.end(); - - auto itr = t.index.i128.begin(); - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().i128 == s.i128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().i128 == s2.i128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().i128 == s3.i128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().i128 == s4.i128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().i128 == s5.i128, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); - } - - [[eosio::action]] - void findf() { - my_table t{"kvtest"_n}; - auto end_itr = t.index.test_float.end(); - - auto itr = t.index.test_float.begin(); - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().test_float == s5.test_float, "Got the wrong value"); - ++itr; - eosio::check(itr.value().test_float == s4.test_float, "Got the wrong value"); - ++itr; - eosio::check(itr.value().test_float == s.test_float, "Got the wrong value"); - ++itr; - eosio::check(itr.value().test_float == s2.test_float, "Got the wrong value"); - ++itr; - eosio::check(itr.value().test_float == s3.test_float, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); - } - - [[eosio::action]] - void finds() { - my_table t{"kvtest"_n}; - auto end_itr = t.index.tstruct.end(); - - auto itr = t.index.tstruct.begin(); - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tstruct.a == s.tstruct.a, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct.a == s3.tstruct.a, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct.a == s2.tstruct.a, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct.a == s4.tstruct.a, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct.a == s5.tstruct.a, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + auto itr = t.index.primary_key.find("C"); + auto val = itr.value(); } [[eosio::action]] void iteration() { my_table t{"kvtest"_n}; - auto begin_itr = t.index.foo.begin(); - auto end_itr = t.index.foo.end(); - - // operator++ (case sensitive string) - // ---------- - auto itr = t.index.foo.begin(); - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().foo == "C", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "I", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "a", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "e", "Got the wrong value"); - ++itr; - eosio::check(itr.value().foo == "g", "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); - - // operator-- (case sensitive string) - // ---------- - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); - --itr; - eosio::check(itr == begin_itr, "Should be the beginning"); - - // operator int32_t - // ---------------- - itr = t.index.baz.begin(); - eosio::check(itr.value().baz == -2, "Got the wrong value"); - ++itr; - eosio::check(itr.value().baz == -1, "Got the wrong value"); - ++itr; - eosio::check(itr.value().baz == 0, "Got the wrong value"); - ++itr; - eosio::check(itr.value().baz == 1, "Got the wrong value"); - ++itr; - eosio::check(itr.value().baz == 2, "Got the wrong value"); - } - - [[eosio::action]] - void range() { - my_table t{"kvtest"_n}; - - std::vector expected{s5, s4, s3}; - uint64_t b = 1; - uint64_t e = 3; - auto vals = t.index.bar.range(b, e); - eosio::check(vals == expected, "range did not return expected vector"); - - expected = {s3}; - vals = t.index.bar.range(e, e); - eosio::check(vals == expected, "range did not return expected vector"); + auto foo_begin_itr = t.index.foo.begin(); + auto foo_end_itr = t.index.foo.end(); + + auto bar_begin_itr = t.index.bar.begin(); + auto bar_end_itr = t.index.bar.end(); + + auto foo_itr = t.index.foo.begin(); + auto bar_itr = t.index.bar.begin(); + + eosio::check(foo_itr != foo_end_itr, "Should not be the end"); + eosio::check(bar_itr != bar_end_itr, "Should not be the end"); + eosio::check(foo_itr.value().foo == s2.foo, "Got the wrong value"); + eosio::check(bar_itr.value().bar == s5.bar, "Got the wrong value"); + + ++foo_itr; + ++bar_itr; + eosio::check(foo_itr.value().foo == s5.foo, "Got the wrong value"); + eosio::check(bar_itr.value().bar == s4.bar, "Got the wrong value"); + + ++foo_itr; + ++bar_itr; + eosio::check(foo_itr.value().foo == s1.foo, "Got the wrong value"); + eosio::check(bar_itr.value().bar == s3.bar, "Got the wrong value"); + + ++foo_itr; + ++bar_itr; + eosio::check(foo_itr.value().foo == s3.foo, "Got the wrong value"); + eosio::check(bar_itr.value().bar == s2.bar, "Got the wrong value"); + + ++foo_itr; + ++bar_itr; + eosio::check(foo_itr.value().foo == s4.foo, "Got the wrong value"); + eosio::check(bar_itr.value().bar == s1.bar, "Got the wrong value"); + + ++foo_itr; + ++bar_itr; + eosio::check(foo_itr == foo_end_itr, "Should be the end"); + eosio::check(bar_itr == bar_end_itr, "Should be the end"); + + --foo_itr; + --bar_itr; + eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); + eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + + --foo_itr; + --bar_itr; + eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); + eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + + --foo_itr; + --bar_itr; + eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); + eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + + --foo_itr; + --bar_itr; + eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); + eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + + --foo_itr; + --bar_itr; + eosio::check(foo_itr == foo_begin_itr, "Should be the beginning"); + eosio::check(bar_itr == bar_begin_itr, "Should be the beginning"); } }; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 6ee8037d21..9dde0fb9be 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -2,15 +2,9 @@ struct my_struct { eosio::name primary_key; - eosio::name n2; - std::string foo; - std::string bar; bool operator==(const my_struct b) const { - return primary_key == b.primary_key && - n2 == b.n2 && - foo == b.foo && - bar == b.bar; + return primary_key == b.primary_key; } }; @@ -21,34 +15,19 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { using contract::contract; my_struct s{ - .primary_key = "bob"_n, - .n2 = "alice"_n, - .foo = "a", - .bar = "b" + .primary_key = "bob"_n }; my_struct s2{ - .primary_key = "alice"_n, - .n2 = "bob"_n, - .foo = "c", - .bar = "d" + .primary_key = "alice"_n }; my_struct s3{ - .primary_key = "john"_n, - .n2 = "joe"_n, - .foo = "e", - .bar = "f" + .primary_key = "john"_n }; my_struct s4{ - .primary_key = "joe"_n, - .n2 = "john"_n, - .foo = "g", - .bar = "h" + .primary_key = "joe"_n }; my_struct s5{ - .primary_key = "billy"_n, - .n2 = "vincent"_n, - .foo = "i", - .bar = "j" + .primary_key = "billy"_n }; [[eosio::action]] @@ -71,31 +50,26 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - eosio::check(val.n2 == "alice"_n, "Got the wrong n2"); itr = t.index.primary_key.find("joe"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); - eosio::check(val.n2 == "john"_n, "Got the wrong n2"); itr = t.index.primary_key.find("alice"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); - eosio::check(val.n2 == "bob"_n, "Got the wrong n2"); itr = t.index.primary_key.find("john"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); - eosio::check(val.n2 == "joe"_n, "Got the wrong n2"); itr = t.index.primary_key.find("billy"_n); val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - eosio::check(val.n2 == "vincent"_n, "Got the wrong n2"); } [[eosio::action]] From af7fd6664c233d5bbeee1915c45a5ba9fb9dce81 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 23 Jan 2020 09:20:07 -0500 Subject: [PATCH 168/659] Fix handing of null (deleted) indexes --- .../eosiolib/contracts/eosio/key_value.hpp | 36 ++++++++++++------- .../kv_multiple_indices_tests.cpp | 6 ++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6251617c5e..376bc79abe 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #define EOSIO_CDT_KV_INDEX_nullptr @@ -21,30 +21,40 @@ #define EOSIO_CDT_CAT2(x, y) x ## y #define EOSIO_CDT_CAT(x, y) EOSIO_CDT_CAT2(x, y) #define EOSIO_CDT_APPLY(f, args) f args -#define EOSIO_CDT_FIX_KV_INDEX_TYPE_0(index_name) kv_index -#define EOSIO_CDT_FIX_KV_INDEX_TYPE_1(index_name) null_kv_index -#define EOSIO_CDT_FIX_KV_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_FIX_KV_INDEX_TYPE_ ## iskeyword -#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_0(value_class, index_name) {&value_class::index_name} -#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_1(value_class, index_name) -#define EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT(iskeyword, garbage) EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT_ ## iskeyword +#define EOSIO_CDT_KV_FIX_INDEX_NAME_0(index_name, i) index_name +#define EOSIO_CDT_KV_FIX_INDEX_NAME_1(index_name, i) index_name ## i +#define EOSIO_CDT_KV_FIX_INDEX_NAME(x, i) EOSIO_CDT_KV_FIX_INDEX_NAME_ ## x + +#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) kv_index +#define EOSIO_CDT_KV_FIX_INDEX_TYPE_1(index_name) null_kv_index +#define EOSIO_CDT_KV_FIX_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_TYPE_ ## iskeyword + +#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_0(value_class, index_name) {&value_class::index_name} +#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_1(value_class, index_name) +#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_ ## iskeyword + +#define EOSIO_CDT_KV_INDEX_NAME(index_name, i) \ + EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_NAME, \ + (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(index_name, i) #define EOSIO_CDT_KV_INDEX_TYPE(index_name) \ - EOSIO_CDT_APPLY(EOSIO_CDT_FIX_KV_INDEX_TYPE, \ + EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_TYPE, \ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(index_name) #define EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name) \ - EOSIO_CDT_APPLY(EOSIO_CDT_FIX_KV_INDEX_CONSTRUCT, \ + EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT, \ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(value_class, index_name) -#define CREATE_KV_INDEX(r, value_class, index_name) \ - EOSIO_CDT_KV_INDEX_TYPE(index_name) index_name EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); +#define CREATE_KV_INDEX(r, value_class, i, index_name) \ + EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); #define LIST_INDICES(value_class, ...) \ - BOOST_PP_SEQ_FOR_EACH(CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) + BOOST_PP_SEQ_FOR_EACH_I(CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) #define TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ eosio::kv_table @@ -540,6 +550,8 @@ class kv_table { std::function key_function; }; + class null_kv_index : public kv_index {}; + template void init(eosio::name contract, Indices indices) { contract_name = contract; diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index c01531492b..8bce37ec3d 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -18,6 +18,12 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", bar ) +DEFINE_TABLE(my_table_2, my_struct, "testtable", "eosio.kvram", + primary_key, + nullptr, + bar +) + class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; From 1234d3212008c4c9a598c0285ba646f98745bab6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 23 Jan 2020 15:03:31 -0500 Subject: [PATCH 169/659] Add open method for initializing tables --- .../eosiolib/contracts/eosio/key_value.hpp | 40 ++++++++++++++++ tests/integration/kv_tests.cpp | 1 - .../unit/test_contracts/kv_make_key_tests.cpp | 48 +++++++++++-------- .../kv_multiple_indices_tests.cpp | 8 ++-- .../test_contracts/kv_single_index_tests.cpp | 24 +++++----- 5 files changed, 83 insertions(+), 38 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 376bc79abe..281182e5fb 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -623,6 +623,46 @@ class kv_table { } } + static Class open(eosio::name contract_name) { + Class c = Class(contract_name); + return c; + } + +protected: + kv_table() = default; + + template + void init(eosio::name contract, Indices indices) { + contract_name = contract; + uint64_t index_name = 1; + + auto& primary = get<0>(*indices); + + primary_index = &primary; + primary_index->name = eosio::name{index_name}; + primary_index->contract_name = contract_name; + primary_index->table_name = table_name; + primary_index->tbl = this; + + ++index_name; + + for_each_field(*indices, [&](auto& idx) { + if (idx.name != primary.name) { + kv_index* si = &idx; + si->name = eosio::name{index_name}; + si->contract_name = contract_name; + si->table_name = table_name; + si->tbl = this; + secondary_indices.push_back(si); + ++index_name; + } + }); + + // Makes sure the indexes are run in the correct order. + // This is mainly useful for debugging, this probably could be deleted. + std::reverse(std::begin(secondary_indices), std::end(secondary_indices)); + } + private: constexpr static uint64_t db = static_cast(DbName); constexpr static eosio::name table_name = static_cast(TableName); diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 5cea8c9136..90f342c3a3 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -106,5 +106,4 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() - BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index a7e462613d..ab7796e088 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -22,17 +22,23 @@ struct my_struct { auto itstring() const { return eosio::make_insensitive(tstring); } }; -DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - tname, - tstring, - tui64, - ti32, - ti128, - tfloat, - tstruct, - ttuple, - itstring -) +struct my_table : eosio::kv_table { + struct { + kv_index tname{&my_struct::tname}; + kv_index tstring{&my_struct::tstring}; + kv_index tui64{&my_struct::tui64}; + kv_index ti32{&my_struct::ti32}; + kv_index ti128{&my_struct::ti128}; + kv_index tfloat{&my_struct::tfloat}; + kv_index tstruct{&my_struct::tstruct}; + kv_index ttuple{&my_struct::ttuple}; + kv_index itstring{&my_struct::itstring}; + } index; + + my_table(eosio::name contract_name) { + init(contract_name, &index); + } +}; class [[eosio::contract]] kv_make_key_tests : public eosio::contract { public: @@ -90,7 +96,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); t.put(s1); t.put(s2); @@ -101,7 +107,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyname() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.tname.end(); auto itr = t.index.tname.begin(); @@ -122,7 +128,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeystr() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.tstring.end(); auto itr = t.index.tstring.begin(); @@ -143,7 +149,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyistr() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.itstring.end(); auto itr = t.index.itstring.begin(); @@ -164,7 +170,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyuill() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.tui64.end(); auto itr = t.index.tui64.begin(); @@ -185,7 +191,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyil() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.ti32.end(); auto itr = t.index.ti32.begin(); @@ -206,7 +212,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyilll() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.ti128.end(); auto itr = t.index.ti128.begin(); @@ -227,7 +233,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyflt() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.tfloat.end(); auto itr = t.index.tfloat.begin(); @@ -248,7 +254,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeystct() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.tstruct.end(); auto itr = t.index.tstruct.begin(); @@ -269,7 +275,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeytup() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.ttuple.end(); auto itr = t.index.ttuple.begin(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 8bce37ec3d..18aed9d57c 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -55,7 +55,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); t.put(s1); t.put(s2); @@ -66,7 +66,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto itr = t.index.primary_key.find("bob"_n); auto val = itr.value(); @@ -83,7 +83,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void finderror() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto itr = t.index.primary_key.find("C"); auto val = itr.value(); @@ -91,7 +91,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void iteration() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto foo_begin_itr = t.index.foo.begin(); auto foo_end_itr = t.index.foo.end(); diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 9dde0fb9be..424584c67f 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -32,7 +32,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); t.put(s3); t.put(s); @@ -43,7 +43,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.primary_key.end(); auto itr = t.index.primary_key.find("bob"_n); @@ -74,14 +74,14 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void finderror() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto itr = t.index.primary_key.find("larry"_n); auto val = itr.value(); } [[eosio::action]] void iteration() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto begin_itr = t.index.primary_key.begin(); auto end_itr = t.index.primary_key.end(); @@ -121,21 +121,21 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void itrerror1() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.primary_key.end(); ++end_itr; } [[eosio::action]] void itrerror2() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto begin_itr = t.index.primary_key.begin(); --begin_itr; } [[eosio::action]] void range() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); std::vector expected{s, s4, s3}; auto vals = t.index.primary_key.range("bob"_n, "john"_n); @@ -148,25 +148,25 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void rangeerror1() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto vals = t.index.primary_key.range("joe"_n, "alice"_n); } [[eosio::action]] void rangeerror2() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto vals = t.index.primary_key.range("chris"_n, "joe"_n); } [[eosio::action]] void rangeerror3() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto vals = t.index.primary_key.range("alice"_n, "chris"_n); } [[eosio::action]] void erase() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); auto end_itr = t.index.primary_key.end(); t.erase("joe"_n); @@ -180,7 +180,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void eraseerror() { - my_table t{"kvtest"_n}; + my_table t = my_table::open("kvtest"_n); t.erase("chris"_n); } }; From 49260900bbc38f300900fdb3b7fa9ef932c591bf Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 24 Jan 2020 11:25:29 -0500 Subject: [PATCH 170/659] Add function level documentation --- Doxyfile | 2 +- .../eosiolib/contracts/eosio/key_value.hpp | 406 +++++++++++++++++- 2 files changed, 406 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index 266e1614ae..15a035a229 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1980,7 +1980,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = _DOXYGEN_ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 281182e5fb..69e02a2e89 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -59,6 +59,47 @@ #define TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ eosio::kv_table +/** + * @brief Macro to define a table. + * @details The resulting table will have a member `index` that has fields on it that match 1-1 with the names of the + * fields passed into the list. See example for further clarification. + * + * @param table_class - The name of the class of the user defined table that inherits from eosio::kv_table + * @param value_class - The name of the class of the data stored as the value of the table + * @param table_name - The name of the table + * @param db_name - The type of the EOSIO Key Value database. Defaulted to eosio.kvram + * @param ... - A variadic list of 1 or more indexes to define on the table. + * + * Example: + * + * @code + * struct myrecord { + * std::string primary_key; + * uint64_t secondary_1; + * std::tuple secondary_2; + * } + * + * DEFINE_TABLE(mytable, myrecord, "testtable", + * primary_key, + * secondary_1, + * secondary_2 + * ) + * + * // The above macro results in the following class. + * + * struct mytable : kv_table { + * struct { + * kv_index primary_key{&myrecord::primary_key}; + * kv_index secondary_1{&myrecord::secondary_1}; + * kv_index secondary_2{&myrecord::secondary_2}; + * } index; + * + * mytable(eosio::name contract_name) { + * init(contract_name, &index); + * } + * } + * @endcode + */ #define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ struct table_class : TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ struct { \ @@ -120,6 +161,9 @@ namespace eosio { } } +/** + * The key_type struct is used to store the binary representation of a key. + */ struct key_type { size_t size; std::string buffer; @@ -136,6 +180,7 @@ namespace detail { constexpr static size_t max_stack_buffer_size = 512; } +/* @cond PRIVATE */ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { using namespace detail; @@ -332,12 +377,104 @@ inline key_type make_key(std::tuple val) { } return {data_size, s}; } - +/* @endcond */ + +// This is the "best" way to document a function that does not technically exist using Doxygen. +#if _DOXYGEN_ +/** + * @brief A function for converting types to the appropriate binary representation for the EOSIO Key Value database. + * @details The CDT provides implementations of this function for many of the common primitives and for structs/tuples. + * If sticking with standard types, contract developers should not need to interact with this function. + * If doing something more advanced, contract developers may need to provide their own implementation for a special type. + */ +template +inline key_type make_key(T val) { + return {}; +} +#endif + + +/** + * Used to return the appropriate representation of a case insensitive string for the EOSIO Key Value database. + * + * @param val - The string to be made case-insensitive + * @return The binary representation of the case-insensitive string + * + * Example: + * + * @code + * struct location { + * std::string city; + * std::string state; + * uint64_t zip_code; + * + * auto icity() { return eosio::make_insensitive(city); } + * auto istate() { return eosio::make_insensitive(state); } + * } + * + * DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", + * icity, + * istate, + * zip_code + * ) + * @endcode + */ inline key_type make_insensitive(const std::string& val) { return make_key(val, true); } +/** + * @defgroup keyvalue Key Value Table + * @ingroup contracts + * + * @brief Defines an EOSIO Key Value Table + * @details EOSIO Key Value API provides a C++ interface to the EOSIO Key Value database. + * Key Value Tables require 1 primary index, of any type that can be serialized to a binary representation. + * Key Value Tables support 0 or more secondary index, of any type that can be serialized to a binary representation. + * Indexes must be a member variable or a member function. + * + * @tparam Class - the name of the class of the user defined table that inherits from eosio::kv_table + * @tparam T - the type of the data stored as the value of the table + * @tparam TableName - the name of the table + * @tparam DbName - the type of the EOSIO Key Value database. Defaulted to eosio.kvram + * + * Example: + * + * @code + * #include + * using namespace eosio; + * + * struct address { + * uint64_t account_name; + * string first_name; + * string last_name; + * string street; + * string city; + * string state; + * + * auto full_name() { return first_name + " " + last_name; } + * } + * + * struct address_table : kv_table { + * struct { + * kv_index account_name{&address::account_name}; + * kv_index full_name{&address::full_name}; + * } index; + * + * addresses(eosio::name contract_name) { + * init(contract_name, &index); + * } + * } + * + * class addressbook : contract { + * public: + * void myaction() { + * auto addresses = address_table::open("mycontract"_n); + * } + * } + * @endcode + */ template class kv_table { @@ -348,12 +485,40 @@ class kv_table { }; public: + /** + * @ingroup keyvalue + * + * @brief Defines an index on an EOSIO Key Value Table + * @details A Key Value Index allows a user of the table to search based on a given field. + * The only restrictions on that field are that it is serializable to a binary representation. + * Convenience functions exist to handle most of the primitive types as well as some more complex types, and are + * used automatically where possible. + */ class kv_index { class iterator { public: iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size, kv_index* idx) : contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size}, idx{idx} {} + /** + * Returns the value that the iterator points to. + * @ingroup keyvalue + * + * @return The value that the iterator points to. + * + * Example: + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * // add dan account to table - see put example + * + * auto dan = addresses.index.full_name.find("Dan Larimer"); + * eosio::check(dan != addresses.index.full_name.end(), "Dan Larimer is not in the table"); + * eosio::check(dan.value().city == "Blacksburg", "Got the wrong value"); + * } + * @endcode + */ T value() const { using namespace detail; @@ -473,6 +638,31 @@ class kv_table { }; } + /** + * Search for an existing object in a table by the index, using the given key. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced by the key param. + * + * @param key - The key to search for. + * @return An iterator to the found object OR the `end` iterator if the given key was not found. + * + * Example: + * + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * // add dan account to table - see put example + * + * auto itr = addresses.index.account_name.find("dan"_n); + * eosio::check(itr != addresses.index.account_name.end(), "Couldn't get him."); + * + * auto itr = addresses.index.full_name.find("Dan Larimer"); + * eosio::check(itr != addresses.index.full_name.end(), "Couldn't get him."); + * } + * @endcode + */ template iterator find(K key) { uint32_t value_size; @@ -495,6 +685,28 @@ class kv_table { return {contract_name, itr, static_cast(itr_stat), value_size, this}; } + /** + * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. + * @ingroup keyvalue + * + * @return An iterator referring to the `past-the-end` element. + * + * Example: + * + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * // add dan account to table - see put example + * + * auto itr = addresses.index.account_name.find("brendan"_n); + * eosio::check(itr == addresses.index.account_name.end(), "brendan should not be in the table."); + * + * auto itr = addresses.index.full_name.find("Brendan Blumer"); + * eosio::check(itr == addresses.index.full_name.end(), "Brendan Blumer should not be in the table."); + * } + * @endcode + */ iterator end() { auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); @@ -503,6 +715,28 @@ class kv_table { return {contract_name, itr, static_cast(itr_stat), 0, this}; } + /** + * Returns an iterator to the object with the lowest key (by this index) in the table. + * @ingroup keyvalue + * + * @return An iterator to the object with the lowest key (by this index) in the table. + * + * Example: + * + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * // add dan account to table - see put example + * + * auto itr = addresses.index.account_name.find("dan"_n); + * eosio::check(itr == addresses.index.account_name.begin(), "dan should be at the beginning."); + * + * auto itr = addresses.index.full_name.find("Dan Larimer"); + * eosio::check(itr == addresses.index.full_name.begin(), "Dan Larimer should be at the beginning."); + * } + * @endcode + */ iterator begin() { auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); @@ -517,6 +751,40 @@ class kv_table { return {contract_name, itr, static_cast(itr_stat), value_size, this}; } + /** + * Returns a vector of objects that fall between the specifed range. The range is inclusive on both ends. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced by the key param. + * + * @param begin - The beginning of the range. + * @param end - The end of the range. + * @return A vector containing all the objects that fall between the range. + * + * Example: + * + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * // add dan account to table - see put example + * // add brendan account to table - see put example + * // add john account to table - see put example + * + * address dan = {...} + * address brendan = {...} + * address john = {...} + * + * std::vector expected_values = {brendan, dan, john}; + * auto values = addresses.index.account_name.range("brendan"_n, "john"_n); + * eosio::check(values == expected_values, "Did not get the expected values"); + * + * std::vector expected_values = {dan}; + * auto values = addresses.index.account_name.range("dan"_n, "dan"_n); + * eosio::check(values == expected_values, "Did not get the expected values"); + * } + * @endcode + */ template std::vector range(K begin, K end) { auto begin_itr = find(begin); @@ -550,8 +818,66 @@ class kv_table { std::function key_function; }; + /** + * @ingroup keyvalue + * + * @brief Defines a deleted index on an EOSIO Key Value Table + * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. + * A null_kv_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. + * + * Example: + * @code + * // Original table: + * DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + * primary_key, + * secondary_1, + * secondary_2 + * ) + * + * struct my_table : kv_table { + * struct { + * kv_index primary_key ...; + * kv_index secondary_1 ...; + * kv_index secondary_2 ...; + * } index; + * + * my_table(eosio::name contract_name) { + * init(contract_name, &index); + * } + * } + * + * // Table with secondary_1 deleted: + * DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + * primary_key, + * nullptr + * secondary_2 + * ) + * + * struct my_table : kv_table { + * struct { + * kv_index primary_key ...; + * null_kv_index nullptr1 ...; + * kv_index secondary_2 ...; + * } index; + * + * my_table(eosio::name contract_name) { + * init(contract_name, &index); + * } + * } + * @endcode + */ class null_kv_index : public kv_index {}; + /** + * Initializes a key value table. This method is intended to be called in the constructor of the user defined table class. + * If using the DEFINE_TABLE macro, this is handled for the developer. + * @ingroup keyvalue + * + * @tparam Indices - a list of types of the indices. This will be auto-deduced through the indices parameter. + * + * @param contract - the name of the contract this table is associated with + * @param indices - a list of 1 or more indices to add to the table + */ template void init(eosio::name contract, Indices indices) { contract_name = contract; @@ -584,6 +910,30 @@ class kv_table { std::reverse(std::begin(secondary_indices), std::end(secondary_indices)); } + /** + * Puts a value into the table. If the value already exists, it updates the existing entry. + * The key is determined from the defined primary index. + * @ingroup keyvalue + * + * @param value - The entry to be stored in the table. + * + * Example: + * @code + * // This assumes the code from the class example. + * + * void myaction() { + * auto addresses = address_table::open("mycontract"_n); + * addresses.put({ + * .account_name = "dan"_n, + * .first_name = "Daniel", + * .last_name = "Larimer", + * .street = "1 EOS Way", + * .city = "Blacksburg", + * .state = "VA" + * }); + * } + * @endcode + */ void put(const T& value) { using namespace detail; @@ -606,6 +956,26 @@ class kv_table { } } + /** + * Removes a value from the table. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced through the key parameter. + * + * @param key - The key of the value to be removed. + * + * Example: + * // This assumes the code from the class example. + * @code + * void myaction() { + * auto addresses = address_table::open("mycontract"_n); + * + * auto itr = addresses.index.account_name.find("dan"_n); + * eosio::check(itr != addresses.index.account_name.end()); + * addresses.erase("dan"_n); + * } + * @endcode + */ template void erase(K key) { auto primary_itr = primary_index->find(key); @@ -623,6 +993,30 @@ class kv_table { } } + /** + * Initializes and returns an instance of the Key Value table scoped to the contract name. + * + * @param contract_name - The name of the contract. + * @return An initialized instance of the user specifed Key Value table class. + * + * Example: + * + * @code + * struct myrecord { + * std::string primary_key; + * } + * + * DEFINE_TABLE(mytable, myrecord, "testtable", primary_key) + * + * class mycontract : contract { + * public: + * void myaction() { + * auto t = mytable::open("mycontract"_n); + * } + * } + * + * @endcode + */ static Class open(eosio::name contract_name) { Class c = Class(contract_name); return c; @@ -631,6 +1025,16 @@ class kv_table { protected: kv_table() = default; + /** + * Initializes a key value table. This method is intended to be called in the constructor of the user defined table class. + * If using the DEFINE_TABLE macro, this is handled for the developer. + * @ingroup keyvalue + * + * @tparam Indices - a list of types of the indices. This will be auto-deduced through the indices parameter. + * + * @param contract - the name of the contract this table is associated with + * @param indices - a list of 1 or more indices to add to the table + */ template void init(eosio::name contract, Indices indices) { contract_name = contract; From 2d54d3edc467aefa8705c956fedf9244df1d712f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 24 Jan 2020 12:15:29 -0500 Subject: [PATCH 171/659] Cleanup --- .../eosiolib/contracts/eosio/key_value.hpp | 58 ++----------------- .../unit/test_contracts/kv_make_key_tests.cpp | 2 +- 2 files changed, 5 insertions(+), 55 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 69e02a2e89..a6e5026932 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -182,19 +182,17 @@ namespace detail { /* @cond PRIVATE */ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { - using namespace detail; - auto bige_table = swap_endian(table_name.value); auto bige_index = swap_endian(index_name.value); - size_t size_64 = sizeof(index_name); + size_t size_name = sizeof(index_name); - size_t buffer_size = (2 * size_64) + sizeof(status); + size_t buffer_size = (2 * size_name) + sizeof(status); void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); memcpy(buffer, &status, sizeof(status)); - memcpy(((char*)buffer) + sizeof(status), &bige_table, size_64); - memcpy(((char*)buffer) + sizeof(status) + size_64, &bige_index, size_64); + memcpy(((char*)buffer) + sizeof(status), &bige_table, size_name); + memcpy(((char*)buffer) + sizeof(status) + size_name, &bige_index, size_name); std::string s((char*)buffer, buffer_size); @@ -206,8 +204,6 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint } inline key_type table_key(const key_type& prefix, const key_type& key) { - using namespace detail; - size_t buffer_size = key.size + prefix.size; void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); @@ -239,8 +235,6 @@ inline I get_msb(I val) { template ::value, int> = 0> inline key_type make_key(I val) { - using namespace detail; - if (std::is_signed::value) { val = flip_msb(val); } @@ -291,8 +285,6 @@ inline key_type make_key(F val) { } inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { - using namespace detail; - size_t data_size = size + 3; void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); @@ -868,48 +860,6 @@ class kv_table { */ class null_kv_index : public kv_index {}; - /** - * Initializes a key value table. This method is intended to be called in the constructor of the user defined table class. - * If using the DEFINE_TABLE macro, this is handled for the developer. - * @ingroup keyvalue - * - * @tparam Indices - a list of types of the indices. This will be auto-deduced through the indices parameter. - * - * @param contract - the name of the contract this table is associated with - * @param indices - a list of 1 or more indices to add to the table - */ - template - void init(eosio::name contract, Indices indices) { - contract_name = contract; - uint64_t index_name = 1; - - auto& primary = get<0>(*indices); - - primary_index = &primary; - primary_index->name = eosio::name{index_name}; - primary_index->contract_name = contract_name; - primary_index->table_name = table_name; - primary_index->tbl = this; - - ++index_name; - - for_each_field(*indices, [&](auto& idx) { - if (idx.name != primary.name) { - kv_index* si = &idx; - si->name = eosio::name{index_name}; - si->contract_name = contract_name; - si->table_name = table_name; - si->tbl = this; - secondary_indices.push_back(si); - ++index_name; - } - }); - - // Makes sure the indexes are run in the correct order. - // This is mainly useful for debugging, this probably could be deleted. - std::reverse(std::begin(secondary_indices), std::end(secondary_indices)); - } - /** * Puts a value into the table. If the value already exists, it updates the existing entry. * The key is determined from the defined primary index. diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index ab7796e088..3aee47d36f 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -61,7 +61,7 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .ti128 = (static_cast(1) << 127) - 4, .tfloat = 5.2574, .tstruct = { 5, 6 }, - .ttuple = { 100, 32.44, "def"} + .ttuple = { 100, 32.43, "def"} }; my_struct s3{ .tname = "john"_n, From 7448faa2dfd448d91f0ee8d3f17db21ee2789f43 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 24 Jan 2020 13:02:26 -0500 Subject: [PATCH 172/659] PR feedback --- Doxyfile | 2 +- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doxyfile b/Doxyfile index 15a035a229..171f16435a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1980,7 +1980,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = _DOXYGEN_ +PREDEFINED = EOSIO_CDT_DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index a6e5026932..077e18635c 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -177,7 +177,7 @@ struct key_type { }; namespace detail { - constexpr static size_t max_stack_buffer_size = 512; + constexpr inline size_t max_stack_buffer_size = 512; } /* @cond PRIVATE */ @@ -372,7 +372,7 @@ inline key_type make_key(std::tuple val) { /* @endcond */ // This is the "best" way to document a function that does not technically exist using Doxygen. -#if _DOXYGEN_ +#if EOSIO_CDT_DOXYGEN /** * @brief A function for converting types to the appropriate binary representation for the EOSIO Key Value database. * @details The CDT provides implementations of this function for many of the common primitives and for structs/tuples. From 946f125fd77eca8db5ccbed5671d7c60c74358fe Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 24 Jan 2020 15:10:38 -0500 Subject: [PATCH 173/659] Change key_type to inherit from std::string --- .../eosiolib/contracts/eosio/key_value.hpp | 82 +++++++++---------- modules/TestsExternalProject.txt | 2 +- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 077e18635c..b71be94935 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -164,16 +164,8 @@ namespace eosio { /** * The key_type struct is used to store the binary representation of a key. */ -struct key_type { - size_t size; - std::string buffer; - - bool operator==(const key_type& k) const { - return std::tie(size, buffer) == std::tie(k.size, k.buffer); - } - bool operator!=(const key_type& k) const { - return !(*this == k); - } +struct key_type : std::string { + using std::string::string; }; namespace detail { @@ -194,29 +186,29 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint memcpy(((char*)buffer) + sizeof(status), &bige_table, size_name); memcpy(((char*)buffer) + sizeof(status) + size_name, &bige_index, size_name); - std::string s((char*)buffer, buffer_size); + key_type s((const char*)buffer, buffer_size); if (buffer_size > detail::max_stack_buffer_size) { free(buffer); } - return {buffer_size, s}; + return s; } inline key_type table_key(const key_type& prefix, const key_type& key) { - size_t buffer_size = key.size + prefix.size; + size_t buffer_size = key.size() + prefix.size(); void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - memcpy(buffer, prefix.buffer.data(), prefix.size); - memcpy(((char*)buffer) + prefix.size, key.buffer.data(), key.size); + memcpy(buffer, prefix.data(), prefix.size()); + memcpy(((char*)buffer) + prefix.size(), key.data(), key.size()); - std::string s((char*)buffer, buffer_size); + key_type s((const char*)buffer, buffer_size); if (buffer_size > detail::max_stack_buffer_size) { free(buffer); } - return {buffer_size, s}; + return s; } template @@ -241,10 +233,10 @@ inline key_type make_key(I val) { auto big_endian = swap_endian(val); - char* bytes = reinterpret_cast(&big_endian); + const char* bytes = reinterpret_cast(&big_endian); constexpr size_t size = sizeof(big_endian); - std::string s(bytes, size); - return {size, s}; + key_type s(bytes, size); + return s; } template @@ -262,10 +254,10 @@ inline key_type make_floating_key(F val) { auto big_endian = swap_endian(bit_val); - char* bytes = reinterpret_cast(&big_endian); + const char* bytes = reinterpret_cast(&big_endian); constexpr size_t size = sizeof(big_endian); - std::string s(bytes, size); - return {size, s}; + key_type s(bytes, size); + return s; } template ::value, int> = 0> @@ -298,12 +290,12 @@ inline key_type make_key(const char* str, size_t size, bool case_insensitive=fal ((char*)data_buffer)[data_size - 2] = 0x00; ((char*)data_buffer)[data_size - 1] = 0x00; - std::string s((char*)data_buffer, data_size); + key_type s((const char*)data_buffer, data_size); if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } - return {data_size, s}; + return s; } inline key_type make_key(const std::string& val, bool case_insensitive=false) { @@ -318,6 +310,10 @@ inline key_type make_key(eosio::name n) { return make_key(n.value); } +inline key_type make_key(key_type&& val) { + return val; +} + template ::value, int> = 0> inline key_type make_key(S val) { size_t data_size = 0; @@ -332,16 +328,16 @@ inline key_type make_key(S val) { boost::pfr::for_each_field(val, [&](auto& field) { auto kt = make_key(field); - memcpy((char*)data_buffer + pos, kt.buffer.data(), kt.size); - pos += kt.size; + memcpy((char*)data_buffer + pos, kt.data(), kt.size()); + pos += kt.size(); }); - std::string s((char*)data_buffer, data_size); + key_type s((const char*)data_buffer, data_size); if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } - return {data_size, s}; + return s; } template @@ -358,16 +354,16 @@ inline key_type make_key(std::tuple val) { boost::fusion::for_each(val, [&](auto& field) { auto kt = make_key(field); - memcpy((char*)data_buffer + pos, kt.buffer.data(), kt.size); - pos += kt.size; + memcpy((char*)data_buffer + pos, kt.data(), kt.size()); + pos += kt.size(); }); - std::string s((char*)data_buffer, data_size); + key_type s((const char*)data_buffer, data_size); if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } - return {data_size, s}; + return s; } /* @endcond */ @@ -662,15 +658,15 @@ class kv_table { auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.buffer.data(), t_key.size, value_size); + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { return end(); } - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.buffer.data(), t_key.size); - auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.buffer.data(), t_key.size); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); eosio::check(cmp == 0, "This key does not exist in this iterator"); @@ -701,7 +697,7 @@ class kv_table { */ iterator end() { auto prefix = make_prefix(table_name, name); - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); return {contract_name, itr, static_cast(itr_stat), 0, this}; @@ -731,7 +727,7 @@ class kv_table { */ iterator begin() { auto prefix = make_prefix(table_name, name); - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.buffer.data(), prefix.size); + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); uint32_t value_size; @@ -894,11 +890,11 @@ class kv_table { datastream data_ds((char*)data_buffer, data_size); data_ds << value; - internal_use_do_not_use::kv_set(db, contract_name.value, t_key.buffer.data(), t_key.size, (const char*)data_buffer, data_size); + internal_use_do_not_use::kv_set(db, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); for (auto& idx : secondary_indices) { auto st_key = table_key(make_prefix(table_name, idx->name), idx->get_key(value)); - internal_use_do_not_use::kv_set(db, contract_name.value, st_key.buffer.data(), st_key.size, t_key.buffer.data(), t_key.size); + internal_use_do_not_use::kv_set(db, contract_name.value, st_key.data(), st_key.size(), t_key.data(), t_key.size()); } if (data_size > detail::max_stack_buffer_size) { @@ -935,11 +931,11 @@ class kv_table { T val = primary_itr.value(); auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); - internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)k.buffer.data(), k.size); + internal_use_do_not_use::kv_erase(db, contract_name.value, k.data(), k.size()); for (auto& idx : secondary_indices) { auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(val)); - internal_use_do_not_use::kv_erase(db, contract_name.value, (const char*)skey.buffer.data(), skey.size); + internal_use_do_not_use::kv_erase(db, contract_name.value, skey.data(), skey.size()); } } diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index c33d1b6e8f..c04460e6cc 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -6,7 +6,7 @@ ExternalProject_Add( EosioWasmTests SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/unit" BINARY_DIR "${CMAKE_BINARY_DIR}/tests/unit" - CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Release -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" From ee1499bad8798a0b9fa89e39c470f6af39791f99 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 15:15:21 -0500 Subject: [PATCH 174/659] Remove Travis. Bump to CentOS 7.7. --- .cicd/build.sh | 4 +-- ...s-7.6.dockerfile => centos-7.7.dockerfile} | 2 +- .cicd/tests.sh | 2 +- .cicd/toolchain-tests.sh | 2 +- .travis.yml | 27 ------------------- 5 files changed, 5 insertions(+), 32 deletions(-) rename .cicd/docker/{centos-7.6.dockerfile => centos-7.7.dockerfile} (98%) delete mode 100644 .travis.yml diff --git a/.cicd/build.sh b/.cicd/build.sh index 0268ae9e6a..db56484114 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -21,13 +21,13 @@ else # Linux PRE_COMMANDS="cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake .. && make -j$JOBS" - [[ $IMAGE_TAG == 'centos-7.6' ]] && PRE_COMMANDS="$PRE_COMMANDS && source /opt/rh/devtoolset-7/enable" + [[ $IMAGE_TAG == 'centos-7.7' ]] && PRE_COMMANDS="$PRE_COMMANDS && source /opt/rh/devtoolset-7/enable" # Docker Commands if [[ $BUILDKITE == true ]]; then # Generate Base Images $CICD_DIR/generate-base-images.sh elif [[ $TRAVIS == true ]]; then - ARGS="$ARGS -e JOBS -e CCACHE_DIR=/opt/.ccache" + ARGS="$ARGS -e JOBS" fi COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" diff --git a/.cicd/docker/centos-7.6.dockerfile b/.cicd/docker/centos-7.7.dockerfile similarity index 98% rename from .cicd/docker/centos-7.6.dockerfile rename to .cicd/docker/centos-7.7.dockerfile index 890b2c5d94..d98ff24ca0 100644 --- a/.cicd/docker/centos-7.6.dockerfile +++ b/.cicd/docker/centos-7.7.dockerfile @@ -1,4 +1,4 @@ -FROM centos:7.6.1810 +FROM centos:7.7.1908 # install dependencies RUN yum update -y && \ yum --enablerepo=extras install -y centos-release-scl && \ diff --git a/.cicd/tests.sh b/.cicd/tests.sh index 41a4537b36..d828c5f6d3 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -23,7 +23,7 @@ else # Linux . $HELPERS_DIR/docker-hash.sh - [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS -e CCACHE_DIR=/opt/.ccache" + [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS" # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then diff --git a/.cicd/toolchain-tests.sh b/.cicd/toolchain-tests.sh index a369b1e68a..6b44e5803e 100755 --- a/.cicd/toolchain-tests.sh +++ b/.cicd/toolchain-tests.sh @@ -20,7 +20,7 @@ else # Linux . $HELPERS_DIR/docker-hash.sh - [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS -e CCACHE_DIR=/opt/.ccache" + [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS" # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8858c04709..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: cpp -git: - depth: false -if: fork = true OR type = api OR type = cron -matrix: - include: - - os: linux - dist: xenial - services: docker - env: - - IMAGE_TAG='ubuntu-18.04' - - os: linux - dist: xenial - services: docker - env: - - IMAGE_TAG='ubuntu-16.04' - - os: linux - dist: xenial - services: docker - env: - - IMAGE_TAG='amazonlinux-2' - - os: linux - dist: xenial - services: docker - env: - - IMAGE_TAG='centos-7.6' -script: "./.cicd/build.sh && ./.cicd/tests.sh" From d778e000bb4a7f814325ea6be1dddbe059f25af9 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 15:23:03 -0500 Subject: [PATCH 175/659] Remove Travis. Bump to CentOS 7.7. --- .cicd/pipeline.yml | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index c1c7c09df7..85af8720fd 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -13,12 +13,12 @@ steps: timeout: ${TIMEOUT:-10} skip: $SKIP_AMAZON_LINUX_2 - - label: ":centos: CentOS 7.6 - Build" + - label: ":centos: CentOS 7.7 - Build" command: - "./.cicd/build.sh" - "tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" env: - IMAGE_TAG: "centos-7.6" + IMAGE_TAG: "centos-7.7" agents: queue: "automation-eks-eos-builder-fleet" timeout: ${TIMEOUT:-10} @@ -66,6 +66,8 @@ steps: always-pull: true debug: true wait-network: true + - thedyrt/skip-checkout#v0.1.1: + cd: ~ agents: - "queue=mac-anka-large-node-fleet" skip: $SKIP_MOJAVE @@ -83,12 +85,12 @@ steps: timeout: ${TIMEOUT:-10} skip: ${SKIP_AMAZON_LINUX_2}${SKIP_UNIT_TESTS} - - label: ":centos: CentOS 7.6 - Unit Tests" + - label: ":centos: CentOS 7.7 - Unit Tests" command: - - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.6 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.7 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" - "./.cicd/tests.sh" env: - IMAGE_TAG: "centos-7.6" + IMAGE_TAG: "centos-7.7" agents: queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} @@ -136,6 +138,8 @@ steps: always-pull: true debug: true wait-network: true + - thedyrt/skip-checkout#v0.1.1: + cd: ~ agents: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} @@ -151,12 +155,12 @@ steps: timeout: ${TIMEOUT:-10} skip: ${SKIP_AMAZON_LINUX_2}${SKIP_TOOLCHAIN_TESTS} - - label: ":centos: CentOS 7.6 - Toolchain Tests" + - label: ":centos: CentOS 7.7 - Toolchain Tests" command: - - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.6 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.7 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" - "./.cicd/toolchain-tests.sh" env: - IMAGE_TAG: "centos-7.6" + IMAGE_TAG: "centos-7.7" agents: queue: "automation-eks-eos-tester-fleet" timeout: ${TIMEOUT:-10} @@ -204,6 +208,8 @@ steps: always-pull: true debug: true wait-network: true + - thedyrt/skip-checkout#v0.1.1: + cd: ~ agents: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MOJAVE}${SKIP_TOOLCHAIN_TESTS} @@ -224,13 +230,13 @@ steps: - wait - - label: ":centos: Centos 7.6 - Package Builder" + - label: ":centos: Centos 7.7 - Package Builder" command: - - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.6 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" + - "buildkite-agent artifact download build.tar.gz . --step ':centos: CentOS 7.7 - Build' --agent-access-token $$BUILDKITE_AGENT_ACCESS_TOKEN && tar -xzf build.tar.gz" - "./.cicd/package.sh" env: BUILDKITE_AGENT_ACCESS_TOKEN: - IMAGE_TAG: "centos-7.6" + IMAGE_TAG: "centos-7.7" OS: "el7" # OS and PKGTYPE required for lambdas PKGTYPE: "rpm" agents: @@ -269,6 +275,8 @@ steps: always-pull: true debug: true wait-network: true + - thedyrt/skip-checkout#v0.1.1: + cd: ~ agents: - "queue=mac-anka-node-fleet" timeout: 10 From 26d837b5f92fe1c10a37e990edad76d347e071f0 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 15:52:10 -0500 Subject: [PATCH 176/659] Testing Actions. --- .github/workflows/main.yml | 312 +++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..5b09ba1e52 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,312 @@ +name: Pull Request +on: [push] + +jobs: + start-job: + name: Start Job + runs-on: ubuntu-latest + steps: + - name: Start Job. + run: echo "PR created. Builds will be triggered here for forked PRs or Buildkite for internal PRs." + + + amazon_linux-2-build: + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + name: Amazon_Linux 2 | Build + runs-on: ubuntu-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Build + run: | + ./.cicd/build.sh + tar -pczf build.tar.gz build + env: + IMAGE_TAG: amazonlinux-2 + - name: Upload Build Artifact + uses: actions/upload-artifact@v1 + with: + name: amazon_linux-2-build + path: build.tar.gz + amazon_linux-2-unit-test: + name: Amazon_Linux 2 | Unit Test + runs-on: ubuntu-latest + needs: amazon_linux-2-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: amazon_linux-2-build + - name: Unit Test + run: | + tar -xzf amazon_linux-2-build/build.tar.gz + ./.cicd/test.sh + env: + IMAGE_TAG: amazonlinux-2 + amazon_linux-2-toolchain-test: + name: Amazon_Linux 2 | Toolchain Test + runs-on: ubuntu-latest + needs: amazon_linux-2-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: amazon_linux-2-build + - name: Toolchain Test + run: | + tar -xzf amazon_linux-2-build/build.tar.gz + ./.cicd/toolchain-tests.sh + env: + IMAGE_TAG: amazonlinux-2 + + + centos-77-build: + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + name: CentOS 7.7 | Build + runs-on: ubuntu-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Build + run: | + ./.cicd/build.sh + tar -pczf build.tar.gz build + env: + IMAGE_TAG: centos-7.7 + - name: Upload Build Artifact + uses: actions/upload-artifact@v1 + with: + name: centos-77-build + path: build.tar.gz + centos-77-unit-test: + name: CentOS 7.7 | Unit Test + runs-on: ubuntu-latest + needs: centos-77-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: centos-77-build + - name: Unit Test + run: | + tar -xzf centos-77-build/build.tar.gz + ./.cicd/test.sh + env: + IMAGE_TAG: centos-7.7 + centos-77-toolchain-test: + name: CentOS 7.7 | Toolchain Test + runs-on: ubuntu-latest + needs: centos-77-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: centos-77-build + - name: Toolchain Test + run: | + tar -xzf centos-77-build/build.tar.gz + ./.cicd/toolchain-tests.sh + env: + IMAGE_TAG: centos-7.7 + + + ubuntu-1604-build: + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + name: Ubuntu 16.04 | Build + runs-on: ubuntu-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Build + run: | + ./.cicd/build.sh + tar -pczf build.tar.gz build + env: + IMAGE_TAG: ubuntu-16.04 + - name: Upload Build Artifact + uses: actions/upload-artifact@v1 + with: + name: ubuntu-1604-build + path: build.tar.gz + ubuntu-1604-unit-test: + name: Ubuntu 16.04 | Unit Test + runs-on: ubuntu-latest + needs: ubuntu-1604-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: ubuntu-1604-build + - name: Unit Test + run: | + tar -xzf ubuntu-1604-build/build.tar.gz + ./.cicd/test.sh + env: + IMAGE_TAG: ubuntu-16.04 + ubuntu-1604-toolchain-test: + name: Ubuntu 16.04 | Toolchain Test + runs-on: ubuntu-latest + needs: ubuntu-1604-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: ubuntu-1604-build + - name: Toolchain Test + run: | + tar -xzf ubuntu-1604-build/build.tar.gz + ./.cicd/toolchain-tests.sh + env: + IMAGE_TAG: ubuntu-16.04 + + + ubuntu-1804-build: + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + name: Ubuntu 18.04 | Build + runs-on: ubuntu-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Build + run: | + ./.cicd/build.sh + tar -pczf build.tar.gz build + env: + IMAGE_TAG: ubuntu-18.04 + - name: Upload Build Artifact + uses: actions/upload-artifact@v1 + with: + name: ubuntu-1804-build + path: build.tar.gz + ubuntu-1804-unit-test: + name: Ubuntu 18.04 | Unit Test + runs-on: ubuntu-latest + needs: ubuntu-1804-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: ubuntu-1804-build + - name: Unit Test + run: | + tar -xzf ubuntu-1804-build/build.tar.gz + ./.cicd/test.sh + env: + IMAGE_TAG: ubuntu-18.04 + ubuntu-1804-toolchain-test: + name: Ubuntu 18.04 | Toolchain Test + runs-on: ubuntu-latest + needs: ubuntu-1804-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: ubuntu-1804-build + - name: Toolchain Test + run: | + tar -xzf ubuntu-1804-build/build.tar.gz + ./.cicd/toolchain-tests.sh + env: + IMAGE_TAG: ubuntu-18.04 + + + macos-1015-build: + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + name: MacOS 10.15 | Build + runs-on: macos-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Build + run: | + brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 + ./.cicd/build.sh + tar -pczf build.tar.gz build + - name: Upload Build Artifact + uses: actions/upload-artifact@v1 + with: + name: macos-1015-build + path: build.tar.gz + macos-1015-unit-test: + name: MacOS 10.15 | Unit Test + runs-on: macos-latest + needs: amazon_linux-2-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: macos-1015-build + - name: Unit Test + run: | + brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 + tar -xzf macos-1015-build/build.tar.gz + ./.cicd/test.sh + macos-1015-toolchain-test: + name: MacOS 10.15 | Toolchain Test + runs-on: macos-latest + needs: macos-1015-build + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Download Build Artifact + uses: actions/download-artifact@v1 + with: + name: macos-1015-build + - name: Toolchain Test + run: | + brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 + tar -xzf macos-1015-build/build.tar.gz + ./.cicd/toolchain-tests.sh From 15e09f2c29b41e4ff61121768807de6476caff16 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 15:53:14 -0500 Subject: [PATCH 177/659] YAML is picky. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5b09ba1e52..ce414434d5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -153,7 +153,7 @@ jobs: with: name: ubuntu-1604-build path: build.tar.gz - ubuntu-1604-unit-test: + ubuntu-1604-unit-test: name: Ubuntu 16.04 | Unit Test runs-on: ubuntu-latest needs: ubuntu-1604-build From d72b0583245e756b6f96f1c3958c06d60644ba6f Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 16:14:55 -0500 Subject: [PATCH 178/659] Typo on test script. --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ce414434d5..903c29a536 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,7 +47,7 @@ jobs: - name: Unit Test run: | tar -xzf amazon_linux-2-build/build.tar.gz - ./.cicd/test.sh + ./.cicd/tests.sh env: IMAGE_TAG: amazonlinux-2 amazon_linux-2-toolchain-test: @@ -108,7 +108,7 @@ jobs: - name: Unit Test run: | tar -xzf centos-77-build/build.tar.gz - ./.cicd/test.sh + ./.cicd/tests.sh env: IMAGE_TAG: centos-7.7 centos-77-toolchain-test: @@ -169,7 +169,7 @@ jobs: - name: Unit Test run: | tar -xzf ubuntu-1604-build/build.tar.gz - ./.cicd/test.sh + ./.cicd/tests.sh env: IMAGE_TAG: ubuntu-16.04 ubuntu-1604-toolchain-test: @@ -230,7 +230,7 @@ jobs: - name: Unit Test run: | tar -xzf ubuntu-1804-build/build.tar.gz - ./.cicd/test.sh + ./.cicd/tests.sh env: IMAGE_TAG: ubuntu-18.04 ubuntu-1804-toolchain-test: @@ -291,7 +291,7 @@ jobs: run: | brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 tar -xzf macos-1015-build/build.tar.gz - ./.cicd/test.sh + ./.cicd/tests.sh macos-1015-toolchain-test: name: MacOS 10.15 | Toolchain Test runs-on: macos-latest From 97453a09f67ed1d23c52aea9e02a85a99da91dbe Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 16:51:59 -0500 Subject: [PATCH 179/659] Remove Travis. --- .cicd/build.sh | 2 -- .cicd/tests.sh | 2 -- .cicd/toolchain-tests.sh | 2 -- 3 files changed, 6 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index db56484114..fcedffbf24 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -26,8 +26,6 @@ else # Linux if [[ $BUILDKITE == true ]]; then # Generate Base Images $CICD_DIR/generate-base-images.sh - elif [[ $TRAVIS == true ]]; then - ARGS="$ARGS -e JOBS" fi COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" diff --git a/.cicd/tests.sh b/.cicd/tests.sh index d828c5f6d3..e0d2a2cedc 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -23,8 +23,6 @@ else # Linux . $HELPERS_DIR/docker-hash.sh - [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS" - # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="" diff --git a/.cicd/toolchain-tests.sh b/.cicd/toolchain-tests.sh index 6b44e5803e..0ed9352bd1 100755 --- a/.cicd/toolchain-tests.sh +++ b/.cicd/toolchain-tests.sh @@ -20,8 +20,6 @@ else # Linux . $HELPERS_DIR/docker-hash.sh - [[ $TRAVIS == true ]] && ARGS="$ARGS -e JOBS" - # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="" From db9a35057fdb2b17e0d3d7d9f88d7bbe1a6fc41f Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 24 Jan 2020 17:02:38 -0500 Subject: [PATCH 180/659] Fixed incorrect Mac test dependency on Actions. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 903c29a536..7704ce30f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -277,7 +277,7 @@ jobs: macos-1015-unit-test: name: MacOS 10.15 | Unit Test runs-on: macos-latest - needs: amazon_linux-2-build + needs: macos-1015-build steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e From c0c9afacabae00d8748fb0a171ddb2ed9faa66a1 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 27 Jan 2020 11:01:02 -0500 Subject: [PATCH 181/659] Port submodule regression checker changes from EOS. --- .cicd/submodule-regression-checker.sh | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/.cicd/submodule-regression-checker.sh b/.cicd/submodule-regression-checker.sh index 47b4bcacc4..8099906720 100755 --- a/.cicd/submodule-regression-checker.sh +++ b/.cicd/submodule-regression-checker.sh @@ -2,16 +2,15 @@ set -eo pipefail declare -A PR_MAP declare -A BASE_MAP -# Support Travis and BK -if ${TRAVIS:-false}; then - [[ -z $TRAVIS_PULL_REQUEST_BRANCH ]] && echo "Unable to find TRAVIS_PULL_REQUEST_BRANCH ENV. Skipping submodule regression check." && exit 0 - BASE_BRANCH=$TRAVIS_BRANCH - CURRENT_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH - [[ ! -z $TRAVIS_PULL_REQUEST_SLUG ]] && CURRENT_BRANCH=$TRAVIS_COMMIT # When we're not running from a PR, the slug is not set. When we are, we need to use the TRAVIS_COMMIT to be sure we're supporting the Forked PR's merge/code that's in the EOS repo. This is needed for the git log below. -else + +if [[ $BUILDKITE == true ]]; then [[ -z $BUILDKITE_PULL_REQUEST_BASE_BRANCH ]] && echo "Unable to find BUILDKITE_PULL_REQUEST_BASE_BRANCH ENV. Skipping submodule regression check." && exit 0 BASE_BRANCH=$BUILDKITE_PULL_REQUEST_BASE_BRANCH CURRENT_BRANCH=$BUILDKITE_BRANCH +else + [[ -z $GITHUB_BASE_REF ]] && echo "Cannot find \$GITHUB_BASE_REF, so we have nothing to compare submodules to. Skipping submodule regression check." && exit 0 + BASE_BRANCH=$GITHUB_BASE_REF + CURRENT_BRANCH=$GITHUB_SHA fi echo "getting submodule info for $CURRENT_BRANCH" @@ -27,17 +26,15 @@ while read -r a b; do done < <(git submodule --quiet foreach --recursive 'echo $path `git log -1 --format=%ct`') # We need to switch back to the PR ref/head so we can git log properly -if [[ $TRAVIS == true && ! -z $TRAVIS_PULL_REQUEST_SLUG ]]; then - echo "git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge:" - git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge: 1> /dev/null - echo "switching back to $TRAVIS_COMMIT" - echo 'git checkout -qf FETCH_HEAD' - git checkout -qf FETCH_HEAD 1> /dev/null -elif [[ $BUILDKITE == true ]]; then - echo "switching back to $CURRENT_BRANCH" - git checkout -f $CURRENT_BRANCH 1> /dev/null +if [[ $BUILDKITE != true ]]; then + echo "git fetch origin +$GITHUB_REF:" + git fetch origin +${GITHUB_REF}: 1> /dev/null fi +echo "switching back to $CURRENT_BRANCH..." +echo "git checkout -qf $CURRENT_BRANCH" +git checkout -qf $CURRENT_BRANCH 1> /dev/null + for k in "${!BASE_MAP[@]}"; do base_ts=${BASE_MAP[$k]} pr_ts=${PR_MAP[$k]} From bb3cb3ed1cf36de2e0240cbb70109a20ea3b9b0c Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 27 Jan 2020 11:06:52 -0500 Subject: [PATCH 182/659] Add submodule checker to Actions. --- .github/workflows/main.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7704ce30f1..7c42cae545 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,6 +10,19 @@ jobs: run: echo "PR created. Builds will be triggered here for forked PRs or Buildkite for internal PRs." + submodule_regression_check: + name: Submodule Regression Check + runs-on: ubuntu-latest + needs: start-job + steps: + - name: Checkout + uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e + with: + submodules: recursive + - name: Submodule Regression Check + run: ./.cicd/submodule-regression-checker.sh + + amazon_linux-2-build: # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Amazon_Linux 2 | Build From 39e74e94df43032bd75b1b53a6dafa76917d9aa3 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 27 Jan 2020 11:18:25 -0500 Subject: [PATCH 183/659] Setup to only run on forked PRs. --- .github/workflows/main.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7c42cae545..faa2f76485 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ name: Pull Request -on: [push] +on: [pull_request] jobs: start-job: @@ -11,6 +11,7 @@ jobs: submodule_regression_check: + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Submodule Regression Check runs-on: ubuntu-latest needs: start-job @@ -24,7 +25,7 @@ jobs: amazon_linux-2-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Amazon_Linux 2 | Build runs-on: ubuntu-latest needs: start-job @@ -85,7 +86,7 @@ jobs: centos-77-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: CentOS 7.7 | Build runs-on: ubuntu-latest needs: start-job @@ -146,7 +147,7 @@ jobs: ubuntu-1604-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 16.04 | Build runs-on: ubuntu-latest needs: start-job @@ -207,7 +208,7 @@ jobs: ubuntu-1804-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 18.04 | Build runs-on: ubuntu-latest needs: start-job @@ -268,7 +269,7 @@ jobs: macos-1015-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: MacOS 10.15 | Build runs-on: macos-latest needs: start-job From ec3677f5baa0dcc9bfb2be27768d98f59bfc2529 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Tue, 28 Jan 2020 10:05:23 -0500 Subject: [PATCH 184/659] Update Buildkite plugins. --- .cicd/pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 85af8720fd..f27e410037 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -66,7 +66,7 @@ steps: always-pull: true debug: true wait-network: true - - thedyrt/skip-checkout#v0.1.1: + - EOSIO/skip-checkout#v0.1.1: cd: ~ agents: - "queue=mac-anka-large-node-fleet" @@ -138,7 +138,7 @@ steps: always-pull: true debug: true wait-network: true - - thedyrt/skip-checkout#v0.1.1: + - EOSIO/skip-checkout#v0.1.1: cd: ~ agents: - "queue=mac-anka-large-node-fleet" @@ -275,7 +275,7 @@ steps: always-pull: true debug: true wait-network: true - - thedyrt/skip-checkout#v0.1.1: + - EOSIO/skip-checkout#v0.1.1: cd: ~ agents: - "queue=mac-anka-node-fleet" From 3cac1fb797dbe62abbebc538f6f6b99a0023e0f6 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Tue, 28 Jan 2020 10:06:55 -0500 Subject: [PATCH 185/659] Update Buildkite plugins. --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index f27e410037..b5608aaa22 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -208,7 +208,7 @@ steps: always-pull: true debug: true wait-network: true - - thedyrt/skip-checkout#v0.1.1: + - EOSIO/skip-checkout#v0.1.1: cd: ~ agents: - "queue=mac-anka-large-node-fleet" From 275b266cb79447f0a7606e38fa05667beeeb3e5c Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 28 Jan 2020 16:17:57 -0500 Subject: [PATCH 186/659] Return end if not found --- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index b71be94935..f99cd11f85 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -668,7 +668,9 @@ class kv_table { int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); - eosio::check(cmp == 0, "This key does not exist in this iterator"); + if (!cmp) { + return end(); + } return {contract_name, itr, static_cast(itr_stat), value_size, this}; } From 760dc2db79f1feac6401337a00fa1296beb11db1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 09:12:41 -0500 Subject: [PATCH 187/659] Add lower_bound to kv_index --- .../eosiolib/contracts/eosio/key_value.hpp | 31 ++++++++++++++++-- tests/integration/kv_tests.cpp | 11 +++++++ .../test_contracts/kv_single_index_tests.cpp | 32 +++++++++++++------ 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index f99cd11f85..4494d8ae9b 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -664,17 +664,44 @@ class kv_table { } uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); - if (!cmp) { + if (cmp != 0) { return end(); } return {contract_name, itr, static_cast(itr_stat), value_size, this}; } + /** + * Returns an iterator pointing to the element with the lowest key greater than or equal to the given key. + * @ingroup keyvalue + * + * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. + */ + template + iterator lower_bound(K key) { + auto prefix = make_prefix(table_name, name); + auto t_key = table_key(prefix, make_key(key)); + + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + + if (static_cast(itr_stat) == kv_it_stat::iterator_end) { + return end(); + } + + uint32_t value_size; + + // kv_it_value is just used to get the value_size + void* buffer = alloca(1); + internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); + + return {contract_name, itr, static_cast(itr_stat), value_size, this}; + } + /** * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. * @ingroup keyvalue diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 90f342c3a3..0ce270c1f6 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -24,6 +24,17 @@ BOOST_FIXTURE_TEST_CASE(single_tests_find, tester) try { eosio_assert_message_is("Cannot read end iterator")); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(bounds), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(single_tests_iteration, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 424584c67f..e9f3b7b78c 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -47,29 +47,24 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto end_itr = t.index.primary_key.end(); auto itr = t.index.primary_key.find("bob"_n); - auto val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); itr = t.index.primary_key.find("joe"_n); - val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.primary_key == "joe"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); itr = t.index.primary_key.find("alice"_n); - val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong primary_key"); itr = t.index.primary_key.find("john"_n); - val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.primary_key == "john"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key"); itr = t.index.primary_key.find("billy"_n); - val = itr.value(); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong primary_key"); } [[eosio::action]] @@ -79,6 +74,23 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto val = itr.value(); } + [[eosio::action]] + void bounds() { + my_table t = my_table::open("kvtest"_n); + auto end_itr = t.index.primary_key.end(); + + auto itr = t.index.primary_key.lower_bound("bob"_n); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); + + itr = t.index.primary_key.lower_bound("catherine"_n); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); + + itr = t.index.primary_key.lower_bound("william"_n); + eosio::check(itr == end_itr, "Should be the end"); + } + [[eosio::action]] void iteration() { my_table t = my_table::open("kvtest"_n); From 26dfe2192e4a9d04f07a559e88ba61c4af1b92c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 09:52:01 -0500 Subject: [PATCH 188/659] Move Example documentation to new file. --- .../06_key_value/01_key_value_examples.md | 239 ++++++++++++++++ .../eosiolib/contracts/eosio/key_value.hpp | 260 +----------------- 2 files changed, 240 insertions(+), 259 deletions(-) create mode 100644 docs/06_how-to-guides/06_key_value/01_key_value_examples.md diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md new file mode 100644 index 0000000000..e5ecf87e40 --- /dev/null +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -0,0 +1,239 @@ +### DEFINE_TABLE Example: +```cpp +struct myrecord { + std::string primary_key; + uint64_t secondary_1; + std::tuple secondary_2; +} + +DEFINE_TABLE(mytable, myrecord, "testtable", + primary_key, + secondary_1, + secondary_2 +) + +// The above macro results in the following class. + +struct mytable : kv_table { + struct { + kv_index primary_key{&myrecord::primary_key}; + kv_index secondary_1{&myrecord::secondary_1}; + kv_index secondary_2{&myrecord::secondary_2}; + } index; + + mytable(eosio::name contract_name) { + init(contract_name, &index); + } +} +``` + +### make_insensitive Example: + +```cpp +struct location { + std::string city; + std::string state; + uint64_t zip_code; + + auto icity() { return eosio::make_insensitive(city); } + auto istate() { return eosio::make_insensitive(state); } +} + +DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", + icity, + istate, + zip_code +) +``` + +### kv_table Example: +```cpp +#include +using namespace eosio; + +struct address { + uint64_t account_name; + string first_name; + string last_name; + string street; + string city; + string state; + + auto full_name() { return first_name + " " + last_name; } +} + +struct address_table : kv_table { + struct { + kv_index account_name{&address::account_name}; + kv_index full_name{&address::full_name}; + } index; + + addresses(eosio::name contract_name) { + init(contract_name, &index); + } +} + +class addressbook : contract { + public: + void myaction() { + auto addresses = address_table::open("mycontract"_n); + } +} +``` + +### iterator::value Example: +```cpp +// This assumes the code from the class example. + void myaction() { + // add dan account to table - see put example + auto dan = addresses.index.full_name.find("Dan Larimer"); + eosio::check(dan != addresses.index.full_name.end(), "Dan Larimer is not in the table"); + eosio::check(dan.value().city == "Blacksburg", "Got the wrong value"); + } +``` + +### kv_index::find Example: +```cpp + // This assumes the code from the class example. + void myaction() { + // add dan account to table - see put example + auto itr = addresses.index.account_name.find("dan"_n); + eosio::check(itr != addresses.index.account_name.end(), "Couldn't get him."); + + auto itr = addresses.index.full_name.find("Dan Larimer"); + eosio::check(itr != addresses.index.full_name.end(), "Couldn't get him."); + } +``` + +### kv_index::end Example: +```cpp + // This assumes the code from the class example. + void myaction() { + // add dan account to table - see put example + auto itr = addresses.index.account_name.find("brendan"_n); + eosio::check(itr == addresses.index.account_name.end(), "brendan should not be in the table."); + + auto itr = addresses.index.full_name.find("Brendan Blumer"); + eosio::check(itr == addresses.index.full_name.end(), "Brendan Blumer should not be in the table."); + } +``` + +### kv_index::begin Example: +```cpp + // This assumes the code from the class example. + void myaction() { + // add dan account to table - see put example + auto itr = addresses.index.account_name.find("dan"_n); + eosio::check(itr == addresses.index.account_name.begin(), "dan should be at the beginning."); + + auto itr = addresses.index.full_name.find("Dan Larimer"); + eosio::check(itr == addresses.index.full_name.begin(), "Dan Larimer should be at the beginning."); + } +``` + +### kv_index::range Example: +```cpp + // This assumes the code from the class example. + void myaction() { + // add dan account to table - see put example + // add brendan account to table - see put example + // add john account to table - see put example + + address dan = {...} + address brendan = {...} + address john = {...} + + std::vector expected_values = {brendan, dan, john}; + auto values = addresses.index.account_name.range("brendan"_n, "john"_n); + eosio::check(values == expected_values, "Did not get the expected values"); + + std::vector expected_values = {dan}; + auto values = addresses.index.account_name.range("dan"_n, "dan"_n); + eosio::check(values == expected_values, "Did not get the expected values"); + } +``` + +### null_kv_index Example: +```cpp +// Original table: +DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + primary_key, + secondary_1, + secondary_2 +) + +struct my_table : kv_table { + struct { + kv_index primary_key ...; + kv_index secondary_1 ...; + kv_index secondary_2 ...; + } index; + + my_table(eosio::name contract_name) { + init(contract_name, &index); + } +} + +// Table with secondary_1 deleted: +DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", + primary_key, + nullptr + secondary_2 +) + +struct my_table : kv_table { + struct { + kv_index primary_key ...; + null_kv_index nullptr1 ...; + kv_index secondary_2 ...; + } index; + + my_table(eosio::name contract_name) { + init(contract_name, &index); + } +} +``` + +### kv_table::put Example: +```cpp +// This assumes the code from the class example. +void myaction() { + auto addresses = address_table::open("mycontract"_n); + addresses.put({ + .account_name = "dan"_n, + .first_name = "Daniel", + .last_name = "Larimer", + .street = "1 EOS Way", + .city = "Blacksburg", + .state = "VA" + }); +} +``` + +### kv_table::erase Example: +```cpp +// This assumes the code from the class example. +void myaction() { + auto addresses = address_table::open("mycontract"_n); + + auto itr = addresses.index.account_name.find("dan"_n); + eosio::check(itr != addresses.index.account_name.end()); + addresses.erase("dan"_n); +} +``` + +### kv_table::open Example: +```cpp +struct myrecord { + std::string primary_key; +} + +DEFINE_TABLE(mytable, myrecord, "testtable", primary_key) + +class mycontract : contract { + public: + void myaction() { + auto t = mytable::open("mycontract"_n); + } +} +``` diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 4494d8ae9b..0c433f446e 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -69,36 +69,6 @@ * @param table_name - The name of the table * @param db_name - The type of the EOSIO Key Value database. Defaulted to eosio.kvram * @param ... - A variadic list of 1 or more indexes to define on the table. - * - * Example: - * - * @code - * struct myrecord { - * std::string primary_key; - * uint64_t secondary_1; - * std::tuple secondary_2; - * } - * - * DEFINE_TABLE(mytable, myrecord, "testtable", - * primary_key, - * secondary_1, - * secondary_2 - * ) - * - * // The above macro results in the following class. - * - * struct mytable : kv_table { - * struct { - * kv_index primary_key{&myrecord::primary_key}; - * kv_index secondary_1{&myrecord::secondary_1}; - * kv_index secondary_2{&myrecord::secondary_2}; - * } index; - * - * mytable(eosio::name contract_name) { - * init(contract_name, &index); - * } - * } - * @endcode */ #define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ struct table_class : TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ @@ -387,25 +357,6 @@ inline key_type make_key(T val) { * * @param val - The string to be made case-insensitive * @return The binary representation of the case-insensitive string - * - * Example: - * - * @code - * struct location { - * std::string city; - * std::string state; - * uint64_t zip_code; - * - * auto icity() { return eosio::make_insensitive(city); } - * auto istate() { return eosio::make_insensitive(state); } - * } - * - * DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", - * icity, - * istate, - * zip_code - * ) - * @endcode */ inline key_type make_insensitive(const std::string& val) { return make_key(val, true); @@ -426,43 +377,7 @@ inline key_type make_insensitive(const std::string& val) { * @tparam T - the type of the data stored as the value of the table * @tparam TableName - the name of the table * @tparam DbName - the type of the EOSIO Key Value database. Defaulted to eosio.kvram - * - * Example: - * - * @code - * #include - * using namespace eosio; - * - * struct address { - * uint64_t account_name; - * string first_name; - * string last_name; - * string street; - * string city; - * string state; - * - * auto full_name() { return first_name + " " + last_name; } - * } - * - * struct address_table : kv_table { - * struct { - * kv_index account_name{&address::account_name}; - * kv_index full_name{&address::full_name}; - * } index; - * - * addresses(eosio::name contract_name) { - * init(contract_name, &index); - * } - * } - * - * class addressbook : contract { - * public: - * void myaction() { - * auto addresses = address_table::open("mycontract"_n); - * } - * } - * @endcode - */ + */ template class kv_table { @@ -493,19 +408,6 @@ class kv_table { * @ingroup keyvalue * * @return The value that the iterator points to. - * - * Example: - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * // add dan account to table - see put example - * - * auto dan = addresses.index.full_name.find("Dan Larimer"); - * eosio::check(dan != addresses.index.full_name.end(), "Dan Larimer is not in the table"); - * eosio::check(dan.value().city == "Blacksburg", "Got the wrong value"); - * } - * @endcode */ T value() const { using namespace detail; @@ -634,22 +536,6 @@ class kv_table { * * @param key - The key to search for. * @return An iterator to the found object OR the `end` iterator if the given key was not found. - * - * Example: - * - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * // add dan account to table - see put example - * - * auto itr = addresses.index.account_name.find("dan"_n); - * eosio::check(itr != addresses.index.account_name.end(), "Couldn't get him."); - * - * auto itr = addresses.index.full_name.find("Dan Larimer"); - * eosio::check(itr != addresses.index.full_name.end(), "Couldn't get him."); - * } - * @endcode */ template iterator find(K key) { @@ -707,22 +593,6 @@ class kv_table { * @ingroup keyvalue * * @return An iterator referring to the `past-the-end` element. - * - * Example: - * - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * // add dan account to table - see put example - * - * auto itr = addresses.index.account_name.find("brendan"_n); - * eosio::check(itr == addresses.index.account_name.end(), "brendan should not be in the table."); - * - * auto itr = addresses.index.full_name.find("Brendan Blumer"); - * eosio::check(itr == addresses.index.full_name.end(), "Brendan Blumer should not be in the table."); - * } - * @endcode */ iterator end() { auto prefix = make_prefix(table_name, name); @@ -737,22 +607,6 @@ class kv_table { * @ingroup keyvalue * * @return An iterator to the object with the lowest key (by this index) in the table. - * - * Example: - * - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * // add dan account to table - see put example - * - * auto itr = addresses.index.account_name.find("dan"_n); - * eosio::check(itr == addresses.index.account_name.begin(), "dan should be at the beginning."); - * - * auto itr = addresses.index.full_name.find("Dan Larimer"); - * eosio::check(itr == addresses.index.full_name.begin(), "Dan Larimer should be at the beginning."); - * } - * @endcode */ iterator begin() { auto prefix = make_prefix(table_name, name); @@ -777,30 +631,6 @@ class kv_table { * @param begin - The beginning of the range. * @param end - The end of the range. * @return A vector containing all the objects that fall between the range. - * - * Example: - * - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * // add dan account to table - see put example - * // add brendan account to table - see put example - * // add john account to table - see put example - * - * address dan = {...} - * address brendan = {...} - * address john = {...} - * - * std::vector expected_values = {brendan, dan, john}; - * auto values = addresses.index.account_name.range("brendan"_n, "john"_n); - * eosio::check(values == expected_values, "Did not get the expected values"); - * - * std::vector expected_values = {dan}; - * auto values = addresses.index.account_name.range("dan"_n, "dan"_n); - * eosio::check(values == expected_values, "Did not get the expected values"); - * } - * @endcode */ template std::vector range(K begin, K end) { @@ -841,47 +671,6 @@ class kv_table { * @brief Defines a deleted index on an EOSIO Key Value Table * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. * A null_kv_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. - * - * Example: - * @code - * // Original table: - * DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - * primary_key, - * secondary_1, - * secondary_2 - * ) - * - * struct my_table : kv_table { - * struct { - * kv_index primary_key ...; - * kv_index secondary_1 ...; - * kv_index secondary_2 ...; - * } index; - * - * my_table(eosio::name contract_name) { - * init(contract_name, &index); - * } - * } - * - * // Table with secondary_1 deleted: - * DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - * primary_key, - * nullptr - * secondary_2 - * ) - * - * struct my_table : kv_table { - * struct { - * kv_index primary_key ...; - * null_kv_index nullptr1 ...; - * kv_index secondary_2 ...; - * } index; - * - * my_table(eosio::name contract_name) { - * init(contract_name, &index); - * } - * } - * @endcode */ class null_kv_index : public kv_index {}; @@ -891,23 +680,6 @@ class kv_table { * @ingroup keyvalue * * @param value - The entry to be stored in the table. - * - * Example: - * @code - * // This assumes the code from the class example. - * - * void myaction() { - * auto addresses = address_table::open("mycontract"_n); - * addresses.put({ - * .account_name = "dan"_n, - * .first_name = "Daniel", - * .last_name = "Larimer", - * .street = "1 EOS Way", - * .city = "Blacksburg", - * .state = "VA" - * }); - * } - * @endcode */ void put(const T& value) { using namespace detail; @@ -938,18 +710,6 @@ class kv_table { * @tparam K - The type of the key. This will be auto-deduced through the key parameter. * * @param key - The key of the value to be removed. - * - * Example: - * // This assumes the code from the class example. - * @code - * void myaction() { - * auto addresses = address_table::open("mycontract"_n); - * - * auto itr = addresses.index.account_name.find("dan"_n); - * eosio::check(itr != addresses.index.account_name.end()); - * addresses.erase("dan"_n); - * } - * @endcode */ template void erase(K key) { @@ -973,24 +733,6 @@ class kv_table { * * @param contract_name - The name of the contract. * @return An initialized instance of the user specifed Key Value table class. - * - * Example: - * - * @code - * struct myrecord { - * std::string primary_key; - * } - * - * DEFINE_TABLE(mytable, myrecord, "testtable", primary_key) - * - * class mycontract : contract { - * public: - * void myaction() { - * auto t = mytable::open("mycontract"_n); - * } - * } - * - * @endcode */ static Class open(eosio::name contract_name) { Class c = Class(contract_name); From 4be2a68138fd490d95717f23b57f8bbf27adc347 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 10:24:24 -0500 Subject: [PATCH 189/659] Add get to kv_index --- .../eosiolib/contracts/eosio/key_value.hpp | 34 +++++++++++++++++++ tests/integration/kv_tests.cpp | 11 ++++++ .../test_contracts/kv_single_index_tests.cpp | 12 +++++++ 3 files changed, 57 insertions(+) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 0c433f446e..f636c62ec0 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -561,6 +561,40 @@ class kv_table { return {contract_name, itr, static_cast(itr_stat), value_size, this}; } + /** + * Get the value for an existing object in a table by the index, using the given key. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced by the key param. + * + * @param key - The key to search for. + * @return A std::optional of the value corresponding to the key. + */ + template + std::optional get(K key) { + uint32_t value_size; + + auto prefix = make_prefix(table_name, name); + auto t_key = table_key(prefix, make_key(key)); + + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); + if (!success) { + return std::nullopt; + } + + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db, 0, (char*)buffer, value_size); + + datastream ds((char*)buffer, value_size); + + T val; + ds >> val; + if (value_size > detail::max_stack_buffer_size) { + free(buffer); + } + return val; + } + /** * Returns an iterator pointing to the element with the lowest key greater than or equal to the given key. * @ingroup keyvalue diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 0ce270c1f6..9354bd47a4 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -24,6 +24,17 @@ BOOST_FIXTURE_TEST_CASE(single_tests_find, tester) try { eosio_assert_message_is("Cannot read end iterator")); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(single_tests_get, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(get), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index e9f3b7b78c..70238290d1 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -74,6 +74,18 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto val = itr.value(); } + [[eosio::action]] + void get() { + my_table t = my_table::open("kvtest"_n); + auto end_itr = t.index.primary_key.end(); + + auto val = t.index.primary_key.get("bob"_n); + eosio::check(val->primary_key == "bob"_n, "Got the wrong value"); + + val = t.index.primary_key.get("william"_n); + eosio::check(!val, "Should not have gotten a value"); + } + [[eosio::action]] void bounds() { my_table t = my_table::open("kvtest"_n); From 8bed4876bddfcff7eee56dd3968a70253ca5581e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 10:46:54 -0500 Subject: [PATCH 190/659] Cleanup intrinsics use and don't error on non-existant erase --- .../eosiolib/contracts/eosio/key_value.hpp | 22 +++++++++---------- tests/integration/kv_tests.cpp | 4 ---- .../test_contracts/kv_single_index_tests.cpp | 6 ----- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index f636c62ec0..b430998d04 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -544,11 +544,6 @@ class kv_table { auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); - if (!success) { - return end(); - } - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); @@ -558,6 +553,9 @@ class kv_table { return end(); } + void* buffer = alloca(1); + itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); + return {contract_name, itr, static_cast(itr_stat), value_size, this}; } @@ -617,7 +615,7 @@ class kv_table { // kv_it_value is just used to get the value_size void* buffer = alloca(1); - internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); + itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); return {contract_name, itr, static_cast(itr_stat), value_size, this}; } @@ -651,7 +649,7 @@ class kv_table { // kv_it_value is just used to get the value_size void* buffer = alloca(1); - internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); + itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); return {contract_name, itr, static_cast(itr_stat), value_size, this}; } @@ -747,17 +745,17 @@ class kv_table { */ template void erase(K key) { - auto primary_itr = primary_index->find(key); - - eosio::check(primary_itr != primary_index->end(), "Attempted to erase non-existent key"); + auto primary_value = primary_index->get(key); - T val = primary_itr.value(); + if (!primary_value) { + return; + } auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); internal_use_do_not_use::kv_erase(db, contract_name.value, k.data(), k.size()); for (auto& idx : secondary_indices) { - auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(val)); + auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(*primary_value)); internal_use_do_not_use::kv_erase(db, contract_name.value, skey.data(), skey.size()); } } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 9354bd47a4..542087cf1a 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -95,10 +95,6 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(erase), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(eraseerror), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Attempted to erase non-existent key")); } FC_LOG_AND_RETHROW() // Multi diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 70238290d1..6533a11c6f 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -201,10 +201,4 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } - - [[eosio::action]] - void eraseerror() { - my_table t = my_table::open("kvtest"_n); - t.erase("chris"_n); - } }; From 79c595bc431dbdf887deec90e97111d2fc28a131 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 14:03:52 -0500 Subject: [PATCH 191/659] Add additional constructor to allow for named indices --- .../eosiolib/contracts/eosio/key_value.hpp | 25 ++++++++-- tests/integration/kv_tests.cpp | 18 +++++++ .../kv_multiple_indices_tests.cpp | 48 +++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index b430998d04..61b549c8e0 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -513,7 +513,7 @@ class kv_table { }; public: - eosio::name name; + eosio::name name{0}; eosio::name table_name; eosio::name contract_name; @@ -528,6 +528,13 @@ class kv_table { }; } + template + kv_index(eosio::name name, KF&& kf) : name{name} { + key_function = [=](const T& t) { + return make_key(std::invoke(kf, &t)); + }; + } + /** * Search for an existing object in a table by the index, using the given key. * @ingroup keyvalue @@ -787,25 +794,37 @@ class kv_table { template void init(eosio::name contract, Indices indices) { contract_name = contract; + bool is_named = false; uint64_t index_name = 1; auto& primary = get<0>(*indices); primary_index = &primary; - primary_index->name = eosio::name{index_name}; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; + if (primary_index->name.value > 0) { + is_named = true; + } else { + primary_index->name = eosio::name{index_name}; + } + + ++index_name; for_each_field(*indices, [&](auto& idx) { if (idx.name != primary.name) { kv_index* si = &idx; - si->name = eosio::name{index_name}; si->contract_name = contract_name; si->table_name = table_name; si->tbl = this; + if (is_named) { + eosio::check(si->name.value > 0, "All indices must be named if one is named."); + } else { + eosio::check(si->name.value <= 0, "All indices must be named if one is named."); + si->name = eosio::name{index_name}; + } secondary_indices.push_back(si); ++index_name; } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 542087cf1a..fe1c3c9104 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -99,6 +99,24 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { // Multi // ----- +BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(indices), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("All indices must be named if one is named.")); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("All indices must be named if one is named.")); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 18aed9d57c..3a6f068072 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -24,6 +24,39 @@ DEFINE_TABLE(my_table_2, my_struct, "testtable", "eosio.kvram", bar ) +struct my_table_idx : eosio::kv_table { + struct { + kv_index primary_key{"prim"_n, &my_struct::primary_key}; + kv_index foo{"f"_n, &my_struct::foo}; + } index; + + my_table_idx(eosio::name contract_name) { + init(contract_name, &index); + } +}; + +struct my_table_idx_err : eosio::kv_table { + struct { + kv_index primary_key{"prim"_n, &my_struct::primary_key}; + kv_index foo{&my_struct::foo}; + } index; + + my_table_idx_err(eosio::name contract_name) { + init(contract_name, &index); + } +}; + +struct my_table_idx_err_2 : eosio::kv_table { + struct { + kv_index primary_key{&my_struct::primary_key}; + kv_index foo{"f"_n, &my_struct::foo}; + } index; + + my_table_idx_err_2(eosio::name contract_name) { + init(contract_name, &index); + } +}; + class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; @@ -64,6 +97,21 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { t.put(s5); } + [[eosio::action]] + void indices() { + my_table_idx t{"kvtest"_n}; + } + + [[eosio::action]] + void indiceserr() { + my_table_idx_err t{"kvtest"_n}; + } + + [[eosio::action]] + void indiceserr2() { + my_table_idx_err_2 t{"kvtest"_n}; + } + [[eosio::action]] void find() { my_table t = my_table::open("kvtest"_n); From 835fbc1f12ac8f007b8aa3128d7015f10652a4f2 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 13:18:12 -0500 Subject: [PATCH 192/659] Add upper_bound to kv_index --- .../eosiolib/contracts/eosio/key_value.hpp | 53 +++++++++++++++++-- .../test_contracts/kv_single_index_tests.cpp | 11 ++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 61b549c8e0..368dc2a68b 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -413,13 +413,19 @@ class kv_table { using namespace detail; eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); - eosio::check(data_size > 0, "Cannot read a value of size 0"); + uint32_t value_size; uint32_t actual_value_size; uint32_t offset = 0; - void* buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, data_size, actual_value_size); + // call once to get the value_size + void* b = alloca(1); + internal_use_do_not_use::kv_it_value(itr, 0, (char*)b, 0, value_size); + + eosio::check(value_size > 0, "Cannot read a value of size 0"); + + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, value_size, actual_value_size); eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); @@ -428,7 +434,7 @@ class kv_table { T val; ds >> val; - if (data_size > detail::max_stack_buffer_size) { + if (value_size > detail::max_stack_buffer_size) { free(buffer); } return val; @@ -450,7 +456,7 @@ class kv_table { if (actual_data_size > detail::max_stack_buffer_size) { free(pk_buffer); } - if (data_size > detail::max_stack_buffer_size) { + if (value_size > detail::max_stack_buffer_size) { free(buffer); } return val; @@ -510,6 +516,8 @@ class kv_table { key_type key() const { return idx->get_key(value()); } + + friend kv_index; }; public: @@ -627,6 +635,41 @@ class kv_table { return {contract_name, itr, static_cast(itr_stat), value_size, this}; } + /** + * Returns an iterator pointing to the element with the highest key less than or equal to the given key. + * @ingroup keyvalue + * + * @return An iterator pointing to the element with the highest key less than or equal to the given key. + */ + template + iterator upper_bound(K key) { + auto prefix = make_prefix(table_name, name); + auto t_key = table_key(prefix, make_key(key)); + + uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + + uint32_t value_size; + + // kv_it_value is just used to get the value_size + void* buffer = alloca(1); + itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); + + iterator it{contract_name, itr, static_cast(itr_stat), value_size, this}; + + auto cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); + while(cmp > 0) { + if (it == begin()) { + return end(); + } + --it; + cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); + } + + return it; + + } + /** * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. * @ingroup keyvalue diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 6533a11c6f..2e4b53e093 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -101,6 +101,17 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { itr = t.index.primary_key.lower_bound("william"_n); eosio::check(itr == end_itr, "Should be the end"); + + itr = t.index.primary_key.upper_bound("bob"_n); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); + + itr = t.index.primary_key.upper_bound("matt"_n); + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key"); + + itr = t.index.primary_key.upper_bound("ab"_n); + eosio::check(itr == end_itr, "Should be the end"); } [[eosio::action]] From 4d01ab8a25b4c0286bf1e14683f9e0af437982ec Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 15:16:10 -0500 Subject: [PATCH 193/659] Remove data_size from iterator as it led to caching issues --- libraries/eosiolib/contracts/eosio/key_value.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 368dc2a68b..8d593a2977 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -400,8 +400,8 @@ class kv_table { class kv_index { class iterator { public: - iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, size_t data_size, kv_index* idx) : - contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, data_size{data_size}, idx{idx} {} + iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, kv_index* idx) : + contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, idx{idx} {} /** * Returns the value that the iterator points to. @@ -508,8 +508,6 @@ class kv_table { eosio::name contract_name; const kv_index* idx; - size_t data_size; - uint32_t itr; kv_it_stat itr_stat; @@ -571,7 +569,7 @@ class kv_table { void* buffer = alloca(1); itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), value_size, this}; + return {contract_name, itr, static_cast(itr_stat), this}; } /** @@ -632,7 +630,7 @@ class kv_table { void* buffer = alloca(1); itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), value_size, this}; + return {contract_name, itr, static_cast(itr_stat), this}; } /** @@ -655,7 +653,7 @@ class kv_table { void* buffer = alloca(1); itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - iterator it{contract_name, itr, static_cast(itr_stat), value_size, this}; + iterator it{contract_name, itr, static_cast(itr_stat), this}; auto cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); while(cmp > 0) { @@ -681,7 +679,7 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); - return {contract_name, itr, static_cast(itr_stat), 0, this}; + return {contract_name, itr, static_cast(itr_stat), this}; } /** @@ -701,7 +699,7 @@ class kv_table { void* buffer = alloca(1); itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), value_size, this}; + return {contract_name, itr, static_cast(itr_stat), this}; } /** From 137c3d3ea265ee622bfe5b8bcd035e67ba0b8ac0 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 29 Jan 2020 11:32:24 -0500 Subject: [PATCH 194/659] Update range to follow C++ standard --- .../eosiolib/contracts/eosio/key_value.hpp | 25 ++++++++-------- tests/integration/kv_tests.cpp | 10 ------- .../test_contracts/kv_single_index_tests.cpp | 30 +++++++------------ 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 8d593a2977..54a994178b 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -486,7 +486,7 @@ class kv_table { bool operator<(const iterator& b) const { auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp == -1; + return cmp < 0; } bool operator<=(const iterator& b) const { @@ -496,7 +496,7 @@ class kv_table { bool operator>(const iterator& b) const { auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp == 1; + return cmp > 0; } bool operator>=(const iterator& b) const { @@ -703,7 +703,7 @@ class kv_table { } /** - * Returns a vector of objects that fall between the specifed range. The range is inclusive on both ends. + * Returns a vector of objects that fall between the specifed range. The range is inclusive, exclusive. * @ingroup keyvalue * * @tparam K - The type of the key. This will be auto-deduced by the key param. @@ -714,25 +714,24 @@ class kv_table { */ template std::vector range(K begin, K end) { - auto begin_itr = find(begin); - auto end_itr = find(end); - eosio::check(begin_itr != this->end(), "beginning of range is not in table"); - eosio::check(end_itr != this->end(), "end of range is not in table"); + auto begin_itr = lower_bound(begin); + auto end_itr = upper_bound(end); - eosio::check(begin <= end, "Beginning of range should be less than or equal to end"); + bool include_last = find(end) != end_itr; - if (begin == end) { - std::vector t; - t.push_back(find(begin).value()); - return t; + if (begin_itr == end_itr || begin_itr > end_itr) { + return {}; } std::vector return_values; - return_values.push_back(begin_itr.value()); iterator itr = begin_itr; while(itr != end_itr) { + return_values.push_back(itr.value()); ++itr; + } + + if (include_last) { return_values.push_back(itr.value()); } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index fe1c3c9104..e29c27ed01 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -74,16 +74,6 @@ BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { push_action(N(kvtest), N(setup), N(kvtest), {}); push_action(N(kvtest), N(range), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror1), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Beginning of range should be less than or equal to end")); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror2), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("beginning of range is not in table")); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(rangeerror3), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("end of range is not in table")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 2e4b53e093..3affce75e0 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -172,31 +172,21 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { void range() { my_table t = my_table::open("kvtest"_n); - std::vector expected{s, s4, s3}; + std::vector expected{s, s4}; auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); - expected = {s}; + expected = {}; vals = t.index.primary_key.range("bob"_n, "bob"_n); eosio::check(vals == expected, "range did not return expected vector"); - } - - [[eosio::action]] - void rangeerror1() { - my_table t = my_table::open("kvtest"_n); - auto vals = t.index.primary_key.range("joe"_n, "alice"_n); - } - - [[eosio::action]] - void rangeerror2() { - my_table t = my_table::open("kvtest"_n); - auto vals = t.index.primary_key.range("chris"_n, "joe"_n); - } + vals = t.index.primary_key.range("chris"_n, "joe"_n); + eosio::check(vals == expected, "range did not return expected vector"); + vals = t.index.primary_key.range("joe"_n, "alice"_n); + eosio::check(vals == expected, "range did not return expected vector"); - [[eosio::action]] - void rangeerror3() { - my_table t = my_table::open("kvtest"_n); - auto vals = t.index.primary_key.range("alice"_n, "chris"_n); + expected = {s2, s5, s, s4, s3}; + vals = t.index.primary_key.range("alice"_n, "william"_n); + eosio::check(vals == expected, "range did not return expected vector"); } [[eosio::action]] @@ -208,7 +198,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto itr = t.index.primary_key.find("joe"_n); eosio::check(itr == end_itr, "key was not properly deleted"); - std::vector expected = {s, s3}; + std::vector expected = {s}; auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } From 5d508396f6aff00fc3b9cda695b11a27a073e32d Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 30 Jan 2020 11:07:02 -0500 Subject: [PATCH 195/659] Minor cleanup from PR feedback --- .../eosiolib/contracts/eosio/key_value.hpp | 51 +++---------------- tests/integration/kv_tests.cpp | 2 +- 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 54a994178b..e3a8d49a42 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -166,19 +166,7 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint } inline key_type table_key(const key_type& prefix, const key_type& key) { - size_t buffer_size = key.size() + prefix.size(); - void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - - memcpy(buffer, prefix.data(), prefix.size()); - memcpy(((char*)buffer) + prefix.size(), key.data(), key.size()); - - key_type s((const char*)buffer, buffer_size); - - if (buffer_size > detail::max_stack_buffer_size) { - free(buffer); - } - - return s; + return key_type{prefix + key}; } template @@ -190,9 +178,7 @@ inline I flip_msb(I val) { template inline I get_msb(I val) { constexpr static size_t bits = sizeof(I) * 8; - constexpr static I mask = static_cast(0x08) << (bits - 4); - I masked = val & mask; - return masked >> (bits - 1); + return val >> (bits - 1); } template ::value, int> = 0> @@ -232,7 +218,7 @@ inline key_type make_floating_key(F val) { template ::value, int> = 0> inline key_type make_key(F val) { - static_assert(sizeof(F) != sizeof(long double), "long doubles are currently not supported by make_key"); + static_assert(!std::is_same_v, "long doubles are currently not supported by make_key"); if (val == -0) { val = +0; @@ -419,8 +405,7 @@ class kv_table { uint32_t offset = 0; // call once to get the value_size - void* b = alloca(1); - internal_use_do_not_use::kv_it_value(itr, 0, (char*)b, 0, value_size); + internal_use_do_not_use::kv_it_value(itr, 0, (char*)nullptr, 0, value_size); eosio::check(value_size > 0, "Cannot read a value of size 0"); @@ -471,7 +456,7 @@ class kv_table { iterator& operator--() { itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); - eosio::check(itr_stat != kv_it_stat::iterator_end, "incremented past the beginning"); + eosio::check(itr_stat != kv_it_stat::iterator_end, "decremented past the beginning"); return *this; } @@ -552,8 +537,6 @@ class kv_table { */ template iterator find(K key) { - uint32_t value_size; - auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); @@ -566,9 +549,6 @@ class kv_table { return end(); } - void* buffer = alloca(1); - itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), this}; } @@ -624,12 +604,6 @@ class kv_table { return end(); } - uint32_t value_size; - - // kv_it_value is just used to get the value_size - void* buffer = alloca(1); - itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), this}; } @@ -647,12 +621,6 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - uint32_t value_size; - - // kv_it_value is just used to get the value_size - void* buffer = alloca(1); - itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - iterator it{contract_name, itr, static_cast(itr_stat), this}; auto cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); @@ -693,12 +661,6 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - uint32_t value_size; - - // kv_it_value is just used to get the value_size - void* buffer = alloca(1); - itr_stat = internal_use_do_not_use::kv_it_value(itr, 0, (char*)buffer, 0, value_size); - return {contract_name, itr, static_cast(itr_stat), this}; } @@ -814,8 +776,7 @@ class kv_table { * @return An initialized instance of the user specifed Key Value table class. */ static Class open(eosio::name contract_name) { - Class c = Class(contract_name); - return c; + return Class(contract_name); } protected: diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index e29c27ed01..eac1240cef 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_CASE(single_tests_iteration, tester) try { BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(itrerror2), N(kvtest), {}), eosio_assert_message_exception, - eosio_assert_message_is("incremented past the beginning")); + eosio_assert_message_is("decremented past the beginning")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { From 938e66d12bf312bf02fe9bc29e840f8f2a98707f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 30 Jan 2020 12:27:50 -0500 Subject: [PATCH 196/659] Minor cleanup from PR feedback --- .../unit/test_contracts/kv_make_key_tests.cpp | 178 ++++-------------- 1 file changed, 33 insertions(+), 145 deletions(-) diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index 3aee47d36f..cf0c2c885f 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -4,7 +4,7 @@ struct testing_struct { uint16_t a; uint16_t b; - bool operator==(testing_struct rhs){ + bool operator==(const testing_struct& rhs) const { return a == rhs.a && b == rhs.b; } }; @@ -19,6 +19,17 @@ struct my_struct { testing_struct tstruct; std::tuple ttuple; + bool operator==(const my_struct& rhs) const { + return tname == rhs.tname && + tstring == rhs.tstring && + tui64 == rhs.tui64 && + ti32 == rhs.ti32 && + ti128 == rhs.ti128 && + tfloat == rhs.tfloat && + tstruct == rhs.tstruct && + ttuple == rhs.ttuple; + } + auto itstring() const { return eosio::make_insensitive(tstring); } }; @@ -43,6 +54,18 @@ struct my_table : eosio::kv_table& expected) { + auto end_itr = idx.end(); + auto itr = idx.begin(); + for (const auto& expect : expected) { + eosio::check(itr != end_itr, "Should not be the end"); + eosio::check(itr.value() == expect, "Got the wrong value"); + ++itr; + } + eosio::check(itr == end_itr, "Should be the end"); + } + my_struct s1{ .tname = "bob"_n, .tstring = "a", @@ -108,189 +131,54 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyname() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.tname.end(); - auto itr = t.index.tname.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tname == s2.tname, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tname == s5.tname, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tname == s1.tname, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tname == s4.tname, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tname == s3.tname, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.tname, {s2, s5, s1, s4, s3}); } [[eosio::action]] void makekeystr() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.tstring.end(); - auto itr = t.index.tstring.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tstring == s2.tstring, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstring == s5.tstring, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstring == s1.tstring, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstring == s3.tstring, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstring == s4.tstring, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.tstring, {s2, s5, s1, s3, s4}); } [[eosio::action]] void makekeyistr() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.itstring.end(); - auto itr = t.index.itstring.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().itstring() == s1.itstring(), "Got the wrong value"); - ++itr; - eosio::check(itr.value().itstring() == s2.itstring(), "Got the wrong value"); - ++itr; - eosio::check(itr.value().itstring() == s3.itstring(), "Got the wrong value"); - ++itr; - eosio::check(itr.value().itstring() == s4.itstring(), "Got the wrong value"); - ++itr; - eosio::check(itr.value().itstring() == s5.itstring(), "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.itstring, {s1, s2, s3, s4, s5}); } [[eosio::action]] void makekeyuill() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.tui64.end(); - auto itr = t.index.tui64.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tui64 == s5.tui64, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tui64 == s4.tui64, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tui64 == s3.tui64, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tui64 == s2.tui64, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tui64 == s1.tui64, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.tui64, {s5, s4, s3, s2, s1}); } [[eosio::action]] void makekeyil() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.ti32.end(); - auto itr = t.index.ti32.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().ti32 == s3.ti32, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti32 == s2.ti32, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti32 == s1.ti32, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti32 == s4.ti32, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti32 == s5.ti32, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.ti32, {s3, s2, s1, s4, s5}); } [[eosio::action]] void makekeyilll() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.ti128.end(); - auto itr = t.index.ti128.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().ti128 == s1.ti128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti128 == s2.ti128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti128 == s3.ti128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti128 == s4.ti128, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ti128 == s5.ti128, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.ti128, {s1, s2, s3, s4, s5}); } [[eosio::action]] void makekeyflt() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.tfloat.end(); - auto itr = t.index.tfloat.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tfloat == s5.tfloat, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tfloat == s4.tfloat, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tfloat == s1.tfloat, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tfloat == s2.tfloat, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tfloat == s3.tfloat, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.tfloat, {s5, s4, s1, s2, s3}); } [[eosio::action]] void makekeystct() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.tstruct.end(); - auto itr = t.index.tstruct.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().tstruct == s1.tstruct, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct == s3.tstruct, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct == s2.tstruct, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct == s4.tstruct, "Got the wrong value"); - ++itr; - eosio::check(itr.value().tstruct == s5.tstruct, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.tstruct, {s1, s3, s2, s4, s5}); } [[eosio::action]] void makekeytup() { my_table t = my_table::open("kvtest"_n); - - auto end_itr = t.index.ttuple.end(); - auto itr = t.index.ttuple.begin(); - - eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().ttuple == s1.ttuple, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ttuple == s2.ttuple, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ttuple == s3.ttuple, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ttuple == s4.ttuple, "Got the wrong value"); - ++itr; - eosio::check(itr.value().ttuple == s5.ttuple, "Got the wrong value"); - ++itr; - eosio::check(itr == end_itr, "Should be the end"); + check_index(t.index.ttuple, {s1, s2, s3, s4, s5}); } }; From 618282f5388a3bcd2a6679cc7d5ef3eae5f34b66 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 30 Jan 2020 15:26:04 -0500 Subject: [PATCH 197/659] Remove potential undefined behaviour from swap_endian --- libraries/eosiolib/core/eosio/utility.hpp | 39 +++++++------------ tests/integration/kv_make_key_tests.cpp | 8 +++- .../unit/test_contracts/kv_make_key_tests.cpp | 34 +++++++++++----- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/libraries/eosiolib/core/eosio/utility.hpp b/libraries/eosiolib/core/eosio/utility.hpp index 92fc1c6518..e1c0a632c8 100644 --- a/libraries/eosiolib/core/eosio/utility.hpp +++ b/libraries/eosiolib/core/eosio/utility.hpp @@ -8,33 +8,24 @@ namespace eosio { if constexpr (sizeof(T) == 1) return val; else if constexpr (sizeof(T) == 2) - return (val << 8) |(val >> 8); + return (val << 8) | (val >> 8); else if constexpr (sizeof(T) == 4) { - union i32_swap { - T value; - uint32_t ui; - i32_swap(T v) : value(v) { ui = __builtin_bswap32(ui); } - }; - return i32_swap(val).value; + T value; + auto swapped = __builtin_bswap32(val); + memcpy((char*)&value, (char*)&swapped, sizeof(T)); + return value; } else if constexpr (sizeof(T) == 8) { - union i64_swap { - T value; - uint64_t ui; - i64_swap(T v) : value(v) { ui = __builtin_bswap64(ui); } - }; - return i64_swap(val).value; + T value; + auto swapped = __builtin_bswap64(val); + memcpy((char*)&value, (char*)&swapped, sizeof(T)); + return value; } else { - union i128_swap { - uint64_t high; - uint64_t low; - T value; - i128_swap(const T& val) : value(val) { - uint64_t tmp = high; - high = __builtin_bswap64(low); - low = __builtin_bswap64(tmp); - } - }; - return i128_swap(val).value; + T value; + uint128_t swapped_high = __builtin_bswap64((uint64_t)val); + uint64_t swapped_low = __builtin_bswap64((uint64_t)(val >> 64)); + T swapped = (swapped_high << 64) | swapped_low; + memcpy((char*)&value, (char*)&swapped, sizeof(T)); + return value; } } } diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp index 31ea9b7fe4..1eb480e325 100644 --- a/tests/integration/kv_make_key_tests.cpp +++ b/tests/integration/kv_make_key_tests.cpp @@ -42,14 +42,18 @@ BOOST_AUTO_TEST_CASE(makekeyil) try { make_key_test(N(makekeyil)); } FC_LOG_AND_RETHROW() -BOOST_AUTO_TEST_CASE(makekeyilll) try { - make_key_test(N(makekeyil)); +BOOST_AUTO_TEST_CASE(makekeyuilll) try { + make_key_test(N(makekeyuilll)); } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_CASE(makekeyflt) try { make_key_test(N(makekeyflt)); } FC_LOG_AND_RETHROW() +BOOST_AUTO_TEST_CASE(makekeydbl) try { + make_key_test(N(makekeydbl)); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_CASE(makekeystct) try { make_key_test(N(makekeystct)); } FC_LOG_AND_RETHROW() diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index cf0c2c885f..2c62448fa9 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -14,8 +14,9 @@ struct my_struct { std::string tstring; uint64_t tui64; int32_t ti32; - uint128_t ti128; + uint128_t tui128; float tfloat; + double tdouble; testing_struct tstruct; std::tuple ttuple; @@ -24,8 +25,9 @@ struct my_struct { tstring == rhs.tstring && tui64 == rhs.tui64 && ti32 == rhs.ti32 && - ti128 == rhs.ti128 && + tui128 == rhs.tui128 && tfloat == rhs.tfloat && + tdouble == rhs.tdouble && tstruct == rhs.tstruct && ttuple == rhs.ttuple; } @@ -39,8 +41,9 @@ struct my_table : eosio::kv_table(1) << 127) - 5, + .tui128 = 1000, .tfloat = 4.2574, + .tdouble = 4.2574, .tstruct = { 1, 2 }, .ttuple = { 100, 32.43, "abc"} }; @@ -81,8 +85,9 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .tstring = "C", .tui64 = 4, .ti32 = -1, - .ti128 = (static_cast(1) << 127) - 4, + .tui128 = 0, .tfloat = 5.2574, + .tdouble = 50000.2574, .tstruct = { 5, 6 }, .ttuple = { 100, 32.43, "def"} }; @@ -91,8 +96,9 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .tstring = "e", .tui64 = 3, .ti32 = -2, - .ti128 = (static_cast(1) << 127) - 3, .tfloat = 187234, + .tui128 = (static_cast(1) << 127) - 1, + .tdouble = 1872340000, .tstruct = { 3, 4 }, .ttuple = { 100, 33.43, "abc"} }; @@ -101,8 +107,9 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .tstring = "g", .tui64 = 2, .ti32 = 1, - .ti128 = (static_cast(1) << 127) - 2, + .tui128 = (static_cast(1) << 127) - 2, .tfloat = 0, + .tdouble = 0, .tstruct = { 7, 8 }, .ttuple = { 101, 32.43, "abc"} }; @@ -111,8 +118,9 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { .tstring = "I", .tui64 = 1, .ti32 = 2, - .ti128 = (static_cast(1) << 127) - 1, + .tui128 = 54321, .tfloat = -4.2574, + .tdouble = -40000.2574, .tstruct = { 9, 10 }, .ttuple = { 101, 34.43, "abc"} }; @@ -159,9 +167,9 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { } [[eosio::action]] - void makekeyilll() { + void makekeyuilll() { my_table t = my_table::open("kvtest"_n); - check_index(t.index.ti128, {s1, s2, s3, s4, s5}); + check_index(t.index.tui128, {s2, s1, s5, s4, s3}); } [[eosio::action]] @@ -170,6 +178,12 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { check_index(t.index.tfloat, {s5, s4, s1, s2, s3}); } + [[eosio::action]] + void makekeydbl() { + my_table t = my_table::open("kvtest"_n); + check_index(t.index.tdouble, {s5, s4, s1, s2, s3}); + } + [[eosio::action]] void makekeystct() { my_table t = my_table::open("kvtest"_n); From af32c1556e2ac92274cea2bc09af28c7f321187d Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 30 Jan 2020 15:37:24 -0500 Subject: [PATCH 198/659] Minor cleanup from PR feedback --- .../eosiolib/contracts/eosio/key_value.hpp | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index e3a8d49a42..28e2a23418 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -50,13 +50,13 @@ EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(value_class, index_name) -#define CREATE_KV_INDEX(r, value_class, i, index_name) \ +#define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); -#define LIST_INDICES(value_class, ...) \ - BOOST_PP_SEQ_FOR_EACH_I(CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) +#define EOSIO_CDT_LIST_INDICES(value_class, ...) \ + BOOST_PP_SEQ_FOR_EACH_I(EOSIO_CDT_CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) -#define TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ +#define EOSIO_CDT_TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ eosio::kv_table /** @@ -71,9 +71,9 @@ * @param ... - A variadic list of 1 or more indexes to define on the table. */ #define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ - struct table_class : TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ + struct table_class : EOSIO_CDT_TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ struct { \ - LIST_INDICES(value_class, __VA_ARGS__) \ + EOSIO_CDT_LIST_INDICES(value_class, __VA_ARGS__) \ } index; \ \ table_class(eosio::name contract_name) { \ @@ -197,6 +197,10 @@ inline key_type make_key(I val) { template inline key_type make_floating_key(F val) { + if (val == -0) { + val = +0; + } + auto* ival = reinterpret_cast(&val); I bit_val; auto msb = get_msb(*ival); @@ -216,20 +220,12 @@ inline key_type make_floating_key(F val) { return s; } -template ::value, int> = 0> -inline key_type make_key(F val) { - static_assert(!std::is_same_v, "long doubles are currently not supported by make_key"); - - if (val == -0) { - val = +0; - } +inline key_type make_key(float val) { + return make_floating_key(val); +} - if (sizeof(F) == sizeof(float)) { - return make_floating_key(val); - } - else { - return make_floating_key(val); - } +inline key_type make_key(double val) { + return make_floating_key(val); } inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { @@ -277,7 +273,7 @@ inline key_type make_key(S val) { void* data_buffer; boost::pfr::for_each_field(val, [&](auto& field) { - data_size += pack_size(field); + data_size += sizeof(field); }); data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); @@ -303,7 +299,7 @@ inline key_type make_key(std::tuple val) { void* data_buffer; boost::fusion::for_each(val, [&](auto& field) { - data_size += pack_size(field); + data_size += sizeof(field); }); data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); @@ -536,7 +532,7 @@ class kv_table { * @return An iterator to the found object OR the `end` iterator if the given key was not found. */ template - iterator find(K key) { + iterator find(const K& key) { auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); From e64b1cbc043f28b2edf2f423be409283e427417a Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 30 Jan 2020 15:51:01 -0500 Subject: [PATCH 199/659] Minor cleanup from PR feedback --- .../eosiolib/contracts/eosio/key_value.hpp | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 28e2a23418..66abd6e165 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -258,6 +258,10 @@ inline key_type make_key(const char* str, bool case_insensitive=false) { return make_key(std::string{str}, case_insensitive); } +inline key_type make_key(const std::string_view& val, bool case_insensitive=false) { + return make_key(val.data(), val.size(), case_insensitive); +} + inline key_type make_key(eosio::name n) { return make_key(n.value); } @@ -410,18 +414,12 @@ class kv_table { eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); - if (idx->name == idx->tbl->primary_index->name) { - datastream ds((char*)buffer, actual_value_size); + void* serialize = buffer; + size_t serialize_size = actual_value_size; - T val; - ds >> val; - if (value_size > detail::max_stack_buffer_size) { - free(buffer); - } - return val; - } else { + if (idx->name != idx->tbl->primary_index->name) { uint32_t actual_data_size; - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (const char*)buffer, actual_value_size, actual_data_size); + auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (char*)buffer, actual_value_size, actual_data_size); eosio::check(success, "failure getting primary key"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); @@ -429,19 +427,14 @@ class kv_table { eosio::check(copy_size > 0, "failure getting primary index data"); - datastream ds((char*)pk_buffer, copy_size); - - T val; - ds >> val; - - if (actual_data_size > detail::max_stack_buffer_size) { - free(pk_buffer); - } - if (value_size > detail::max_stack_buffer_size) { - free(buffer); - } - return val; + serialize = pk_buffer; + serialize_size = actual_data_size; } + + datastream ds((char*)serialize, serialize_size); + T val; + ds >> val; + return val; } iterator& operator++() { From b0a8ccf239ce62cfd23cacdfa133084255d552fd Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 31 Jan 2020 12:22:57 -0500 Subject: [PATCH 200/659] Drop underscore from macro --- libraries/eosiolib/contracts/eosio/key_value.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 66abd6e165..3cf2461273 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -12,7 +12,7 @@ #include #include -#define EOSIO_CDT_KV_INDEX_nullptr +#define EOSIO_CDT_KV_INDEXnullptr #define EOSIO_CDT_KV_INDEX_TEST() 1 #define EOSIO_CDT_KV_INDEX_TEST_EOSIO_CDT_KV_INDEX_TEST 0, @@ -37,17 +37,17 @@ #define EOSIO_CDT_KV_INDEX_NAME(index_name, i) \ EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_NAME, \ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(index_name, i) + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(index_name, i) #define EOSIO_CDT_KV_INDEX_TYPE(index_name) \ EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_TYPE, \ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(index_name) + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(index_name) #define EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name) \ EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT, \ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX_ ## index_name ()))))(value_class, index_name) + EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(value_class, index_name) #define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ From e0dee3522bcb4589959765ab93cca7d5d0d6c174 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 31 Jan 2020 14:16:01 -0500 Subject: [PATCH 201/659] Make prefix class member --- .../eosiolib/contracts/eosio/key_value.hpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 3cf2461273..dab7be6f93 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -526,7 +526,6 @@ class kv_table { */ template iterator find(const K& key) { - auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); @@ -554,7 +553,6 @@ class kv_table { std::optional get(K key) { uint32_t value_size; - auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); @@ -583,7 +581,6 @@ class kv_table { */ template iterator lower_bound(K key) { - auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); @@ -604,7 +601,6 @@ class kv_table { */ template iterator upper_bound(K key) { - auto prefix = make_prefix(table_name, name); auto t_key = table_key(prefix, make_key(key)); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); @@ -632,7 +628,6 @@ class kv_table { * @return An iterator referring to the `past-the-end` element. */ iterator end() { - auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); @@ -646,7 +641,6 @@ class kv_table { * @return An iterator to the object with the lowest key (by this index) in the table. */ iterator begin() { - auto prefix = make_prefix(table_name, name); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); @@ -692,7 +686,14 @@ class kv_table { key_type get_key(const T& inst) const { return key_function(inst); } private: + friend kv_table; + std::function key_function; + key_type prefix; + + void set_prefix() { + prefix = make_prefix(table_name, name); + } }; /** @@ -800,7 +801,7 @@ class kv_table { primary_index->name = eosio::name{index_name}; } - + primary_index->set_prefix(); ++index_name; for_each_field(*indices, [&](auto& idx) { @@ -809,12 +810,14 @@ class kv_table { si->contract_name = contract_name; si->table_name = table_name; si->tbl = this; + if (is_named) { eosio::check(si->name.value > 0, "All indices must be named if one is named."); } else { eosio::check(si->name.value <= 0, "All indices must be named if one is named."); si->name = eosio::name{index_name}; } + si->set_prefix(); secondary_indices.push_back(si); ++index_name; } From f6c6fc7b9ec7988338bc378f377a8bb60d97ce22 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 31 Jan 2020 12:36:54 -0500 Subject: [PATCH 202/659] Performance cleanup --- .../eosiolib/contracts/eosio/key_value.hpp | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index dab7be6f93..f655a2efb6 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -254,14 +254,14 @@ inline key_type make_key(const std::string& val, bool case_insensitive=false) { return make_key(val.data(), val.size(), case_insensitive); } -inline key_type make_key(const char* str, bool case_insensitive=false) { - return make_key(std::string{str}, case_insensitive); -} - inline key_type make_key(const std::string_view& val, bool case_insensitive=false) { return make_key(val.data(), val.size(), case_insensitive); } +inline key_type make_key(const char* str, bool case_insensitive=false) { + return make_key(std::string_view{str}, case_insensitive); +} + inline key_type make_key(eosio::name n) { return make_key(n.value); } @@ -534,6 +534,7 @@ class kv_table { auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); if (cmp != 0) { + internal_use_do_not_use::kv_it_destroy(itr); return end(); } @@ -552,12 +553,13 @@ class kv_table { template std::optional get(K key) { uint32_t value_size; + std::optional ret_val; auto t_key = table_key(prefix, make_key(key)); auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { - return std::nullopt; + return ret_val; } void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); @@ -565,12 +567,12 @@ class kv_table { datastream ds((char*)buffer, value_size); - T val; - ds >> val; + ret_val.emplace(); + ds >> *ret_val; if (value_size > detail::max_stack_buffer_size) { free(buffer); } - return val; + return ret_val; } /** @@ -587,6 +589,7 @@ class kv_table { int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); if (static_cast(itr_stat) == kv_it_stat::iterator_end) { + internal_use_do_not_use::kv_it_destroy(itr); return end(); } @@ -629,9 +632,8 @@ class kv_table { */ iterator end() { uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_move_to_end(itr); - return {contract_name, itr, static_cast(itr_stat), this}; + return {contract_name, itr, kv_it_stat::iterator_end, this}; } /** From c54406bf92814cfcaa5f45bfaa2c4ec836044be9 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 31 Jan 2020 16:16:37 -0500 Subject: [PATCH 203/659] Performance cleanup --- .../eosiolib/contracts/eosio/key_value.hpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index f655a2efb6..98d4d54f92 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -271,7 +271,7 @@ inline key_type make_key(key_type&& val) { } template ::value, int> = 0> -inline key_type make_key(S val) { +inline key_type make_key(const S& val) { size_t data_size = 0; size_t pos = 0; void* data_buffer; @@ -297,7 +297,7 @@ inline key_type make_key(S val) { } template -inline key_type make_key(std::tuple val) { +inline key_type make_key(const std::tuple& val) { size_t data_size = 0; size_t pos = 0; void* data_buffer; @@ -525,8 +525,8 @@ class kv_table { * @return An iterator to the found object OR the `end` iterator if the given key was not found. */ template - iterator find(const K& key) { - auto t_key = table_key(prefix, make_key(key)); + iterator find(K&& key) { + auto t_key = table_key(prefix, make_key(std::forward(key))); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); @@ -551,11 +551,11 @@ class kv_table { * @return A std::optional of the value corresponding to the key. */ template - std::optional get(K key) { + std::optional get(K&& key) { uint32_t value_size; std::optional ret_val; - auto t_key = table_key(prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(std::forward(key))); auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { @@ -582,8 +582,8 @@ class kv_table { * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. */ template - iterator lower_bound(K key) { - auto t_key = table_key(prefix, make_key(key)); + iterator lower_bound(K&& key) { + auto t_key = table_key(prefix, make_key(std::forward(key))); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); @@ -603,8 +603,8 @@ class kv_table { * @return An iterator pointing to the element with the highest key less than or equal to the given key. */ template - iterator upper_bound(K key) { - auto t_key = table_key(prefix, make_key(key)); + iterator upper_bound(K&& key) { + auto t_key = table_key(prefix, make_key(std::forward(key))); uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); @@ -660,9 +660,9 @@ class kv_table { * @return A vector containing all the objects that fall between the range. */ template - std::vector range(K begin, K end) { - auto begin_itr = lower_bound(begin); - auto end_itr = upper_bound(end); + std::vector range(K&& begin, K&& end) { + auto begin_itr = lower_bound(std::forward(begin)); + auto end_itr = upper_bound(std::forward(end)); bool include_last = find(end) != end_itr; @@ -745,7 +745,7 @@ class kv_table { * @param key - The key of the value to be removed. */ template - void erase(K key) { + void erase(const K& key) { auto primary_value = primary_index->get(key); if (!primary_value) { From 37ac6cd6951ef95cd96a1d30edfed814a64d4ed4 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 31 Jan 2020 17:01:05 -0500 Subject: [PATCH 204/659] API change to remove more templating. --- .../eosiolib/contracts/eosio/key_value.hpp | 58 ++++++++----------- .../unit/test_contracts/kv_make_key_tests.cpp | 26 ++++----- .../kv_multiple_indices_tests.cpp | 20 +++---- .../test_contracts/kv_single_index_tests.cpp | 22 +++---- 4 files changed, 59 insertions(+), 67 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 98d4d54f92..d1c86cd61d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -56,9 +56,6 @@ #define EOSIO_CDT_LIST_INDICES(value_class, ...) \ BOOST_PP_SEQ_FOR_EACH_I(EOSIO_CDT_CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) -#define EOSIO_CDT_TABLE_INHERITANCE(table_class, value_class, table_name, db_name) \ - eosio::kv_table - /** * @brief Macro to define a table. * @details The resulting table will have a member `index` that has fields on it that match 1-1 with the names of the @@ -71,13 +68,13 @@ * @param ... - A variadic list of 1 or more indexes to define on the table. */ #define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ - struct table_class : EOSIO_CDT_TABLE_INHERITANCE(table_class, value_class, table_name, db_name) { \ + struct table_class : eosio::kv_table { \ struct { \ EOSIO_CDT_LIST_INDICES(value_class, __VA_ARGS__) \ } index; \ \ table_class(eosio::name contract_name) { \ - init(contract_name, &index); \ + init(contract_name, table_name##_n, db_name##_n, &index); \ } \ }; @@ -364,7 +361,7 @@ inline key_type make_insensitive(const std::string& val) { * @tparam TableName - the name of the table * @tparam DbName - the type of the EOSIO Key Value database. Defaulted to eosio.kvram */ -template +template class kv_table { enum class kv_it_stat { @@ -419,11 +416,11 @@ class kv_table { if (idx->name != idx->tbl->primary_index->name) { uint32_t actual_data_size; - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, (char*)buffer, actual_value_size, actual_data_size); + auto success = internal_use_do_not_use::kv_get(idx->tbl->db_name, contract_name.value, (char*)buffer, actual_value_size, actual_data_size); eosio::check(success, "failure getting primary key"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - auto copy_size = internal_use_do_not_use::kv_get_data(db, 0, (char*)pk_buffer, actual_data_size); + auto copy_size = internal_use_do_not_use::kv_get_data(idx->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); eosio::check(copy_size > 0, "failure getting primary index data"); @@ -528,7 +525,7 @@ class kv_table { iterator find(K&& key) { auto t_key = table_key(prefix, make_key(std::forward(key))); - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); @@ -557,13 +554,13 @@ class kv_table { auto t_key = table_key(prefix, make_key(std::forward(key))); - auto success = internal_use_do_not_use::kv_get(db, contract_name.value, t_key.data(), t_key.size(), value_size); + auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { return ret_val; } void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(db, 0, (char*)buffer, value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); datastream ds((char*)buffer, value_size); @@ -585,7 +582,7 @@ class kv_table { iterator lower_bound(K&& key) { auto t_key = table_key(prefix, make_key(std::forward(key))); - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); if (static_cast(itr_stat) == kv_it_stat::iterator_end) { @@ -606,7 +603,7 @@ class kv_table { iterator upper_bound(K&& key) { auto t_key = table_key(prefix, make_key(std::forward(key))); - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); iterator it{contract_name, itr, static_cast(itr_stat), this}; @@ -631,7 +628,7 @@ class kv_table { * @return An iterator referring to the `past-the-end` element. */ iterator end() { - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); return {contract_name, itr, kv_it_stat::iterator_end, this}; } @@ -643,7 +640,7 @@ class kv_table { * @return An iterator to the object with the lowest key (by this index) in the table. */ iterator begin() { - uint32_t itr = internal_use_do_not_use::kv_it_create(db, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); return {contract_name, itr, static_cast(itr_stat), this}; @@ -698,6 +695,8 @@ class kv_table { } }; + using iterator = typename kv_index::iterator; + /** * @ingroup keyvalue * @@ -724,11 +723,11 @@ class kv_table { datastream data_ds((char*)data_buffer, data_size); data_ds << value; - internal_use_do_not_use::kv_set(db, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); + internal_use_do_not_use::kv_set(db_name, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); for (auto& idx : secondary_indices) { auto st_key = table_key(make_prefix(table_name, idx->name), idx->get_key(value)); - internal_use_do_not_use::kv_set(db, contract_name.value, st_key.data(), st_key.size(), t_key.data(), t_key.size()); + internal_use_do_not_use::kv_set(db_name, contract_name.value, st_key.data(), st_key.size(), t_key.data(), t_key.size()); } if (data_size > detail::max_stack_buffer_size) { @@ -753,24 +752,14 @@ class kv_table { } auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); - internal_use_do_not_use::kv_erase(db, contract_name.value, k.data(), k.size()); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, k.data(), k.size()); for (auto& idx : secondary_indices) { auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(*primary_value)); - internal_use_do_not_use::kv_erase(db, contract_name.value, skey.data(), skey.size()); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, skey.data(), skey.size()); } } - /** - * Initializes and returns an instance of the Key Value table scoped to the contract name. - * - * @param contract_name - The name of the contract. - * @return An initialized instance of the user specifed Key Value table class. - */ - static Class open(eosio::name contract_name) { - return Class(contract_name); - } - protected: kv_table() = default; @@ -785,8 +774,11 @@ class kv_table { * @param indices - a list of 1 or more indices to add to the table */ template - void init(eosio::name contract, Indices indices) { + void init(eosio::name contract, eosio::name table, eosio::name db, Indices indices) { contract_name = contract; + table_name = table; + db_name = db.value; + bool is_named = false; uint64_t index_name = 1; @@ -831,10 +823,10 @@ class kv_table { } private: - constexpr static uint64_t db = static_cast(DbName); - constexpr static eosio::name table_name = static_cast(TableName); - eosio::name contract_name; + eosio::name table_name; + uint64_t db_name; + kv_index* primary_index; std::vector secondary_indices; diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index 2c62448fa9..20b5383452 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -35,7 +35,7 @@ struct my_struct { auto itstring() const { return eosio::make_insensitive(tstring); } }; -struct my_table : eosio::kv_table { +struct my_table : eosio::kv_table { struct { kv_index tname{&my_struct::tname}; kv_index tstring{&my_struct::tstring}; @@ -50,7 +50,7 @@ struct my_table : eosio::kv_table { +struct my_table_idx : eosio::kv_table { struct { kv_index primary_key{"prim"_n, &my_struct::primary_key}; kv_index foo{"f"_n, &my_struct::foo}; } index; my_table_idx(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); } }; -struct my_table_idx_err : eosio::kv_table { +struct my_table_idx_err : eosio::kv_table { struct { kv_index primary_key{"prim"_n, &my_struct::primary_key}; kv_index foo{&my_struct::foo}; } index; my_table_idx_err(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); } }; -struct my_table_idx_err_2 : eosio::kv_table { +struct my_table_idx_err_2 : eosio::kv_table { struct { kv_index primary_key{&my_struct::primary_key}; kv_index foo{"f"_n, &my_struct::foo}; } index; my_table_idx_err_2(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); } }; @@ -88,7 +88,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; t.put(s1); t.put(s2); @@ -114,7 +114,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto itr = t.index.primary_key.find("bob"_n); auto val = itr.value(); @@ -131,7 +131,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void finderror() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto itr = t.index.primary_key.find("C"); auto val = itr.value(); @@ -139,7 +139,7 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { [[eosio::action]] void iteration() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto foo_begin_itr = t.index.foo.begin(); auto foo_end_itr = t.index.foo.end(); diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 3affce75e0..083d79cb0f 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -32,7 +32,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void setup() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; t.put(s3); t.put(s); @@ -43,8 +43,8 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void find() { - my_table t = my_table::open("kvtest"_n); - auto end_itr = t.index.primary_key.end(); + my_table t{"kvtest"_n}; + my_table::iterator end_itr = t.index.primary_key.end(); auto itr = t.index.primary_key.find("bob"_n); eosio::check(itr != end_itr, "Should not be the end"); @@ -69,14 +69,14 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void finderror() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto itr = t.index.primary_key.find("larry"_n); auto val = itr.value(); } [[eosio::action]] void get() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto end_itr = t.index.primary_key.end(); auto val = t.index.primary_key.get("bob"_n); @@ -88,7 +88,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void bounds() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto end_itr = t.index.primary_key.end(); auto itr = t.index.primary_key.lower_bound("bob"_n); @@ -116,7 +116,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void iteration() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto begin_itr = t.index.primary_key.begin(); auto end_itr = t.index.primary_key.end(); @@ -156,21 +156,21 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void itrerror1() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto end_itr = t.index.primary_key.end(); ++end_itr; } [[eosio::action]] void itrerror2() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto begin_itr = t.index.primary_key.begin(); --begin_itr; } [[eosio::action]] void range() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; std::vector expected{s, s4}; auto vals = t.index.primary_key.range("bob"_n, "john"_n); @@ -191,7 +191,7 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void erase() { - my_table t = my_table::open("kvtest"_n); + my_table t{"kvtest"_n}; auto end_itr = t.index.primary_key.end(); t.erase("joe"_n); From 83c5bc8800a9512a4b9e669120bddf73fb1aa7df Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 3 Feb 2020 09:31:43 -0500 Subject: [PATCH 205/659] Fix upper_bound and cleanup range --- .../eosiolib/contracts/eosio/key_value.hpp | 24 ++++++------------- .../test_contracts/kv_single_index_tests.cpp | 8 +++---- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index d1c86cd61d..73aa793792 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -594,7 +594,7 @@ class kv_table { } /** - * Returns an iterator pointing to the element with the highest key less than or equal to the given key. + * Returns an iterator pointing to the first element greater than the given key. * @ingroup keyvalue * * @return An iterator pointing to the element with the highest key less than or equal to the given key. @@ -609,12 +609,8 @@ class kv_table { iterator it{contract_name, itr, static_cast(itr_stat), this}; auto cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); - while(cmp > 0) { - if (it == begin()) { - return end(); - } - --it; - cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); + if (cmp == 0) { + ++it; } return it; @@ -657,11 +653,9 @@ class kv_table { * @return A vector containing all the objects that fall between the range. */ template - std::vector range(K&& begin, K&& end) { - auto begin_itr = lower_bound(std::forward(begin)); - auto end_itr = upper_bound(std::forward(end)); - - bool include_last = find(end) != end_itr; + std::vector range(K&& b, K&& e) { + auto begin_itr = lower_bound(std::forward(b)); + auto end_itr = lower_bound(std::forward(e)); if (begin_itr == end_itr || begin_itr > end_itr) { return {}; @@ -670,15 +664,11 @@ class kv_table { std::vector return_values; iterator itr = begin_itr; - while(itr != end_itr) { + while(itr < end_itr) { return_values.push_back(itr.value()); ++itr; } - if (include_last) { - return_values.push_back(itr.value()); - } - return return_values; } diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 083d79cb0f..b0e8f6a873 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -102,15 +102,15 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { itr = t.index.primary_key.lower_bound("william"_n); eosio::check(itr == end_itr, "Should be the end"); - itr = t.index.primary_key.upper_bound("bob"_n); + itr = t.index.primary_key.upper_bound("billy"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.upper_bound("matt"_n); + itr = t.index.primary_key.upper_bound("ian"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.upper_bound("ab"_n); + itr = t.index.primary_key.upper_bound("john"_n); eosio::check(itr == end_itr, "Should be the end"); } From 6b73c65f8d6f36d031099f2051d6c57eb1a8efd1 Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Mon, 3 Feb 2020 10:10:38 -0500 Subject: [PATCH 206/659] Add prefix expression to name --- libraries/eosiolib/core/eosio/name.hpp | 32 ++++++++++++++++++++++++++ tests/unit/name_tests.cpp | 24 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/libraries/eosiolib/core/eosio/name.hpp b/libraries/eosiolib/core/eosio/name.hpp index 525377104a..b635ee8b68 100644 --- a/libraries/eosiolib/core/eosio/name.hpp +++ b/libraries/eosiolib/core/eosio/name.hpp @@ -170,6 +170,38 @@ namespace eosio { return name{ ((value & mask) << shift) + (thirteenth_character << (shift-1)) }; } + /** + * Returns the prefix of the %name + */ + constexpr name prefix() const { + uint64_t result = value; + bool not_dot_character_seen = false; + uint64_t mask = 0xFull; + + // Get characters one-by-one in name in order from right to left + for( int32_t offset = 0; offset <= 59; ) { + auto c = (value >> offset) & mask; + + if( !c ) { // if this character is a dot + if(not_dot_character_seen) { // we found the rightmost dot character + result = (value >> offset) << offset; + break; + } + } else { + not_dot_character_seen = true; + } + + if (offset == 0) { + offset += 4; + mask = 0x1Full; + } else { + offset += 5; + } + } + + return name{ result }; + } + /** * Casts a name to raw * diff --git a/tests/unit/name_tests.cpp b/tests/unit/name_tests.cpp index f5425b56ca..464a9bf855 100644 --- a/tests/unit/name_tests.cpp +++ b/tests/unit/name_tests.cpp @@ -130,6 +130,30 @@ EOSIO_TEST_BEGIN(name_type_test) CHECK_EQUAL( name{"e.o.s.i.o.a.c"}.suffix(), name{"c"} ) CHECK_EQUAL( name{"eos.ioa.cco"}.suffix(), name{"cco"} ) + // ---------------------------- + // constexpr name prefix()const + + CHECK_EQUAL( name{".eosioaccounj"}.prefix(), name{} ) + CHECK_EQUAL( name{"e.osioaccounj"}.prefix(), name{"e"} ) + CHECK_EQUAL( name{"eo.sioaccounj"}.prefix(), name{"eo"} ) + CHECK_EQUAL( name{"eos.ioaccounj"}.prefix(), name{"eos"} ) + CHECK_EQUAL( name{"eosi.oaccounj"}.prefix(), name{"eosi"} ) + CHECK_EQUAL( name{"eosio.accounj"}.prefix(), name{"eosio"} ) + CHECK_EQUAL( name{"eosioa.ccounj"}.prefix(), name{"eosioa"} ) + CHECK_EQUAL( name{"eosioac.counj"}.prefix(), name{"eosioac"} ) + CHECK_EQUAL( name{"eosioacc.ounj"}.prefix(), name{"eosioacc"} ) + CHECK_EQUAL( name{"eosioacco.unj"}.prefix(), name{"eosioacco"} ) + CHECK_EQUAL( name{"eosioaccou.nj"}.prefix(), name{"eosioaccou"} ) + CHECK_EQUAL( name{"eosioaccoun.j"}.prefix(), name{"eosioaccoun"} ) + CHECK_EQUAL( name{"eosioaccounj."}.prefix(), name{"eosioaccounj"} ) + CHECK_EQUAL( name{"eosioaccountj"}.prefix(), name{"eosioaccountj"} ) + + CHECK_EQUAL( name{"e.o.s.i.o.a.c"}.prefix(), name{"e.o.s.i.o.a"} ) + CHECK_EQUAL( name{"eos.ioa.cco"}.prefix(), name{"eos.ioa"} ) + + CHECK_EQUAL( name{"a.my.account"}.prefix(), name{"a.my"} ) + CHECK_EQUAL( name{"a.my.account"}.prefix().prefix(), name{"a"} ) + // ----------------------------- // constexpr operator raw()const CHECK_EQUAL( name{"1"}.operator name::raw(), static_cast(576460752303423488ULL) ) From 5c420c746f727a6b90fe709ea17d5c034bf690b9 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 3 Feb 2020 15:07:31 -0500 Subject: [PATCH 207/659] Add move semantics, end returns empty itr, allow empty value --- .../eosiolib/contracts/eosio/key_value.hpp | 66 ++++++++++++++----- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 73aa793792..6b81a48bea 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -386,6 +386,28 @@ class kv_table { iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, kv_index* idx) : contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, idx{idx} {} + iterator(iterator&& other) : + contract_name(std::move(other.contract_name)), + itr(std::exchange(other.itr, 0)), + itr_stat(std::move(other.itr_stat)), + idx(std::exchange(other.idx, nullptr)) + {} + + ~iterator() { + if (itr) { + internal_use_do_not_use::kv_it_destroy(itr); + } + } + + iterator& operator=(iterator&& other) { + contract_name = std::move(other.contract_name); + itr = std::exchange(other.itr, 0); + itr_stat = std::move(other.itr_stat); + idx = std::exchange(other.idx, nullptr); + + return *this; + } + /** * Returns the value that the iterator points to. * @ingroup keyvalue @@ -404,8 +426,6 @@ class kv_table { // call once to get the value_size internal_use_do_not_use::kv_it_value(itr, 0, (char*)nullptr, 0, value_size); - eosio::check(value_size > 0, "Cannot read a value of size 0"); - void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, value_size, actual_value_size); @@ -422,7 +442,7 @@ class kv_table { void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); auto copy_size = internal_use_do_not_use::kv_get_data(idx->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); - eosio::check(copy_size > 0, "failure getting primary index data"); + eosio::check(copy_size != actual_value_size, "failure getting primary index data"); serialize = pk_buffer; serialize_size = actual_data_size; @@ -441,38 +461,36 @@ class kv_table { } iterator& operator--() { + if (!itr) { + itr = internal_use_do_not_use::kv_it_create(idx->tbl->db_name, contract_name.value, idx->prefix.data(), idx->prefix.size()); + } itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); eosio::check(itr_stat != kv_it_stat::iterator_end, "decremented past the beginning"); return *this; } bool operator==(const iterator& b) const { - auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp == 0; + return compare(b) == 0; } bool operator!=(const iterator& b) const { - return !(*this == b); + return compare(b) != 0; } bool operator<(const iterator& b) const { - auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp < 0; + return compare(b) < 0; } bool operator<=(const iterator& b) const { - auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp <= 0; + return compare(b) <= 0; } bool operator>(const iterator& b) const { - auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp > 0; + return compare(b) > 0; } bool operator>=(const iterator& b) const { - auto cmp = internal_use_do_not_use::kv_it_compare(itr, b.itr); - return cmp >= 0; + return compare(b) >= 0; } private: @@ -486,6 +504,20 @@ class kv_table { return idx->get_key(value()); } + int compare(const iterator& b) const { + bool a_is_end = !itr || itr_stat == kv_it_stat::iterator_end; + bool b_is_end = !b.itr || b.itr_stat == kv_it_stat::iterator_end; + if (a_is_end && b_is_end) { + return 0; + } else if (a_is_end && b.itr) { + return 1; + } else if (itr && b_is_end) { + return -1; + } else { + return internal_use_do_not_use::kv_it_compare(itr, b.itr); + } + } + friend kv_index; }; @@ -624,9 +656,7 @@ class kv_table { * @return An iterator referring to the `past-the-end` element. */ iterator end() { - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); - - return {contract_name, itr, kv_it_stat::iterator_end, this}; + return {contract_name, 0, kv_it_stat::iterator_end, this}; } /** @@ -663,7 +693,7 @@ class kv_table { std::vector return_values; - iterator itr = begin_itr; + iterator itr = std::move(begin_itr); while(itr < end_itr) { return_values.push_back(itr.value()); ++itr; From afb571df51476f7ef2073de178461213c3c28fbe Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Wed, 5 Feb 2020 13:30:52 -0500 Subject: [PATCH 208/659] CI/CD support for Catalina (#723) * fixed packager version * anka plugin fixes * 10.15.1 -> 10.15.3 --- .cicd/pipeline.yml | 74 ++++++++++++++++++++++++++++++++++++-- scripts/generate_bottle.sh | 14 ++++---- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index b5608aaa22..86317dff39 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -70,7 +70,31 @@ steps: cd: ~ agents: - "queue=mac-anka-large-node-fleet" - skip: $SKIP_MOJAVE + skip: $SKIP_MACOS_10_14 + + - label: ":darwin: macOS 10.15 - Build" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && ./.cicd/build.sh" + - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" + plugins: + - EOSIO/anka#v0.6.0: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.3_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-large-node-fleet" + skip: $SKIP_MACOS_10_15 + - wait @@ -142,7 +166,30 @@ steps: cd: ~ agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MOJAVE}${SKIP_UNIT_TESTS} + skip: ${SKIP_MACOS_10_14}${SKIP_UNIT_TESTS} + + - label: ":darwin: macOS 10.15 - Unit Tests" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/tests.sh" + plugins: + - EOSIO/anka#v0.6.0: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.3_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-large-node-fleet" + skip: ${SKIP_MACOS_10_15}${SKIP_UNIT_TESTS} - label: ":aws: Amazon_Linux 2 - Toolchain Tests" command: @@ -280,7 +327,28 @@ steps: agents: - "queue=mac-anka-node-fleet" timeout: 10 - skip: ${SKIP_MOJAVE}${SKIP_PACKAGE_BUILDER} + skip: ${SKIP_MACOS_10_14}${SKIP_PACKAGE_BUILDER} + + - label: ":darwin: Catalina - Package Builder" + command: + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/package.sh" + plugins: + - EOSIO/anka#v0.6.0: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.3_6C_14G_40G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + always-pull: true + debug: true + wait-network: true + agents: + - "queue=mac-anka-node-fleet" + timeout: 10 + skip: ${SKIP_MACOS_10_15}${SKIP_PACKAGE_BUILDER} - label: ":git: Git Submodule Regression Check" command: diff --git a/scripts/generate_bottle.sh b/scripts/generate_bottle.sh index d93dc23190..12a1db9b1f 100644 --- a/scripts/generate_bottle.sh +++ b/scripts/generate_bottle.sh @@ -1,17 +1,15 @@ #! /bin/bash -VERS=`sw_vers -productVersion | awk '/10\.13\..*/{print $0}'` -if [[ -z "$VERS" ]]; -then - VERS=`sw_vers -productVersion | awk '/10\.14.*/{print $0}'` - if [[ -z "$VERS" ]]; - then +VERS=`sw_vers -productVersion | awk '/10\.14\..*/{print $0}'` +if [[ -z "$VERS" ]]; then + VERS=`sw_vers -productVersion | awk '/10\.15.*/{print $0}'` + if [[ -z $VERS ]]; then echo "Error, unsupported OS X version" exit -1 fi - MAC_VERSION="mojave" + MAC_VERSION="catalina" else - MAC_VERSION="high_sierra" + MAC_VERSION="mojave" fi NAME="${PROJECT}-${VERSION}.${MAC_VERSION}.bottle" From c4195c7e0387791f6a3d5cc1d60cf6d5259c009f Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Wed, 5 Feb 2020 14:25:06 -0500 Subject: [PATCH 209/659] Add support for creation of a time_point_sec from an iso string --- libraries/eosiolib/core/eosio/time.hpp | 22 ++++++++++++++++++++++ libraries/libc++/CMakeLists.txt | 2 +- libraries/libc++/libcxx | 2 +- libraries/libc/musl | 2 +- tests/unit/time_tests.cpp | 6 ++++++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index 9bdc0ad10d..b42efe0111 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -1,6 +1,9 @@ #pragma once #include #include +#include +#include +#include #include "check.hpp" #include "serialize.hpp" @@ -97,6 +100,25 @@ namespace eosio { static time_point_sec maximum() { return time_point_sec(0xffffffff); } static time_point_sec min() { return time_point_sec(0); } + static time_point_sec from_iso_string(std::string dateStr){ + int y,mon,d,h,m; + float s; + sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &mon, &d, &h, &m, &s); + + std::tm tm; + tm.tm_year = y - 1900; // Year since 1900 + tm.tm_mon = mon - 1; // 0-11 + tm.tm_mday = d; + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = (int)s; + + auto tp = std::chrono::system_clock::from_time_t( ::mktime( &tm ) ); + auto duration = std::chrono::duration_cast( tp.time_since_epoch() ); + + return time_point_sec{ static_cast(duration.count()) }; + } + operator time_point()const { return time_point( eosio::seconds( utc_seconds) ); } uint32_t sec_since_epoch()const { return utc_seconds; } diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index 8158bf0d71..0a511d4524 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -1,4 +1,4 @@ -SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp condition_variable.cpp functional.cpp +SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp chrono.cpp condition_variable.cpp functional.cpp future.cpp hash.cpp ios.cpp iostream.cpp locale.cpp memory.cpp mutex.cpp new.cpp optional.cpp regex.cpp stdexcept.cpp string.cpp strstream.cpp system_error.cpp exception.cpp typeinfo.cpp utility.cpp valarray.cpp variant.cpp vector.cpp eosio.cpp) diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index d45faf798d..3ad8004cbb 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit d45faf798dd6b56e322e89b0af8d120a33a34b4c +Subproject commit 3ad8004cbb0ae6a564f31017bdb062618769caa2 diff --git a/libraries/libc/musl b/libraries/libc/musl index 5c68a528ad..86c3bafaee 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 5c68a528ad29c364245d3b56eec7b4a375acd19b +Subproject commit 86c3bafaee157170e825a01f93ba43c4dc0dc4c5 diff --git a/tests/unit/time_tests.cpp b/tests/unit/time_tests.cpp index d5d46ff2b0..7b0f683765 100644 --- a/tests/unit/time_tests.cpp +++ b/tests/unit/time_tests.cpp @@ -364,6 +364,12 @@ EOSIO_TEST_BEGIN(time_point_sec_type_test) // friend bool operator>=(const time_point_sec&, const time_point_sec&) CHECK_EQUAL( (time_point_sec{1} >= time_point_sec{1}), true ) CHECK_EQUAL( (time_point_sec{1} >= time_point_sec{2}), false ) + + // -------------------------------------------------------------------- + // static time_point_sec from_iso_string() + CHECK_EQUAL( time_point_sec::from_iso_string("1970-01-01T00:00:00.000").utc_seconds, 0); + CHECK_EQUAL( time_point_sec::from_iso_string("1998-06-15T08:13:12.000").utc_seconds, 897898392); + CHECK_EQUAL( time_point_sec::from_iso_string("2020-01-01T00:00:00.000").utc_seconds, 1577836800); EOSIO_TEST_END // Definitions in `eosio.cdt/libraries/eosio/time.hpp` From 0463f9b5624b77fe16378e00d78310f6b6614bf0 Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Wed, 5 Feb 2020 16:39:08 -0500 Subject: [PATCH 210/659] musl submodule update --- libraries/libc/musl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc/musl b/libraries/libc/musl index 86c3bafaee..4215a86ace 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 86c3bafaee157170e825a01f93ba43c4dc0dc4c5 +Subproject commit 4215a86acef8108d15129e568379344320d01cd5 From f6b598fc03d57bde5cc470a70e7a152f54dc4cb6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 4 Feb 2020 17:35:13 -0500 Subject: [PATCH 211/659] Serialize non-variants as 0 index variant for upgrade compatibility --- .../eosiolib/contracts/eosio/key_value.hpp | 63 ++++++++++++--- tests/integration/kv_tests.cpp | 10 +++ .../test_contracts/kv_single_index_tests.cpp | 76 +++++++++++++++++++ 3 files changed, 137 insertions(+), 12 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6b81a48bea..01d8ba8782 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -3,6 +3,7 @@ #include "../../core/eosio/name.hpp" #include "../../core/eosio/print.hpp" #include "../../core/eosio/utility.hpp" +#include "../../core/eosio/varint.hpp" #include #include @@ -431,8 +432,8 @@ class kv_table { eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); - void* serialize = buffer; - size_t serialize_size = actual_value_size; + void* deserialize_buffer = buffer; + size_t deserialize_size = actual_value_size; if (idx->name != idx->tbl->primary_index->name) { uint32_t actual_data_size; @@ -444,13 +445,12 @@ class kv_table { eosio::check(copy_size != actual_value_size, "failure getting primary index data"); - serialize = pk_buffer; - serialize_size = actual_data_size; + deserialize_buffer = pk_buffer; + deserialize_size = actual_data_size; } - datastream ds((char*)serialize, serialize_size); T val; - ds >> val; + deserialize(val, deserialize_buffer, deserialize_size); return val; } @@ -594,10 +594,8 @@ class kv_table { void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); - datastream ds((char*)buffer, value_size); - ret_val.emplace(); - ds >> *ret_val; + deserialize(*ret_val, buffer, copy_size); if (value_size > detail::max_stack_buffer_size) { free(buffer); } @@ -738,10 +736,10 @@ class kv_table { auto t_key = table_key(make_prefix(table_name, primary_index->name), primary_index->get_key(value)); - size_t data_size = pack_size(value); + size_t data_size = get_size(value); void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - datastream data_ds((char*)data_buffer, data_size); - data_ds << value; + + serialize(value, data_buffer, data_size); internal_use_do_not_use::kv_set(db_name, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); @@ -876,5 +874,46 @@ class kv_table { constexpr size_t num_elems = (sizeof(U) / sizeof(kv_index)) - 1; for_each_field(u, f); } + + template + static void serialize(const V& value, void* buffer, size_t size) { + datastream ds((char*)buffer, size); + unsigned_int i{0}; + ds << i; + ds << value; + } + + template + static void serialize(const std::variant& value, void* buffer, size_t size) { + datastream ds((char*)buffer, size); + ds << value; + } + + template + static void deserialize(V& value, void* buffer, size_t size) { + unsigned_int idx; + datastream ds((char*)buffer, size); + + ds >> idx; + ds >> value; + } + + template + static void deserialize(std::variant& value, void* buffer, size_t size) { + datastream ds((char*)buffer, size); + ds >> value; + } + + template + static size_t get_size(V&& value) { + auto size = pack_size(std::forward(value)); + return size + 1; + } + + template + static size_t get_size(std::variant&& value) { + auto size = pack_size(std::forward>(value)); + return size; + } }; } // eosio diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index eac1240cef..9e74916e42 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -87,6 +87,16 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { push_action(N(kvtest), N(erase), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(single_tests_variant, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_single_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(vriant), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + // Multi // ----- BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index b0e8f6a873..f1cfe5f25f 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -8,8 +8,46 @@ struct my_struct { } }; +struct my_struct_v { + uint64_t age; + std::string full_name; +}; + +struct my_struct_v2 { + std::string first_name; + std::string last_name; + uint64_t age; +}; + DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) +struct my_table_v : eosio::kv_table> { + struct { + kv_index primary_key{[](const auto& obj) { + return std::visit([&](auto&& a) { + using V = std::decay_t; + if constexpr(std::is_same_v) { + return a.full_name; + } else if constexpr(std::is_same_v) { + return a.first_name + " : " + a.last_name; + } else { + eosio::check(false, "BAD TYPE"); + return ""; + } + }, *obj); + }}; + kv_index age{[](const auto& obj) { + return std::visit([&](auto&& a) { + return a.age; + }, *obj); + }}; + } index; + + my_table_v(eosio::name contract_name) { + init(contract_name, "testtable2"_n, "eosio.kvram"_n, &index); + } +}; + class [[eosio::contract]] kv_single_index_tests : public eosio::contract { public: using contract::contract; @@ -202,4 +240,42 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto vals = t.index.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } + + [[eosio::action]] + void vriant() { + my_table_v t{"kvtest"_n}; + + my_struct_v s1{ + .full_name = "Dan Larimer", + .age = 25 + }; + + my_struct_v s2{ + .full_name = "Brendan Blumer", + .age = 24 + }; + + my_struct_v2 s3{ + .first_name = "Bob", + .last_name = "Smith", + .age = 30 + }; + + t.put(s1); + t.put(s2); + t.put(s3); + + auto itr = t.index.primary_key.find("Dan Larimer"); + auto val = itr.value(); + auto vval = std::get(val); + eosio::check(vval.age == 25, "wrong value"); + + auto val2 = t.index.primary_key.get("Brendan Blumer"); + auto vval2 = std::get(*val2); + eosio::check(vval2.age == 24, "wrong value"); + + auto val3 = t.index.primary_key.get("Bob : Smith"); + auto vval3 = std::get(*val3); + eosio::check(vval3.age == 30, "wrong value"); + } }; From d60ab27db1adf9534dd13e2d69e3a36b88ba0d02 Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Mon, 10 Feb 2020 18:40:23 -0500 Subject: [PATCH 212/659] Add support for creation of a time_point, time_point_sec and block_timestamp from an iso string, to_string was also implemented --- libraries/eosiolib/core/eosio/time.hpp | 49 +++++++++++++++++--------- libraries/libc++/libcxx | 2 +- libraries/libc/musl | 2 +- tests/unit/time_tests.cpp | 38 ++++++++++++++++++-- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index b42efe0111..440156034f 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -61,6 +61,24 @@ namespace eosio { const microseconds& time_since_epoch()const { return elapsed; } uint32_t sec_since_epoch()const { return uint32_t(elapsed.count() / 1000000); } + static time_point from_iso_string(std::string dateStr) { + std::tm tm; + check(strptime(dateStr.c_str(), "%Y-%m-%dT%H:%M:%S", &tm), "date parsing failed"); + + auto tp = std::chrono::system_clock::from_time_t( ::mktime( &tm ) ); + auto duration = std::chrono::duration_cast( tp.time_since_epoch() ); + return time_point{ microseconds{ static_cast(duration.count()) } }; + } + + std::string to_string() const { + time_t rawtime = sec_since_epoch(); + + char buf[100]; + strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", gmtime ( &rawtime )); + + return std::string{buf}; + } + /// @cond INTERNAL bool operator > ( const time_point& t )const { return elapsed._count > t.elapsed._count; } bool operator >=( const time_point& t )const { return elapsed._count >=t.elapsed._count; } @@ -100,23 +118,13 @@ namespace eosio { static time_point_sec maximum() { return time_point_sec(0xffffffff); } static time_point_sec min() { return time_point_sec(0); } - static time_point_sec from_iso_string(std::string dateStr){ - int y,mon,d,h,m; - float s; - sscanf(dateStr.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &mon, &d, &h, &m, &s); - - std::tm tm; - tm.tm_year = y - 1900; // Year since 1900 - tm.tm_mon = mon - 1; // 0-11 - tm.tm_mday = d; - tm.tm_hour = h; - tm.tm_min = m; - tm.tm_sec = (int)s; - - auto tp = std::chrono::system_clock::from_time_t( ::mktime( &tm ) ); - auto duration = std::chrono::duration_cast( tp.time_since_epoch() ); + static time_point_sec from_iso_string(std::string dateStr) { + auto time_p = time_point::from_iso_string(dateStr); + return time_point_sec{ time_p }; + } - return time_point_sec{ static_cast(duration.count()) }; + std::string to_string() const { + return ((time_point)(*this)).to_string(); } operator time_point()const { return time_point( eosio::seconds( utc_seconds) ); } @@ -193,6 +201,15 @@ namespace eosio { return time_point(milliseconds(msec)); } + static block_timestamp from_iso_string(std::string dateStr) { + auto time_p = time_point::from_iso_string(dateStr); + return block_timestamp{ time_p }; + } + + std::string to_string() const { + return to_time_point().to_string(); + } + /// @cond INTERNAL void operator = (const time_point& t ) { set_time_point(t); diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index 3ad8004cbb..fb4b3725ab 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit 3ad8004cbb0ae6a564f31017bdb062618769caa2 +Subproject commit fb4b3725ab993d85384e67c4d634d2a404c0c381 diff --git a/libraries/libc/musl b/libraries/libc/musl index 4215a86ace..7941d81911 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 4215a86acef8108d15129e568379344320d01cd5 +Subproject commit 7941d8191103ce94fb86c2c518878aef474165b5 diff --git a/tests/unit/time_tests.cpp b/tests/unit/time_tests.cpp index 7b0f683765..0b4f614bed 100644 --- a/tests/unit/time_tests.cpp +++ b/tests/unit/time_tests.cpp @@ -201,6 +201,18 @@ EOSIO_TEST_BEGIN(time_point_type_test) // bool operator>=(const time_point&) CHECK_EQUAL( (time_point{ms1} >= time_point{ms1}), true ) CHECK_EQUAL( (time_point{ms0} >= time_point{ms1}), false ) + + CHECK_EQUAL( time_point::from_iso_string("1970-01-01T00:00:00").elapsed.count(), 0); + CHECK_EQUAL( time_point::from_iso_string("1998-06-15T08:13:12").elapsed.count(), 897898392000000LL); + CHECK_EQUAL( time_point::from_iso_string("2020-01-01T00:00:00").elapsed.count(), 1577836800000000LL); + CHECK_EQUAL( time_point::from_iso_string("2038-01-19T03:14:07").elapsed.count(), 2147483647000000LL); + CHECK_ASSERT( "date parsing failed", [](){ time_point::from_iso_string("invalid string"); }); + CHECK_ASSERT( "date parsing failed", [](){ time_point::from_iso_string("2010-13-81T00:00:00"); }); + + CHECK_EQUAL( time_point{ microseconds{0} }.to_string(), "1970-01-01T00:00:00"); + CHECK_EQUAL( time_point{ microseconds{897898392000000LL} }.to_string(), "1998-06-15T08:13:12"); + CHECK_EQUAL( time_point{ microseconds{1577836800000000LL} }.to_string(), "2020-01-01T00:00:00"); + CHECK_EQUAL( time_point{ microseconds{2147483647000000LL} }.to_string(), "2038-01-19T03:14:07"); EOSIO_TEST_END // Definitions in `eosio.cdt/libraries/eosio/time.hpp` @@ -367,9 +379,18 @@ EOSIO_TEST_BEGIN(time_point_sec_type_test) // -------------------------------------------------------------------- // static time_point_sec from_iso_string() - CHECK_EQUAL( time_point_sec::from_iso_string("1970-01-01T00:00:00.000").utc_seconds, 0); - CHECK_EQUAL( time_point_sec::from_iso_string("1998-06-15T08:13:12.000").utc_seconds, 897898392); - CHECK_EQUAL( time_point_sec::from_iso_string("2020-01-01T00:00:00.000").utc_seconds, 1577836800); + CHECK_EQUAL( time_point_sec::from_iso_string("1970-01-01T00:00:00").utc_seconds, 0); + CHECK_EQUAL( time_point_sec::from_iso_string("1998-06-15T08:13:12").utc_seconds, 897898392); + CHECK_EQUAL( time_point_sec::from_iso_string("2020-01-01T00:00:00").utc_seconds, 1577836800); + CHECK_EQUAL( time_point_sec::from_iso_string("2038-01-19T03:14:07").utc_seconds, 2147483647); + CHECK_ASSERT( "date parsing failed", [](){ time_point_sec::from_iso_string("2010-12-0aT00:00:00"); }); + + // -------------------------------------------------------------------- + // std::string to_string() + CHECK_EQUAL( time_point_sec{0}.to_string(), "1970-01-01T00:00:00"); + CHECK_EQUAL( time_point_sec{897898392}.to_string(), "1998-06-15T08:13:12"); + CHECK_EQUAL( time_point_sec{1577836800}.to_string(), "2020-01-01T00:00:00"); + CHECK_EQUAL( time_point_sec{2147483647}.to_string(), "2038-01-19T03:14:07"); EOSIO_TEST_END // Definitions in `eosio.cdt/libraries/eosio/time.hpp` @@ -474,6 +495,17 @@ EOSIO_TEST_BEGIN(block_timestamp_type_test) // bool operator>=(const block_timestamp&) CHECK_EQUAL( block_timestamp{1} >= block_timestamp{1}, true ) CHECK_EQUAL( block_timestamp{1} >= block_timestamp{2}, false ) + + // -------------------------------------------------------------------- + // static block_timestamp from_iso_string() + CHECK_EQUAL( block_timestamp::from_iso_string("2020-01-01T00:00:00").to_time_point().elapsed.count(), 1577836800000000LL); + CHECK_EQUAL( block_timestamp::from_iso_string("2038-01-19T03:14:07").to_time_point().elapsed.count(), 2147483647000000LL); + CHECK_ASSERT( "date parsing failed", [](){ block_timestamp::from_iso_string("2010-12-08T00:00:99"); }); + + // -------------------------------------------------------------------- + // std::string to_string() + CHECK_EQUAL( block_timestamp{ time_point{ microseconds{1577836800000000LL} } }.to_string(), "2020-01-01T00:00:00"); + CHECK_EQUAL( block_timestamp{ time_point{ microseconds{2147483647000000LL} } }.to_string(), "2038-01-19T03:14:07"); EOSIO_TEST_END int main(int argc, char* argv[]) { From f993dce63c0f104d4241bac094c889961b8043d0 Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Mon, 10 Feb 2020 18:43:40 -0500 Subject: [PATCH 213/659] Add support for creation of a time_point, time_point_sec and block_timestamp from an iso string, to_string was also implemented --- tests/unit/time_tests.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/time_tests.cpp b/tests/unit/time_tests.cpp index 0b4f614bed..414314f6f2 100644 --- a/tests/unit/time_tests.cpp +++ b/tests/unit/time_tests.cpp @@ -202,6 +202,8 @@ EOSIO_TEST_BEGIN(time_point_type_test) CHECK_EQUAL( (time_point{ms1} >= time_point{ms1}), true ) CHECK_EQUAL( (time_point{ms0} >= time_point{ms1}), false ) + // -------------------------------------------------------------------- + // static time_point from_iso_string() CHECK_EQUAL( time_point::from_iso_string("1970-01-01T00:00:00").elapsed.count(), 0); CHECK_EQUAL( time_point::from_iso_string("1998-06-15T08:13:12").elapsed.count(), 897898392000000LL); CHECK_EQUAL( time_point::from_iso_string("2020-01-01T00:00:00").elapsed.count(), 1577836800000000LL); @@ -209,6 +211,8 @@ EOSIO_TEST_BEGIN(time_point_type_test) CHECK_ASSERT( "date parsing failed", [](){ time_point::from_iso_string("invalid string"); }); CHECK_ASSERT( "date parsing failed", [](){ time_point::from_iso_string("2010-13-81T00:00:00"); }); + // -------------------------------------------------------------------- + // std::string to_string() CHECK_EQUAL( time_point{ microseconds{0} }.to_string(), "1970-01-01T00:00:00"); CHECK_EQUAL( time_point{ microseconds{897898392000000LL} }.to_string(), "1998-06-15T08:13:12"); CHECK_EQUAL( time_point{ microseconds{1577836800000000LL} }.to_string(), "2020-01-01T00:00:00"); From 2729dca8fb49c5045ec0ee8fa7ef46a0e9ebdd24 Mon Sep 17 00:00:00 2001 From: Victor Camacho Date: Tue, 11 Feb 2020 11:16:50 -0500 Subject: [PATCH 214/659] Add support for creation of a time_point, time_point_sec and block_timestamp from an iso string, to_string was also implemented, change some code to snake case format --- libraries/eosiolib/core/eosio/time.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index 440156034f..1c0e1b9a94 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -61,9 +61,9 @@ namespace eosio { const microseconds& time_since_epoch()const { return elapsed; } uint32_t sec_since_epoch()const { return uint32_t(elapsed.count() / 1000000); } - static time_point from_iso_string(std::string dateStr) { + static time_point from_iso_string(std::string date_str) { std::tm tm; - check(strptime(dateStr.c_str(), "%Y-%m-%dT%H:%M:%S", &tm), "date parsing failed"); + check(strptime(date_str.c_str(), "%Y-%m-%dT%H:%M:%S", &tm), "date parsing failed"); auto tp = std::chrono::system_clock::from_time_t( ::mktime( &tm ) ); auto duration = std::chrono::duration_cast( tp.time_since_epoch() ); @@ -118,8 +118,8 @@ namespace eosio { static time_point_sec maximum() { return time_point_sec(0xffffffff); } static time_point_sec min() { return time_point_sec(0); } - static time_point_sec from_iso_string(std::string dateStr) { - auto time_p = time_point::from_iso_string(dateStr); + static time_point_sec from_iso_string(std::string date_str) { + auto time_p = time_point::from_iso_string(date_str); return time_point_sec{ time_p }; } @@ -201,8 +201,8 @@ namespace eosio { return time_point(milliseconds(msec)); } - static block_timestamp from_iso_string(std::string dateStr) { - auto time_p = time_point::from_iso_string(dateStr); + static block_timestamp from_iso_string(std::string date_str) { + auto time_p = time_point::from_iso_string(date_str); return block_timestamp{ time_p }; } From 0d9a056c546b9cb723bf6865904c18318122d0cb Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 11 Feb 2020 15:24:02 -0500 Subject: [PATCH 215/659] support for action results --- libraries/eosiolib/capi/eosio/action.h | 2 +- libraries/eosiolib/contracts/eosio/action.hpp | 35 +- libraries/native/intrinsics.cpp | 2 +- modules/TestsExternalProject.txt | 2 +- tests/integration/CMakeLists.txt | 4 +- tests/integration/action_results_test.cpp | 67 ++ tests/integration/contracts.hpp.in | 2 + .../abigen-pass/action_results_test.abi | 52 ++ .../abigen-pass/action_results_test.cpp | 17 + .../abigen-pass/action_results_test.json | 9 + .../aliased_type_variant_template_arg.abi | 38 ++ .../aliased_type_variant_template_arg.json | 3 +- .../abigen-pass/struct_base_typedefd.abi | 48 ++ .../abigen-pass/struct_base_typedefd.json | 2 +- tests/unit/test_contracts/CMakeLists.txt | 1 + .../test_contracts/action_results_test.cpp | 17 + tests/unit/test_contracts/capi/action.c | 2 +- tools/CMakeLists.txt | 5 +- tools/abidiff/eosio-abidiff.cpp.in | 27 + tools/abigen/CMakeLists.txt | 3 - tools/abigen/eosio-abigen.cpp.in | 616 ------------------ tools/cc/eosio-cpp.cpp.in | 9 +- tools/include/compiler_options.hpp.in | 20 +- tools/include/eosio/abi.hpp | 15 +- tools/include/eosio/abigen.hpp | 39 +- tools/include/eosio/abimerge.hpp | 27 +- tools/include/eosio/codegen.hpp | 57 +- tools/toolchain-tester/tests.py | 8 +- 28 files changed, 412 insertions(+), 717 deletions(-) create mode 100644 tests/integration/action_results_test.cpp create mode 100644 tests/toolchain/abigen-pass/action_results_test.abi create mode 100644 tests/toolchain/abigen-pass/action_results_test.cpp create mode 100644 tests/toolchain/abigen-pass/action_results_test.json create mode 100644 tests/toolchain/abigen-pass/aliased_type_variant_template_arg.abi create mode 100644 tests/toolchain/abigen-pass/struct_base_typedefd.abi create mode 100644 tests/unit/test_contracts/action_results_test.cpp delete mode 100644 tools/abigen/CMakeLists.txt delete mode 100644 tools/abigen/eosio-abigen.cpp.in diff --git a/libraries/eosiolib/capi/eosio/action.h b/libraries/eosiolib/capi/eosio/action.h index 741c268c95..58d345848a 100644 --- a/libraries/eosiolib/capi/eosio/action.h +++ b/libraries/eosiolib/capi/eosio/action.h @@ -176,7 +176,7 @@ capi_name current_receiver( void ); * @pre `return_value` is a valid pointer to an array at least `size` bytes long */ __attribute__((eosio_wasm_import)) -void set_action_return_value(char *return_value, size_t size); +void set_action_return_value(void *return_value, size_t size); #ifdef __cplusplus } diff --git a/libraries/eosiolib/contracts/eosio/action.hpp b/libraries/eosiolib/contracts/eosio/action.hpp index 44d81e233d..195c85f842 100644 --- a/libraries/eosiolib/contracts/eosio/action.hpp +++ b/libraries/eosiolib/contracts/eosio/action.hpp @@ -52,9 +52,6 @@ namespace eosio { __attribute__((eosio_wasm_import)) uint64_t current_receiver(); - - __attribute__((eosio_wasm_import)) - void set_action_return_value(char *return_value, size_t size); } }; @@ -153,18 +150,6 @@ namespace eosio { return name{internal_use_do_not_use::current_receiver()}; } - /** - * Set the action return value which will be included in action_receipt - * @ingroup action - * @tparam T type of return value - * @param v the return value to set - */ - template - inline void set_action_return_value( const T& v ) { - auto packed_value = pack( v ); - internal_use_do_not_use::set_action_return_value( &packed_value[0], packed_value.size() ); - } - /** * Copy up to length bytes of current action data to the specified location * @@ -448,9 +433,9 @@ namespace eosio { } /** - * Wrapper for an action object. + * Wrapper for an action object. * - * @brief Used to wrap an a particular action to simplify the process of other contracts sending inline actions to "wrapped" action. + * @brief Used to wrap an a particular action to simplify the process of other contracts sending inline actions to "wrapped" action. * Example: * @code * // defined by contract writer of the actions @@ -591,7 +576,7 @@ INLINE_ACTION_SENDER3( CONTRACT_CLASS, NAME, ::eosio::name(#NAME) ) * Send an inline-action from inside a contract. * * @brief A macro to simplify calling inline actions - * @details The send inline action macro is intended to simplify the process of calling inline actions. When calling new actions from existing actions + * @details The send inline action macro is intended to simplify the process of calling inline actions. When calling new actions from existing actions * EOSIO supports two communication models, inline and deferred. Inline actions are executed as part of the current transaction. This macro * creates an @ref action using the supplied parameters and automatically calls action.send() on this newly created action. * @@ -599,15 +584,15 @@ INLINE_ACTION_SENDER3( CONTRACT_CLASS, NAME, ::eosio::name(#NAME) ) * @code * SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} ); * @endcode - * - * The example above is taken from eosio.token. - * This example: - * uses the passed in, dereferenced `this` pointer, to call this.get_self() i.e. the eosio.token contract; - * calls the eosio.token::transfer() action; + * + * The example above is taken from eosio.token. + * This example: + * uses the passed in, dereferenced `this` pointer, to call this.get_self() i.e. the eosio.token contract; + * calls the eosio.token::transfer() action; * uses the active permission of the "issuer" account; - * uses parameters st.issuer, to, quantity and memo. + * uses parameters st.issuer, to, quantity and memo. * This macro creates an action struct used to 'send()' (call) transfer(account_name from, account_name to, asset quantity, string memo) - * + * * @param CONTRACT - The contract to call, which contains the action being sent, maps to the @ref account * @param NAME - The name of the action to be called, maps to a @ref name * @param ... - The authorising permission, maps to an @ref authorization , followed by the parameters of the action, maps to a @ref data. diff --git a/libraries/native/intrinsics.cpp b/libraries/native/intrinsics.cpp index d70bf28a8c..8cf32e96a0 100644 --- a/libraries/native/intrinsics.cpp +++ b/libraries/native/intrinsics.cpp @@ -292,7 +292,7 @@ extern "C" { capi_name current_receiver() { return intrinsics::get().call(); } - void set_action_return_value( char* rv, size_t len ) { + void set_action_return_value( void* rv, size_t len ) { intrinsics::get().call(rv, len); } void require_recipient( capi_name name ) { diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index c33d1b6e8f..9efdf7906e 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -6,7 +6,7 @@ ExternalProject_Add( EosioWasmTests SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/unit" BINARY_DIR "${CMAKE_BINARY_DIR}/tests/unit" - CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index 816b4ad62b..018172d145 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required( VERSION 3.5 ) -set(EOSIO_VERSION_MIN "1.4") -set(EOSIO_VERSION_SOFT_MAX "2.0") +set(EOSIO_VERSION_MIN "2.0") +set(EOSIO_VERSION_SOFT_MAX "3.0") #set(EOSIO_VERSION_HARD_MAX "") find_package(eosio) diff --git a/tests/integration/action_results_test.cpp b/tests/integration/action_results_test.cpp new file mode 100644 index 0000000000..4886b9bbda --- /dev/null +++ b/tests/integration/action_results_test.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +#include + +#include + +#include + +using namespace eosio; +using namespace eosio::testing; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +BOOST_AUTO_TEST_SUITE(action_results_tests_suite) + +BOOST_FIXTURE_TEST_CASE( action_results_tests, tester ) try { + create_accounts( { N(test) } ); + produce_block(); + + const auto& pfm = control->get_protocol_feature_manager(); + + set_code( N(test), contracts::action_results_test_wasm() ); + set_abi( N(test), contracts::action_results_test_abi().data() ); + auto d = pfm.get_builtin_digest(builtin_protocol_feature_t::action_return_value) + schedule_protocol_features( {*d} ); + + produce_blocks(); + const auto& trace = push_action(N(test), N(action1), N(test), mvo()); + + /* + BOOST_CHECK_THROW(push_action(N(test), N(test1), N(test), mvo()("nm", "notbucky")), + fc::exception); + + push_action(N(test), N(test2), N(test), + mvo() + ("arg0", 33) + ("arg1", "some string")); + BOOST_CHECK_THROW(push_action(N(test), N(test2), N(test), mvo() ("arg0", 30)("arg1", "some string")), fc::exception); + BOOST_CHECK_THROW(push_action(N(test), N(test2), N(test), mvo() ("arg0", 33)("arg1", "not some string")), fc::exception); + + set_abi( N(test), contracts::simple_wrong_abi().data() ); + produce_blocks(); + + BOOST_CHECK_THROW(push_action(N(test), N(test3), N(test), mvo() ("arg0", 33) ("arg1", "some string")), fc::exception); + + set_abi( N(test), contracts::simple_abi().data() ); + produce_blocks(); + + push_action(N(test), N(test4), N(test), mvo() ("to", "someone")); + push_action(N(test), N(test5), N(test), mvo() ("to", "someone")); + push_action(N(test), N(testa), N(test), mvo() ("to", "someone")); + BOOST_CHECK_THROW(push_action(N(test), N(testb), N(test), mvo() ("to", "someone")), fc::exception); + + // test that the pre_dispatch will short circuit dispatching if false + push_action(N(test), N(testc), N(test), mvo() ("nm", "bucky")); + BOOST_CHECK_THROW(push_action(N(test), N(testc), N(test), mvo() ("nm", "someone")), fc::exception); + push_action(N(test), N(testc), N(test), mvo() ("nm", "quit")); + */ + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 8d0f140bbc..afd1ffff67 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -19,6 +19,8 @@ struct contracts { static std::vector capi_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.wasm"); } static std::vector capi_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/capi_tests.abi"); } + static std::vector action_results_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/action_results_test.wasm"); } + static std::vector action_results_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/action_results_test.abi"); } }; }} //ns eosio::testing diff --git a/tests/toolchain/abigen-pass/action_results_test.abi b/tests/toolchain/abigen-pass/action_results_test.abi new file mode 100644 index 0000000000..b9ae26e007 --- /dev/null +++ b/tests/toolchain/abigen-pass/action_results_test.abi @@ -0,0 +1,52 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.2", + "types": [], + "structs": [ + { + "name": "action1", + "base": "", + "fields": [] + }, + { + "name": "action2", + "base": "", + "fields": [] + }, + { + "name": "action3", + "base": "", + "fields": [] + } + ], + "actions": [ + { + "name": "action1", + "type": "action1", + "ricardian_contract": "" + }, + { + "name": "action2", + "type": "action2", + "ricardian_contract": "" + }, + { + "name": "action3", + "type": "action3", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "action_results": [ + { + "name": "action2", + "result_type": "uint32" + }, + { + "name": "action3", + "result_type": "string" + } + ] +} \ No newline at end of file diff --git a/tests/toolchain/abigen-pass/action_results_test.cpp b/tests/toolchain/abigen-pass/action_results_test.cpp new file mode 100644 index 0000000000..0d09d79a4d --- /dev/null +++ b/tests/toolchain/abigen-pass/action_results_test.cpp @@ -0,0 +1,17 @@ +#include + +using namespace eosio; + +class [[eosio::contract]] action_results_test : public contract { + public: + using contract::contract; + + [[eosio::action]] + void action1() {} + + [[eosio::action]] + uint32_t action2() { return 42; } + + [[eosio::action]] + std::string action3() { return "foo"; } +}; diff --git a/tests/toolchain/abigen-pass/action_results_test.json b/tests/toolchain/abigen-pass/action_results_test.json new file mode 100644 index 0000000000..cbe7d91c39 --- /dev/null +++ b/tests/toolchain/abigen-pass/action_results_test.json @@ -0,0 +1,9 @@ +{ + "tests" : [ + { + "expected" : { + "abi-file" : "action_results_test.abi" + } + } + ] +} diff --git a/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.abi b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.abi new file mode 100644 index 0000000000..7720526915 --- /dev/null +++ b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.abi @@ -0,0 +1,38 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.2", + "types": [ + { + "new_type_name": "str", + "type": "string" + } + ], + "structs": [ + { + "name": "hi", + "base": "", + "fields": [ + { + "name": "v", + "type": "variant_uint64_str" + } + ] + } + ], + "actions": [ + { + "name": "hi", + "type": "hi", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [ + { + "name": "variant_uint64_str", + "types": ["uint64","str"] + } + ], + "action_results": [] +} \ No newline at end of file diff --git a/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json index 3a5f5d8150..9a34cb3238 100644 --- a/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json +++ b/tests/toolchain/abigen-pass/aliased_type_variant_template_arg.json @@ -2,9 +2,8 @@ "tests": [ { "expected": { - "abi": "{\n \"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT \",\n \"version\": \"eosio::abi\/1.1\",\n \"types\": [\n {\n \"new_type_name\": \"str\",\n \"type\": \"string\"\n }\n ],\n \"structs\": [\n {\n \"name\": \"hi\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"v\",\n \"type\": \"variant_uint64_str\"\n }\n ]\n }\n ],\n \"actions\": [\n {\n \"name\": \"hi\",\n \"type\": \"hi\",\n \"ricardian_contract\": \"\"\n }\n ],\n \"tables\": [],\n \"ricardian_clauses\": [],\n \"variants\": [\n {\n \"name\": \"variant_uint64_str\",\n \"types\": [\"uint64\",\"str\"]\n }\n ]\n}" + "abi-file": "aliased_type_variant_template_arg.abi" } } ] } - diff --git a/tests/toolchain/abigen-pass/struct_base_typedefd.abi b/tests/toolchain/abigen-pass/struct_base_typedefd.abi new file mode 100644 index 0000000000..d24aa61cbb --- /dev/null +++ b/tests/toolchain/abigen-pass/struct_base_typedefd.abi @@ -0,0 +1,48 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.2", + "types": [ + { + "new_type_name": "bar", + "type": "foo" + } + ], + "structs": [ + { + "name": "baz", + "base": "bar", + "fields": [] + }, + { + "name": "foo", + "base": "", + "fields": [ + { + "name": "value", + "type": "int32" + } + ] + }, + { + "name": "hi", + "base": "", + "fields": [ + { + "name": "b", + "type": "baz" + } + ] + } + ], + "actions": [ + { + "name": "hi", + "type": "hi", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "action_results": [] +} \ No newline at end of file diff --git a/tests/toolchain/abigen-pass/struct_base_typedefd.json b/tests/toolchain/abigen-pass/struct_base_typedefd.json index 0f56342de1..ba945e78dc 100644 --- a/tests/toolchain/abigen-pass/struct_base_typedefd.json +++ b/tests/toolchain/abigen-pass/struct_base_typedefd.json @@ -2,7 +2,7 @@ "tests": [ { "expected": { - "abi": "{\n \"____comment\": \"This file was generated with eosio-abigen. DO NOT EDIT \",\n \"version\": \"eosio::abi\/1.1\",\n \"types\": [\n {\n \"new_type_name\": \"bar\",\n \"type\": \"foo\"\n }\n ],\n \"structs\": [\n {\n \"name\": \"baz\",\n \"base\": \"bar\",\n \"fields\": []\n },\n {\n \"name\": \"foo\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"value\",\n \"type\": \"int32\"\n }\n ]\n },\n {\n \"name\": \"hi\",\n \"base\": \"\",\n \"fields\": [\n {\n \"name\": \"b\",\n \"type\": \"baz\"\n }\n ]\n }\n ],\n \"actions\": [\n {\n \"name\": \"hi\",\n \"type\": \"hi\",\n \"ricardian_contract\": \"\"\n }\n ],\n \"tables\": [],\n \"ricardian_clauses\": [],\n \"variants\": []\n}" + "abi-file": "struct_base_typedefd.abi" } } ] diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index d5582ac3d0..ea206f4d3f 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -1,3 +1,4 @@ +add_contract(action_results_test action_results_test action_results_test.cpp) add_contract(malloc_tests malloc_tests malloc_tests.cpp) add_contract(malloc_tests old_malloc_tests malloc_tests.cpp) add_contract(simple_tests simple_tests simple_tests.cpp) diff --git a/tests/unit/test_contracts/action_results_test.cpp b/tests/unit/test_contracts/action_results_test.cpp new file mode 100644 index 0000000000..0d09d79a4d --- /dev/null +++ b/tests/unit/test_contracts/action_results_test.cpp @@ -0,0 +1,17 @@ +#include + +using namespace eosio; + +class [[eosio::contract]] action_results_test : public contract { + public: + using contract::contract; + + [[eosio::action]] + void action1() {} + + [[eosio::action]] + uint32_t action2() { return 42; } + + [[eosio::action]] + std::string action3() { return "foo"; } +}; diff --git a/tests/unit/test_contracts/capi/action.c b/tests/unit/test_contracts/capi/action.c index 63824f2bff..956510a44d 100644 --- a/tests/unit/test_contracts/capi/action.c +++ b/tests/unit/test_contracts/capi/action.c @@ -13,5 +13,5 @@ void test_action( void ) { send_context_free_inline(NULL, 0); publication_time(); current_receiver(); - set_action_return_value(NULL, 0); + //set_action_return_value(NULL, 0); } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index a563e73dd5..141ae16197 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -29,9 +29,9 @@ macro (add_tool name) set(LLVM_LINK_COMPONENTS support) include_directories(include) - + add_executable(${name} ${CMAKE_BINARY_DIR}/${name}.cpp) - set_property(TARGET ${name} PROPERTY CXX_STANDARD 14) + set_property(TARGET ${name} PROPERTY CXX_STANDARD 17) target_compile_options(${name} PRIVATE -fexceptions -fno-rtti) target_include_directories(${name} PUBLIC ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../jsoncons/include ${CMAKE_SOURCE_DIR}/eosio_llvm/tools/clang/include ${LLVM_INCLUDE_DIR}) target_link_libraries(${name} @@ -71,7 +71,6 @@ macro (add_tool name) add_custom_command( TARGET ${name} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_BINARY_DIR}/bin/ ) endmacro() -add_subdirectory(abigen) add_subdirectory(abidiff) add_subdirectory(cc) add_subdirectory(ld) diff --git a/tools/abidiff/eosio-abidiff.cpp.in b/tools/abidiff/eosio-abidiff.cpp.in index 2ab40bee1f..f927ec6c43 100644 --- a/tools/abidiff/eosio-abidiff.cpp.in +++ b/tools/abidiff/eosio-abidiff.cpp.in @@ -224,6 +224,26 @@ class abidiff { } } + void print_action_results(const ojson& abi, int index, char direction) { + std::cout << direction << " action_result\n"; + std::cout << pretty_print(abi["action_results"].at(index)) << "\n"; + } + + void find_action_results(const ojson& abi1, const ojson& abi2, char direction) { + for ( int i=0; i < abi1["action_results"].size(); i++ ) { + bool found = false; + for ( int j=0; j < abi2["action_results"].size(); j++ ) { + if (abi1["action_results"].at(i)["name"] == abi2["action_results"].at(j)["name"]) { + if (abi1["action_results"].at(i)["result_type"] != abi2["action_results"].at(i)["result_type"]) + break; + found = true; + } + + } + if (!found) + print_action_results(abi1, i, direction); + } + } void diff_structs() { find_structs(abi_1, abi_2, '<'); find_structs(abi_2, abi_1, '>'); @@ -254,6 +274,11 @@ class abidiff { find_variants(abi_2, abi_1, '>'); } + void diff_action_results() { + find_action_results(abi_1, abi_2, '<'); + find_action_results(abi_2, abi_1, '>'); + } + void diff() { diff_version(); diff_structs(); @@ -263,6 +288,8 @@ class abidiff { diff_clauses(); if ( get_version(abi_1) >= 11 && get_version(abi_2) >= 11 ) diff_variants(); + if ( get_version(abi_1) >= 12 && get_version(abi_2) >= 12 ) + diff_action_results(); } }; diff --git a/tools/abigen/CMakeLists.txt b/tools/abigen/CMakeLists.txt deleted file mode 100644 index d5001a6af0..0000000000 --- a/tools/abigen/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/eosio-abigen.cpp.in ${CMAKE_BINARY_DIR}/eosio-abigen.cpp) - -add_tool(eosio-abigen) diff --git a/tools/abigen/eosio-abigen.cpp.in b/tools/abigen/eosio-abigen.cpp.in deleted file mode 100644 index 96021b4f5b..0000000000 --- a/tools/abigen/eosio-abigen.cpp.in +++ /dev/null @@ -1,616 +0,0 @@ -// Declares clang::SyntaxOnlyAction. -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Tooling.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -#include "clang/Basic/Builtins.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "llvm/Support/FileSystem.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// Declares llvm::cl::extrahelp. -#include "llvm/Support/CommandLine.h" -using namespace clang::tooling; -using namespace clang::ast_matchers; -using namespace llvm; -using namespace eosio; -using namespace eosio::cdt; -using jsoncons::json; -using jsoncons::ojson; - -struct abigen_exception : public std::exception { - virtual const char* what() const throw() { - return "eosio.abigen fatal error"; - } -} abigen_ex; - - -DeclarationMatcher function_decl_matcher = cxxMethodDecl().bind("eosio_abis"); -DeclarationMatcher record_decl_matcher = cxxRecordDecl().bind("eosio_abis"); -DeclarationMatcher typedef_decl_matcher = typedefDecl().bind("eosio_abis"); -auto class_tmp_matcher = classTemplateSpecializationDecl().bind("eosio_abis"); - -class abigen : public generation_utils { - public: - abigen() : generation_utils([&](){throw abigen_ex;}) {} - void add_typedef( const clang::QualType& t ) { - abi_typedef ret; - ret.new_type_name = get_base_type_name( t ); - auto td = get_type_alias(t); - if (td.empty()) - return; - ret.type = translate_type(td[0]); - if(!is_builtin_type(td[0])) - add_type(td[0]); - _abi.typedefs.insert(ret); - } - - void add_action( const clang::CXXRecordDecl* decl ) { - abi_action ret; - auto action_name = decl->getEosioActionAttr()->getName(); - - if (rcs[get_action_name(decl)].empty()) - std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; - - ret.ricardian_contract = rcs[get_action_name(decl)]; - - if (action_name.empty()) { - try { - validate_name( decl->getName().str(), error_handler ); - } catch (...) { - std::cout << "Error, name <" <getName().str() << "> is an invalid EOSIO name.\n"; - throw; - } - ret.name = decl->getName().str(); - } - else { - try { - validate_name( action_name.str(), error_handler ); - } catch (...) { - std::cout << "Error, name <" << action_name.str() << "> is an invalid EOSIO name.\n"; - throw; - } - ret.name = action_name.str(); - } - ret.type = decl->getName().str(); - _abi.actions.insert(ret); - } - - void add_action( const clang::CXXMethodDecl* decl ) { - abi_action ret; - - auto action_name = decl->getEosioActionAttr()->getName(); - - if (rcs[get_action_name(decl)].empty()) - std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; - - ret.ricardian_contract = rcs[get_action_name(decl)]; - - if (action_name.empty()) { - try { - validate_name( decl->getNameAsString(), error_handler ); - } catch (...) { - std::cout << "Error, name <" <getNameAsString() << "> is an invalid EOSIO name.\n"; - } - ret.name = decl->getNameAsString(); - } - else { - try { - validate_name( action_name.str(), error_handler ); - } catch (...) { - std::cout << "Error, name <" << action_name.str() << "> is an invalid EOSIO name.\n"; - } - ret.name = action_name.str(); - } - ret.type = decl->getNameAsString(); - _abi.actions.insert(ret); - } - - void add_tuple(const clang::QualType& type) { - auto pt = llvm::dyn_cast(type.getTypePtr()); - auto tst = llvm::dyn_cast(pt->desugar().getTypePtr()); - if (!tst) - throw abigen_ex; - abi_struct tup; - tup.name = get_type(type); - for (int i = 0; i < tst->getNumArgs(); ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); - add_type(ftype); - tup.fields.push_back( {"field_"+std::to_string(i), - translate_type(ftype)} ); - } - _abi.structs.insert(tup); - } - - void add_pair(const clang::QualType& type) { - for (int i = 0; i < 2; ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); - std::string ty = translate_type(ftype); - add_type(ftype); - } - abi_struct pair; - pair.name = get_type(type); - pair.fields.push_back( {"first", translate_type(get_template_argument(type).getAsType())} ); - pair.fields.push_back( {"second", translate_type(get_template_argument(type, 1).getAsType())} ); - add_type(get_template_argument(type).getAsType()); - add_type(get_template_argument(type, 1).getAsType()); - _abi.structs.insert(pair); - } - - void add_map(const clang::QualType& type) { - for (int i = 0; i < 2; ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); - std::string ty = translate_type(ftype); - add_type(ftype); - } - abi_struct kv; - std::string name = get_type(type); - kv.name = name.substr(0, name.length() - 2); - kv.fields.push_back( {"key", translate_type(get_template_argument(type).getAsType())} ); - kv.fields.push_back( {"value", translate_type(get_template_argument(type, 1).getAsType())} ); - add_type(get_template_argument(type).getAsType()); - add_type(get_template_argument(type, 1).getAsType()); - _abi.structs.insert(kv); - } - - void add_struct( const clang::CXXRecordDecl* decl, const std::string& rname="" ) { - abi_struct ret; - if ( decl->getNumBases() == 1 ) { - ret.base = get_type(decl->bases_begin()->getType()); - add_struct(decl->bases_begin()->getType().getTypePtr()->getAsCXXRecordDecl()); - } - std::string sub_name = ""; - for ( auto field : decl->fields() ) { - if ( field->getName() == "transaction_extensions") { - abi_struct ext; - ext.name = "extension"; - ext.fields.push_back( {"type", "uint16"} ); - ext.fields.push_back( {"data", "bytes"} ); - ret.fields.push_back( {"transaction_extensions", "extension[]"}); - _abi.structs.insert(ext); - } - else { - ret.fields.push_back({field->getName().str(), get_type(field->getType())}); - sub_name += "_" + get_type(field->getType()); - add_type(field->getType()); - } - } - if (!rname.empty()) - ret.name = rname; - else - ret.name = decl->getName().str(); - _abi.structs.insert(ret); - } - - void add_struct( const clang::CXXMethodDecl* decl ) { - abi_struct new_struct; - new_struct.name = decl->getNameAsString(); - for (auto param : decl->parameters() ) { - auto param_type = param->getType().getNonReferenceType().getUnqualifiedType(); - new_struct.fields.push_back({param->getNameAsString(), get_type(param_type)}); - add_type(param_type); - } - _abi.structs.insert(new_struct); - } - - std::string to_index_type( std::string t ) { - return "i64"; - } - - void add_table( const clang::CXXRecordDecl* decl ) { - tables.insert(decl); - abi_table t; - t.type = decl->getNameAsString(); - auto table_name = decl->getEosioTableAttr()->getName(); - if (!table_name.empty()) { - try { - validate_name( table_name.str(), error_handler ); - } catch (...) { - } - t.name = table_name.str(); - } - else { - t.name = t.type; - } - ctables.insert(t); - } - - void add_table( uint64_t name, const clang::CXXRecordDecl* decl ) { - if (!(decl->isEosioTable() && abigen::is_eosio_contract(decl, get_contract_name()))) - return; - abi_table t; - t.type = decl->getNameAsString(); - t.name = name_to_string(name); - _abi.tables.insert(t); - } - - void add_clauses( const std::vector>& clauses ) { - for ( auto clp : clauses ) { - _abi.ricardian_clauses.push_back({std::get<0>(clp), std::get<1>(clp)}); - } - } - - void add_contracts( const std::map& rc ) { - rcs = rc; - } - - void add_variant( const clang::QualType& t ) { - abi_variant var; - auto pt = llvm::dyn_cast(t.getTypePtr()); - auto tst = llvm::dyn_cast(pt ? pt->desugar().getTypePtr() : t.getTypePtr()); - var.name = get_type(t); - for (int i=0; i < tst->getNumArgs(); ++i) - var.types.push_back(translate_type(get_template_argument( t, i ).getAsType())); - _abi.variants.insert(var); - } - - void add_type( const clang::QualType& t ) { - auto type = get_ignored_type(t); - if (!is_builtin_type(translate_type(type))) { - if (is_aliasing(type)) - add_typedef(type); - else if (is_template_specialization(type, {"vector", "set", "deque", "list", "optional", "binary_extension", "ignore"})) { - add_type(get_template_argument(type).getAsType()); - } - else if (is_template_specialization(type, {"map"})) - add_map(type); - else if (is_template_specialization(type, {"pair"})) - add_pair(type); - else if (is_template_specialization(type, {"tuple"})) - add_tuple(type); - else if (is_template_specialization(type, {"variant"})) - add_variant(type); - else if (is_template_specialization(type, {})) { - add_struct(type.getTypePtr()->getAsCXXRecordDecl(), get_template_name(type)); - } - else if (type.getTypePtr()->isRecordType()) - add_struct(type.getTypePtr()->getAsCXXRecordDecl()); - } - } - - std::string generate_json_comment() { - std::stringstream ss; - ss << "This file was generated with eosio-abigen."; - ss << " DO NOT EDIT"; - return ss.str(); - } - - ojson struct_to_json( const abi_struct& s ) { - ojson o; - o["name"] = s.name; - o["base"] = s.base; - o["fields"] = ojson::array(); - for ( auto field : s.fields ) { - ojson f; - f["name"] = field.name; - f["type"] = field.type; - o["fields"].push_back(f); - } - return o; - } - - ojson variant_to_json( const abi_variant& v ) { - ojson o; - o["name"] = v.name; - o["types"] = ojson::array(); - for ( auto ty : v.types ) { - o["types"].push_back( ty ); - } - return o; - } - - ojson typedef_to_json( const abi_typedef& t ) { - ojson o; - o["new_type_name"] = t.new_type_name; - o["type"] = t.type; - return o; - } - - ojson action_to_json( const abi_action& a ) { - ojson o; - o["name"] = a.name; - o["type"] = a.type; - o["ricardian_contract"] = a.ricardian_contract; - return o; - } - - ojson clause_to_json( const abi_ricardian_clause_pair& clause ) { - ojson o; - o["id"] = clause.id; - o["body"] = clause.body; - return o; - } - - ojson table_to_json( const abi_table& t ) { - ojson o; - o["name"] = t.name; - o["type"] = t.type; - o["index_type"] = "i64"; - o["key_names"] = ojson::array(); - o["key_types"] = ojson::array(); - return o; - } - - ojson to_json() { - ojson o; - o["____comment"] = generate_json_comment(); - o["version"] = _abi.version; - o["structs"] = ojson::array(); - auto remove_suffix = [&]( std::string name ) { - int i = name.length()-1; - for (; i >= 0; i--) - if ( name[i] != '[' && name[i] != ']' && name[i] != '?' && name[i] != '$' ) - break; - return name.substr(0,i+1); - }; - - std::set set_of_tables; - for ( auto t : ctables ) { - bool has_multi_index = false; - for ( auto u : _abi.tables ) { - if (t.type == u.type) { - has_multi_index = true; - break; - } - set_of_tables.insert(u); - } - if (!has_multi_index) - set_of_tables.insert(t); - } - for ( auto t : _abi.tables ) { - set_of_tables.insert(t); - } - - auto validate_struct = [&]( abi_struct as ) { - if ( is_builtin_type(_translate_type(as.name)) ) - return false; - for ( auto s : _abi.structs ) { - for ( auto f : s.fields ) { - if (as.name == _translate_type(remove_suffix(f.type))) - return true; - } - if (s.base == as.name) - return true; - } - for ( auto a : _abi.actions ) { - if (as.name == _translate_type(a.type)) - return true; - } - for( auto t : set_of_tables ) { - if (as.name == _translate_type(t.type)) - return true; - } - for( auto td : _abi.typedefs ) { - if (as.name == _translate_type(remove_suffix(td.type))) - return true; - } - return false; - }; - - auto validate_types = [&]( abi_typedef td ) { - for ( auto as : _abi.structs ) - if (validate_struct(as)) - for ( auto f : as.fields ) - if ( remove_suffix(f.type) == td.new_type_name ) - return true; - for ( auto t : _abi.tables ) - if ( t.type == td.new_type_name ) - return true; - for ( auto a : _abi.actions ) - if ( a.type == td.new_type_name ) - return true; - for ( auto _td : _abi.typedefs ) - if ( remove_suffix(_td.type) == td.new_type_name ) - return true; - return false; - }; - - for ( auto s : _abi.structs ) { - if (validate_struct(s)) - o["structs"].push_back(struct_to_json(s)); - } - o["types"] = ojson::array(); - for ( auto t : _abi.typedefs ) { - if (validate_types(t)) - o["types"].push_back(typedef_to_json( t )); - } - o["actions"] = ojson::array(); - for ( auto a : _abi.actions ) { - o["actions"].push_back(action_to_json( a )); - } - o["tables"] = ojson::array(); - for ( auto t : set_of_tables ) { - o["tables"].push_back(table_to_json( t )); - } - o["ricardian_clauses"] = ojson::array(); - for ( auto rc : _abi.ricardian_clauses ) { - o["ricardian_clauses"].push_back(clause_to_json( rc )); - } - o["variants"] = ojson::array(); - for ( auto v : _abi.variants ) { - o["variants"].push_back(variant_to_json( v )); - } - o["abi_extensions"] = ojson::array(); - return o; - } - - abi& get_abi_ref() { return _abi; } - - - private: - abi _abi; - std::set tables; - std::set ctables; - std::map rcs; -}; - -abigen& get_abigen_ref() { - static abigen ag; - return ag; -} - -class EosioMethodMatcher : public MatchFinder::MatchCallback { - public: - virtual void run( const MatchFinder::MatchResult& res ) { - if (const clang::CXXMethodDecl* decl = res.Nodes.getNodeAs("eosio_abis")->getCanonicalDecl()) { - abi abi; - if (decl->isEosioAction() && abigen::is_eosio_contract(decl, get_abigen_ref().get_contract_name())) { - get_abigen_ref().add_struct(decl); - get_abigen_ref().add_action(decl); - auto params = decl->parameters(); - for (auto param : params) { - get_abigen_ref().add_type(param->getType()); - } - } - } - } -}; - -class EosioRecordMatcher : public MatchFinder::MatchCallback { - public: - bool has_added_clauses = false; - virtual void run( const MatchFinder::MatchResult& res ) { - if (const clang::CXXRecordDecl* decl = res.Nodes.getNodeAs("eosio_abis")) { - if (!has_added_clauses) { - get_abigen_ref().add_clauses(get_abigen_ref().parse_clauses()); - get_abigen_ref().add_contracts(get_abigen_ref().parse_contracts()); - has_added_clauses = true; - } - if (decl->isEosioAction() && abigen::is_eosio_contract(decl, get_abigen_ref().get_contract_name())) { - get_abigen_ref().add_struct(decl); - get_abigen_ref().add_action(decl); - for (auto field : decl->fields()) { - get_abigen_ref().add_type( field->getType() ); - } - } - if (decl->isEosioTable() && abigen::is_eosio_contract(decl, get_abigen_ref().get_contract_name())) { - get_abigen_ref().add_struct(decl); - get_abigen_ref().add_table(decl); - for (auto field : decl->fields()) - get_abigen_ref().add_type( field->getType() ); - } - } - - if (const clang::ClassTemplateSpecializationDecl* decl = res.Nodes.getNodeAs("eosio_abis")) { - if ( decl->getName() == "multi_index" ) { - get_abigen_ref().add_table(decl->getTemplateArgs()[0].getAsIntegral().getExtValue(), - (clang::CXXRecordDecl*)((clang::RecordType*)decl->getTemplateArgs()[1].getAsType().getTypePtr())->getDecl()); - } - } - } - - -}; - -int main(int argc, const char **argv) { - - cl::SetVersionPrinter([](llvm::raw_ostream& os) { - os << "eosio-abigen version " << "${VERSION_FULL}" << "\n"; - }); - cl::OptionCategory cat("eosio-abigen", "generates an abi from C++ project input"); - - cl::opt abidir( - "output", - cl::desc("Set the output filename and fullpath"), - cl::Required, - cl::cat(cat)); - cl::opt contract_name( - "contract", - cl::desc("Set the contract name"), - cl::Required, - cl::cat(cat)); - cl::opt def( - "default", - cl::desc(""), - cl::Hidden, - cl::cat(cat)); - cl::list resource_paths( - "R", - cl::desc("Add a resource path for inclusion"), - cl::cat(cat), - cl::Prefix, - cl::ZeroOrMore); - - std::vector options; - for (size_t i=0; i < argc; i++) { - options.push_back(argv[i]); - } - bool has_dash_dash = false; - for (auto opt : options) { - if ( opt.compare("--") == 0 ) { - has_dash_dash = true; - break; - } - } - if (!has_dash_dash) - options.push_back("--"); - options.push_back("--target=wasm32"); - options.push_back("-nostdlib"); - options.push_back("-ffreestanding"); - options.push_back("-fno-builtin"); - options.push_back("-fno-rtti"); - options.push_back("-fno-exceptions"); - options.push_back("-I${Boost_INCLUDE_DIRS}"); - options.push_back("-DBOOST_DISABLE_ASSERTS"); - options.push_back("-DBOOST_EXCEPTION_DISABLE"); - options.push_back("-Wno-everything"); - options.push_back("-std=c++17"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../include/libcxx"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../include/libc"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../include"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../../../../../libraries/libc++/libcxx/include"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../../../../../libraries/libc/musl/include"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../../../../../libraries"); - options.push_back(std::string("-I")+eosio::cdt::whereami::where()+"/../../../../../libraries/boost/include"); - - int size = options.size(); - const char** new_argv = new const char*[size]; - for (size_t i=0; i < size; i++) - new_argv[i] = options[i].c_str(); - - CommonOptionsParser opts( size, new_argv, cat, 0 ); - - ClangTool tool( opts.getCompilations(), opts.getSourcePathList()); - get_abigen_ref().set_contract_name(contract_name); - get_abigen_ref().set_resource_dirs(resource_paths); - EosioMethodMatcher eosio_method_matcher; - EosioRecordMatcher eosio_record_matcher; - MatchFinder finder; - finder.addMatcher(function_decl_matcher, &eosio_method_matcher); - finder.addMatcher(record_decl_matcher, &eosio_record_matcher); - finder.addMatcher(class_tmp_matcher, &eosio_record_matcher); - - llvm::errs() << "Warning, this tool is deprecated. Only use eosio-cpp in the future." << '\n'; - int tool_run = -1; - try { - tool_run = tool.run(newFrontendActionFactory(&finder).get()); - std::ofstream output(abidir); - output << pretty_print(get_abigen_ref().to_json()); - output.close(); - } catch (std::exception& ex) { - std::cout << ex.what() << "\n"; - tool_run = -1; - } - - return tool_run; -} diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index b87c0b3686..fb1d6bf262 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -107,7 +107,7 @@ namespace eosio { namespace cdt { }; }} // ns eosio::cdt -void generate(const std::vector& base_options, std::string input, std::string contract_name, const std::vector& resource_paths, bool abigen) { +void generate(const std::vector& base_options, std::string input, std::string contract_name, const std::vector& resource_paths, const std::pair& abi_version, bool abigen) { std::vector options; options.push_back("eosio-cpp"); options.push_back(input); // don't remove oddity of CommonOptionsParser? @@ -130,6 +130,7 @@ void generate(const std::vector& base_options, std::string input, s get_abigen_ref().set_contract_name(contract_name); get_abigen_ref().set_resource_dirs(resource_paths); + get_abigen_ref().set_abi_version(std::get<0>(abi_version), std::get<1>(abi_version)); codegen::get().set_contract_name(contract_name); EosioMethodMatcher eosio_method_matcher; @@ -189,7 +190,7 @@ int main(int argc, const char **argv) { tool_opts.erase(std::remove_if(tool_opts.begin(), tool_opts.end(), [&](const auto& opt){ return non_tool_opts.count(opt); }), tool_opts.end()); - generate(tool_opts, input, opts.abigen_contract, opts.abigen_resources, opts.abigen); + generate(tool_opts, input, opts.abigen_contract, opts.abigen_resources, opts.abi_version, opts.abigen); auto src = SmallString<64>(input); llvm::sys::path::remove_filename(src); @@ -214,10 +215,10 @@ int main(int argc, const char **argv) { new_opts.insert(new_opts.begin(), "-xc++"); if (!eosio::cdt::environment::exec_subprogram("clang-7", new_opts)) { - llvm::sys::fs::remove(tmp_file); + //llvm::sys::fs::remove(tmp_file); return -1; } - llvm::sys::fs::remove(tmp_file); + //llvm::sys::fs::remove(tmp_file); } } catch (std::runtime_error& err) { llvm::errs() << err.what() << '\n'; diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index b461905ac8..20ea092420 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -19,6 +20,10 @@ static llvm::cl::OptionCategory EosioLdToolCategory("ld options"); #endif /// begin ld options +static cl::opt abi_version_opt( + "abi-version", + cl::desc("Which ABI version to generate"), + cl::cat(LD_CAT)); static cl::opt only_export_opt( "only-export", cl::desc("Export only this symbol"), @@ -364,6 +369,7 @@ struct Options { std::vector abigen_resources; bool debug; bool native; + std::pair abi_version; }; static void GetCompDefaults(std::vector& copts) { @@ -867,9 +873,19 @@ static Options CreateOptions(bool add_defaults=true) { ldopts.emplace_back("-fuse-main"); #endif + /* TODO add some way of defaulting these to the current highest version */ + int abi_version_major = 1; + int abi_version_minor = 2; + + if (!abi_version_opt.empty()) { + abi_version_major = std::stoi(abi_version_opt); + float tmp = std::stof(abi_version_opt); + abi_version_minor = ((tmp - (int)tmp)*10); + } + #ifndef ONLY_LD - return {output_fn, inputs, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; + return {output_fn, inputs, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; #else - return {output_fn, {}, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt}; + return {output_fn, {}, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; #endif } diff --git a/tools/include/eosio/abi.hpp b/tools/include/eosio/abi.hpp index 206718245a..b45c3d4c66 100644 --- a/tools/include/eosio/abi.hpp +++ b/tools/include/eosio/abi.hpp @@ -55,9 +55,17 @@ struct abi_error_message { std::string error_msg; }; +struct abi_action_result { + std::string name; + std::string type; + bool operator<(const abi_action_result& ar) const { return name < ar.name; } +}; + /// From eosio libraries/chain/include/eosio/chain/abi_def.hpp struct abi { - std::string version = "eosio::abi/1.1"; + int version_major = 1; + int version_minor = 1; + std::string version_string()const { return std::string("eosio::abi/")+std::to_string(version_major)+"."+std::to_string(version_minor); } std::set structs; std::set typedefs; std::set actions; @@ -65,11 +73,12 @@ struct abi { std::set variants; std::vector ricardian_clauses; std::vector error_messages; + std::set action_results; }; inline void dump( const abi& abi ) { - std::cout << "ABI : "; - std::cout << "\n\tversion : " << abi.version; + std::cout << "ABI : "; + std::cout << "\n\tversion : " << abi.version_string(); std::cout << "\n\tstructs : "; for (auto s : abi.structs) { std::cout << "\n\t\tstruct : "; diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 02fd768b65..04f7b3b0e9 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -35,6 +35,12 @@ namespace eosio { namespace cdt { abigen() : generation_utils([&](){throw abigen_ex;}) { } + + void set_abi_version(int major, int minor) { + _abi.version_major = major; + _abi.version_minor = minor; + } + void add_typedef( const clang::QualType& t ) { abi_typedef ret; ret.new_type_name = get_base_type_name( t ); @@ -106,6 +112,8 @@ namespace eosio { namespace cdt { } ret.type = decl->getNameAsString(); _abi.actions.insert(ret); + if (translate_type(decl->getReturnType()) != "void") + _abi.action_results.insert({get_action_name(decl), translate_type(decl->getReturnType())}); } void add_tuple(const clang::QualType& type) { @@ -133,11 +141,11 @@ namespace eosio { namespace cdt { abi_struct pair; pair.name = get_type(type); pair.fields.push_back( {"first", translate_type(get_template_argument(type).getAsType())} ); - pair.fields.push_back( {"second", translate_type(get_template_argument(type, 1).getAsType())} ); + pair.fields.push_back( {"second", translate_type(get_template_argument(type, 1).getAsType())} ); add_type(get_template_argument(type).getAsType()); add_type(get_template_argument(type, 1).getAsType()); _abi.structs.insert(pair); - } + } void add_map(const clang::QualType& type) { for (int i = 0; i < 2; ++i) { @@ -149,7 +157,7 @@ namespace eosio { namespace cdt { std::string name = get_type(type); kv.name = name.substr(0, name.length() - 2); kv.fields.push_back( {"key", translate_type(get_template_argument(type).getAsType())} ); - kv.fields.push_back( {"value", translate_type(get_template_argument(type, 1).getAsType())} ); + kv.fields.push_back( {"value", translate_type(get_template_argument(type, 1).getAsType())} ); add_type(get_template_argument(type).getAsType()); add_type(get_template_argument(type, 1).getAsType()); _abi.structs.insert(kv); @@ -243,7 +251,7 @@ namespace eosio { namespace cdt { var.types.push_back(translate_type(get_template_argument( t, i ).getAsType())); add_type(get_template_argument( t, i ).getAsType()); } - _abi.variants.insert(var); + _abi.variants.insert(var); } void add_type( const clang::QualType& t ) { @@ -277,7 +285,7 @@ namespace eosio { namespace cdt { std::stringstream ss; ss << "This file was generated with eosio-abigen."; ss << " DO NOT EDIT "; - return ss.str(); + return ss.str(); } ojson struct_to_json( const abi_struct& s ) { @@ -335,7 +343,14 @@ namespace eosio { namespace cdt { o["key_types"] = ojson::array(); return o; } - + + ojson action_result_to_json( const abi_action_result& result ) { + ojson o; + o["name"] = result.name; + o["result_type"] = result.type; + return o; + } + bool is_empty() { std::set set_of_tables; for ( auto t : ctables ) { @@ -360,11 +375,11 @@ namespace eosio { namespace cdt { ojson to_json() { ojson o; o["____comment"] = generate_json_comment(); - o["version"] = _abi.version; + o["version"] = _abi.version_string(); o["structs"] = ojson::array(); auto remove_suffix = [&]( std::string name ) { int i = name.length()-1; - for (; i >= 0; i--) + for (; i >= 0; i--) if ( name[i] != '[' && name[i] != ']' && name[i] != '?' && name[i] != '$' ) break; return name.substr(0,i+1); @@ -481,10 +496,16 @@ namespace eosio { namespace cdt { o["variants"].push_back(variant_to_json( v )); } o["abi_extensions"] = ojson::array(); + if (_abi.version_major == 1 && _abi.version_minor == 2) { + o["action_results"] = ojson::array(); + for ( auto ar : _abi.action_results ) { + o["action_results"].push_back(action_result_to_json( ar )); + } + } return o; } - private: + private: abi _abi; std::set tables; std::set ctables; diff --git a/tools/include/eosio/abimerge.hpp b/tools/include/eosio/abimerge.hpp index d5f650ce86..1198f66768 100644 --- a/tools/include/eosio/abimerge.hpp +++ b/tools/include/eosio/abimerge.hpp @@ -25,7 +25,7 @@ class ABIMerger { } ojson merge(ojson other) { ojson ret; - ret["____comment"] = abi["____comment"]; + ret["____comment"] = abi["____comment"]; ret["version"] = merge_version(other); ret["types"] = merge_types(other); ret["structs"] = merge_structs(other); @@ -33,6 +33,10 @@ class ABIMerger { ret["tables"] = merge_tables(other); ret["ricardian_clauses"] = merge_clauses(other); ret["variants"] = merge_variants(other); + std::string vers = abi["version"].as(); + if (std::stod(vers.substr(vers.size()-3))*10 >= 12) { + ret["action_results"] = merge_action_results(other); + } return ret; } private: @@ -99,13 +103,18 @@ class ABIMerger { a["key_names"] == b["key_names"] && a["key_types"] == b["key_types"]; } - + static bool clause_is_same(ojson a, ojson b) { return a["id"] == b["id"] && a["body"] == b["body"]; - } - - template + } + + static bool action_result_is_same(ojson a, ojson b) { + return a["name"] == b["name"] && + a["result_type"] == b["result_type"]; + } + + template void add_object(ojson& ret, ojson a, ojson b, std::string type, std::string id, F&& is_same_func) { for (auto obj_a : a[type].array_range()) { ret.push_back(obj_a); @@ -125,7 +134,7 @@ class ABIMerger { ret.push_back(obj_b); } } - + ojson merge_structs(ojson b) { ojson structs = ojson::array(); add_object(structs, abi, b, "structs", "name", struct_is_same); @@ -162,6 +171,12 @@ class ABIMerger { return cls; } + ojson merge_action_results(ojson b) { + ojson res = ojson::array(); + add_object(res, abi, b, "action_results", "name", action_result_is_same); + return res; + } + ojson abi; }; #pragma GCC diagnostic pop diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index aedc6c0145..c2c2faeafd 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -241,6 +241,11 @@ namespace eosio { namespace cdt { ss << "uint32_t action_data_size();\n"; ss << "__attribute__((eosio_wasm_import))\n"; ss << "uint32_t read_action_data(void*, uint32_t);\n"; + const auto& return_ty = decl->getReturnType().getAsString(); + if (return_ty != "void") { + ss << "__attribute__((eosio_wasm_import))\n"; + ss << "void set_action_return_value(void*, size_t);\n"; + } ss << "__attribute__((weak, " << attr << "(\""; ss << get_str(decl); ss << ":"; @@ -267,13 +272,23 @@ namespace eosio { namespace cdt { ss << tn << " arg" << i << "; ds >> arg" << i << ";\n"; i++; } - ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{r},eosio::name{c},ds}." << decl->getNameAsString() << "("; - for (int i=0; i < decl->parameters().size(); i++) { - ss << "arg" << i; - if (i < decl->parameters().size()-1) - ss << ", "; + const auto& call_action = [&]() { + ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{r},eosio::name{c},ds}." << decl->getNameAsString() << "("; + for (int i=0; i < decl->parameters().size(); i++) { + ss << "arg" << i; + if (i < decl->parameters().size()-1) + ss << ", "; + } + ss << ");\n"; + }; + if (return_ty != "void") { + ss << return_ty << " result = "; + } + call_action(); + if (return_ty != "void") { + ss << "const auto& packed_result = eosio::pack(result);\n"; + ss << "set_action_return_value((void*)packed_result.data(), packed_result.size());\n"; } - ss << ");"; ss << "}}\n"; rewriter.InsertTextAfter(ci->getSourceManager().getLocForEndOfFile(main_fid), ss.str()); @@ -344,34 +359,6 @@ namespace eosio { namespace cdt { } return true; } - - /* - virtual bool VisitRecordDecl(RecordDecl* decl) { - static std::set _action_set; //used for validations - std::string rec_name = decl->getQualifiedNameAsString(); - cg.records.emplace(rec_name, decl); - return true; - } - virtual bool VisitCallExpr(CallExpr* expr) { - if (auto callee = expr->getDirectCallee()) { - if (callee->getNumParams() == 2) { - if (is_datastream(callee->getParamDecl(0)->getOriginalType())) { - cg.datastream_uses.insert(get_base_type(callee->getParamDecl(1)->getOriginalType())); - } - } - } - return true; - } - virtual bool VisitCXXRecordDecl(CXXRecordDecl* decl) { - std::string rec_name = decl->getQualifiedNameAsString(); - if (decl->isEosioAction()) { - rec_name = generation_utils::get_action_name(decl); - cg.actions.insert(rec_name); - } - cg.cxx_records.emplace(rec_name, decl); - return true; - } - */ }; class eosio_codegen_consumer : public ASTConsumer { @@ -397,7 +384,7 @@ namespace eosio { namespace cdt { visitor->TraverseDecl(Context.getTranslationUnitDecl()); for (auto ad : visitor->action_decls) visitor->create_action_dispatch(ad); - + for (auto nd : visitor->notify_decls) visitor->create_notify_dispatch(nd); diff --git a/tools/toolchain-tester/tests.py b/tools/toolchain-tester/tests.py index 6f5a2e2c73..d2734ff96f 100644 --- a/tools/toolchain-tester/tests.py +++ b/tools/toolchain-tester/tests.py @@ -97,8 +97,12 @@ def handle_expecteds(self, res: subprocess.CompletedProcess): failing_test=self, ) - if expected.get("abi"): - expected_abi = expected["abi"] + if expected.get("abi") or expected.get("abi-file"): + if expected.get("abi"): + expected_abi = expected["abi"] + else: + expected_abi_file = open(expected["abi-file"]) + expected_abi = expected_abi_file.read() with open(f"{self._name}.abi") as f: actual_abi = f.read() From c87a6d49aefc768f8dcae2d5141c273110260b09 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 11 Feb 2020 15:25:46 -0500 Subject: [PATCH 216/659] update pipeline to point to proper version of eos --- pipeline.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipeline.jsonc b/pipeline.jsonc index 508acc722c..5a5bbecdf6 100644 --- a/pipeline.jsonc +++ b/pipeline.jsonc @@ -4,7 +4,7 @@ "pipeline-branch": "master", "dependencies": // dependencies to pull for cdt integration tests, by branch, tag, or commit hash { - "eosio": "release/1.7.x" + "eosio": "develop" } } -} \ No newline at end of file +} From 85147f9a24d52ddd9a978c6927fd75a9a396e60f Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 11 Feb 2020 15:27:45 -0500 Subject: [PATCH 217/659] add back capi test --- tests/integration/capi_tests.cpp | 6 ++++++ tests/unit/test_contracts/capi/action.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/integration/capi_tests.cpp b/tests/integration/capi_tests.cpp index 632042352b..95d904703c 100644 --- a/tests/integration/capi_tests.cpp +++ b/tests/integration/capi_tests.cpp @@ -21,6 +21,12 @@ BOOST_AUTO_TEST_SUITE(capi_tests) BOOST_FIXTURE_TEST_CASE( capi_tests, tester ) try { create_accounts( { N(test) } ); produce_block(); + + const auto& pfm = control->get_protocol_feature_manager(); + + auto d = pfm.get_builtin_digest(builtin_protocol_feature_t::action_return_value) + schedule_protocol_features( {*d} ); + set_code( N(test), contracts::capi_tests_wasm() ); set_abi( N(test), contracts::capi_tests_abi().data() ); produce_blocks(); diff --git a/tests/unit/test_contracts/capi/action.c b/tests/unit/test_contracts/capi/action.c index 956510a44d..63824f2bff 100644 --- a/tests/unit/test_contracts/capi/action.c +++ b/tests/unit/test_contracts/capi/action.c @@ -13,5 +13,5 @@ void test_action( void ) { send_context_free_inline(NULL, 0); publication_time(); current_receiver(); - //set_action_return_value(NULL, 0); + set_action_return_value(NULL, 0); } From 0d6716aaa7ed8dfce6047842e708f9e3f53e2f84 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 11 Feb 2020 15:35:57 -0500 Subject: [PATCH 218/659] revert commented out code --- tools/cc/eosio-cpp.cpp.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index fb1d6bf262..cedc25d0b6 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -215,10 +215,10 @@ int main(int argc, const char **argv) { new_opts.insert(new_opts.begin(), "-xc++"); if (!eosio::cdt::environment::exec_subprogram("clang-7", new_opts)) { - //llvm::sys::fs::remove(tmp_file); + llvm::sys::fs::remove(tmp_file); return -1; } - //llvm::sys::fs::remove(tmp_file); + llvm::sys::fs::remove(tmp_file); } } catch (std::runtime_error& err) { llvm::errs() << err.what() << '\n'; From e983ed1c30b6dcd385d7f7b21ffe85fa09c70bd8 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Tue, 11 Feb 2020 19:16:37 -0500 Subject: [PATCH 219/659] finishing up changes --- modules/InstallCDT.cmake | 1 - tests/integration/action_results_test.cpp | 40 ++++------------------- tests/integration/capi_tests.cpp | 5 --- tools/toolchain-tester/tests.py | 1 + 4 files changed, 8 insertions(+), 39 deletions(-) diff --git a/modules/InstallCDT.cmake b/modules/InstallCDT.cmake index 36ec86f0a0..a762d4d71f 100644 --- a/modules/InstallCDT.cmake +++ b/modules/InstallCDT.cmake @@ -72,7 +72,6 @@ eosio_tool_install_and_symlink(eosio-wasm2wast eosio-wasm2wast) eosio_tool_install_and_symlink(eosio-cc eosio-cc) eosio_tool_install_and_symlink(eosio-cpp eosio-cpp) eosio_tool_install_and_symlink(eosio-ld eosio-ld) -eosio_tool_install_and_symlink(eosio-abigen eosio-abigen) eosio_tool_install_and_symlink(eosio-abidiff eosio-abidiff) eosio_tool_install_and_symlink(eosio-init eosio-init) diff --git a/tests/integration/action_results_test.cpp b/tests/integration/action_results_test.cpp index 4886b9bbda..3b9023bcb9 100644 --- a/tests/integration/action_results_test.cpp +++ b/tests/integration/action_results_test.cpp @@ -22,45 +22,19 @@ BOOST_FIXTURE_TEST_CASE( action_results_tests, tester ) try { create_accounts( { N(test) } ); produce_block(); - const auto& pfm = control->get_protocol_feature_manager(); - set_code( N(test), contracts::action_results_test_wasm() ); set_abi( N(test), contracts::action_results_test_abi().data() ); - auto d = pfm.get_builtin_digest(builtin_protocol_feature_t::action_return_value) - schedule_protocol_features( {*d} ); - - produce_blocks(); - const auto& trace = push_action(N(test), N(action1), N(test), mvo()); - - /* - BOOST_CHECK_THROW(push_action(N(test), N(test1), N(test), mvo()("nm", "notbucky")), - fc::exception); - - push_action(N(test), N(test2), N(test), - mvo() - ("arg0", 33) - ("arg1", "some string")); - BOOST_CHECK_THROW(push_action(N(test), N(test2), N(test), mvo() ("arg0", 30)("arg1", "some string")), fc::exception); - BOOST_CHECK_THROW(push_action(N(test), N(test2), N(test), mvo() ("arg0", 33)("arg1", "not some string")), fc::exception); - - set_abi( N(test), contracts::simple_wrong_abi().data() ); - produce_blocks(); - - BOOST_CHECK_THROW(push_action(N(test), N(test3), N(test), mvo() ("arg0", 33) ("arg1", "some string")), fc::exception); - set_abi( N(test), contracts::simple_abi().data() ); produce_blocks(); + auto trace = push_action(N(test), N(action1), N(test), mvo()); + // need to fix this test after Kevin fixes action_return + wdump((trace)); - push_action(N(test), N(test4), N(test), mvo() ("to", "someone")); - push_action(N(test), N(test5), N(test), mvo() ("to", "someone")); - push_action(N(test), N(testa), N(test), mvo() ("to", "someone")); - BOOST_CHECK_THROW(push_action(N(test), N(testb), N(test), mvo() ("to", "someone")), fc::exception); + trace = push_action(N(test), N(action2), N(test), mvo()); + wdump((trace)); - // test that the pre_dispatch will short circuit dispatching if false - push_action(N(test), N(testc), N(test), mvo() ("nm", "bucky")); - BOOST_CHECK_THROW(push_action(N(test), N(testc), N(test), mvo() ("nm", "someone")), fc::exception); - push_action(N(test), N(testc), N(test), mvo() ("nm", "quit")); - */ + trace = push_action(N(test), N(action3), N(test), mvo()); + wdump((trace)); } FC_LOG_AND_RETHROW() diff --git a/tests/integration/capi_tests.cpp b/tests/integration/capi_tests.cpp index 95d904703c..f33330682b 100644 --- a/tests/integration/capi_tests.cpp +++ b/tests/integration/capi_tests.cpp @@ -22,11 +22,6 @@ BOOST_FIXTURE_TEST_CASE( capi_tests, tester ) try { create_accounts( { N(test) } ); produce_block(); - const auto& pfm = control->get_protocol_feature_manager(); - - auto d = pfm.get_builtin_digest(builtin_protocol_feature_t::action_return_value) - schedule_protocol_features( {*d} ); - set_code( N(test), contracts::capi_tests_wasm() ); set_abi( N(test), contracts::capi_tests_abi().data() ); produce_blocks(); diff --git a/tools/toolchain-tester/tests.py b/tools/toolchain-tester/tests.py index d2734ff96f..a1a4873187 100644 --- a/tools/toolchain-tester/tests.py +++ b/tools/toolchain-tester/tests.py @@ -103,6 +103,7 @@ def handle_expecteds(self, res: subprocess.CompletedProcess): else: expected_abi_file = open(expected["abi-file"]) expected_abi = expected_abi_file.read() + expected_abi_file.close() with open(f"{self._name}.abi") as f: actual_abi = f.read() From 7d2efbb72d003ad4f1562496169e40a5d843ac76 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Wed, 12 Feb 2020 10:23:47 -0500 Subject: [PATCH 220/659] generate symlinks for missing tools and remove abigen --- scripts/generate_tarball.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/generate_tarball.sh b/scripts/generate_tarball.sh index cd4f25057b..2a9a56120f 100644 --- a/scripts/generate_tarball.sh +++ b/scripts/generate_tarball.sh @@ -4,7 +4,7 @@ NAME=$1 CDT_PREFIX=${PREFIX}/${SUBPREFIX} mkdir -p ${PREFIX}/bin/ mkdir -p ${PREFIX}/lib/cmake/${PROJECT} -mkdir -p ${CDT_PREFIX}/bin +mkdir -p ${CDT_PREFIX}/bin mkdir -p ${CDT_PREFIX}/include mkdir -p ${CDT_PREFIX}/lib/cmake/${PROJECT} mkdir -p ${CDT_PREFIX}/cmake @@ -13,7 +13,7 @@ mkdir -p ${CDT_PREFIX}/licenses #echo "${PREFIX} ** ${SUBPREFIX} ** ${CDT_PREFIX}" -# install binaries +# install binaries cp -R ${BUILD_DIR}/bin/* ${CDT_PREFIX}/bin || exit 1 cp -R ${BUILD_DIR}/licenses/* ${CDT_PREFIX}/licenses || exit 1 @@ -50,10 +50,16 @@ create_symlink eosio-cpp eosio-cpp create_symlink eosio-ld eosio-ld create_symlink eosio-pp eosio-pp create_symlink eosio-init eosio-init -create_symlink eosio-abigen eosio-abigen create_symlink eosio-wasm2wast eosio-wasm2wast create_symlink eosio-wast2wasm eosio-wast2wasm create_symlink eosio-ar eosio-ar +create_symlink eosio-abidiff eosio-abidiff +create_symlink eosio-nm eosio-nm +create_symlink eosio-objcopy eosio-objcopy +create_symlink eosio-objdump eosio-objdump +create_symlink eosio-ranlib eosio-ranlib +create_symlink eosio-readelf eosio-readelf +create_symlink eosio-strip eosio-strip echo "Generating Tarball $NAME.tar.gz..." tar -cvzf $NAME.tar.gz ./${PREFIX}/* || exit 1 From 2c37881904f20ea4b827089252feed35758f8570 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Wed, 12 Feb 2020 15:56:33 -0500 Subject: [PATCH 221/659] Update abigen.hpp --- tools/include/eosio/abigen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 04f7b3b0e9..96a28146b4 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -496,7 +496,7 @@ namespace eosio { namespace cdt { o["variants"].push_back(variant_to_json( v )); } o["abi_extensions"] = ojson::array(); - if (_abi.version_major == 1 && _abi.version_minor == 2) { + if (_abi.version_major == 1 && _abi.version_minor >= 2) { o["action_results"] = ojson::array(); for ( auto ar : _abi.action_results ) { o["action_results"].push_back(action_result_to_json( ar )); From d2bc6aa20167d1f8c46b3ae55fa9bba03ffafc98 Mon Sep 17 00:00:00 2001 From: smlu Date: Thu, 13 Feb 2020 10:36:18 +0100 Subject: [PATCH 222/659] Fix (eosio::string): Add inline specifier to friend functions --- libraries/eosiolib/core/eosio/string.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/eosiolib/core/eosio/string.hpp b/libraries/eosiolib/core/eosio/string.hpp index cbb5c8e5c2..d92686f8bd 100644 --- a/libraries/eosiolib/core/eosio/string.hpp +++ b/libraries/eosiolib/core/eosio/string.hpp @@ -424,7 +424,7 @@ namespace eosio { } }; - bool operator< (const string& lhs, const string& rhs) { + inline bool operator< (const string& lhs, const string& rhs) { const char* beg_lhs{lhs.cbegin()}; const char* end_lhs{lhs.cend()}; const char* beg_rhs{rhs.cbegin()}; const char* end_rhs{rhs.cend()}; @@ -438,27 +438,27 @@ namespace eosio { return beg_lhs == end_lhs && beg_rhs != end_rhs; } - bool operator> (const string& lhs, const string& rhs) { + inline bool operator> (const string& lhs, const string& rhs) { return (rhs < lhs); } - bool operator<=(const string& lhs, const string& rhs) { + inline bool operator<=(const string& lhs, const string& rhs) { return !(rhs < lhs); } - bool operator>=(const string& lhs, const string& rhs) { + inline bool operator>=(const string& lhs, const string& rhs) { return !(lhs < rhs); } - bool operator==(const string& lhs, const string& rhs) { + inline bool operator==(const string& lhs, const string& rhs) { return !(lhs < rhs) && !(rhs < lhs); } - bool operator!=(const string& lhs, const string& rhs) { + inline bool operator!=(const string& lhs, const string& rhs) { return !(lhs == rhs); } - string operator+(const string& lhs, const string& rhs) { + inline string operator+(const string& lhs, const string& rhs) { string res{lhs}; res += rhs; return res; From f0344e7fa1120b2b13884c5708d52cf2d8d86842 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Fri, 14 Feb 2020 12:27:04 -0500 Subject: [PATCH 223/659] Update time.hpp --- libraries/eosiolib/core/eosio/time.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index 1c0e1b9a94..3cea71733c 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -61,7 +61,7 @@ namespace eosio { const microseconds& time_since_epoch()const { return elapsed; } uint32_t sec_since_epoch()const { return uint32_t(elapsed.count() / 1000000); } - static time_point from_iso_string(std::string date_str) { + static time_point from_iso_string(const std::string& date_str) { std::tm tm; check(strptime(date_str.c_str(), "%Y-%m-%dT%H:%M:%S", &tm), "date parsing failed"); @@ -118,7 +118,7 @@ namespace eosio { static time_point_sec maximum() { return time_point_sec(0xffffffff); } static time_point_sec min() { return time_point_sec(0); } - static time_point_sec from_iso_string(std::string date_str) { + static time_point_sec from_iso_string(const std::string& date_str) { auto time_p = time_point::from_iso_string(date_str); return time_point_sec{ time_p }; } @@ -201,7 +201,7 @@ namespace eosio { return time_point(milliseconds(msec)); } - static block_timestamp from_iso_string(std::string date_str) { + static block_timestamp from_iso_string(const std::string& date_str) { auto time_p = time_point::from_iso_string(date_str); return block_timestamp{ time_p }; } From a8217c728cb834fc7eef82c6efd46a446d4737fa Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 18 Feb 2020 09:41:43 -0500 Subject: [PATCH 224/659] Address PR feedback --- libraries/eosiolib/contracts/eosio/key_value.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 01d8ba8782..7be801399f 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -895,6 +895,7 @@ class kv_table { datastream ds((char*)buffer, size); ds >> idx; + eosio::check(idx==unsigned_int(0), "there was an error deserializing this value."); ds >> value; } @@ -911,8 +912,8 @@ class kv_table { } template - static size_t get_size(std::variant&& value) { - auto size = pack_size(std::forward>(value)); + static size_t get_size(const std::variant& value) { + auto size = pack_size(value); return size; } }; From 26de2175574194c24bbc6585a10e56d2a0bb5ca5 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 18 Feb 2020 10:46:59 -0500 Subject: [PATCH 225/659] Minor cleanup from PR feedback --- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 7be801399f..90473d40f8 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -906,8 +906,8 @@ class kv_table { } template - static size_t get_size(V&& value) { - auto size = pack_size(std::forward(value)); + static size_t get_size(const V& value) { + auto size = pack_size(value); return size + 1; } From de570363292408bd73211482b442a500d4c71d0e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 19 Feb 2020 16:49:14 -0500 Subject: [PATCH 226/659] Update tests to use Release instead of Debug. This fixes an issue where tests that are fairly small can have generated wasms that exceed our default function limit. --- modules/TestsExternalProject.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/TestsExternalProject.txt b/modules/TestsExternalProject.txt index 9efdf7906e..365b374c80 100644 --- a/modules/TestsExternalProject.txt +++ b/modules/TestsExternalProject.txt @@ -6,7 +6,7 @@ ExternalProject_Add( EosioWasmTests SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/unit" BINARY_DIR "${CMAKE_BINARY_DIR}/tests/unit" - CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DCMAKE_BUILD_TYPE=Release -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" From 728cefcea466e30abace142f18c54c77692c6e35 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 20 Feb 2020 15:41:41 +0200 Subject: [PATCH 227/659] move guide about ABI files from welcome to eosio.cdt --- .../08_abi/00_understanding-abi-files.md | 507 ++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100644 docs/05_best-practices/08_abi/00_understanding-abi-files.md diff --git a/docs/05_best-practices/08_abi/00_understanding-abi-files.md b/docs/05_best-practices/08_abi/00_understanding-abi-files.md new file mode 100644 index 0000000000..955846bdee --- /dev/null +++ b/docs/05_best-practices/08_abi/00_understanding-abi-files.md @@ -0,0 +1,507 @@ +--- +content_title: "Understanding ABI Files" +link_text: "Understanding ABI Files" +--- +## Introduction +Previously you deployed the `eosio.token` contract using the provided ABI file. This tutorial will overview how the ABI file correlates to the `eosio.token` contract. + +ABI files can be generated using the `eosio-cpp` utility provided by `eosio.cdt`. However, there are several situations that may cause ABI's generation to malfunction or fail altogether. Advanced C++ patterns can trip it up and custom types can sometimes cause issues for ABI generation. For this reason, it's **imperative** you understand how ABI files work, so you can debug and fix if and when necessary. +## What is an ABI? +The Application Binary Interface (ABI) is a JSON-based description on how to convert user actions between their JSON and Binary representations. The ABI also describes how to convert the database state to/from JSON. Once you have described your contract via an ABI then developers and users will be able to interact with your contract seamlessly via JSON. + +[[warning | Security Note]] +| ABI can be bypassed when executing transactions. Messages and actions passed to a contract do not have to conform to the ABI. The ABI is a guide, not a gatekeeper. + +## Create an ABI File +Start with an empty ABI, name it `eosio.token.abi` + +```text +{ + "version": "eosio::abi/1.0", + "types": [], + "structs": [], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "abi_extensions": [], + "___comment" : "" +} +``` + +## Types +An ABI enables any client or interface to interpret and even generate a GUI for your contract. For this to work consistently, describe the custom types that are used as a parameter in any public action or struct that needs to be described in the ABI. + +[[info | Built-in Types]] +| EOSIO implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with EOSIO's built-ins, they are defined [here](https://github.com/EOSIO/eos/blob/master/libraries/chain/abi_serializer.cpp#L59-L100) + + +```json +{ + "new_type_name": "name", + "type": "name" +} +``` +The ABI now looks like this: + +```json +{ + "version": "eosio::abi/1.1", + "types": [{ + "new_type_name": "name", + "type": "name" + }], + "structs": [], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "abi_extensions": [] +} +``` + +## Structs +Structs that are exposed to the ABI also need to be described. By looking at eosio.token.hpp, it can be quickly determined which structs are utilized by public actions. This is particularly important for the next step. + +A struct's object definition in JSON looks like the following: + +```json +{ + "name": "issue", //The name + "base": "", //Inheritance, parent struct + "fields": [] //Array of field objects describing the struct's fields. +} +``` +## Fields + +```json +{ + "name":"", // The field's name + "type":"" // The field's type +} +``` +In the `eosio.token` contract, there's a number of structs that require definition. Please note, not all of the structs are explicitly defined, some correspond to an actions' parameters. Here's a list of structs that require an ABI description for the `eosio.token` contract: + +## Implicit Structs + +The following structs are implicit in that a struct was never explicitly defined in the contract. Looking at the [create](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#create) action, you'll find two parameters, `issuer` of type `name ` and `maximum_supply` of type `asset`. For brevity this tutorial won't break down every struct, but applying the same logic, you will end up with the following: + +### [create](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#create) + +```json +{ + "name": "create", + "base": "", + "fields": [ + { + "name":"issuer", + "type":"name" + }, + { + "name":"maximum_supply", + "type":"asset" + } + ] +} +``` +### [issue](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#issue) + +```json +{ + "name": "issue", + "base": "", + "fields": [ + { + "name":"to", + "type":"name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [retire](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#retire) + +```json +{ + "name": "retire", + "base": "", + "fields": [ + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [transfer](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#transfer) + +```json +{ + "name": "transfer", + "base": "", + "fields": [ + { + "name":"from", + "type":"name" + }, + { + "name":"to", + "type":"name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] +} +``` +### [close](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#close) + +```json +{ + "name": "close", + "base": "", + "fields": [ + { + "name":"owner", + "type":"name" + }, + { + "name":"symbol", + "type":"symbol" + } + ] + } +``` +## Explicit Structs +These structs are explicitly defined, as they are a requirement to instantiate a multi-index table. Describing them is no different than defining the implicit structs as demonstrated above. + +### [account](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120) + +```json +{ + "name": "account", + "base": "", + "fields": [ + { + "name":"balance", + "type":"asset" + } + ] +} +``` + +## Actions +An action's JSON object definition looks like the following: + +```json +{ + "name": "transfer", //The name of the action as defined in the contract + "type": "transfer", //The name of the implicit struct as described in the ABI + "ricardian_contract": "" //An optional ricardian clause to associate to this action describing its intended functionality. +} +``` +Describe the actions of the `eosio.token` contract by aggregating all the public functions described in the `eosio.token` contract's [header file](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp). + +Then describe each action's *type* according to its previously described struct. In most situations, the function name and the struct name will be equal, but are not required to be equal. + +Below is a list of actions that link to their source code with example JSON provided for how each action would be described. + +## [create](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L35-L37) + +```json +{ + "name": "create", + "type": "create", + "ricardian_contract": "" +} +``` +## [issue](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L45-L46) + +```json +{ + "name": "issue", + "type": "issue", + "ricardian_contract": "" +} +``` +## [retire](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L55-L56) + +```json +{ + "name": "retire", + "type": "retire", + "ricardian_contract": "" +} +``` +## [transfer](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L67-L71) + +```json +{ + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" +} +``` +## [close](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L96-L97) + +```json +{ + "name": "close", + "type": "close", + "ricardian_contract": "" +} +``` + +## Tables +Describe the tables. Here's a table's JSON object definition: + +```json +{ + "name": "", //The name of the table, determined during instantiation. + "type": "", //The table's corresponding struct + "index_type": "", //The type of primary index of this table + "key_names" : [], //An array of key names, length must equal length of key_types member + "key_types" : [] //An array of key types that correspond to key names array member, length of array must equal length of key names array. +} +``` +The eosio.token contract instantiates two tables, [accounts](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L134) and [stat](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L135). + +The `accounts` table is an i64 index, based on the [`account` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120-L124), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L123) + +Here's how the accounts table would be described in the ABI + +```json +{ + "name": "accounts", + "type": "account", // Corresponds to previously defined struct + "index_type": "i64", + "key_names" : ["primary_key"], + "key_types" : ["uint64"] +} +``` +The `stat` table is an i64 index, based on the [`currency_stats` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L126-L132), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L131) + +Here's how the stat table would be described in the ABI + +```json +{ + "name": "stat", + "type": "currency_stats", + "index_type": "i64", + "key_names" : ["primary_key"], + "key_types" : ["uint64"] +} +``` +You'll notice the above tables have the same "key name." Naming your keys similar names is symbolic in that it can potentially suggest a subjective relationship. As with this implementation, implying that any given value can be used to query different tables. + +## Putting it all Together +Finally, an ABI file that accurately describes the `eosio.token` contract. + +```json +{ + "version": "eosio::abi/1.1", + "types": [ + { + "new_type_name": "name", + "type": "name" + } + ], + "structs": [ + { + "name": "create", + "base": "", + "fields": [ + { + "name":"issuer", + "type":"name" + }, + { + "name":"maximum_supply", + "type":"asset" + } + ] + }, + { + "name": "issue", + "base": "", + "fields": [ + { + "name":"to", + "type":"name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "retire", + "base": "", + "fields": [ + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "close", + "base": "", + "fields": [ + { + "name":"owner", + "type":"name" + }, + { + "name":"symbol", + "type":"symbol" + } + ] + }, + { + "name": "transfer", + "base": "", + "fields": [ + { + "name":"from", + "type":"name" + }, + { + "name":"to", + "type":"name" + }, + { + "name":"quantity", + "type":"asset" + }, + { + "name":"memo", + "type":"string" + } + ] + }, + { + "name": "account", + "base": "", + "fields": [ + { + "name":"balance", + "type":"asset" + } + ] + }, + { + "name": "currency_stats", + "base": "", + "fields": [ + { + "name":"supply", + "type":"asset" + }, + { + "name":"max_supply", + "type":"asset" + }, + { + "name":"issuer", + "type":"name" + } + ] + } + ], + "actions": [ + { + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" + }, + { + "name": "issue", + "type": "issue", + "ricardian_contract": "" + }, + { + "name": "retire", + "type": "retire", + "ricardian_contract": "" + }, + { + "name": "create", + "type": "create", + "ricardian_contract": "" + }, + { + "name": "close", + "type": "close", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "accounts", + "type": "account", + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] + }, + { + "name": "stat", + "type": "currency_stats", + "index_type": "i64", + "key_names" : ["currency"], + "key_types" : ["uint64"] + } + ], + "ricardian_clauses": [], + "abi_extensions": [] +} +``` + +## Cases not Covered by Token Contract +## Vectors +When describing a vector in your ABI file, simply append the type with `[]`, so if you need to describe a vector of permission levels, you would describe it like so: `permission_level[]` + +## Struct Base +It's a rarely used property worth mentioning. You can use **base** ABI struct property to reference another struct for inheritance, as long as that struct is also described in the same ABI file. Base will do nothing or potentially throw an error if your smart contract logic does not support inheritance. + +You can see an example of base in use in the system contract [source code](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/include/eosio.system/eosio.system.hpp#L46) and [ABI](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/abi/eosio.system.abi#L262) +## Extra ABI Properties Not Covered Here +A few properties of the ABI specification were skipped here for brevity, however, there is a pending ABI specification that will outline every property of the ABI in its entirety. + +## Ricardian Clauses +Ricardian clauses describe the intended outcome of a particular actions. It may also be utilized to establish terms between the sender and the contract. + +## ABI Extensions +A generic "future proofing" layer that allows old clients to skip the parsing of "chunks" of extension data. For now, this property is unused. In the future each extension would have its own "chunk" in that vector so that older clients skip it and newer clients that understand how to interpret it. +## Maintenance +Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases failure to update your ABI file will not produce any error. +## Troubleshooting +## Table returns no rows + +Check that your table is accurately described in the ABI file. For example, If you use `cleos` to add a table on a contract with a malformed ABI definition and then get rows from that table, you will receive an empty result. `cleos` will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its ABI. + +## What's Next? +- [Data Persistence](./04_data-persistence.md): Learn how data persistence works on EOSIO by writing a simple smart contract that functions as an address book. From 456aecb9986b0cad44ead44577724edb18c8fe86 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 20 Feb 2020 15:48:17 +0200 Subject: [PATCH 228/659] make necessary changes to fit in the current repo and documentation context --- .../08_abi/00_understanding-abi-files.md | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/05_best-practices/08_abi/00_understanding-abi-files.md b/docs/05_best-practices/08_abi/00_understanding-abi-files.md index 955846bdee..71356d0ff1 100644 --- a/docs/05_best-practices/08_abi/00_understanding-abi-files.md +++ b/docs/05_best-practices/08_abi/00_understanding-abi-files.md @@ -3,17 +3,19 @@ content_title: "Understanding ABI Files" link_text: "Understanding ABI Files" --- ## Introduction -Previously you deployed the `eosio.token` contract using the provided ABI file. This tutorial will overview how the ABI file correlates to the `eosio.token` contract. ABI files can be generated using the `eosio-cpp` utility provided by `eosio.cdt`. However, there are several situations that may cause ABI's generation to malfunction or fail altogether. Advanced C++ patterns can trip it up and custom types can sometimes cause issues for ABI generation. For this reason, it's **imperative** you understand how ABI files work, so you can debug and fix if and when necessary. -## What is an ABI? + +## What is an ABI + The Application Binary Interface (ABI) is a JSON-based description on how to convert user actions between their JSON and Binary representations. The ABI also describes how to convert the database state to/from JSON. Once you have described your contract via an ABI then developers and users will be able to interact with your contract seamlessly via JSON. [[warning | Security Note]] | ABI can be bypassed when executing transactions. Messages and actions passed to a contract do not have to conform to the ABI. The ABI is a guide, not a gatekeeper. ## Create an ABI File -Start with an empty ABI, name it `eosio.token.abi` + +Start with an empty ABI, for exemplification we will work based on the `eosio.token` therefore name it `eosio.token.abi`: ```text { @@ -29,6 +31,7 @@ Start with an empty ABI, name it `eosio.token.abi` ``` ## Types + An ABI enables any client or interface to interpret and even generate a GUI for your contract. For this to work consistently, describe the custom types that are used as a parameter in any public action or struct that needs to be described in the ABI. [[info | Built-in Types]] @@ -59,6 +62,7 @@ The ABI now looks like this: ``` ## Structs + Structs that are exposed to the ABI also need to be described. By looking at eosio.token.hpp, it can be quickly determined which structs are utilized by public actions. This is particularly important for the next step. A struct's object definition in JSON looks like the following: @@ -142,6 +146,7 @@ The following structs are implicit in that a struct was never explicitly defined ] } ``` + ### [transfer](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#transfer) ```json @@ -168,6 +173,7 @@ The following structs are implicit in that a struct was never explicitly defined ] } ``` + ### [close](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#close) ```json @@ -186,6 +192,7 @@ The following structs are implicit in that a struct was never explicitly defined ] } ``` + ## Explicit Structs These structs are explicitly defined, as they are a requirement to instantiate a multi-index table. Describing them is no different than defining the implicit structs as demonstrated above. @@ -205,6 +212,7 @@ These structs are explicitly defined, as they are a requirement to instantiate a ``` ## Actions + An action's JSON object definition looks like the following: ```json @@ -229,6 +237,7 @@ Below is a list of actions that link to their source code with example JSON prov "ricardian_contract": "" } ``` + ## [issue](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L45-L46) ```json @@ -238,6 +247,7 @@ Below is a list of actions that link to their source code with example JSON prov "ricardian_contract": "" } ``` + ## [retire](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L55-L56) ```json @@ -247,6 +257,7 @@ Below is a list of actions that link to their source code with example JSON prov "ricardian_contract": "" } ``` + ## [transfer](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L67-L71) ```json @@ -256,6 +267,7 @@ Below is a list of actions that link to their source code with example JSON prov "ricardian_contract": "" } ``` + ## [close](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L96-L97) ```json @@ -267,6 +279,7 @@ Below is a list of actions that link to their source code with example JSON prov ``` ## Tables + Describe the tables. Here's a table's JSON object definition: ```json @@ -278,6 +291,7 @@ Describe the tables. Here's a table's JSON object definition: "key_types" : [] //An array of key types that correspond to key names array member, length of array must equal length of key names array. } ``` + The eosio.token contract instantiates two tables, [accounts](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L134) and [stat](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L135). The `accounts` table is an i64 index, based on the [`account` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120-L124), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L123) @@ -293,6 +307,7 @@ Here's how the accounts table would be described in the ABI "key_types" : ["uint64"] } ``` + The `stat` table is an i64 index, based on the [`currency_stats` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L126-L132), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L131) Here's how the stat table would be described in the ABI @@ -309,6 +324,7 @@ Here's how the stat table would be described in the ABI You'll notice the above tables have the same "key name." Naming your keys similar names is symbolic in that it can potentially suggest a subjective relationship. As with this implementation, implying that any given value can be used to query different tables. ## Putting it all Together + Finally, an ABI file that accurately describes the `eosio.token` contract. ```json @@ -481,27 +497,35 @@ Finally, an ABI file that accurately describes the `eosio.token` contract. ``` ## Cases not Covered by Token Contract + ## Vectors + When describing a vector in your ABI file, simply append the type with `[]`, so if you need to describe a vector of permission levels, you would describe it like so: `permission_level[]` ## Struct Base + It's a rarely used property worth mentioning. You can use **base** ABI struct property to reference another struct for inheritance, as long as that struct is also described in the same ABI file. Base will do nothing or potentially throw an error if your smart contract logic does not support inheritance. You can see an example of base in use in the system contract [source code](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/include/eosio.system/eosio.system.hpp#L46) and [ABI](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/abi/eosio.system.abi#L262) + ## Extra ABI Properties Not Covered Here + A few properties of the ABI specification were skipped here for brevity, however, there is a pending ABI specification that will outline every property of the ABI in its entirety. ## Ricardian Clauses + Ricardian clauses describe the intended outcome of a particular actions. It may also be utilized to establish terms between the sender and the contract. ## ABI Extensions + A generic "future proofing" layer that allows old clients to skip the parsing of "chunks" of extension data. For now, this property is unused. In the future each extension would have its own "chunk" in that vector so that older clients skip it and newer clients that understand how to interpret it. + ## Maintenance + Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases failure to update your ABI file will not produce any error. + ## Troubleshooting -## Table returns no rows -Check that your table is accurately described in the ABI file. For example, If you use `cleos` to add a table on a contract with a malformed ABI definition and then get rows from that table, you will receive an empty result. `cleos` will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its ABI. +### Table returns no rows -## What's Next? -- [Data Persistence](./04_data-persistence.md): Learn how data persistence works on EOSIO by writing a simple smart contract that functions as an address book. +Check that your table is accurately described in the ABI file. For example, If you use `cleos` to add a table on a contract with a malformed ABI definition and then get rows from that table, you will receive an empty result. `cleos` will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its ABI. From 459cb4547e9d6bfc3d3cd4f0cd62bde4255af38f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 21 Feb 2020 10:24:32 -0500 Subject: [PATCH 229/659] Minor cleanup from PR feedback --- libraries/eosiolib/contracts/eosio/key_value.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 90473d40f8..52d2405201 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -402,7 +402,7 @@ class kv_table { iterator& operator=(iterator&& other) { contract_name = std::move(other.contract_name); - itr = std::exchange(other.itr, 0); + itr = std::exchange(other.itr, itr); itr_stat = std::move(other.itr_stat); idx = std::exchange(other.idx, nullptr); @@ -441,9 +441,7 @@ class kv_table { eosio::check(success, "failure getting primary key"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - auto copy_size = internal_use_do_not_use::kv_get_data(idx->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); - - eosio::check(copy_size != actual_value_size, "failure getting primary index data"); + internal_use_do_not_use::kv_get_data(idx->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); deserialize_buffer = pk_buffer; deserialize_size = actual_data_size; From 4b680389f231e580cfb99aec375c73af4a6f1cd7 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Fri, 21 Feb 2020 15:58:14 -0500 Subject: [PATCH 230/659] update to use const auto& instead of functions return_ty to not have to worry about fully qualified names --- tools/include/eosio/codegen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index c2c2faeafd..7b24f9a7a9 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -282,7 +282,7 @@ namespace eosio { namespace cdt { ss << ");\n"; }; if (return_ty != "void") { - ss << return_ty << " result = "; + ss << "const auto& result = "; } call_action(); if (return_ty != "void") { From f5d9a84f51c23cb49ba8e3c4f3255c72fdc15ce2 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 24 Feb 2020 10:06:15 -0500 Subject: [PATCH 231/659] Actions now recognizes when all jobs are skipped. --- .github/workflows/main.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index faa2f76485..ca779ca7f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,19 +2,10 @@ name: Pull Request on: [pull_request] jobs: - start-job: - name: Start Job - runs-on: ubuntu-latest - steps: - - name: Start Job. - run: echo "PR created. Builds will be triggered here for forked PRs or Buildkite for internal PRs." - - submodule_regression_check: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Submodule Regression Check runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e @@ -28,7 +19,6 @@ jobs: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Amazon_Linux 2 | Build runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e @@ -89,7 +79,6 @@ jobs: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: CentOS 7.7 | Build runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e @@ -150,7 +139,6 @@ jobs: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 16.04 | Build runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e @@ -211,7 +199,6 @@ jobs: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 18.04 | Build runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e @@ -272,7 +259,6 @@ jobs: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: MacOS 10.15 | Build runs-on: macos-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e From 47c6b5ab24840f82291dc9977ce7ccfb3372d33f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 3 Feb 2020 16:50:11 -0500 Subject: [PATCH 232/659] Add support for unique and non-unique indexes. --- .../eosiolib/contracts/eosio/key_value.hpp | 158 ++++++++++++++++-- tests/integration/kv_tests.cpp | 16 +- tests/integration/main.cpp | 1 + .../unit/test_contracts/kv_make_key_tests.cpp | 20 +-- .../kv_multiple_indices_tests.cpp | 108 +++++++----- 5 files changed, 231 insertions(+), 72 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 52d2405201..d650f43ed4 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -9,8 +9,9 @@ #include #include -#include +#include #include +#include #include #define EOSIO_CDT_KV_INDEXnullptr @@ -51,9 +52,15 @@ EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(value_class, index_name) -#define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ +#define EOSIO_CDT_CREATE_KV_NON_UNIQUE_INDEX(r, value_class, i, index_name) \ EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); +#define EOSIO_CDT_CREATE_KV_UNIQUE_INDEX(r, value_class, i, index_name) \ + kv_unique_index EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); + +#define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ + BOOST_PP_IF(i, EOSIO_CDT_CREATE_KV_NON_UNIQUE_INDEX, EOSIO_CDT_CREATE_KV_UNIQUE_INDEX)(r, value_class, i, index_name) + #define EOSIO_CDT_LIST_INDICES(value_class, ...) \ BOOST_PP_SEQ_FOR_EACH_I(EOSIO_CDT_CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) @@ -134,6 +141,9 @@ namespace eosio { */ struct key_type : std::string { using std::string::string; + + // TODO: Instead, get rid of implicit conversion and overload + operator + key_type(const std::string& s) : std::string(s.data(), s.size()) {} }; namespace detail { @@ -524,8 +534,6 @@ class kv_table { eosio::name table_name; eosio::name contract_name; - kv_table* tbl; - kv_index() = default; template @@ -642,7 +650,6 @@ class kv_table { } return it; - } /** @@ -698,13 +705,17 @@ class kv_table { return return_values; } + virtual bool is_unique() = 0; + + protected: key_type get_key(const T& inst) const { return key_function(inst); } + kv_table* tbl; + key_type prefix; private: friend kv_table; std::function key_function; - key_type prefix; void set_prefix() { prefix = make_prefix(table_name, name); @@ -713,6 +724,103 @@ class kv_table { using iterator = typename kv_index::iterator; + class kv_unique_index : public kv_index { + public: + kv_unique_index() = default; + + template + kv_unique_index(KF&& kf): kv_index{kf} {} + + template + kv_unique_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} + + /** + * Search for an existing object in a table by the index, using the given key. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced by the key param. + * + * @param key - The key to search for. + * @return An iterator to the found object OR the `end` iterator if the given key was not found. + */ + template + iterator find(K&& key) { + auto t_key = table_key(prefix, make_key(std::forward(key))); + + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + + auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); + + if (cmp != 0) { + internal_use_do_not_use::kv_it_destroy(itr); + return this->end(); + } + + return {contract_name, itr, static_cast(itr_stat), this}; + } + + /** + * Get the value for an existing object in a table by the index, using the given key. + * @ingroup keyvalue + * + * @tparam K - The type of the key. This will be auto-deduced by the key param. + * + * @param key - The key to search for. + * @return A std::optional of the value corresponding to the key. + */ + template + std::optional get(K&& key) { + uint32_t value_size; + std::optional ret_val; + + auto t_key = table_key(prefix, make_key(std::forward(key))); + + auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); + if (!success) { + return ret_val; + } + + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); + + datastream ds((char*)buffer, value_size); + + ret_val.emplace(); + ds >> *ret_val; + if (value_size > detail::max_stack_buffer_size) { + free(buffer); + } + return ret_val; + } + + bool is_unique() override { + return true; + } + + using kv_table::kv_index::tbl; + using kv_table::kv_index::contract_name; + using kv_table::kv_index::prefix; + }; + + class kv_non_unique_index : public kv_index { + public: + kv_non_unique_index() = default; + + template + kv_non_unique_index(KF&& kf): kv_index{kf} {} + + template + kv_non_unique_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} + + using kv_table::kv_index::tbl; + + bool is_unique() override { + return false; + } + }; + + /** * @ingroup keyvalue * @@ -720,7 +828,18 @@ class kv_table { * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. * A null_kv_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. */ - class null_kv_index : public kv_index {}; + class null_kv_index : public kv_index { + public: + template + null_kv_index(KF&& kf): kv_index{kf} {} + + template + null_kv_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} + + bool is_unique() override { + return false; + } + }; /** * Puts a value into the table. If the value already exists, it updates the existing entry. @@ -742,7 +861,14 @@ class kv_table { internal_use_do_not_use::kv_set(db_name, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); for (auto& idx : secondary_indices) { - auto st_key = table_key(make_prefix(table_name, idx->name), idx->get_key(value)); + key_type sk; + if (idx->is_unique()) { + sk = idx->get_key(value); + } else { + sk = key_type{idx->get_key(value) + primary_index->get_key(value)}; + } + + auto st_key = table_key(make_prefix(table_name, idx->name), sk); internal_use_do_not_use::kv_set(db_name, contract_name.value, st_key.data(), st_key.size(), t_key.data(), t_key.size()); } @@ -771,7 +897,15 @@ class kv_table { internal_use_do_not_use::kv_erase(db_name, contract_name.value, k.data(), k.size()); for (auto& idx : secondary_indices) { - auto skey = table_key(make_prefix(table_name, idx->name), idx->get_key(*primary_value)); + key_type sk; + + if (idx->is_unique()) { + sk = idx->get_key(*primary_value); + } else { + sk = idx->get_key(*primary_value) + make_key(key); + } + + auto skey = table_key(make_prefix(table_name, idx->name), sk); internal_use_do_not_use::kv_erase(db_name, contract_name.value, skey.data(), skey.size()); } } @@ -800,7 +934,9 @@ class kv_table { auto& primary = get<0>(*indices); - primary_index = &primary; + eosio::check(primary.is_unique(), "primary index should be kv_unique_index"); + + primary_index = (kv_unique_index*)&primary; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; @@ -844,7 +980,7 @@ class kv_table { uint64_t db_name; - kv_index* primary_index; + kv_unique_index* primary_index; std::vector secondary_indices; template diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 9e74916e42..0d28bf814a 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -115,9 +115,12 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), eosio_assert_message_exception, eosio_assert_message_is("All indices must be named if one is named.")); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr3), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("primary index should be kv_unique_index")); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { +BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { create_accounts( { N(kvtest) } ); produce_block(); set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); @@ -125,14 +128,10 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { produce_blocks(); push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(find), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(finderror), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Cannot read end iterator")); + push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { +BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { create_accounts( { N(kvtest) } ); produce_block(); set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); @@ -140,6 +139,7 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { produce_blocks(); push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(iteration), N(kvtest), {}); + push_action(N(kvtest), N(range), N(kvtest), {}); } FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/main.cpp b/tests/integration/main.cpp index f88e58a51d..5ee93e6599 100644 --- a/tests/integration/main.cpp +++ b/tests/integration/main.cpp @@ -29,6 +29,7 @@ boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { } } if(!is_verbose) fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::off); + if(is_verbose) fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::all); // Register fc::exception translator boost::unit_test::unit_test_monitor.template register_exception_translator(&translate_fc_exception); diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index 20b5383452..b95fceac19 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -37,16 +37,16 @@ struct my_struct { struct my_table : eosio::kv_table { struct { - kv_index tname{&my_struct::tname}; - kv_index tstring{&my_struct::tstring}; - kv_index tui64{&my_struct::tui64}; - kv_index ti32{&my_struct::ti32}; - kv_index tui128{&my_struct::tui128}; - kv_index tfloat{&my_struct::tfloat}; - kv_index tdouble{&my_struct::tdouble}; - kv_index tstruct{&my_struct::tstruct}; - kv_index ttuple{&my_struct::ttuple}; - kv_index itstring{&my_struct::itstring}; + kv_unique_index tname{&my_struct::tname}; + kv_non_unique_index tstring{&my_struct::tstring}; + kv_non_unique_index tui64{&my_struct::tui64}; + kv_non_unique_index ti32{&my_struct::ti32}; + kv_non_unique_index tui128{&my_struct::tui128}; + kv_non_unique_index tfloat{&my_struct::tfloat}; + kv_non_unique_index tdouble{&my_struct::tdouble}; + kv_non_unique_index tstruct{&my_struct::tstruct}; + kv_non_unique_index ttuple{&my_struct::ttuple}; + kv_non_unique_index itstring{&my_struct::itstring}; } index; my_table(eosio::name contract_name) { diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 0e7092bf19..c0fcfd404f 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -4,6 +4,7 @@ struct my_struct { eosio::name primary_key; std::string foo; uint64_t bar; + int32_t baz; bool operator==(const my_struct b) const { return primary_key == b.primary_key && @@ -12,22 +13,35 @@ struct my_struct { } }; -DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - primary_key, - foo, - bar -) +struct my_table : eosio::kv_table { + struct { + kv_unique_index primary_key{&my_struct::primary_key}; + kv_non_unique_index foo{&my_struct::foo}; + kv_non_unique_index bar{&my_struct::bar}; + kv_non_unique_index baz{&my_struct::baz}; + } index; -DEFINE_TABLE(my_table_2, my_struct, "testtable", "eosio.kvram", - primary_key, - nullptr, - bar -) + my_table(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + } +}; + +struct my_table2 : eosio::kv_table { + struct { + kv_unique_index primary_key{&my_struct::primary_key}; + null_kv_index nullptr_2{&my_struct::foo}; + kv_non_unique_index bar{&my_struct::bar}; + } index; + + my_table2(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + } +}; struct my_table_idx : eosio::kv_table { struct { - kv_index primary_key{"prim"_n, &my_struct::primary_key}; - kv_index foo{"f"_n, &my_struct::foo}; + kv_unique_index primary_key{"prim"_n, &my_struct::primary_key}; + kv_non_unique_index foo{"f"_n, &my_struct::foo}; } index; my_table_idx(eosio::name contract_name) { @@ -37,8 +51,8 @@ struct my_table_idx : eosio::kv_table { struct my_table_idx_err : eosio::kv_table { struct { - kv_index primary_key{"prim"_n, &my_struct::primary_key}; - kv_index foo{&my_struct::foo}; + kv_unique_index primary_key{"prim"_n, &my_struct::primary_key}; + kv_non_unique_index foo{&my_struct::foo}; } index; my_table_idx_err(eosio::name contract_name) { @@ -48,8 +62,8 @@ struct my_table_idx_err : eosio::kv_table { struct my_table_idx_err_2 : eosio::kv_table { struct { - kv_index primary_key{&my_struct::primary_key}; - kv_index foo{"f"_n, &my_struct::foo}; + kv_unique_index primary_key{&my_struct::primary_key}; + kv_non_unique_index foo{"f"_n, &my_struct::foo}; } index; my_table_idx_err_2(eosio::name contract_name) { @@ -57,33 +71,48 @@ struct my_table_idx_err_2 : eosio::kv_table { } }; +struct my_table_idx_err_3 : eosio::kv_table { + struct { + kv_non_unique_index primary_key{&my_struct::primary_key}; + } index; + + my_table_idx_err_3(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + } +}; + class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; my_struct s1{ .primary_key = "bob"_n, .foo = "a", - .bar = 5 + .bar = 5, + .baz = 2 }; my_struct s2{ .primary_key = "alice"_n, .foo = "C", - .bar = 4 + .bar = 4, + .baz = 1 }; my_struct s3{ .primary_key = "john"_n, .foo = "e", - .bar = 3 + .bar = 3, + .baz = 1 }; my_struct s4{ .primary_key = "joe"_n, .foo = "g", - .bar = 2 + .bar = 2, + .baz = 1 }; my_struct s5{ .primary_key = "billy"_n, .foo = "I", - .bar = 1 + .bar = 1, + .baz = 1 }; [[eosio::action]] @@ -113,28 +142,8 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { } [[eosio::action]] - void find() { - my_table t{"kvtest"_n}; - - auto itr = t.index.primary_key.find("bob"_n); - auto val = itr.value(); - eosio::check(val.primary_key == "bob"_n, "Got the wrong primary_key"); - - itr = t.index.foo.find("C"); - val = itr.value(); - eosio::check(val.primary_key == "alice"_n, "Got the wrong primary_key"); - - itr = t.index.bar.find((uint64_t)1); - val = itr.value(); - eosio::check(val.primary_key == "billy"_n, "Got the wrong primary_key"); - } - - [[eosio::action]] - void finderror() { - my_table t{"kvtest"_n}; - - auto itr = t.index.primary_key.find("C"); - auto val = itr.value(); + void indiceserr3() { + my_table_idx_err_3 t{"kvtest"_n}; } [[eosio::action]] @@ -205,4 +214,17 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(foo_itr == foo_begin_itr, "Should be the beginning"); eosio::check(bar_itr == bar_begin_itr, "Should be the beginning"); } + + [[eosio::action]] + void range() { + my_table t{"kvtest"_n}; + + std::vector expected = {s2, s5, s4, s3, s1}; + auto actual = t.index.baz.range(1l, 3l); + + eosio::check(actual == expected, "range did not return expected vector"); + for (const auto& a : actual) { + eosio::print_f("% %\n", a.baz, a.primary_key); + } + } }; From 8a6d7e6d5e00c960112884032266574f337fdb6e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 5 Feb 2020 10:49:33 -0500 Subject: [PATCH 233/659] Remove implicit conversions between key_type and std::string --- .../eosiolib/contracts/eosio/key_value.hpp | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index d650f43ed4..0251f16fef 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -136,19 +136,30 @@ namespace eosio { } } +namespace detail { + constexpr inline size_t max_stack_buffer_size = 512; +} + /** * The key_type struct is used to store the binary representation of a key. */ -struct key_type : std::string { - using std::string::string; +struct key_type : private std::string { + key_type() : std::string() {} + key_type(const char* c, size_t s) : std::string(c, s) {} - // TODO: Instead, get rid of implicit conversion and overload + operator - key_type(const std::string& s) : std::string(s.data(), s.size()) {} -}; -namespace detail { - constexpr inline size_t max_stack_buffer_size = 512; -} + key_type operator+(const key_type& b) const { + size_t buffer_size = size() + b.size(); + void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); + + memcpy(buffer, data(), size()); + memcpy(((char*)buffer) + size(), b.data(), b.size()); + return {(char*)buffer, buffer_size}; + } + + using std::string::data; + using std::string::size; +}; /* @cond PRIVATE */ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { @@ -174,7 +185,7 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint } inline key_type table_key(const key_type& prefix, const key_type& key) { - return key_type{prefix + key}; + return prefix + key; } template From ee214514fd16771ca484d5e4fccdbea8cbf603a4 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 5 Feb 2020 13:27:21 -0500 Subject: [PATCH 234/659] Add support for get on non-primary unique indexes --- .../eosiolib/contracts/eosio/key_value.hpp | 20 ++++++++++++++++++- tests/integration/kv_tests.cpp | 11 ++++++++++ .../kv_multiple_indices_tests.cpp | 19 +++++++++++++----- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 0251f16fef..ca78b2d35d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -795,13 +795,31 @@ class kv_table { void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); - datastream ds((char*)buffer, value_size); + void* serialize = buffer; + size_t serialize_size = copy_size; + + if (this->name != tbl->primary_index->name) { + uint32_t actual_data_size; + auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, (char*)buffer, copy_size, actual_data_size); + eosio::check(success, "failure getting primary key"); + + void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); + auto pk_copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)pk_buffer, actual_data_size); + + eosio::check(pk_copy_size != copy_size, "failure getting primary index data"); + + serialize = pk_buffer; + serialize_size = pk_copy_size; + } + + datastream ds((char*)serialize, serialize_size); ret_val.emplace(); ds >> *ret_val; if (value_size > detail::max_stack_buffer_size) { free(buffer); } + return ret_val; } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 0d28bf814a..c99d6fed82 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -99,6 +99,17 @@ BOOST_FIXTURE_TEST_CASE(single_tests_variant, tester) try { // Multi // ----- +BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(find), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index c0fcfd404f..9c28f8a62c 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -9,7 +9,8 @@ struct my_struct { bool operator==(const my_struct b) const { return primary_key == b.primary_key && foo == b.foo && - bar == b.bar; + bar == b.bar && + baz == b.baz; } }; @@ -17,7 +18,7 @@ struct my_table : eosio::kv_table { struct { kv_unique_index primary_key{&my_struct::primary_key}; kv_non_unique_index foo{&my_struct::foo}; - kv_non_unique_index bar{&my_struct::bar}; + kv_unique_index bar{&my_struct::bar}; kv_non_unique_index baz{&my_struct::baz}; } index; @@ -126,6 +127,17 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { t.put(s5); } + [[eosio::action]] + void find() { + my_table t{"kvtest"_n}; + + auto itr = t.index.bar.find(5ull); + eosio::check(itr.value().bar == s1.bar, "wrong value"); + + auto val = t.index.bar.get(4ull); + eosio::check(val->bar == s2.bar, "wrong value"); + } + [[eosio::action]] void indices() { my_table_idx t{"kvtest"_n}; @@ -223,8 +235,5 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { auto actual = t.index.baz.range(1l, 3l); eosio::check(actual == expected, "range did not return expected vector"); - for (const auto& a : actual) { - eosio::print_f("% %\n", a.baz, a.primary_key); - } } }; From 0493ad16a26507c2e2518be2dd63f5da6a58bc7e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 5 Feb 2020 14:52:13 -0500 Subject: [PATCH 235/659] Add cleanup of secondary indices --- libraries/eosiolib/contracts/eosio/key_value.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index ca78b2d35d..d365d961a1 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -889,6 +889,14 @@ class kv_table { internal_use_do_not_use::kv_set(db_name, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); + // Cleanup secondary indices before updating. + // This is the only way to guarantee they are cleaned up if they have changed, + // as we have no way to derive the original value of the index. + for (auto& idx : secondary_indices) { + auto prefix = make_prefix(table_name, idx->name); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, prefix.data(), prefix.size()); + } + for (auto& idx : secondary_indices) { key_type sk; if (idx->is_unique()) { From 388dc4bbc1afe1f382d8b552cf0e11ad0ebbb470 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 18 Feb 2020 10:59:54 -0500 Subject: [PATCH 236/659] Fix macro to correctly create non_unique indexes --- libraries/eosiolib/contracts/eosio/key_value.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index d365d961a1..65c7d299d3 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -28,7 +28,7 @@ #define EOSIO_CDT_KV_FIX_INDEX_NAME_1(index_name, i) index_name ## i #define EOSIO_CDT_KV_FIX_INDEX_NAME(x, i) EOSIO_CDT_KV_FIX_INDEX_NAME_ ## x -#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) kv_index +#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) kv_non_unique_index #define EOSIO_CDT_KV_FIX_INDEX_TYPE_1(index_name) null_kv_index #define EOSIO_CDT_KV_FIX_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_TYPE_ ## iskeyword From 2efaaf7e6797618772abcf236d6250cdb336b70e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 19 Feb 2020 15:30:50 -0500 Subject: [PATCH 237/659] Fix bad merge --- tests/integration/kv_tests.cpp | 11 ----------- .../unit/test_contracts/kv_multiple_indices_tests.cpp | 11 ----------- tests/unit/test_contracts/kv_single_index_tests.cpp | 4 ++-- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index c99d6fed82..0d28bf814a 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -99,17 +99,6 @@ BOOST_FIXTURE_TEST_CASE(single_tests_variant, tester) try { // Multi // ----- -BOOST_FIXTURE_TEST_CASE(multi_tests_find, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(find), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { create_accounts( { N(kvtest) } ); produce_block(); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 9c28f8a62c..a1e58730e1 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -127,17 +127,6 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { t.put(s5); } - [[eosio::action]] - void find() { - my_table t{"kvtest"_n}; - - auto itr = t.index.bar.find(5ull); - eosio::check(itr.value().bar == s1.bar, "wrong value"); - - auto val = t.index.bar.get(4ull); - eosio::check(val->bar == s2.bar, "wrong value"); - } - [[eosio::action]] void indices() { my_table_idx t{"kvtest"_n}; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index f1cfe5f25f..4f626b6cdc 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -23,7 +23,7 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) struct my_table_v : eosio::kv_table> { struct { - kv_index primary_key{[](const auto& obj) { + kv_unique_index primary_key{[](const auto& obj) { return std::visit([&](auto&& a) { using V = std::decay_t; if constexpr(std::is_same_v) { @@ -36,7 +36,7 @@ struct my_table_v : eosio::kv_table> { } }, *obj); }}; - kv_index age{[](const auto& obj) { + kv_non_unique_index age{[](const auto& obj) { return std::visit([&](auto&& a) { return a.age; }, *obj); From b48eeaa9bc3c41f01816925d57aa329aa10561fa Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 24 Feb 2020 11:10:47 -0500 Subject: [PATCH 238/659] Fixes from merge --- .../eosiolib/contracts/eosio/key_value.hpp | 71 ++----------------- 1 file changed, 6 insertions(+), 65 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 65c7d299d3..6677b37437 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -561,64 +561,6 @@ class kv_table { }; } - /** - * Search for an existing object in a table by the index, using the given key. - * @ingroup keyvalue - * - * @tparam K - The type of the key. This will be auto-deduced by the key param. - * - * @param key - The key to search for. - * @return An iterator to the found object OR the `end` iterator if the given key was not found. - */ - template - iterator find(K&& key) { - auto t_key = table_key(prefix, make_key(std::forward(key))); - - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - - auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); - - if (cmp != 0) { - internal_use_do_not_use::kv_it_destroy(itr); - return end(); - } - - return {contract_name, itr, static_cast(itr_stat), this}; - } - - /** - * Get the value for an existing object in a table by the index, using the given key. - * @ingroup keyvalue - * - * @tparam K - The type of the key. This will be auto-deduced by the key param. - * - * @param key - The key to search for. - * @return A std::optional of the value corresponding to the key. - */ - template - std::optional get(K&& key) { - uint32_t value_size; - std::optional ret_val; - - auto t_key = table_key(prefix, make_key(std::forward(key))); - - auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); - if (!success) { - return ret_val; - } - - void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); - - ret_val.emplace(); - deserialize(*ret_val, buffer, copy_size); - if (value_size > detail::max_stack_buffer_size) { - free(buffer); - } - return ret_val; - } - /** * Returns an iterator pointing to the element with the lowest key greater than or equal to the given key. * @ingroup keyvalue @@ -795,8 +737,8 @@ class kv_table { void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); - void* serialize = buffer; - size_t serialize_size = copy_size; + void* deserialize_buffer = buffer; + size_t deserialize_size = copy_size; if (this->name != tbl->primary_index->name) { uint32_t actual_data_size; @@ -808,14 +750,13 @@ class kv_table { eosio::check(pk_copy_size != copy_size, "failure getting primary index data"); - serialize = pk_buffer; - serialize_size = pk_copy_size; + deserialize_buffer = pk_buffer; + deserialize_size = pk_copy_size; } - datastream ds((char*)serialize, serialize_size); - ret_val.emplace(); - ds >> *ret_val; + deserialize(*ret_val, deserialize_buffer, deserialize_size); + if (value_size > detail::max_stack_buffer_size) { free(buffer); } From 8ebabc4e4964ff10807c4b47e7943717ad98886b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 25 Feb 2020 11:36:52 -0500 Subject: [PATCH 239/659] Fix secondary index cleanup and handling of unique secondary indexes --- .../eosiolib/contracts/eosio/key_value.hpp | 77 ++++++++++++++----- tests/integration/kv_tests.cpp | 26 +++++++ .../kv_multiple_indices_tests.cpp | 43 +++++++++++ 3 files changed, 126 insertions(+), 20 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6677b37437..6f4eaa682a 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -157,6 +157,13 @@ struct key_type : private std::string { return {(char*)buffer, buffer_size}; } + bool operator==(const key_type& b) const { + if (size() != b.size()) { + return false; + } + return memcmp(data(), b.data(), b.size()) == 0; + } + using std::string::data; using std::string::size; }; @@ -819,37 +826,67 @@ class kv_table { * @param value - The entry to be stored in the table. */ void put(const T& value) { - using namespace detail; + uint32_t value_size; + T old_value; - auto t_key = table_key(make_prefix(table_name, primary_index->name), primary_index->get_key(value)); - - size_t data_size = get_size(value); - void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + auto primary_key = primary_index->get_key(value); + auto tbl_key = table_key(make_prefix(table_name, primary_index->name), primary_key); + auto primary_key_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), value_size); - serialize(value, data_buffer, data_size); + if (primary_key_found) { + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); - internal_use_do_not_use::kv_set(db_name, contract_name.value, t_key.data(), t_key.size(), (const char*)data_buffer, data_size); + deserialize(old_value, buffer, copy_size); - // Cleanup secondary indices before updating. - // This is the only way to guarantee they are cleaned up if they have changed, - // as we have no way to derive the original value of the index. - for (auto& idx : secondary_indices) { - auto prefix = make_prefix(table_name, idx->name); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, prefix.data(), prefix.size()); + if (value_size > detail::max_stack_buffer_size) { + free(buffer); + } } - for (auto& idx : secondary_indices) { - key_type sk; + for (const auto& idx : secondary_indices) { + key_type sec_key; + if (idx->is_unique()) { - sk = idx->get_key(value); + sec_key = idx->get_key(value); + auto sec_tbl_key = table_key(make_prefix(table_name, idx->name), sec_key); + auto sec_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), value_size); + + if (!primary_key_found) { + eosio::check(!sec_found, "Attempted to store an existing unique secondary index."); + } else if (sec_found) { + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); + + eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing unique secondary index."); + auto res = memcmp(buffer, tbl_key.data(), copy_size); + eosio::check(res == 0, "Attempted to update an existing unique secondary index."); + + if (copy_size > detail::max_stack_buffer_size) { + free(buffer); + } + } + + auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); } else { - sk = key_type{idx->get_key(value) + primary_index->get_key(value)}; + auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value) + primary_index->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + + sec_key = idx->get_key(value) + primary_index->get_key(value); } - auto st_key = table_key(make_prefix(table_name, idx->name), sk); - internal_use_do_not_use::kv_set(db_name, contract_name.value, st_key.data(), st_key.size(), t_key.data(), t_key.size()); + auto sec_tbl_key = table_key(make_prefix(table_name, idx->name), sec_key); + internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); } - + + size_t data_size = get_size(value); + void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); + + serialize(value, data_buffer, data_size); + + internal_use_do_not_use::kv_set(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), (const char*)data_buffer, data_size); + if (data_size > detail::max_stack_buffer_size) { free(data_buffer); } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 0d28bf814a..3ff8886b59 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -142,4 +142,30 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { push_action(N(kvtest), N(range), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_unique_secondary, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + push_action(N(kvtest), N(uniqsecidx), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(multi_tests_unique_secondary_error, tester) try { + create_accounts( { N(kvtest) } ); + produce_block(); + set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); + set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); + produce_blocks(); + + push_action(N(kvtest), N(setup), N(kvtest), {}); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(usecidxerr1), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Attempted to store an existing unique secondary index.")); + BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(usecidxerr2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Attempted to update an existing unique secondary index.")); +} FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index a1e58730e1..51c9112cc1 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -225,4 +225,47 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(actual == expected, "range did not return expected vector"); } + + [[eosio::action]] + void uniqsecidx() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "bob"_n, + .foo = "testing", + .bar = 5, + .baz = 3 + }); + + t.put({ + .primary_key = "bob"_n, + .foo = "testing", + .bar = 100, + .baz = 3 + }); + } + + [[eosio::action]] + void usecidxerr1() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "carl"_n, + .foo = "testing", + .bar = 5, + .baz = 3 + }); + } + + [[eosio::action]] + void usecidxerr2() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "alice"_n, + .foo = "testing", + .bar = 5, + .baz = 3 + }); + } }; From c71873cae7796c6d3d2055a1d072080e4fb9d7c4 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 10:34:11 -0500 Subject: [PATCH 240/659] Test updated checkout plugin and manual submodule checkout in Actions. --- .github/workflows/main.yml | 174 +++++++++++++++++++++++++------------ 1 file changed, 119 insertions(+), 55 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca779ca7f3..b19c9b0da6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,29 +1,37 @@ name: Pull Request -on: [pull_request] +on: [push] jobs: submodule_regression_check: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Submodule Regression Check runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Submodule Regression Check run: ./.cicd/submodule-regression-checker.sh amazon_linux-2-build: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Amazon_Linux 2 | Build runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Build run: | ./.cicd/build.sh @@ -41,9 +49,13 @@ jobs: needs: amazon_linux-2-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -60,9 +72,13 @@ jobs: needs: amazon_linux-2-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -76,14 +92,18 @@ jobs: centos-77-build: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: CentOS 7.7 | Build runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Build run: | ./.cicd/build.sh @@ -101,9 +121,13 @@ jobs: needs: centos-77-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -120,9 +144,13 @@ jobs: needs: centos-77-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -136,14 +164,18 @@ jobs: ubuntu-1604-build: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 16.04 | Build runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Build run: | ./.cicd/build.sh @@ -161,9 +193,13 @@ jobs: needs: ubuntu-1604-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -180,9 +216,13 @@ jobs: needs: ubuntu-1604-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -196,14 +236,18 @@ jobs: ubuntu-1804-build: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 18.04 | Build runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Build run: | ./.cicd/build.sh @@ -221,9 +265,13 @@ jobs: needs: ubuntu-1804-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -240,9 +288,13 @@ jobs: needs: ubuntu-1804-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -256,14 +308,18 @@ jobs: macos-1015-build: - if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: MacOS 10.15 | Build runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Build run: | brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 @@ -280,9 +336,13 @@ jobs: needs: macos-1015-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -298,9 +358,13 @@ jobs: needs: macos-1015-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + - name: Submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 - name: Download Build Artifact uses: actions/download-artifact@v1 with: From 4dbb4b3d52c16998bce14715f0c4516308461679 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 10:44:54 -0500 Subject: [PATCH 241/659] Switch back to PRs. --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b19c9b0da6..7f1ce7dc1a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,9 @@ name: Pull Request -on: [push] +on: [pull_request] jobs: submodule_regression_check: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Submodule Regression Check runs-on: ubuntu-latest steps: @@ -20,7 +20,7 @@ jobs: amazon_linux-2-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Amazon_Linux 2 | Build runs-on: ubuntu-latest steps: @@ -92,7 +92,7 @@ jobs: centos-77-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: CentOS 7.7 | Build runs-on: ubuntu-latest steps: @@ -164,7 +164,7 @@ jobs: ubuntu-1604-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 16.04 | Build runs-on: ubuntu-latest steps: @@ -236,7 +236,7 @@ jobs: ubuntu-1804-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 18.04 | Build runs-on: ubuntu-latest steps: @@ -308,7 +308,7 @@ jobs: macos-1015-build: - # if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id + if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: MacOS 10.15 | Build runs-on: macos-latest steps: From 81e18b79a5d4669bb2d077c312b9dbd774829dd4 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 10:49:31 -0500 Subject: [PATCH 242/659] Fetch all history for submodule regression check step. --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f1ce7dc1a..3f74380978 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e + with: + fetch-depth: 0 - name: Submodules shell: bash run: | From 72e9bafac5d50b7efa89993129920080665c5459 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 11:00:56 -0500 Subject: [PATCH 243/659] Full history of submodules. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f74380978..cea78faa51 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: run: | auth_header="$(git config --local --get http.https://github.com/.extraheader)" git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive - name: Submodule Regression Check run: ./.cicd/submodule-regression-checker.sh From dcad83ad9e2ff093f99cc3685d646041e8001229 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 26 Feb 2020 14:44:20 -0500 Subject: [PATCH 244/659] Don't delete the default constructed secondary key --- libraries/eosiolib/contracts/eosio/key_value.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6f4eaa682a..6ba7bc4528 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -867,8 +867,10 @@ class kv_table { } } - auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + if (primary_key_found) { + auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + } } else { auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value) + primary_index->get_key(old_value)); internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); From 8c8ad2c7c77d24ff8dc58ad2022dccb898e4ff07 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 14:47:25 -0500 Subject: [PATCH 245/659] Replace checkout plugin with manual controlled checkouts. --- .github/workflows/main.yml | 178 ++++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 82 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cea78faa51..ea493c26ad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,15 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - with: - fetch-depth: 0 - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Submodule Regression Check run: ./.cicd/submodule-regression-checker.sh @@ -27,13 +26,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -51,13 +51,14 @@ jobs: needs: amazon_linux-2-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -74,13 +75,14 @@ jobs: needs: amazon_linux-2-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -99,13 +101,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -123,13 +126,14 @@ jobs: needs: centos-77-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -146,13 +150,14 @@ jobs: needs: centos-77-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -171,13 +176,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -195,13 +201,14 @@ jobs: needs: ubuntu-1604-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -218,13 +225,14 @@ jobs: needs: ubuntu-1604-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -243,13 +251,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -267,13 +276,14 @@ jobs: needs: ubuntu-1804-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -290,13 +300,14 @@ jobs: needs: ubuntu-1804-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -315,13 +326,14 @@ jobs: runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 @@ -338,13 +350,14 @@ jobs: needs: macos-1015-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -360,13 +373,14 @@ jobs: needs: macos-1015-build steps: - name: Checkout - uses: actions/checkout@f90c7b395dac7c5a277c1a6d93d5057c1cddb74e - - name: Submodules - shell: bash run: | - auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive - git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + git submodule update --init --force --recursive + env: + PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: From 4d88155be82008f7d48b75a5eb0c6585d4e7752d Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 14:48:34 -0500 Subject: [PATCH 246/659] Update regression checker for Actions. --- .cicd/submodule-regression-checker.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.cicd/submodule-regression-checker.sh b/.cicd/submodule-regression-checker.sh index 8099906720..9392ebb43b 100755 --- a/.cicd/submodule-regression-checker.sh +++ b/.cicd/submodule-regression-checker.sh @@ -10,7 +10,7 @@ if [[ $BUILDKITE == true ]]; then else [[ -z $GITHUB_BASE_REF ]] && echo "Cannot find \$GITHUB_BASE_REF, so we have nothing to compare submodules to. Skipping submodule regression check." && exit 0 BASE_BRANCH=$GITHUB_BASE_REF - CURRENT_BRANCH=$GITHUB_SHA + CURRENT_BRANCH="refs/remotes/pull/$PR_NUMBER/merge" fi echo "getting submodule info for $CURRENT_BRANCH" @@ -25,12 +25,6 @@ while read -r a b; do BASE_MAP[$a]=$b done < <(git submodule --quiet foreach --recursive 'echo $path `git log -1 --format=%ct`') -# We need to switch back to the PR ref/head so we can git log properly -if [[ $BUILDKITE != true ]]; then - echo "git fetch origin +$GITHUB_REF:" - git fetch origin +${GITHUB_REF}: 1> /dev/null -fi - echo "switching back to $CURRENT_BRANCH..." echo "git checkout -qf $CURRENT_BRANCH" git checkout -qf $CURRENT_BRANCH 1> /dev/null From b16f1cfca4ac1d7761549763886663dc13cbd56d Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 14:58:54 -0500 Subject: [PATCH 247/659] Define env at workflow level. --- .github/workflows/main.yml | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea493c26ad..f153c1d1ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,9 @@ name: Pull Request on: [pull_request] +env: + PR_NUMBER: ${{ toJson(github.event.number) }} + jobs: submodule_regression_check: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id @@ -14,8 +17,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Submodule Regression Check run: ./.cicd/submodule-regression-checker.sh @@ -32,8 +33,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -57,8 +56,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -81,8 +78,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -107,8 +102,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -132,8 +125,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -156,8 +147,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -182,8 +171,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -207,8 +194,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -231,8 +216,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -257,8 +240,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | ./.cicd/build.sh @@ -282,8 +263,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -306,8 +285,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -332,8 +309,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Build run: | brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3 @@ -356,8 +331,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: @@ -379,8 +352,6 @@ jobs: git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge git submodule sync --recursive git submodule update --init --force --recursive - env: - PR_NUMBER: ${{ toJson(github.event.number) }} - name: Download Build Artifact uses: actions/download-artifact@v1 with: From 614aea1acc9f494693ec4625f49a46db07768c21 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 26 Feb 2020 14:59:25 -0500 Subject: [PATCH 248/659] Don't delete the default constructed secondary key --- libraries/eosiolib/contracts/eosio/key_value.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6ba7bc4528..1deeb42da8 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -872,8 +872,10 @@ class kv_table { internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); } } else { - auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value) + primary_index->get_key(old_value)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + if (primary_key_found) { + auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value) + primary_index->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + } sec_key = idx->get_key(value) + primary_index->get_key(value); } From 0280e3b2db6001509c6b3a9785db6fd8ac3dcfe6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 27 Feb 2020 15:40:38 -0500 Subject: [PATCH 249/659] Remove unnecessary check --- libraries/eosiolib/contracts/eosio/key_value.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 1deeb42da8..e937254532 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -755,8 +755,6 @@ class kv_table { void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); auto pk_copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)pk_buffer, actual_data_size); - eosio::check(pk_copy_size != copy_size, "failure getting primary index data"); - deserialize_buffer = pk_buffer; deserialize_size = pk_copy_size; } From 3b57c6ff1dd98a1c83a8d7f7bd37346df46d9031 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 27 Feb 2020 17:35:56 -0500 Subject: [PATCH 250/659] forgot to add the struct of the return type as possible struct type --- .../abigen-pass/action_results_test.abi | 46 +++++++++++++++++++ .../abigen-pass/action_results_test.cpp | 13 ++++++ tools/include/eosio/abigen.hpp | 22 ++++++++- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/toolchain/abigen-pass/action_results_test.abi b/tests/toolchain/abigen-pass/action_results_test.abi index b9ae26e007..6fd427c2af 100644 --- a/tests/toolchain/abigen-pass/action_results_test.abi +++ b/tests/toolchain/abigen-pass/action_results_test.abi @@ -17,6 +17,34 @@ "name": "action3", "base": "", "fields": [] + }, + { + "name": "action4", + "base": "", + "fields": [] + }, + { + "name": "action5", + "base": "", + "fields": [] + }, + { + "name": "test_res", + "base": "", + "fields": [ + { + "name": "a", + "type": "int32" + }, + { + "name": "b", + "type": "float32" + }, + { + "name": "c", + "type": "name" + } + ] } ], "actions": [ @@ -34,6 +62,16 @@ "name": "action3", "type": "action3", "ricardian_contract": "" + }, + { + "name": "action4", + "type": "action4", + "ricardian_contract": "" + }, + { + "name": "action5", + "type": "action5", + "ricardian_contract": "" } ], "tables": [], @@ -47,6 +85,14 @@ { "name": "action3", "result_type": "string" + }, + { + "name": "action4", + "result_type": "name[]" + }, + { + "name": "action5", + "result_type": "test_res" } ] } \ No newline at end of file diff --git a/tests/toolchain/abigen-pass/action_results_test.cpp b/tests/toolchain/abigen-pass/action_results_test.cpp index 0d09d79a4d..e4cbdeef47 100644 --- a/tests/toolchain/abigen-pass/action_results_test.cpp +++ b/tests/toolchain/abigen-pass/action_results_test.cpp @@ -1,7 +1,14 @@ #include +#include using namespace eosio; +struct test_res { + int a; + float b; + name c; +}; + class [[eosio::contract]] action_results_test : public contract { public: using contract::contract; @@ -14,4 +21,10 @@ class [[eosio::contract]] action_results_test : public contract { [[eosio::action]] std::string action3() { return "foo"; } + + [[eosio::action]] + std::vector action4() { return {"dan"_n}; } + + [[eosio::action]] + test_res action5() { return {4, 42.4f, "bucky"_n}; } }; diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 96a28146b4..5a580fb4b7 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -112,8 +112,19 @@ namespace eosio { namespace cdt { } ret.type = decl->getNameAsString(); _abi.actions.insert(ret); - if (translate_type(decl->getReturnType()) != "void") + if (translate_type(decl->getReturnType()) != "void") { + /** TODO after LLVM 9 update uncomment this code and use new error handling for pretty clang style errors + if (decl->getReturnType() == decl->getDeclaredReturnType()) + */ + add_type(decl->getReturnType()); _abi.action_results.insert({get_action_name(decl), translate_type(decl->getReturnType())}); + /* + else { + std::cout << "Error, currently in eosio.cdt v2.0 `auto` is not allowed for actions\n"; + throw abigen_ex; + } + */ + } } void add_tuple(const clang::QualType& type) { @@ -439,6 +450,11 @@ namespace eosio { namespace cdt { if (as.name == _translate_type(remove_suffix(td.type))) return true; } + for( auto ar : _abi.action_results ) { + std::cout << "AR " << _translate_type(ar.type) << " AS " << as.name << "\n"; + if (as.name == _translate_type(ar.type)) + return true; + } return false; }; @@ -467,6 +483,10 @@ namespace eosio { namespace cdt { for ( auto _td : _abi.typedefs ) if ( remove_suffix(_td.type) == td.new_type_name ) return true; + for ( auto ar : _abi.action_results ) { + if ( ar.type == td.new_type_name ) + return true; + } return false; }; From b34f9cb80ec7beb348f3e84e301592872d5cd2be Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 27 Feb 2020 17:40:39 -0500 Subject: [PATCH 251/659] remove stray cout --- tools/include/eosio/abigen.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 5a580fb4b7..5a8e17e017 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -451,7 +451,6 @@ namespace eosio { namespace cdt { return true; } for( auto ar : _abi.action_results ) { - std::cout << "AR " << _translate_type(ar.type) << " AS " << as.name << "\n"; if (as.name == _translate_type(ar.type)) return true; } From 7f9b777d5053c82a4e32391fe5b6c515b854af81 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 28 Feb 2020 14:52:33 -0500 Subject: [PATCH 252/659] Add missing make_key overload --- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 52d2405201..15e83a3328 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -268,6 +268,10 @@ inline key_type make_key(key_type&& val) { return val; } +inline key_type make_key(const key_type& val) { + return val; +} + template ::value, int> = 0> inline key_type make_key(const S& val) { size_t data_size = 0; From bd1293a8946ed79d618595679486f84cecb1c6da Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 26 Feb 2020 16:27:03 -0500 Subject: [PATCH 253/659] Finalize KV API. - Move away from Reflection. - Add type info to index. - Remove non_unique_index. --- .../eosiolib/contracts/eosio/key_value.hpp | 753 ++++++++---------- tests/integration/kv_tests.cpp | 5 +- .../unit/test_contracts/kv_make_key_tests.cpp | 48 +- .../kv_multiple_indices_tests.cpp | 85 +- .../test_contracts/kv_single_index_tests.cpp | 109 ++- 5 files changed, 465 insertions(+), 535 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 7b2a807a8e..756ba16450 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -24,12 +25,14 @@ #define EOSIO_CDT_CAT(x, y) EOSIO_CDT_CAT2(x, y) #define EOSIO_CDT_APPLY(f, args) f args +#define EOSIO_CDT_GET_RETURN_T(value_class, index_name) std::remove_cv_t()))>> + #define EOSIO_CDT_KV_FIX_INDEX_NAME_0(index_name, i) index_name #define EOSIO_CDT_KV_FIX_INDEX_NAME_1(index_name, i) index_name ## i #define EOSIO_CDT_KV_FIX_INDEX_NAME(x, i) EOSIO_CDT_KV_FIX_INDEX_NAME_ ## x -#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) kv_non_unique_index -#define EOSIO_CDT_KV_FIX_INDEX_TYPE_1(index_name) null_kv_index +#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) index +#define EOSIO_CDT_KV_FIX_INDEX_TYPE_1(index_name) null_index #define EOSIO_CDT_KV_FIX_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_TYPE_ ## iskeyword #define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_0(value_class, index_name) {&value_class::index_name} @@ -51,19 +54,18 @@ (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(value_class, index_name) - -#define EOSIO_CDT_CREATE_KV_NON_UNIQUE_INDEX(r, value_class, i, index_name) \ - EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); - -#define EOSIO_CDT_CREATE_KV_UNIQUE_INDEX(r, value_class, i, index_name) \ - kv_unique_index EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); - #define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ - BOOST_PP_IF(i, EOSIO_CDT_CREATE_KV_NON_UNIQUE_INDEX, EOSIO_CDT_CREATE_KV_UNIQUE_INDEX)(r, value_class, i, index_name) + EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); -#define EOSIO_CDT_LIST_INDICES(value_class, ...) \ +#define EOSIO_CDT_CREATE_KV_INDICES(value_class, ...) \ BOOST_PP_SEQ_FOR_EACH_I(EOSIO_CDT_CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) +#define EOSIO_CDT_LIST_KV_INDEX(r, data, index_name) \ + ,&index_name + +#define EOSIO_CDT_LIST_KV_INDICES(...) \ + BOOST_PP_SEQ_FOR_EACH(EOSIO_CDT_LIST_KV_INDEX, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) + /** * @brief Macro to define a table. * @details The resulting table will have a member `index` that has fields on it that match 1-1 with the names of the @@ -77,12 +79,10 @@ */ #define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ struct table_class : eosio::kv_table { \ - struct { \ - EOSIO_CDT_LIST_INDICES(value_class, __VA_ARGS__) \ - } index; \ + EOSIO_CDT_CREATE_KV_INDICES(value_class, __VA_ARGS__) \ \ table_class(eosio::name contract_name) { \ - init(contract_name, table_name##_n, db_name##_n, &index); \ + init(contract_name, table_name##_n, db_name##_n EOSIO_CDT_LIST_KV_INDICES(__VA_ARGS__)); \ } \ }; @@ -90,10 +90,10 @@ namespace eosio { namespace internal_use_do_not_use { extern "C" { __attribute__((eosio_wasm_import)) - void kv_erase(uint64_t db, uint64_t contract, const char* key, uint32_t key_size); + int64_t kv_erase(uint64_t db, uint64_t contract, const char* key, uint32_t key_size); __attribute__((eosio_wasm_import)) - void kv_set(uint64_t db, uint64_t contract, const char* key, uint32_t key_size, const char* value, uint32_t value_size); + int64_t kv_set(uint64_t db, uint64_t contract, const char* key, uint32_t key_size, const char* value, uint32_t value_size); __attribute__((eosio_wasm_import)) bool kv_get(uint64_t db, uint64_t contract, const char* key, uint32_t key_size, uint32_t& value_size); @@ -403,159 +403,162 @@ class kv_table { iterator_end = -2, // Iterator is out-of-bounds }; -public: - /** - * @ingroup keyvalue - * - * @brief Defines an index on an EOSIO Key Value Table - * @details A Key Value Index allows a user of the table to search based on a given field. - * The only restrictions on that field are that it is serializable to a binary representation. - * Convenience functions exist to handle most of the primitive types as well as some more complex types, and are - * used automatically where possible. - */ - class kv_index { - class iterator { - public: - iterator(eosio::name contract_name, uint32_t itr, kv_it_stat itr_stat, kv_index* idx) : - contract_name{contract_name}, itr{itr}, itr_stat{itr_stat}, idx{idx} {} - - iterator(iterator&& other) : - contract_name(std::move(other.contract_name)), - itr(std::exchange(other.itr, 0)), - itr_stat(std::move(other.itr_stat)), - idx(std::exchange(other.idx, nullptr)) - {} - - ~iterator() { - if (itr) { - internal_use_do_not_use::kv_it_destroy(itr); - } - } + struct index_config { + uint64_t db_name; + eosio::name contract_name; + eosio::name index_name; + eosio::name primary_index_name; + key_type prefix; + }; - iterator& operator=(iterator&& other) { - contract_name = std::move(other.contract_name); - itr = std::exchange(other.itr, itr); - itr_stat = std::move(other.itr_stat); - idx = std::exchange(other.idx, nullptr); + class iterator { + public: + iterator(uint32_t itr, kv_it_stat itr_stat, const index_config& config) : itr{itr}, itr_stat{itr_stat}, config{config} {} - return *this; + iterator(iterator&& other) : + itr(std::exchange(other.itr, 0)), + itr_stat(std::move(other.itr_stat)), + config(std::move(other.config)) + {} + + ~iterator() { + if (itr) { + internal_use_do_not_use::kv_it_destroy(itr); } + } - /** - * Returns the value that the iterator points to. - * @ingroup keyvalue - * - * @return The value that the iterator points to. - */ - T value() const { - using namespace detail; + iterator& operator=(iterator&& other) { + itr = std::exchange(other.itr, itr); + itr_stat = std::move(other.itr_stat); + config = std::move(other.config); - eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); + return *this; + } - uint32_t value_size; - uint32_t actual_value_size; - uint32_t offset = 0; + /** + * Returns the value that the iterator points to. + * @ingroup keyvalue + * + * @return The value that the iterator points to. + */ + T value() const { + using namespace detail; - // call once to get the value_size - internal_use_do_not_use::kv_it_value(itr, 0, (char*)nullptr, 0, value_size); + eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); - void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, value_size, actual_value_size); + uint32_t value_size; + uint32_t actual_value_size; + uint32_t offset = 0; - eosio::check(static_cast(stat) != kv_it_stat::iterator_end, "Error reading value"); + // call once to get the value_size + internal_use_do_not_use::kv_it_value(itr, 0, (char*)nullptr, 0, value_size); - void* deserialize_buffer = buffer; - size_t deserialize_size = actual_value_size; + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, value_size, actual_value_size); - if (idx->name != idx->tbl->primary_index->name) { - uint32_t actual_data_size; - auto success = internal_use_do_not_use::kv_get(idx->tbl->db_name, contract_name.value, (char*)buffer, actual_value_size, actual_data_size); - eosio::check(success, "failure getting primary key"); + eosio::check(static_cast(stat) == kv_it_stat::iterator_ok, "Error reading value"); - void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - internal_use_do_not_use::kv_get_data(idx->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); + void* deserialize_buffer = buffer; + size_t deserialize_size = actual_value_size; - deserialize_buffer = pk_buffer; - deserialize_size = actual_data_size; - } + if (config.index_name != config.primary_index_name) { + uint32_t actual_data_size; + auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, actual_value_size, actual_data_size); + eosio::check(success, "failure getting primary key"); - T val; - deserialize(val, deserialize_buffer, deserialize_size); - return val; - } + void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); + internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)pk_buffer, actual_data_size); - iterator& operator++() { - eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); - itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); - return *this; + deserialize_buffer = pk_buffer; + deserialize_size = actual_data_size; } - iterator& operator--() { - if (!itr) { - itr = internal_use_do_not_use::kv_it_create(idx->tbl->db_name, contract_name.value, idx->prefix.data(), idx->prefix.size()); - } - itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); - eosio::check(itr_stat != kv_it_stat::iterator_end, "decremented past the beginning"); - return *this; - } + T val; + deserialize(val, deserialize_buffer, deserialize_size); + return val; + } - bool operator==(const iterator& b) const { - return compare(b) == 0; - } + iterator& operator++() { + eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); + itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); + return *this; + } - bool operator!=(const iterator& b) const { - return compare(b) != 0; + iterator& operator--() { + if (!itr) { + itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); } + itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); + eosio::check(itr_stat != kv_it_stat::iterator_end, "decremented past the beginning"); + return *this; + } - bool operator<(const iterator& b) const { - return compare(b) < 0; - } + uint32_t key_compare(key_type kt) const { + return internal_use_do_not_use::kv_it_key_compare(itr, kt.data(), kt.size()); + } - bool operator<=(const iterator& b) const { - return compare(b) <= 0; - } + bool operator==(const iterator& b) const { + return compare(b) == 0; + } - bool operator>(const iterator& b) const { - return compare(b) > 0; - } + bool operator!=(const iterator& b) const { + return compare(b) != 0; + } - bool operator>=(const iterator& b) const { - return compare(b) >= 0; - } + bool operator<(const iterator& b) const { + return compare(b) < 0; + } - private: - eosio::name contract_name; - const kv_index* idx; + bool operator<=(const iterator& b) const { + return compare(b) <= 0; + } - uint32_t itr; - kv_it_stat itr_stat; + bool operator>(const iterator& b) const { + return compare(b) > 0; + } - key_type key() const { - return idx->get_key(value()); - } + bool operator>=(const iterator& b) const { + return compare(b) >= 0; + } - int compare(const iterator& b) const { - bool a_is_end = !itr || itr_stat == kv_it_stat::iterator_end; - bool b_is_end = !b.itr || b.itr_stat == kv_it_stat::iterator_end; - if (a_is_end && b_is_end) { - return 0; - } else if (a_is_end && b.itr) { - return 1; - } else if (itr && b_is_end) { - return -1; - } else { - return internal_use_do_not_use::kv_it_compare(itr, b.itr); - } + private: + uint32_t itr; + kv_it_stat itr_stat; + + index_config config; + + int compare(const iterator& b) const { + bool a_is_end = !itr || itr_stat == kv_it_stat::iterator_end; + bool b_is_end = !b.itr || b.itr_stat == kv_it_stat::iterator_end; + if (a_is_end && b_is_end) { + return 0; + } else if (a_is_end && b.itr) { + return 1; + } else if (itr && b_is_end) { + return -1; + } else { + return internal_use_do_not_use::kv_it_compare(itr, b.itr); } + } + }; - friend kv_index; - }; + /** + * @ingroup keyvalue + * + * @brief Defines an index on an EOSIO Key Value Table + * @details A Key Value Index allows a user of the table to search based on a given field. + * The only restrictions on that field are that it is serializable to a binary representation. + * Convenience functions exist to handle most of the primitive types as well as some more complex types, and are + * used automatically where possible. + */ + class kv_index { public: - eosio::name name{0}; + eosio::name index_name{0}; eosio::name table_name; eosio::name contract_name; + protected: kv_index() = default; template @@ -566,112 +569,12 @@ class kv_table { } template - kv_index(eosio::name name, KF&& kf) : name{name} { + kv_index(eosio::name index_name, KF&& kf) : index_name{index_name} { key_function = [=](const T& t) { return make_key(std::invoke(kf, &t)); }; } - /** - * Returns an iterator pointing to the element with the lowest key greater than or equal to the given key. - * @ingroup keyvalue - * - * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. - */ - template - iterator lower_bound(K&& key) { - auto t_key = table_key(prefix, make_key(std::forward(key))); - - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - - if (static_cast(itr_stat) == kv_it_stat::iterator_end) { - internal_use_do_not_use::kv_it_destroy(itr); - return end(); - } - - return {contract_name, itr, static_cast(itr_stat), this}; - } - - /** - * Returns an iterator pointing to the first element greater than the given key. - * @ingroup keyvalue - * - * @return An iterator pointing to the element with the highest key less than or equal to the given key. - */ - template - iterator upper_bound(K&& key) { - auto t_key = table_key(prefix, make_key(std::forward(key))); - - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - - iterator it{contract_name, itr, static_cast(itr_stat), this}; - - auto cmp = internal_use_do_not_use::kv_it_key_compare(it.itr, t_key.data(), t_key.size()); - if (cmp == 0) { - ++it; - } - - return it; - } - - /** - * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. - * @ingroup keyvalue - * - * @return An iterator referring to the `past-the-end` element. - */ - iterator end() { - return {contract_name, 0, kv_it_stat::iterator_end, this}; - } - - /** - * Returns an iterator to the object with the lowest key (by this index) in the table. - * @ingroup keyvalue - * - * @return An iterator to the object with the lowest key (by this index) in the table. - */ - iterator begin() { - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - - return {contract_name, itr, static_cast(itr_stat), this}; - } - - /** - * Returns a vector of objects that fall between the specifed range. The range is inclusive, exclusive. - * @ingroup keyvalue - * - * @tparam K - The type of the key. This will be auto-deduced by the key param. - * - * @param begin - The beginning of the range. - * @param end - The end of the range. - * @return A vector containing all the objects that fall between the range. - */ - template - std::vector range(K&& b, K&& e) { - auto begin_itr = lower_bound(std::forward(b)); - auto end_itr = lower_bound(std::forward(e)); - - if (begin_itr == end_itr || begin_itr > end_itr) { - return {}; - } - - std::vector return_values; - - iterator itr = std::move(begin_itr); - while(itr < end_itr) { - return_values.push_back(itr.value()); - ++itr; - } - - return return_values; - } - - virtual bool is_unique() = 0; - - protected: key_type get_key(const T& inst) const { return key_function(inst); } kv_table* tbl; key_type prefix; @@ -681,37 +584,49 @@ class kv_table { std::function key_function; - void set_prefix() { - prefix = make_prefix(table_name, name); - } + virtual void setup() = 0; }; - using iterator = typename kv_index::iterator; +public: + + using iterator = kv_table::iterator; + + template + class index : public kv_index { + index_config config; - class kv_unique_index : public kv_index { public: - kv_unique_index() = default; + using kv_table::kv_index::tbl; + using kv_table::kv_index::table_name; + using kv_table::kv_index::contract_name; + using kv_table::kv_index::index_name; + using kv_table::kv_index::prefix; + + index() = default; template - kv_unique_index(KF&& kf): kv_index{kf} {} + index(KF&& kf) : kv_index{kf} { + static_assert(std::is_same_v()))>>>, + "Make sure the variable/function passed to the constructor returns the same type as the template parameter."); + } template - kv_unique_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} + index(eosio::name name, KF&& kf) : kv_index{name, kf} { + static_assert(std::is_same_v()))>>>, + "Make sure the variable/function passed to the constructor returns the same type as the template parameter."); + } /** * Search for an existing object in a table by the index, using the given key. * @ingroup keyvalue * - * @tparam K - The type of the key. This will be auto-deduced by the key param. - * * @param key - The key to search for. * @return An iterator to the found object OR the `end` iterator if the given key was not found. */ - template - iterator find(K&& key) { - auto t_key = table_key(prefix, make_key(std::forward(key))); + iterator find(const K& key) { + auto t_key = table_key(config.prefix, make_key(key)); - uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); @@ -721,43 +636,40 @@ class kv_table { return this->end(); } - return {contract_name, itr, static_cast(itr_stat), this}; + return {itr, static_cast(itr_stat), config}; } /** * Get the value for an existing object in a table by the index, using the given key. * @ingroup keyvalue * - * @tparam K - The type of the key. This will be auto-deduced by the key param. - * * @param key - The key to search for. * @return A std::optional of the value corresponding to the key. */ - template - std::optional get(K&& key) { + std::optional get(const K& key) { uint32_t value_size; std::optional ret_val; - auto t_key = table_key(prefix, make_key(std::forward(key))); + auto t_key = table_key(config.prefix, make_key(key)); - auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); + auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { return ret_val; } void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)buffer, value_size); void* deserialize_buffer = buffer; size_t deserialize_size = copy_size; - if (this->name != tbl->primary_index->name) { + if (config.index_name != config.primary_index_name) { uint32_t actual_data_size; - auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, (char*)buffer, copy_size, actual_data_size); + auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, copy_size, actual_data_size); eosio::check(success, "failure getting primary key"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - auto pk_copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)pk_buffer, actual_data_size); + auto pk_copy_size = internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)pk_buffer, actual_data_size); deserialize_buffer = pk_buffer; deserialize_size = pk_copy_size; @@ -773,32 +685,110 @@ class kv_table { return ret_val; } - bool is_unique() override { - return true; + /** + * Returns an iterator to the object with the lowest key (by this index) in the table. + * @ingroup keyvalue + * + * @return An iterator to the object with the lowest key (by this index) in the table. + */ + iterator begin() { + uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); + + return {itr, static_cast(itr_stat), config}; } - using kv_table::kv_index::tbl; - using kv_table::kv_index::contract_name; - using kv_table::kv_index::prefix; - }; + /** + * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. + * @ingroup keyvalue + * + * @return An iterator referring to the `past-the-end` element. + */ + iterator end() { + return {0, kv_it_stat::iterator_end, config}; + } - class kv_non_unique_index : public kv_index { - public: - kv_non_unique_index() = default; + /** + * Returns an iterator pointing to the element with the lowest key greater than or equal to the given key. + * @ingroup keyvalue + * + * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. + */ + iterator lower_bound(const K& key) { + auto t_key = table_key(config.prefix, make_key(key)); - template - kv_non_unique_index(KF&& kf): kv_index{kf} {} + uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - template - kv_non_unique_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} + if (static_cast(itr_stat) == kv_it_stat::iterator_end) { + internal_use_do_not_use::kv_it_destroy(itr); + return end(); + } - using kv_table::kv_index::tbl; + return {itr, static_cast(itr_stat), config}; + } - bool is_unique() override { - return false; + /** + * Returns an iterator pointing to the first element greater than the given key. + * @ingroup keyvalue + * + * @return An iterator pointing to the element with the highest key less than or equal to the given key. + */ + iterator upper_bound(const K& key) { + auto t_key = table_key(config.prefix, make_key(key)); + + uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); + + iterator it{itr, static_cast(itr_stat), config}; + + auto cmp = it.key_compare(t_key); + if (cmp == 0) { + ++it; + } + + return it; } - }; + /** + * Returns a vector of objects that fall between the specifed range. The range is inclusive, exclusive. + * @ingroup keyvalue + * + * @param begin - The beginning of the range. + * @param end - The end of the range. + * @return A vector containing all the objects that fall between the range. + */ + std::vector range(const K& b, const K& e) { + auto begin_itr = lower_bound(b); + auto end_itr = lower_bound(e); + + if (begin_itr == end_itr || begin_itr > end_itr) { + return {}; + } + + std::vector return_values; + + iterator itr = std::move(begin_itr); + while(itr < end_itr) { + return_values.push_back(itr.value()); + ++itr; + } + + return return_values; + } + + void setup() override { + prefix = make_prefix(table_name, index_name); + config = { + .db_name = tbl->db_name, + .contract_name = contract_name, + .index_name = index_name, + .primary_index_name = tbl->primary_index->index_name, + .prefix = prefix + }; + + } + }; /** * @ingroup keyvalue @@ -807,18 +797,8 @@ class kv_table { * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. * A null_kv_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. */ - class null_kv_index : public kv_index { - public: - template - null_kv_index(KF&& kf): kv_index{kf} {} - - template - null_kv_index(eosio::name name, KF&& kf) : kv_index{name, kf} {} - bool is_unique() override { - return false; - } - }; + class null_index{}; /** * Puts a value into the table. If the value already exists, it updates the existing entry. @@ -832,7 +812,7 @@ class kv_table { T old_value; auto primary_key = primary_index->get_key(value); - auto tbl_key = table_key(make_prefix(table_name, primary_index->name), primary_key); + auto tbl_key = table_key(make_prefix(table_name, primary_index->index_name), primary_key); auto primary_key_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), value_size); if (primary_key_found) { @@ -847,42 +827,29 @@ class kv_table { } for (const auto& idx : secondary_indices) { - key_type sec_key; - - if (idx->is_unique()) { - sec_key = idx->get_key(value); - auto sec_tbl_key = table_key(make_prefix(table_name, idx->name), sec_key); - auto sec_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), value_size); - - if (!primary_key_found) { - eosio::check(!sec_found, "Attempted to store an existing unique secondary index."); - } else if (sec_found) { - void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); - - eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing unique secondary index."); - auto res = memcmp(buffer, tbl_key.data(), copy_size); - eosio::check(res == 0, "Attempted to update an existing unique secondary index."); - - if (copy_size > detail::max_stack_buffer_size) { - free(buffer); - } - } + auto sec_tbl_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(value)); + auto sec_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), value_size); - if (primary_key_found) { - auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); - } - } else { - if (primary_key_found) { - auto old_sec_key = table_key(make_prefix(table_name, idx->name), idx->get_key(old_value) + primary_index->get_key(old_value)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + if (!primary_key_found) { + eosio::check(!sec_found, "Attempted to store an existing secondary index."); + } else if (sec_found) { + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); + + eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing secondary index."); + auto res = memcmp(buffer, tbl_key.data(), copy_size); + eosio::check(res == 0, "Attempted to update an existing secondary index."); + + if (copy_size > detail::max_stack_buffer_size) { + free(buffer); } + } - sec_key = idx->get_key(value) + primary_index->get_key(value); + if (primary_key_found) { + auto old_sec_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); } - auto sec_tbl_key = table_key(make_prefix(table_name, idx->name), sec_key); internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); } @@ -906,33 +873,71 @@ class kv_table { * * @param key - The key of the value to be removed. */ - template - void erase(const K& key) { - auto primary_value = primary_index->get(key); + void erase(const T& value) { + uint32_t value_size; - if (!primary_value) { + auto primary_key = primary_index->get_key(value); + auto tbl_key = table_key(make_prefix(table_name, primary_index->index_name), primary_key); + auto primary_key_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), value_size); + + if (!primary_key_found) { return; } - auto k = table_key(make_prefix(table_name, primary_index->name), make_key(key)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, k.data(), k.size()); + for (const auto& idx : secondary_indices) { + auto sec_tbl_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size()); + } - for (auto& idx : secondary_indices) { - key_type sk; + internal_use_do_not_use::kv_erase(db_name, contract_name.value, tbl_key.data(), tbl_key.size()); + } - if (idx->is_unique()) { - sk = idx->get_key(*primary_value); - } else { - sk = idx->get_key(*primary_value) + make_key(key); - } +protected: + kv_table() = default; - auto skey = table_key(make_prefix(table_name, idx->name), sk); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, skey.data(), skey.size()); + template + void setup_indices(uint64_t index_name, bool is_named, null_index* index, Indices... indices) { + ++index_name; + if constexpr (sizeof...(indices) > 0) { + setup_indices(index_name, is_named, indices...); } } -protected: - kv_table() = default; + template + void setup_indices(uint64_t index_name, bool is_named, I index, Indices... indices) { + if (is_named) { + eosio::check(index->index_name.value > 0, "All indices must be named if one is named."); + } else { + eosio::check(index->index_name.value <= 0, "All indices must be named if one is named."); + index->index_name = eosio::name{index_name}; + } + + index->contract_name = contract_name; + index->table_name = table_name; + index->tbl = this; + + index->setup(); + secondary_indices.push_back(index); + ++index_name; + setup_indices(index_name, is_named, indices...); + } + + template + void setup_indices(uint64_t index_name, bool is_named, I index) { + if (is_named) { + eosio::check(index->index_name.value > 0, "All indices must be named if one is named."); + } else { + eosio::check(index->index_name.value <= 0, "All indices must be named if one is named."); + index->index_name = eosio::name{index_name}; + } + + index->contract_name = contract_name; + index->table_name = table_name; + index->tbl = this; + + index->setup(); + secondary_indices.push_back(index); + } /** * Initializes a key value table. This method is intended to be called in the constructor of the user defined table class. @@ -944,8 +949,8 @@ class kv_table { * @param contract - the name of the contract this table is associated with * @param indices - a list of 1 or more indices to add to the table */ - template - void init(eosio::name contract, eosio::name table, eosio::name db, Indices indices) { + template + void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex prim_index, SecondaryIndices... indices) { contract_name = contract; table_name = table; db_name = db.value; @@ -953,46 +958,23 @@ class kv_table { bool is_named = false; uint64_t index_name = 1; - auto& primary = get<0>(*indices); - - eosio::check(primary.is_unique(), "primary index should be kv_unique_index"); - - primary_index = (kv_unique_index*)&primary; + primary_index = prim_index; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; - if (primary_index->name.value > 0) { + if (primary_index->index_name.value > 0) { is_named = true; } else { - primary_index->name = eosio::name{index_name}; + primary_index->index_name = eosio::name{index_name}; + ++index_name; } - primary_index->set_prefix(); - ++index_name; - - for_each_field(*indices, [&](auto& idx) { - if (idx.name != primary.name) { - kv_index* si = &idx; - si->contract_name = contract_name; - si->table_name = table_name; - si->tbl = this; - - if (is_named) { - eosio::check(si->name.value > 0, "All indices must be named if one is named."); - } else { - eosio::check(si->name.value <= 0, "All indices must be named if one is named."); - si->name = eosio::name{index_name}; - } - si->set_prefix(); - secondary_indices.push_back(si); - ++index_name; - } - }); + primary_index->setup(); - // Makes sure the indexes are run in the correct order. - // This is mainly useful for debugging, this probably could be deleted. - std::reverse(std::begin(secondary_indices), std::end(secondary_indices)); + if constexpr (sizeof...(indices) > 0) { + setup_indices(index_name, is_named, indices...); + } } private: @@ -1000,36 +982,9 @@ class kv_table { eosio::name table_name; uint64_t db_name; - - kv_unique_index* primary_index; + kv_index* primary_index; std::vector secondary_indices; - template - constexpr static auto& get(U& u) { - constexpr size_t kv_index_size = sizeof(kv_index); - static_assert(sizeof(U) % kv_index_size == 0); - kv_index* indices = (kv_index*)(&u); - return indices[I]; - } - - template - constexpr static void for_each_field(U& u, F&& f) { - f(get(u)); - if constexpr (S <= 0) { - return; - } else { - for_each_field(u, f); - } - } - - template - constexpr static void for_each_field(U& u, F&& f) { - constexpr size_t kv_index_size = sizeof(kv_index); - static_assert(sizeof(U) % kv_index_size == 0); - constexpr size_t num_elems = (sizeof(U) / sizeof(kv_index)) - 1; - for_each_field(u, f); - } - template static void serialize(const V& value, void* buffer, size_t size) { datastream ds((char*)buffer, size); diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 3ff8886b59..5a9ab375aa 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -115,9 +115,6 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), eosio_assert_message_exception, eosio_assert_message_is("All indices must be named if one is named.")); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr3), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("primary index should be kv_unique_index")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { @@ -131,6 +128,7 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() +/* TODO: These are probably not necessary anymore. BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { create_accounts( { N(kvtest) } ); produce_block(); @@ -168,4 +166,5 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_unique_secondary_error, tester) try { eosio_assert_message_exception, eosio_assert_message_is("Attempted to update an existing unique secondary index.")); } FC_LOG_AND_RETHROW() +*/ BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index b95fceac19..e00d3be746 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -36,21 +36,19 @@ struct my_struct { }; struct my_table : eosio::kv_table { - struct { - kv_unique_index tname{&my_struct::tname}; - kv_non_unique_index tstring{&my_struct::tstring}; - kv_non_unique_index tui64{&my_struct::tui64}; - kv_non_unique_index ti32{&my_struct::ti32}; - kv_non_unique_index tui128{&my_struct::tui128}; - kv_non_unique_index tfloat{&my_struct::tfloat}; - kv_non_unique_index tdouble{&my_struct::tdouble}; - kv_non_unique_index tstruct{&my_struct::tstruct}; - kv_non_unique_index ttuple{&my_struct::ttuple}; - kv_non_unique_index itstring{&my_struct::itstring}; - } index; + index tname{&my_struct::tname}; + index tstring{&my_struct::tstring}; + index tui64{&my_struct::tui64}; + index ti32{&my_struct::ti32}; + index tui128{&my_struct::tui128}; + index tfloat{&my_struct::tfloat}; + index tdouble{&my_struct::tdouble}; + index tstruct{&my_struct::tstruct}; + index> ttuple{&my_struct::ttuple}; + index itstring{&my_struct::itstring}; my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &tname, &tstring, &tui64, &ti32, &tui128, &tfloat, &tdouble, &tstruct, &ttuple, &itstring); } }; @@ -58,9 +56,11 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { public: using contract::contract; - void check_index(my_table::kv_index& idx, const std::vector& expected) { + template + void check_index(I& idx, const std::vector& expected) { auto end_itr = idx.end(); auto itr = idx.begin(); + for (const auto& expect : expected) { eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value() == expect, "Got the wrong value"); @@ -139,60 +139,60 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { [[eosio::action]] void makekeyname() { my_table t{"kvtest"_n}; - check_index(t.index.tname, {s2, s5, s1, s4, s3}); + check_index(t.tname, {s2, s5, s1, s4, s3}); } [[eosio::action]] void makekeystr() { my_table t{"kvtest"_n}; - check_index(t.index.tstring, {s2, s5, s1, s3, s4}); + check_index(t.tstring, {s2, s5, s1, s3, s4}); } [[eosio::action]] void makekeyistr() { my_table t{"kvtest"_n}; - check_index(t.index.itstring, {s1, s2, s3, s4, s5}); + check_index(t.itstring, {s1, s2, s3, s4, s5}); } [[eosio::action]] void makekeyuill() { my_table t{"kvtest"_n}; - check_index(t.index.tui64, {s5, s4, s3, s2, s1}); + check_index(t.tui64, {s5, s4, s3, s2, s1}); } [[eosio::action]] void makekeyil() { my_table t{"kvtest"_n}; - check_index(t.index.ti32, {s3, s2, s1, s4, s5}); + check_index(t.ti32, {s3, s2, s1, s4, s5}); } [[eosio::action]] void makekeyuilll() { my_table t{"kvtest"_n}; - check_index(t.index.tui128, {s2, s1, s5, s4, s3}); + check_index(t.tui128, {s2, s1, s5, s4, s3}); } [[eosio::action]] void makekeyflt() { my_table t{"kvtest"_n}; - check_index(t.index.tfloat, {s5, s4, s1, s2, s3}); + check_index(t.tfloat, {s5, s4, s1, s2, s3}); } [[eosio::action]] void makekeydbl() { my_table t{"kvtest"_n}; - check_index(t.index.tdouble, {s5, s4, s1, s2, s3}); + check_index(t.tdouble, {s5, s4, s1, s2, s3}); } [[eosio::action]] void makekeystct() { my_table t{"kvtest"_n}; - check_index(t.index.tstruct, {s1, s3, s2, s4, s5}); + check_index(t.tstruct, {s1, s3, s2, s4, s5}); } [[eosio::action]] void makekeytup() { my_table t{"kvtest"_n}; - check_index(t.index.ttuple, {s1, s2, s3, s4, s5}); + check_index(t.ttuple, {s1, s2, s3, s4, s5}); } }; diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 51c9112cc1..50fbe2d12e 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -15,70 +15,50 @@ struct my_struct { }; struct my_table : eosio::kv_table { - struct { - kv_unique_index primary_key{&my_struct::primary_key}; - kv_non_unique_index foo{&my_struct::foo}; - kv_unique_index bar{&my_struct::bar}; - kv_non_unique_index baz{&my_struct::baz}; - } index; + index primary_key{&my_struct::primary_key}; + index foo{&my_struct::foo}; + index bar{&my_struct::bar}; + index baz{&my_struct::baz}; my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo, &bar, &baz); } }; struct my_table2 : eosio::kv_table { - struct { - kv_unique_index primary_key{&my_struct::primary_key}; - null_kv_index nullptr_2{&my_struct::foo}; - kv_non_unique_index bar{&my_struct::bar}; - } index; + index primary_key{&my_struct::primary_key}; + null_index nullptr_2; + index bar{&my_struct::bar}; my_table2(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &nullptr_2, &bar); } }; struct my_table_idx : eosio::kv_table { - struct { - kv_unique_index primary_key{"prim"_n, &my_struct::primary_key}; - kv_non_unique_index foo{"f"_n, &my_struct::foo}; - } index; + index primary_key{"prim"_n, &my_struct::primary_key}; + index foo{"f"_n, &my_struct::foo}; my_table_idx(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); } }; struct my_table_idx_err : eosio::kv_table { - struct { - kv_unique_index primary_key{"prim"_n, &my_struct::primary_key}; - kv_non_unique_index foo{&my_struct::foo}; - } index; + index primary_key{"prim"_n, &my_struct::primary_key}; + index foo{&my_struct::foo}; my_table_idx_err(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); } }; struct my_table_idx_err_2 : eosio::kv_table { - struct { - kv_unique_index primary_key{&my_struct::primary_key}; - kv_non_unique_index foo{"f"_n, &my_struct::foo}; - } index; + index primary_key{&my_struct::primary_key}; + index foo{"f"_n, &my_struct::foo}; my_table_idx_err_2(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); - } -}; - -struct my_table_idx_err_3 : eosio::kv_table { - struct { - kv_non_unique_index primary_key{&my_struct::primary_key}; - } index; - - my_table_idx_err_3(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); } }; @@ -95,25 +75,25 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .primary_key = "alice"_n, .foo = "C", .bar = 4, - .baz = 1 + .baz = 3 }; my_struct s3{ .primary_key = "john"_n, .foo = "e", .bar = 3, - .baz = 1 + .baz = 4 }; my_struct s4{ .primary_key = "joe"_n, .foo = "g", .bar = 2, - .baz = 1 + .baz = 5 }; my_struct s5{ .primary_key = "billy"_n, .foo = "I", .bar = 1, - .baz = 1 + .baz = 6 }; [[eosio::action]] @@ -142,23 +122,18 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { my_table_idx_err_2 t{"kvtest"_n}; } - [[eosio::action]] - void indiceserr3() { - my_table_idx_err_3 t{"kvtest"_n}; - } - [[eosio::action]] void iteration() { my_table t{"kvtest"_n}; - auto foo_begin_itr = t.index.foo.begin(); - auto foo_end_itr = t.index.foo.end(); + auto foo_begin_itr = t.foo.begin(); + auto foo_end_itr = t.foo.end(); - auto bar_begin_itr = t.index.bar.begin(); - auto bar_end_itr = t.index.bar.end(); + auto bar_begin_itr = t.bar.begin(); + auto bar_end_itr = t.bar.end(); - auto foo_itr = t.index.foo.begin(); - auto bar_itr = t.index.bar.begin(); + auto foo_itr = t.foo.begin(); + auto bar_itr = t.bar.begin(); eosio::check(foo_itr != foo_end_itr, "Should not be the end"); eosio::check(bar_itr != bar_end_itr, "Should not be the end"); @@ -216,12 +191,13 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(bar_itr == bar_begin_itr, "Should be the beginning"); } + /* TODO: These are probably not necessary anymore [[eosio::action]] void range() { my_table t{"kvtest"_n}; std::vector expected = {s2, s5, s4, s3, s1}; - auto actual = t.index.baz.range(1l, 3l); + auto actual = t.baz.range(1l, 3l); eosio::check(actual == expected, "range did not return expected vector"); } @@ -268,4 +244,5 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .baz = 3 }); } + */ }; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 4f626b6cdc..b496ec825b 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -22,29 +22,27 @@ struct my_struct_v2 { DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) struct my_table_v : eosio::kv_table> { - struct { - kv_unique_index primary_key{[](const auto& obj) { - return std::visit([&](auto&& a) { - using V = std::decay_t; - if constexpr(std::is_same_v) { - return a.full_name; - } else if constexpr(std::is_same_v) { - return a.first_name + " : " + a.last_name; - } else { - eosio::check(false, "BAD TYPE"); - return ""; - } - }, *obj); - }}; - kv_non_unique_index age{[](const auto& obj) { - return std::visit([&](auto&& a) { - return a.age; - }, *obj); - }}; - } index; + index primary_key{[](const auto& obj) { + return std::visit([&](auto&& a) { + using V = std::decay_t; + if constexpr(std::is_same_v) { + return a.full_name; + } else if constexpr(std::is_same_v) { + return a.first_name + " : " + a.last_name; + } else { + eosio::check(false, "BAD TYPE"); + return ""; + } + }, *obj); + }}; + index age{[](const auto& obj) { + return std::visit([&](auto&& a) { + return a.age; + }, *obj); + }}; my_table_v(eosio::name contract_name) { - init(contract_name, "testtable2"_n, "eosio.kvram"_n, &index); + init(contract_name, "testtable2"_n, "eosio.kvram"_n, &primary_key, &age); } }; @@ -82,25 +80,25 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void find() { my_table t{"kvtest"_n}; - my_table::iterator end_itr = t.index.primary_key.end(); + my_table::iterator end_itr = t.primary_key.end(); - auto itr = t.index.primary_key.find("bob"_n); + auto itr = t.primary_key.find("bob"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.find("joe"_n); + itr = t.primary_key.find("joe"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.find("alice"_n); + itr = t.primary_key.find("alice"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.find("john"_n); + itr = t.primary_key.find("john"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.find("billy"_n); + itr = t.primary_key.find("billy"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong primary_key"); } @@ -108,59 +106,59 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void finderror() { my_table t{"kvtest"_n}; - auto itr = t.index.primary_key.find("larry"_n); + auto itr = t.primary_key.find("larry"_n); auto val = itr.value(); } [[eosio::action]] void get() { my_table t{"kvtest"_n}; - auto end_itr = t.index.primary_key.end(); + auto end_itr = t.primary_key.end(); - auto val = t.index.primary_key.get("bob"_n); + auto val = t.primary_key.get("bob"_n); eosio::check(val->primary_key == "bob"_n, "Got the wrong value"); - val = t.index.primary_key.get("william"_n); + val = t.primary_key.get("william"_n); eosio::check(!val, "Should not have gotten a value"); } [[eosio::action]] void bounds() { my_table t{"kvtest"_n}; - auto end_itr = t.index.primary_key.end(); + auto end_itr = t.primary_key.end(); - auto itr = t.index.primary_key.lower_bound("bob"_n); + auto itr = t.primary_key.lower_bound("bob"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.lower_bound("catherine"_n); + itr = t.primary_key.lower_bound("catherine"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.lower_bound("william"_n); + itr = t.primary_key.lower_bound("william"_n); eosio::check(itr == end_itr, "Should be the end"); - itr = t.index.primary_key.upper_bound("billy"_n); + itr = t.primary_key.upper_bound("billy"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.upper_bound("ian"_n); + itr = t.primary_key.upper_bound("ian"_n); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); - itr = t.index.primary_key.upper_bound("john"_n); + itr = t.primary_key.upper_bound("john"_n); eosio::check(itr == end_itr, "Should be the end"); } [[eosio::action]] void iteration() { my_table t{"kvtest"_n}; - auto begin_itr = t.index.primary_key.begin(); - auto end_itr = t.index.primary_key.end(); + auto begin_itr = t.primary_key.begin(); + auto end_itr = t.primary_key.end(); // operator++ // ---------- - auto itr = t.index.primary_key.begin(); + auto itr = t.primary_key.begin(); eosio::check(itr != end_itr, "Should not be the end"); eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong beginning"); ++itr; @@ -195,14 +193,14 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { [[eosio::action]] void itrerror1() { my_table t{"kvtest"_n}; - auto end_itr = t.index.primary_key.end(); + auto end_itr = t.primary_key.end(); ++end_itr; } [[eosio::action]] void itrerror2() { my_table t{"kvtest"_n}; - auto begin_itr = t.index.primary_key.begin(); + auto begin_itr = t.primary_key.begin(); --begin_itr; } @@ -211,33 +209,34 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { my_table t{"kvtest"_n}; std::vector expected{s, s4}; - auto vals = t.index.primary_key.range("bob"_n, "john"_n); + auto vals = t.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); expected = {}; - vals = t.index.primary_key.range("bob"_n, "bob"_n); + vals = t.primary_key.range("bob"_n, "bob"_n); eosio::check(vals == expected, "range did not return expected vector"); - vals = t.index.primary_key.range("chris"_n, "joe"_n); + vals = t.primary_key.range("chris"_n, "joe"_n); eosio::check(vals == expected, "range did not return expected vector"); - vals = t.index.primary_key.range("joe"_n, "alice"_n); + vals = t.primary_key.range("joe"_n, "alice"_n); eosio::check(vals == expected, "range did not return expected vector"); expected = {s2, s5, s, s4, s3}; - vals = t.index.primary_key.range("alice"_n, "william"_n); + vals = t.primary_key.range("alice"_n, "william"_n); eosio::check(vals == expected, "range did not return expected vector"); } [[eosio::action]] void erase() { my_table t{"kvtest"_n}; - auto end_itr = t.index.primary_key.end(); + auto end_itr = t.primary_key.end(); - t.erase("joe"_n); - auto itr = t.index.primary_key.find("joe"_n); + auto v = *(t.primary_key.get("joe"_n)); + t.erase(v); + auto itr = t.primary_key.find("joe"_n); eosio::check(itr == end_itr, "key was not properly deleted"); std::vector expected = {s}; - auto vals = t.index.primary_key.range("bob"_n, "john"_n); + auto vals = t.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } @@ -265,16 +264,16 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { t.put(s2); t.put(s3); - auto itr = t.index.primary_key.find("Dan Larimer"); + auto itr = t.primary_key.find("Dan Larimer"); auto val = itr.value(); auto vval = std::get(val); eosio::check(vval.age == 25, "wrong value"); - auto val2 = t.index.primary_key.get("Brendan Blumer"); + auto val2 = t.primary_key.get("Brendan Blumer"); auto vval2 = std::get(*val2); eosio::check(vval2.age == 24, "wrong value"); - auto val3 = t.index.primary_key.get("Bob : Smith"); + auto val3 = t.primary_key.get("Bob : Smith"); auto vval3 = std::get(*val3); eosio::check(vval3.age == 30, "wrong value"); } From 54225f7290f53cb2008350cc2851e04e24cf358b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 09:25:12 -0500 Subject: [PATCH 254/659] Add small unit test example of non_unique --- tests/integration/kv_tests.cpp | 41 +------ .../kv_multiple_indices_tests.cpp | 103 +++++++----------- 2 files changed, 41 insertions(+), 103 deletions(-) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 5a9ab375aa..f63852cc1b 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -128,43 +128,10 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() -/* TODO: These are probably not necessary anymore. -BOOST_FIXTURE_TEST_CASE(multi_tests_range, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(range), N(kvtest), {}); +BOOST_FIXTURE_TEST_CASE(multi_tests_non_unique, tester) try { + TESTER tester; + setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); + tester.push_action(N(kvtest), N(nonunique), N(kvtest), {}); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(multi_tests_unique_secondary, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(uniqsecidx), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - -BOOST_FIXTURE_TEST_CASE(multi_tests_unique_secondary_error, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(usecidxerr1), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Attempted to store an existing unique secondary index.")); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(usecidxerr2), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Attempted to update an existing unique secondary index.")); -} FC_LOG_AND_RETHROW() -*/ BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 50fbe2d12e..7084c270e0 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -4,13 +4,18 @@ struct my_struct { eosio::name primary_key; std::string foo; uint64_t bar; - int32_t baz; + + std::string fullname; + uint32_t age; + + std::tuple non_unique_name() const { return {fullname, age}; } bool operator==(const my_struct b) const { return primary_key == b.primary_key && foo == b.foo && bar == b.bar && - baz == b.baz; + fullname == b.fullname && + age == b.age; } }; @@ -18,10 +23,11 @@ struct my_table : eosio::kv_table { index primary_key{&my_struct::primary_key}; index foo{&my_struct::foo}; index bar{&my_struct::bar}; - index baz{&my_struct::baz}; + + index> non_unique_name{&my_struct::non_unique_name}; my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo, &bar, &baz); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo, &bar, &non_unique_name); } }; @@ -69,31 +75,36 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { .primary_key = "bob"_n, .foo = "a", .bar = 5, - .baz = 2 + .fullname = "Bob Smith", + .age = 25 }; my_struct s2{ .primary_key = "alice"_n, .foo = "C", .bar = 4, - .baz = 3 + .fullname = "Alice Smith", + .age = 100 }; my_struct s3{ .primary_key = "john"_n, .foo = "e", .bar = 3, - .baz = 4 + .fullname = "John Smith", + .age = 42 }; my_struct s4{ .primary_key = "joe"_n, .foo = "g", .bar = 2, - .baz = 5 + .fullname = "Bob Smith", + .age = 47 }; my_struct s5{ .primary_key = "billy"_n, .foo = "I", .bar = 1, - .baz = 6 + .fullname = "Bob Smith", + .age = 26 }; [[eosio::action]] @@ -137,28 +148,28 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(foo_itr != foo_end_itr, "Should not be the end"); eosio::check(bar_itr != bar_end_itr, "Should not be the end"); - eosio::check(foo_itr.value().foo == s2.foo, "Got the wrong value"); - eosio::check(bar_itr.value().bar == s5.bar, "Got the wrong value"); + eosio::check(foo_itr.value() == s2, "Got the wrong value"); + eosio::check(bar_itr.value() == s5, "Got the wrong value"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value().foo == s5.foo, "Got the wrong value"); - eosio::check(bar_itr.value().bar == s4.bar, "Got the wrong value"); + eosio::check(foo_itr.value() == s5, "Got the wrong value"); + eosio::check(bar_itr.value() == s4, "Got the wrong value"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value().foo == s1.foo, "Got the wrong value"); - eosio::check(bar_itr.value().bar == s3.bar, "Got the wrong value"); + eosio::check(foo_itr.value() == s1, "Got the wrong value"); + eosio::check(bar_itr.value() == s3, "Got the wrong value"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value().foo == s3.foo, "Got the wrong value"); - eosio::check(bar_itr.value().bar == s2.bar, "Got the wrong value"); + eosio::check(foo_itr.value() == s3, "Got the wrong value"); + eosio::check(bar_itr.value() == s2, "Got the wrong value"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value().foo == s4.foo, "Got the wrong value"); - eosio::check(bar_itr.value().bar == s1.bar, "Got the wrong value"); + eosio::check(foo_itr.value() == s4, "Got the wrong value"); + eosio::check(bar_itr.value() == s1, "Got the wrong value"); ++foo_itr; ++bar_itr; @@ -191,58 +202,18 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(bar_itr == bar_begin_itr, "Should be the beginning"); } - /* TODO: These are probably not necessary anymore - [[eosio::action]] - void range() { - my_table t{"kvtest"_n}; - - std::vector expected = {s2, s5, s4, s3, s1}; - auto actual = t.baz.range(1l, 3l); - - eosio::check(actual == expected, "range did not return expected vector"); - } - [[eosio::action]] - void uniqsecidx() { + void nonunique() { my_table t{"kvtest"_n}; - t.put({ - .primary_key = "bob"_n, - .foo = "testing", - .bar = 5, - .baz = 3 - }); - - t.put({ - .primary_key = "bob"_n, - .foo = "testing", - .bar = 100, - .baz = 3 - }); - } - - [[eosio::action]] - void usecidxerr1() { - my_table t{"kvtest"_n}; + std::vector expected{s1, s5, s4}; + auto vals = t.non_unique_name.range({"Bob Smith", 0}, {"Bob Smith", UINT_MAX}); - t.put({ - .primary_key = "carl"_n, - .foo = "testing", - .bar = 5, - .baz = 3 - }); - } + eosio::check(vals == expected, "Range did not return the expected vector."); - [[eosio::action]] - void usecidxerr2() { - my_table t{"kvtest"_n}; + expected = {s1, s5}; + vals = t.non_unique_name.range({"Bob Smith", 0}, {"Bob Smith", 27}); - t.put({ - .primary_key = "alice"_n, - .foo = "testing", - .bar = 5, - .baz = 3 - }); + eosio::check(vals == expected, "Range did not return the expected vector."); } - */ }; From f6e9d55569e0cfc0166dfe2a7ff886f98705a336 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 08:55:25 -0500 Subject: [PATCH 255/659] Update for latest nodeos --- tests/integration/contracts.hpp.in | 3 + tests/integration/kv_make_key_tests.cpp | 24 ++- tests/integration/kv_tests.cpp | 168 ++++++++---------- tests/unit/test_contracts/CMakeLists.txt | 2 + .../test_contracts/kv_bios/CMakeLists.txt | 6 + tests/unit/test_contracts/kv_bios/kv_bios.abi | 96 ++++++++++ tests/unit/test_contracts/kv_bios/kv_bios.cpp | 44 +++++ 7 files changed, 243 insertions(+), 100 deletions(-) create mode 100644 tests/unit/test_contracts/kv_bios/CMakeLists.txt create mode 100644 tests/unit/test_contracts/kv_bios/kv_bios.abi create mode 100644 tests/unit/test_contracts/kv_bios/kv_bios.cpp diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 65652e315a..0ec9407468 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -28,6 +28,9 @@ struct contracts { static std::vector kv_make_key_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.wasm"); } static std::vector kv_make_key_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.abi"); } + static std::vector kv_bios_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_bios.wasm"); } + static std::vector kv_bios_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_bios.abi"); } + static std::vector action_results_test_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/action_results_test.wasm"); } static std::vector action_results_test_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/action_results_test.abi"); } }; diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp index 1eb480e325..d789396d02 100644 --- a/tests/integration/kv_make_key_tests.cpp +++ b/tests/integration/kv_make_key_tests.cpp @@ -1,25 +1,33 @@ #include #include #include +#include #include using namespace eosio; using namespace eosio::testing; +using mvo = fc::mutable_variant_object; + BOOST_AUTO_TEST_SUITE(key_value_make_key_tests) void make_key_test(name test_name) { - tester t; + tester t; + + t.create_accounts( { N(kvtest) } ); + t.produce_block(); + t.set_code( N(kvtest), contracts::kv_make_key_tests_wasm() ); + t.set_abi( N(kvtest), contracts::kv_make_key_tests_abi().data() ); + t.produce_blocks(); - t.create_accounts( { N(kvtest) } ); - t.produce_block(); - t.set_code( N(kvtest), contracts::kv_make_key_tests_wasm() ); - t.set_abi( N(kvtest), contracts::kv_make_key_tests_abi().data() ); - t.produce_blocks(); + t.set_code(config::system_account_name, contracts::kv_bios_wasm()); + t.set_abi(config::system_account_name, contracts::kv_bios_abi().data()); - t.push_action(N(kvtest), N(setup), N(kvtest), {}); - t.push_action(N(kvtest), test_name, N(kvtest), {}); + auto data = mvo()("k", 1024)("v", 1024*1024)("i", 256); + t.push_action(config::system_account_name, N(ramkvlimits), config::system_account_name, data); + t.push_action(N(kvtest), N(setup), N(kvtest), {}); + t.push_action(N(kvtest), test_name, N(kvtest), {}); } BOOST_AUTO_TEST_CASE(makekeyname) try { diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index f63852cc1b..4d26f32764 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -1,131 +1,115 @@ #include -#include + #include +#include + +#include #include using namespace eosio; using namespace eosio::testing; -BOOST_AUTO_TEST_SUITE(key_value_tests) +using mvo = fc::mutable_variant_object; -BOOST_FIXTURE_TEST_CASE(single_tests_find, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); +#ifdef NON_VALIDATING_TEST +#define TESTER tester +#else +#define TESTER validating_tester +#endif - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(find), N(kvtest), {}); +void setup(TESTER& tester, std::vector wasm, std::vector abi) { + tester.create_accounts( { N(kvtest) } ); + tester.produce_block(); + tester.set_code( N(kvtest), wasm ); + tester.set_abi( N(kvtest), abi.data() ); + tester.produce_blocks(); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(finderror), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("Cannot read end iterator")); -} FC_LOG_AND_RETHROW() + tester.set_code(config::system_account_name, contracts::kv_bios_wasm()); + tester.set_abi(config::system_account_name, contracts::kv_bios_abi().data()); + + auto data = mvo()("k", 1024)("v", 1024*1024)("i", 256); + tester.push_action(config::system_account_name, N(ramkvlimits), config::system_account_name, data); + tester.push_action(N(kvtest), N(setup), N(kvtest), {}); -BOOST_FIXTURE_TEST_CASE(single_tests_get, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); + tester.produce_blocks(); +} + +BOOST_AUTO_TEST_SUITE(key_value_tests) + +BOOST_AUTO_TEST_CASE(single_tests_find) try { + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(find), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(finderror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Cannot read end iterator")); +} FC_LOG_AND_RETHROW() - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(get), N(kvtest), {}); +BOOST_AUTO_TEST_CASE(single_tests_get) try { + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(get), N(kvtest), {}); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(bounds), N(kvtest), {}); + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(bounds), N(kvtest), {}); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_iteration, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(iteration), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(itrerror1), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("cannot increment end iterator")); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(itrerror2), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("decremented past the beginning")); + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(iteration), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(itrerror1), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("cannot increment end iterator")); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(itrerror2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("decremented past the beginning")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_range, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(range), N(kvtest), {}); + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(range), N(kvtest), {}); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(erase), N(kvtest), {}); + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(erase), N(kvtest), {}); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_variant, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_single_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_single_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(vriant), N(kvtest), {}); + TESTER tester; + setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); + tester.push_action(N(kvtest), N(vriant), N(kvtest), {}); } FC_LOG_AND_RETHROW() // Multi // ----- BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(indices), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("All indices must be named if one is named.")); - BOOST_CHECK_EXCEPTION(push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("All indices must be named if one is named.")); + TESTER tester; + setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); + tester.push_action(N(kvtest), N(indices), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(indiceserr), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("All indices must be named if one is named.")); + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("All indices must be named if one is named.")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { - create_accounts( { N(kvtest) } ); - produce_block(); - set_code( N(kvtest), contracts::kv_multi_tests_wasm() ); - set_abi( N(kvtest), contracts::kv_multi_tests_abi().data() ); - produce_blocks(); - - push_action(N(kvtest), N(setup), N(kvtest), {}); - push_action(N(kvtest), N(iteration), N(kvtest), {}); + TESTER tester; + setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); + tester.push_action(N(kvtest), N(iteration), N(kvtest), {}); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multi_tests_non_unique, tester) try { diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 83040e6be6..3c75e5340a 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -9,8 +9,10 @@ add_contract(kv_multiple_indices_tests kv_multiple_indices_tests kv_multiple_ind add_contract(kv_make_key_tests kv_make_key_tests kv_make_key_tests.cpp) add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c capi/print.c capi/privileged.c capi/system.c capi/transaction.c) +add_contract(kv_bios kv_bios kv_bios/kv_bios.cpp) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/simple_wrong.abi ${CMAKE_CURRENT_BINARY_DIR}/simple_wrong.abi COPYONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/capi/capi_tests.abi ${CMAKE_CURRENT_BINARY_DIR}/capi_tests.abi COPYONLY ) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios/kv_bios.abi ${CMAKE_CURRENT_BINARY_DIR}/kv_bios.abi COPYONLY ) target_link_libraries(old_malloc_tests PUBLIC --use-freeing-malloc) diff --git a/tests/unit/test_contracts/kv_bios/CMakeLists.txt b/tests/unit/test_contracts/kv_bios/CMakeLists.txt new file mode 100644 index 0000000000..59c20b8c25 --- /dev/null +++ b/tests/unit/test_contracts/kv_bios/CMakeLists.txt @@ -0,0 +1,6 @@ +if( EOSIO_COMPILE_TEST_CONTRACTS ) + add_contract( kv_bios kv_bios kv_bios.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.wasm ${CMAKE_CURRENT_BINARY_DIR}/kv_bios.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.abi ${CMAKE_CURRENT_BINARY_DIR}/kv_bios.abi COPYONLY ) +endif() diff --git a/tests/unit/test_contracts/kv_bios/kv_bios.abi b/tests/unit/test_contracts/kv_bios/kv_bios.abi new file mode 100644 index 0000000000..c7cc890870 --- /dev/null +++ b/tests/unit/test_contracts/kv_bios/kv_bios.abi @@ -0,0 +1,96 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "diskkvlimits", + "base": "", + "fields": [ + { + "name": "k", + "type": "uint32" + }, + { + "name": "v", + "type": "uint32" + }, + { + "name": "i", + "type": "uint32" + } + ] + }, + { + "name": "ramkvlimits", + "base": "", + "fields": [ + { + "name": "k", + "type": "uint32" + }, + { + "name": "v", + "type": "uint32" + }, + { + "name": "i", + "type": "uint32" + } + ] + }, + { + "name": "setdisklimit", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "limit", + "type": "int64" + } + ] + }, + { + "name": "setramlimit", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "limit", + "type": "int64" + } + ] + } + ], + "actions": [ + { + "name": "diskkvlimits", + "type": "diskkvlimits", + "ricardian_contract": "" + }, + { + "name": "ramkvlimits", + "type": "ramkvlimits", + "ricardian_contract": "" + }, + { + "name": "setdisklimit", + "type": "setdisklimit", + "ricardian_contract": "" + }, + { + "name": "setramlimit", + "type": "setramlimit", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [] +} \ No newline at end of file diff --git a/tests/unit/test_contracts/kv_bios/kv_bios.cpp b/tests/unit/test_contracts/kv_bios/kv_bios.cpp new file mode 100644 index 0000000000..dcd627ed03 --- /dev/null +++ b/tests/unit/test_contracts/kv_bios/kv_bios.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +extern "C" __attribute__((eosio_wasm_import)) void set_resource_limit(int64_t, int64_t, int64_t); +extern "C" __attribute__((eosio_wasm_import)) uint32_t get_kv_parameters_packed(uint64_t db, void* params, uint32_t size, uint32_t max_version); +extern "C" __attribute__((eosio_wasm_import)) void set_kv_parameters_packed(uint64_t db, const void* params, uint32_t size); + +using namespace eosio; + +// Manages resources used by the kv-store +class [[eosio::contract]] kv_bios : eosio::contract { + public: + using contract::contract; + [[eosio::action]] void setdisklimit(name account, int64_t limit) { + set_resource_limit(account.value, "disk"_n.value, limit); + } + [[eosio::action]] void setramlimit(name account, int64_t limit) { + set_resource_limit(account.value, "ram"_n.value, limit); + } + [[eosio::action]] void ramkvlimits(uint32_t k, uint32_t v, uint32_t i) { + kvlimits_impl("eosio.kvram"_n, k, v, i); + } + [[eosio::action]] void diskkvlimits(uint32_t k, uint32_t v, uint32_t i) { + kvlimits_impl("eosio.kvdisk"_n, k, v, i); + } + void kvlimits_impl(name db, uint32_t k, uint32_t v, uint32_t i) { + uint32_t limits[4]; + limits[0] = 0; + limits[1] = k; + limits[2] = v; + limits[3] = i; + set_kv_parameters_packed(db.value, limits, sizeof(limits)); + int sz = get_kv_parameters_packed(db.value, nullptr, 0, 0); + std::fill_n(limits, sizeof(limits)/sizeof(limits[0]), 0xFFFFFFFFu); + check(sz == 16, "wrong kv parameters size"); + sz = get_kv_parameters_packed(db.value, limits, sizeof(limits), 0); + check(sz == 16, "wrong kv parameters result"); + check(limits[0] == 0, "wrong version"); + check(limits[1] == k, "wrong key"); + check(limits[2] == v, "wrong value"); + check(limits[3] == i, "wrong iter limit"); + } +}; From 7dee2ae9ae6f4bb0d91ae601fada4d92a77bfb22 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 10:41:27 -0500 Subject: [PATCH 256/659] Documentation update --- .../06_key_value/01_key_value_examples.md | 200 ++++++++---------- .../eosiolib/contracts/eosio/key_value.hpp | 48 ++--- 2 files changed, 110 insertions(+), 138 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index e5ecf87e40..a3cb70a64e 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -6,7 +6,7 @@ struct myrecord { std::tuple secondary_2; } -DEFINE_TABLE(mytable, myrecord, "testtable", +DEFINE_TABLE(mytable, myrecord, "testtable", "eosio.kvram", primary_key, secondary_1, secondary_2 @@ -14,38 +14,17 @@ DEFINE_TABLE(mytable, myrecord, "testtable", // The above macro results in the following class. -struct mytable : kv_table { - struct { - kv_index primary_key{&myrecord::primary_key}; - kv_index secondary_1{&myrecord::secondary_1}; - kv_index secondary_2{&myrecord::secondary_2}; - } index; +struct mytable : kv_table { + index primary_key{&myrecord::primary_key}; + index secondary_1{&myrecord::secondary_1}; + index> secondary_2{&myrecord::secondary_2}; mytable(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &secondary_1, &secondary_2); } } ``` -### make_insensitive Example: - -```cpp -struct location { - std::string city; - std::string state; - uint64_t zip_code; - - auto icity() { return eosio::make_insensitive(city); } - auto istate() { return eosio::make_insensitive(state); } -} - -DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", - icity, - istate, - zip_code -) -``` - ### kv_table Example: ```cpp #include @@ -62,32 +41,70 @@ struct address { auto full_name() { return first_name + " " + last_name; } } -struct address_table : kv_table { - struct { - kv_index account_name{&address::account_name}; - kv_index full_name{&address::full_name}; - } index; +struct address_table : kv_table { + index account_name{&myrecord::account_name}; + index full_name{&myrecord::full_name}; - addresses(eosio::name contract_name) { - init(contract_name, &index); + address_table(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &account_name, &full_name); } } class addressbook : contract { public: void myaction() { - auto addresses = address_table::open("mycontract"_n); + address_table addresses{"mycontract"_n}; } } ``` +### Using RAM vs DISK example: +```cpp +struct myrecord { + std::string primary_key; + uint64_t secondary_1; + std::tuple secondary_2; +} + +DEFINE_TABLE(myramtable, myrecord, "testramtbl", "eosio.kvram", primary_key, secondary_1, secondary_2) +DEFINE_TABLE(mydisktable, myrecord, "testdisktbl", "eosio.kvdisk", primary_key, secondary_1, secondary_2) +``` + +### kv_table::put Example: +```cpp +// This assumes the code from the class example. +void myaction() { + address_table addresses{"mycontract"_n}; + addresses.put({ + .account_name = "dan"_n, + .first_name = "Daniel", + .last_name = "Larimer", + .street = "1 EOS Way", + .city = "Blacksburg", + .state = "VA" + }); +} +``` + +### kv_table::erase Example: +```cpp +// This assumes the code from the class example. +void myaction() { + address_table addresses{"mycontract"_n}; + + auto itr = addresses.account_name.find("dan"_n); + eosio::check(itr != addresses.account_name.end()); + addresses.erase(itr.value()); +} +``` + ### iterator::value Example: ```cpp // This assumes the code from the class example. void myaction() { // add dan account to table - see put example - auto dan = addresses.index.full_name.find("Dan Larimer"); - eosio::check(dan != addresses.index.full_name.end(), "Dan Larimer is not in the table"); + auto dan = addresses.full_name.find("Dan Larimer"); + eosio::check(dan != addresses.full_name.end(), "Dan Larimer is not in the table"); eosio::check(dan.value().city == "Blacksburg", "Got the wrong value"); } ``` @@ -97,11 +114,11 @@ class addressbook : contract { // This assumes the code from the class example. void myaction() { // add dan account to table - see put example - auto itr = addresses.index.account_name.find("dan"_n); - eosio::check(itr != addresses.index.account_name.end(), "Couldn't get him."); + auto itr = addresses.account_name.find("dan"_n); + eosio::check(itr != addresses.account_name.end(), "Couldn't get him."); - auto itr = addresses.index.full_name.find("Dan Larimer"); - eosio::check(itr != addresses.index.full_name.end(), "Couldn't get him."); + auto itr = addresses.full_name.find("Dan Larimer"); + eosio::check(itr != addresses.full_name.end(), "Couldn't get him."); } ``` @@ -110,11 +127,11 @@ class addressbook : contract { // This assumes the code from the class example. void myaction() { // add dan account to table - see put example - auto itr = addresses.index.account_name.find("brendan"_n); - eosio::check(itr == addresses.index.account_name.end(), "brendan should not be in the table."); + auto itr = addresses.account_name.find("brendan"_n); + eosio::check(itr == addresses.account_name.end(), "brendan should not be in the table."); - auto itr = addresses.index.full_name.find("Brendan Blumer"); - eosio::check(itr == addresses.index.full_name.end(), "Brendan Blumer should not be in the table."); + auto itr = addresses.full_name.find("Brendan Blumer"); + eosio::check(itr == addresses.full_name.end(), "Brendan Blumer should not be in the table."); } ``` @@ -123,11 +140,11 @@ class addressbook : contract { // This assumes the code from the class example. void myaction() { // add dan account to table - see put example - auto itr = addresses.index.account_name.find("dan"_n); - eosio::check(itr == addresses.index.account_name.begin(), "dan should be at the beginning."); + auto itr = addresses.account_name.find("dan"_n); + eosio::check(itr == addresses.account_name.begin(), "dan should be at the beginning."); - auto itr = addresses.index.full_name.find("Dan Larimer"); - eosio::check(itr == addresses.index.full_name.begin(), "Dan Larimer should be at the beginning."); + auto itr = addresses.full_name.find("Dan Larimer"); + eosio::check(itr == addresses.full_name.begin(), "Dan Larimer should be at the beginning."); } ``` @@ -143,17 +160,13 @@ class addressbook : contract { address brendan = {...} address john = {...} - std::vector expected_values = {brendan, dan, john}; - auto values = addresses.index.account_name.range("brendan"_n, "john"_n); - eosio::check(values == expected_values, "Did not get the expected values"); - - std::vector expected_values = {dan}; - auto values = addresses.index.account_name.range("dan"_n, "dan"_n); + std::vector expected_values = {brendan, dan}; + auto values = addresses.account_name.range("brendan"_n, "john"_n); eosio::check(values == expected_values, "Did not get the expected values"); } ``` -### null_kv_index Example: +### Deleted Index Example: ```cpp // Original table: DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", @@ -162,15 +175,13 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", secondary_2 ) -struct my_table : kv_table { - struct { - kv_index primary_key ...; - kv_index secondary_1 ...; - kv_index secondary_2 ...; - } index; +struct my_table : kv_table { + index primary_key ...; + index secondary_1 ...; + index secondary_2 ...; my_table(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &secondary_1, &secondary_2); } } @@ -181,59 +192,32 @@ DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", secondary_2 ) -struct my_table : kv_table { - struct { - kv_index primary_key ...; - null_kv_index nullptr1 ...; - kv_index secondary_2 ...; - } index; +struct my_table : kv_table { + kv_index primary_key ...; + null_index nullptr2; + kv_index secondary_2 ...; my_table(eosio::name contract_name) { - init(contract_name, &index); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &nullptr2, &secondary_2); } } ``` -### kv_table::put Example: -```cpp -// This assumes the code from the class example. -void myaction() { - auto addresses = address_table::open("mycontract"_n); - addresses.put({ - .account_name = "dan"_n, - .first_name = "Daniel", - .last_name = "Larimer", - .street = "1 EOS Way", - .city = "Blacksburg", - .state = "VA" - }); -} -``` +### make_insensitive Example: -### kv_table::erase Example: ```cpp -// This assumes the code from the class example. -void myaction() { - auto addresses = address_table::open("mycontract"_n); - - auto itr = addresses.index.account_name.find("dan"_n); - eosio::check(itr != addresses.index.account_name.end()); - addresses.erase("dan"_n); -} -``` +struct location { + std::string city; + std::string state; + uint64_t zip_code; -### kv_table::open Example: -```cpp -struct myrecord { - std::string primary_key; + auto icity() { return eosio::make_insensitive(city); } + auto istate() { return eosio::make_insensitive(state); } } -DEFINE_TABLE(mytable, myrecord, "testtable", primary_key) - -class mycontract : contract { - public: - void myaction() { - auto t = mytable::open("mycontract"_n); - } -} -``` +DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", + icity, + istate, + zip_code +) +``` \ No newline at end of file diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 756ba16450..3caa8c0cc9 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -370,6 +370,7 @@ inline key_type make_key(T val) { /** * Used to return the appropriate representation of a case insensitive string for the EOSIO Key Value database. + * This is only valid for ASCII strings. * * @param val - The string to be made case-insensitive * @return The binary representation of the case-insensitive string @@ -389,10 +390,7 @@ inline key_type make_insensitive(const std::string& val) { * Key Value Tables support 0 or more secondary index, of any type that can be serialized to a binary representation. * Indexes must be a member variable or a member function. * - * @tparam Class - the name of the class of the user defined table that inherits from eosio::kv_table * @tparam T - the type of the data stored as the value of the table - * @tparam TableName - the name of the table - * @tparam DbName - the type of the EOSIO Key Value database. Defaulted to eosio.kvram */ template class kv_table { @@ -542,15 +540,6 @@ class kv_table { } }; - /** - * @ingroup keyvalue - * - * @brief Defines an index on an EOSIO Key Value Table - * @details A Key Value Index allows a user of the table to search based on a given field. - * The only restrictions on that field are that it is serializable to a binary representation. - * Convenience functions exist to handle most of the primitive types as well as some more complex types, and are - * used automatically where possible. - */ class kv_index { public: @@ -591,6 +580,17 @@ class kv_table { using iterator = kv_table::iterator; + /** + * @ingroup keyvalue + * + * @brief Defines an index on an EOSIO Key Value Table + * @details A Key Value Index allows a user of the table to search based on a given field. + * The only restrictions on that field are that it is serializable to a binary representation sortable by the KV intrinsics. + * Convenience functions exist to handle most of the primitive types as well as some more complex types, and are + * used automatically where possible. + * + * @tparam K - The type of the key used in the index. + */ template class index : public kv_index { index_config config; @@ -633,7 +633,7 @@ class kv_table { if (cmp != 0) { internal_use_do_not_use::kv_it_destroy(itr); - return this->end(); + return end(); } return {itr, static_cast(itr_stat), config}; @@ -754,8 +754,8 @@ class kv_table { * Returns a vector of objects that fall between the specifed range. The range is inclusive, exclusive. * @ingroup keyvalue * - * @param begin - The beginning of the range. - * @param end - The end of the range. + * @param begin - The beginning of the range (inclusive). + * @param end - The end of the range (exclusive). * @return A vector containing all the objects that fall between the range. */ std::vector range(const K& b, const K& e) { @@ -795,15 +795,15 @@ class kv_table { * * @brief Defines a deleted index on an EOSIO Key Value Table * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. - * A null_kv_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. + * A null_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. */ - class null_index{}; /** + * @ingroup keyvalue * Puts a value into the table. If the value already exists, it updates the existing entry. * The key is determined from the defined primary index. - * @ingroup keyvalue + * If the put attempts to store over an existing secondary index, the transaction will be aborted. * * @param value - The entry to be stored in the table. */ @@ -869,8 +869,6 @@ class kv_table { * Removes a value from the table. * @ingroup keyvalue * - * @tparam K - The type of the key. This will be auto-deduced through the key parameter. - * * @param key - The key of the value to be removed. */ void erase(const T& value) { @@ -939,16 +937,6 @@ class kv_table { secondary_indices.push_back(index); } - /** - * Initializes a key value table. This method is intended to be called in the constructor of the user defined table class. - * If using the DEFINE_TABLE macro, this is handled for the developer. - * @ingroup keyvalue - * - * @tparam Indices - a list of types of the indices. This will be auto-deduced through the indices parameter. - * - * @param contract - the name of the contract this table is associated with - * @param indices - a list of 1 or more indices to add to the table - */ template void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex prim_index, SecondaryIndices... indices) { contract_name = contract; From b02d2dff9dc46c223bbd397cdd18f8f515a9843b Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 11:01:46 -0500 Subject: [PATCH 257/659] Remove copypasta --- tests/unit/test_contracts/kv_bios/CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 tests/unit/test_contracts/kv_bios/CMakeLists.txt diff --git a/tests/unit/test_contracts/kv_bios/CMakeLists.txt b/tests/unit/test_contracts/kv_bios/CMakeLists.txt deleted file mode 100644 index 59c20b8c25..0000000000 --- a/tests/unit/test_contracts/kv_bios/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -if( EOSIO_COMPILE_TEST_CONTRACTS ) - add_contract( kv_bios kv_bios kv_bios.cpp ) -else() - configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.wasm ${CMAKE_CURRENT_BINARY_DIR}/kv_bios.wasm COPYONLY ) - configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.abi ${CMAKE_CURRENT_BINARY_DIR}/kv_bios.abi COPYONLY ) -endif() From 15fa9cc84937998bdb9bd2dc1c951e504947773f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 14:33:48 -0500 Subject: [PATCH 258/659] Minor PR feedback --- .../eosiolib/contracts/eosio/key_value.hpp | 53 +++++++------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 3caa8c0cc9..79a1f99f6b 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -605,7 +605,7 @@ class kv_table { index() = default; template - index(KF&& kf) : kv_index{kf} { + explicit index(KF&& kf) : kv_index{kf} { static_assert(std::is_same_v()))>>>, "Make sure the variable/function passed to the constructor returns the same type as the template parameter."); } @@ -720,11 +720,6 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - if (static_cast(itr_stat) == kv_it_stat::iterator_end) { - internal_use_do_not_use::kv_it_destroy(itr); - return end(); - } - return {itr, static_cast(itr_stat), config}; } @@ -732,7 +727,7 @@ class kv_table { * Returns an iterator pointing to the first element greater than the given key. * @ingroup keyvalue * - * @return An iterator pointing to the element with the highest key less than or equal to the given key. + * @return An iterator pointing to the first element greater than the given key. */ iterator upper_bound(const K& key) { auto t_key = table_key(config.prefix, make_key(key)); @@ -759,19 +754,10 @@ class kv_table { * @return A vector containing all the objects that fall between the range. */ std::vector range(const K& b, const K& e) { - auto begin_itr = lower_bound(b); - auto end_itr = lower_bound(e); - - if (begin_itr == end_itr || begin_itr > end_itr) { - return {}; - } - std::vector return_values; - iterator itr = std::move(begin_itr); - while(itr < end_itr) { + for(auto itr = lower_bound(b), end_itr = lower_bound(e); itr < end_itr; ++itr) { return_values.push_back(itr.value()); - ++itr; } return return_values; @@ -832,25 +818,26 @@ class kv_table { if (!primary_key_found) { eosio::check(!sec_found, "Attempted to store an existing secondary index."); - } else if (sec_found) { - void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); - - eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing secondary index."); - auto res = memcmp(buffer, tbl_key.data(), copy_size); - eosio::check(res == 0, "Attempted to update an existing secondary index."); - - if (copy_size > detail::max_stack_buffer_size) { - free(buffer); + internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); + } else { + if (sec_found) { + void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); + + eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing secondary index."); + auto res = memcmp(buffer, tbl_key.data(), copy_size); + eosio::check(res == 0, "Attempted to update an existing secondary index."); + + if (copy_size > detail::max_stack_buffer_size) { + free(buffer); + } + } else { + auto old_sec_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(old_value)); + internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); + internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); } } - if (primary_key_found) { - auto old_sec_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(old_value)); - internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); - } - - internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); } size_t data_size = get_size(value); From 150f1888cf6cab0541034d549b8ab54ac99e0ba2 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 5 Mar 2020 16:33:12 -0500 Subject: [PATCH 259/659] Add back some tests --- tests/integration/kv_tests.cpp | 13 +++ .../kv_multiple_indices_tests.cpp | 39 +++++++++ .../unit/test_contracts/kv_variant_tests.cpp | 87 +++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 tests/unit/test_contracts/kv_variant_tests.cpp diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 4d26f32764..7d6c013982 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -118,4 +118,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_non_unique, tester) try { tester.push_action(N(kvtest), N(nonunique), N(kvtest), {}); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(multi_tests_update, tester) try { + TESTER tester; + setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); + tester.push_action(N(kvtest), N(update), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(updateerr1), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Attempted to update an existing secondary index.")); + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(updateerr2), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("Attempted to store an existing secondary index.")); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 7084c270e0..7b8e560215 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -216,4 +216,43 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { eosio::check(vals == expected, "Range did not return the expected vector."); } + + [[eosio::action]] + void update() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "bob"_n, + .foo = "a", + .bar = 1000, + .fullname = "Bob Smith", + .age = 25 + }); + } + + [[eosio::action]] + void updateerr1() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "alice"_n, + .foo = "a", + .bar = 1000, + .fullname = "Bob Smith", + .age = 25 + }); + } + + [[eosio::action]] + void updateerr2() { + my_table t{"kvtest"_n}; + + t.put({ + .primary_key = "will"_n, + .foo = "a", + .bar = 1000, + .fullname = "Bob Smith", + .age = 25 + }); + } }; diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp new file mode 100644 index 0000000000..5e68d13ee0 --- /dev/null +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -0,0 +1,87 @@ +#include + +struct my_struct_v { + uint64_t age; + std::string full_name; +}; + +struct my_struct_v2 { + std::string first_name; + std::string last_name; + uint64_t age; +}; + +DEFINE_TABLE(my_table, my_struct_v, "testtable", "eosio.kvram", &age, &full_name) + +struct my_table_v : eosio::kv_table> { + index primary_key{[](const auto& obj) { + return std::visit([&](auto&& a) { + using V = std::decay_t; + if constexpr(std::is_same_v) { + return a.full_name; + } else if constexpr(std::is_same_v) { + return a.first_name + " : " + a.last_name; + } else { + eosio::check(false, "BAD TYPE"); + return ""; + } + }, *obj); + }}; + index age{[](const auto& obj) { + return std::visit([&](auto&& a) { + return a.age; + }, *obj); + }}; + + my_table_v(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &age); + } +}; + +class [[eosio::contract]] kv_single_index_tests : public eosio::contract { +public: + using contract::contract; + + [[eosio::action]] + void basic_table() { + my_table t{"kvtest"_n}; + } + + [[eosio::action]] + void vriant() { + my_table_v t{"kvtest"_n}; + + my_struct_v s1{ + .full_name = "Dan Larimer", + .age = 25 + }; + + my_struct_v s2{ + .full_name = "Brendan Blumer", + .age = 24 + }; + + my_struct_v2 s3{ + .first_name = "Bob", + .last_name = "Smith", + .age = 30 + }; + + t.put(s1); + t.put(s2); + t.put(s3); + + auto itr = t.primary_key.find("Dan Larimer"); + auto val = itr.value(); + auto vval = std::get(val); + eosio::check(vval.age == 25, "wrong value"); + + auto val2 = t.primary_key.get("Brendan Blumer"); + auto vval2 = std::get(*val2); + eosio::check(vval2.age == 24, "wrong value"); + + auto val3 = t.primary_key.get("Bob : Smith"); + auto vval3 = std::get(*val3); + eosio::check(vval3.age == 30, "wrong value"); + } +}; From 897ef0f55275d509134004978a4aecab8369ea58 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 6 Mar 2020 09:09:48 -0500 Subject: [PATCH 260/659] Add a test for variants and upgrading to a variant --- .../eosiolib/contracts/eosio/key_value.hpp | 4 +- tests/integration/contracts.hpp.in | 3 + tests/integration/kv_tests.cpp | 15 ++-- tests/unit/test_contracts/CMakeLists.txt | 1 + .../test_contracts/kv_single_index_tests.cpp | 74 ------------------- .../unit/test_contracts/kv_variant_tests.cpp | 42 ++++++++++- 6 files changed, 54 insertions(+), 85 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 79a1f99f6b..30ed1bc37f 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -699,10 +699,10 @@ class kv_table { } /** - * Returns an iterator referring to the `past-the-end` element. It does not point to any element, therefore `value` should not be called on it. + * Returns an iterator pointing past the end. It does not point to any element, therefore `value` should not be called on it. * @ingroup keyvalue * - * @return An iterator referring to the `past-the-end` element. + * @return An iterator pointing past the end. */ iterator end() { return {0, kv_it_stat::iterator_end, config}; diff --git a/tests/integration/contracts.hpp.in b/tests/integration/contracts.hpp.in index 0ec9407468..a172a31aeb 100644 --- a/tests/integration/contracts.hpp.in +++ b/tests/integration/contracts.hpp.in @@ -28,6 +28,9 @@ struct contracts { static std::vector kv_make_key_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.wasm"); } static std::vector kv_make_key_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_make_key_tests.abi"); } + static std::vector kv_variant_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_variant_tests.wasm"); } + static std::vector kv_variant_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_variant_tests.abi"); } + static std::vector kv_bios_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_bios.wasm"); } static std::vector kv_bios_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/kv_bios.abi"); } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 7d6c013982..8ebb8b01fc 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -85,12 +85,6 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { tester.push_action(N(kvtest), N(erase), N(kvtest), {}); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(single_tests_variant, tester) try { - TESTER tester; - setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); - tester.push_action(N(kvtest), N(vriant), N(kvtest), {}); -} FC_LOG_AND_RETHROW() - // Multi // ----- BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { @@ -131,4 +125,13 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_update, tester) try { eosio_assert_message_is("Attempted to store an existing secondary index.")); } FC_LOG_AND_RETHROW() +// Multi +// ----- +BOOST_FIXTURE_TEST_CASE(multi_tests_variant, tester) try { + TESTER tester; + setup(tester, contracts::kv_variant_tests_wasm(), contracts::kv_variant_tests_abi()); + tester.push_action(N(kvtest), N(vriant), N(kvtest), {}); + tester.push_action(N(kvtest), N(vriantupgrd), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/CMakeLists.txt b/tests/unit/test_contracts/CMakeLists.txt index 3c75e5340a..2147937cc3 100644 --- a/tests/unit/test_contracts/CMakeLists.txt +++ b/tests/unit/test_contracts/CMakeLists.txt @@ -7,6 +7,7 @@ add_contract(minimal_tests minimal_tests minimal_tests.cpp) add_contract(kv_single_index_tests kv_single_index_tests kv_single_index_tests.cpp) add_contract(kv_multiple_indices_tests kv_multiple_indices_tests kv_multiple_indices_tests.cpp) add_contract(kv_make_key_tests kv_make_key_tests kv_make_key_tests.cpp) +add_contract(kv_variant_tests kv_variant_tests kv_variant_tests.cpp) add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c capi/print.c capi/privileged.c capi/system.c capi/transaction.c) add_contract(kv_bios kv_bios kv_bios/kv_bios.cpp) diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index b496ec825b..cd62027e29 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -8,44 +8,8 @@ struct my_struct { } }; -struct my_struct_v { - uint64_t age; - std::string full_name; -}; - -struct my_struct_v2 { - std::string first_name; - std::string last_name; - uint64_t age; -}; - DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) -struct my_table_v : eosio::kv_table> { - index primary_key{[](const auto& obj) { - return std::visit([&](auto&& a) { - using V = std::decay_t; - if constexpr(std::is_same_v) { - return a.full_name; - } else if constexpr(std::is_same_v) { - return a.first_name + " : " + a.last_name; - } else { - eosio::check(false, "BAD TYPE"); - return ""; - } - }, *obj); - }}; - index age{[](const auto& obj) { - return std::visit([&](auto&& a) { - return a.age; - }, *obj); - }}; - - my_table_v(eosio::name contract_name) { - init(contract_name, "testtable2"_n, "eosio.kvram"_n, &primary_key, &age); - } -}; - class [[eosio::contract]] kv_single_index_tests : public eosio::contract { public: using contract::contract; @@ -239,42 +203,4 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto vals = t.primary_key.range("bob"_n, "john"_n); eosio::check(vals == expected, "range did not return expected vector"); } - - [[eosio::action]] - void vriant() { - my_table_v t{"kvtest"_n}; - - my_struct_v s1{ - .full_name = "Dan Larimer", - .age = 25 - }; - - my_struct_v s2{ - .full_name = "Brendan Blumer", - .age = 24 - }; - - my_struct_v2 s3{ - .first_name = "Bob", - .last_name = "Smith", - .age = 30 - }; - - t.put(s1); - t.put(s2); - t.put(s3); - - auto itr = t.primary_key.find("Dan Larimer"); - auto val = itr.value(); - auto vval = std::get(val); - eosio::check(vval.age == 25, "wrong value"); - - auto val2 = t.primary_key.get("Brendan Blumer"); - auto vval2 = std::get(*val2); - eosio::check(vval2.age == 24, "wrong value"); - - auto val3 = t.primary_key.get("Bob : Smith"); - auto vval3 = std::get(*val3); - eosio::check(vval3.age == 30, "wrong value"); - } }; diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp index 5e68d13ee0..c4160febe7 100644 --- a/tests/unit/test_contracts/kv_variant_tests.cpp +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -11,7 +11,7 @@ struct my_struct_v2 { uint64_t age; }; -DEFINE_TABLE(my_table, my_struct_v, "testtable", "eosio.kvram", &age, &full_name) +DEFINE_TABLE(my_table, my_struct_v, "testtable", "eosio.kvram", age, full_name) struct my_table_v : eosio::kv_table> { index primary_key{[](const auto& obj) { @@ -38,13 +38,49 @@ struct my_table_v : eosio::kv_table> { } }; -class [[eosio::contract]] kv_single_index_tests : public eosio::contract { +class [[eosio::contract]] kv_variant_tests : public eosio::contract { public: using contract::contract; + // Empty action to avoid having conditional logic in the integration tests file. [[eosio::action]] - void basic_table() { + void setup() {} + + [[eosio::action]] + void vriantupgrd() { my_table t{"kvtest"_n}; + + my_struct_v s1{ + .full_name = "Dan Larimer", + .age = 25 + }; + + my_struct_v s2{ + .full_name = "Brendan Blumer", + .age = 24 + }; + + t.put(s1); + t.put(s2); + + my_table_v t1{"kvtest"_n}; + + auto itr = t1.primary_key.find("Dan Larimer"); + auto val = itr.value(); + auto vval = std::get(val); + eosio::check(vval.age == 25, "wrong value"); + + my_struct_v2 s3{ + .first_name = "Bob", + .last_name = "Smith", + .age = 30 + }; + + t1.put(s3); + + auto val2 = t1.primary_key.get("Bob : Smith"); + auto vval2 = std::get(*val2); + eosio::check(vval2.age == 30, "wrong value"); } [[eosio::action]] From e1eb0ada908367eddc0fae2e9749547cbea6d03c Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 6 Mar 2020 16:00:03 -0500 Subject: [PATCH 261/659] Add NAMED_INDEX macro --- libraries/eosiolib/contracts/eosio/key_value.hpp | 16 +++++++++++++++- .../test_contracts/kv_multiple_indices_tests.cpp | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 30ed1bc37f..ba76236cf5 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -25,7 +25,7 @@ #define EOSIO_CDT_CAT(x, y) EOSIO_CDT_CAT2(x, y) #define EOSIO_CDT_APPLY(f, args) f args -#define EOSIO_CDT_GET_RETURN_T(value_class, index_name) std::remove_cv_t()))>> +#define EOSIO_CDT_GET_RETURN_T(value_class, index_name) std::decay_t()))> #define EOSIO_CDT_KV_FIX_INDEX_NAME_0(index_name, i) index_name #define EOSIO_CDT_KV_FIX_INDEX_NAME_1(index_name, i) index_name ## i @@ -86,6 +86,20 @@ } \ }; +/** + * @brief Macro to define a table. + * @details In the case where the autogenerated index names created by DEFINE_TABLE are not enough, a user can instead + * manually define the table and indices. This macro allows users to conveniently define an index without having to specify + * the index template type, as those can be large/unwieldy to type out. + * + * @param variable_name - The variable name in code of the index. + * @param index_name - The index name. + * @param value_class - The class the table stores. + * @parma member_name - The name of the member pointer used for the index. + */ +#define NAMED_INDEX(variable_name, index_name, value_class, member_name) \ + index variable_name{index_name, &value_class::member_name}; + namespace eosio { namespace internal_use_do_not_use { extern "C" { diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 7b8e560215..00245a38aa 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -42,8 +42,8 @@ struct my_table2 : eosio::kv_table { }; struct my_table_idx : eosio::kv_table { - index primary_key{"prim"_n, &my_struct::primary_key}; - index foo{"f"_n, &my_struct::foo}; + NAMED_INDEX(primary_key, "prim"_n, my_struct, primary_key) + NAMED_INDEX(foo, "f"_n, my_struct, foo) my_table_idx(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); From c1d351fc044859c99d6a0d446853abee2c2dbc73 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 6 Mar 2020 16:32:28 -0500 Subject: [PATCH 262/659] PR feedback --- .../eosiolib/contracts/eosio/key_value.hpp | 42 +++----------- tests/integration/kv_make_key_tests.cpp | 48 +++------------- .../kv_multiple_indices_tests.cpp | 55 ++++++++++--------- .../test_contracts/kv_single_index_tests.cpp | 42 +++++++------- 4 files changed, 66 insertions(+), 121 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index ba76236cf5..fcc2ba2111 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -307,7 +307,7 @@ inline key_type make_key(eosio::name n) { } inline key_type make_key(key_type&& val) { - return val; + return std::move(val); } inline key_type make_key(const key_type& val) { @@ -616,8 +616,6 @@ class kv_table { using kv_table::kv_index::index_name; using kv_table::kv_index::prefix; - index() = default; - template explicit index(KF&& kf) : kv_index{kf} { static_assert(std::is_same_v()))>>>, @@ -745,11 +743,7 @@ class kv_table { */ iterator upper_bound(const K& key) { auto t_key = table_key(config.prefix, make_key(key)); - - uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); - int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - - iterator it{itr, static_cast(itr_stat), config}; + auto it = lower_bound(key); auto cmp = it.key_compare(t_key); if (cmp == 0) { @@ -838,9 +832,8 @@ class kv_table { void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto copy_size = internal_use_do_not_use::kv_get_data(db_name, 0, (char*)buffer, value_size); - eosio::check(copy_size == tbl_key.size(), "Attempted to update an existing secondary index."); auto res = memcmp(buffer, tbl_key.data(), copy_size); - eosio::check(res == 0, "Attempted to update an existing secondary index."); + eosio::check(copy_size == tbl_key.size() && res == 0, "Attempted to update an existing secondary index."); if (copy_size > detail::max_stack_buffer_size) { free(buffer); @@ -894,12 +887,12 @@ class kv_table { protected: kv_table() = default; + void setup_indices(uint64_t index_name, bool is_named) {} + template void setup_indices(uint64_t index_name, bool is_named, null_index* index, Indices... indices) { ++index_name; - if constexpr (sizeof...(indices) > 0) { - setup_indices(index_name, is_named, indices...); - } + setup_indices(index_name, is_named, indices...); } template @@ -907,7 +900,7 @@ class kv_table { if (is_named) { eosio::check(index->index_name.value > 0, "All indices must be named if one is named."); } else { - eosio::check(index->index_name.value <= 0, "All indices must be named if one is named."); + eosio::check(index->index_name.value == 0, "All indices must be named if one is named."); index->index_name = eosio::name{index_name}; } @@ -921,23 +914,6 @@ class kv_table { setup_indices(index_name, is_named, indices...); } - template - void setup_indices(uint64_t index_name, bool is_named, I index) { - if (is_named) { - eosio::check(index->index_name.value > 0, "All indices must be named if one is named."); - } else { - eosio::check(index->index_name.value <= 0, "All indices must be named if one is named."); - index->index_name = eosio::name{index_name}; - } - - index->contract_name = contract_name; - index->table_name = table_name; - index->tbl = this; - - index->setup(); - secondary_indices.push_back(index); - } - template void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex prim_index, SecondaryIndices... indices) { contract_name = contract; @@ -961,9 +937,7 @@ class kv_table { primary_index->setup(); - if constexpr (sizeof...(indices) > 0) { - setup_indices(index_name, is_named, indices...); - } + setup_indices(index_name, is_named, indices...); } private: diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp index d789396d02..a001296afa 100644 --- a/tests/integration/kv_make_key_tests.cpp +++ b/tests/integration/kv_make_key_tests.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,7 +11,7 @@ using namespace eosio::testing; using mvo = fc::mutable_variant_object; -BOOST_AUTO_TEST_SUITE(key_value_make_key_tests) +BOOST_AUTO_TEST_SUITE(key_value_tests) void make_key_test(name test_name) { tester t; @@ -30,44 +31,13 @@ void make_key_test(name test_name) { t.push_action(N(kvtest), test_name, N(kvtest), {}); } -BOOST_AUTO_TEST_CASE(makekeyname) try { - make_key_test(N(makekeyname)); -} FC_LOG_AND_RETHROW() +std::vector data_set{ + N(makekeyname), N(makekeystr), N(makekeyistr), N(makekeyuill), N(makekeyil), N(makekeyuilll), + N(makekeyflt), N(makekeydbl), N(makekeystct), N(makekeytup) +}; -BOOST_AUTO_TEST_CASE(makekeystr) try { - make_key_test(N(makekeystr)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeyistr) try { - make_key_test(N(makekeyistr)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeyuill) try { - make_key_test(N(makekeyuill)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeyil) try { - make_key_test(N(makekeyil)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeyuilll) try { - make_key_test(N(makekeyuilll)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeyflt) try { - make_key_test(N(makekeyflt)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeydbl) try { - make_key_test(N(makekeydbl)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeystct) try { - make_key_test(N(makekeystct)); -} FC_LOG_AND_RETHROW() - -BOOST_AUTO_TEST_CASE(makekeytup) try { - make_key_test(N(makekeytup)); -} FC_LOG_AND_RETHROW() +BOOST_DATA_TEST_CASE(makekeytests, data_set) { try { + make_key_test(sample); +} FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 00245a38aa..571640d959 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -10,7 +10,7 @@ struct my_struct { std::tuple non_unique_name() const { return {fullname, age}; } - bool operator==(const my_struct b) const { + bool operator==(const my_struct& b) const { return primary_key == b.primary_key && foo == b.foo && bar == b.bar && @@ -146,60 +146,61 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { auto foo_itr = t.foo.begin(); auto bar_itr = t.bar.begin(); - eosio::check(foo_itr != foo_end_itr, "Should not be the end"); - eosio::check(bar_itr != bar_end_itr, "Should not be the end"); - eosio::check(foo_itr.value() == s2, "Got the wrong value"); - eosio::check(bar_itr.value() == s5, "Got the wrong value"); + eosio::check(foo_itr != foo_end_itr, "foo should not be the end"); + eosio::check(bar_itr != bar_end_itr, "bar should not be the end"); + + eosio::check(foo_itr.value() == s2, "Got the wrong value: foo != s2"); + eosio::check(bar_itr.value() == s5, "Got the wrong value: bar != s5"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value() == s5, "Got the wrong value"); - eosio::check(bar_itr.value() == s4, "Got the wrong value"); + eosio::check(foo_itr.value() == s5, "Got the wrong value: foo != s5"); + eosio::check(bar_itr.value() == s4, "Got the wrong value: bar != s4"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value() == s1, "Got the wrong value"); - eosio::check(bar_itr.value() == s3, "Got the wrong value"); + eosio::check(foo_itr.value() == s1, "Got the wrong value: foo != s1"); + eosio::check(bar_itr.value() == s3, "Got the wrong value: bar != s3"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value() == s3, "Got the wrong value"); - eosio::check(bar_itr.value() == s2, "Got the wrong value"); + eosio::check(foo_itr.value() == s3, "Got the wrong value: foo != s3"); + eosio::check(bar_itr.value() == s2, "Got the wrong value: bar != s2"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr.value() == s4, "Got the wrong value"); - eosio::check(bar_itr.value() == s1, "Got the wrong value"); + eosio::check(foo_itr.value() == s4, "Got the wrong value: foo != s4"); + eosio::check(bar_itr.value() == s1, "Got the wrong value: bar != s1"); ++foo_itr; ++bar_itr; - eosio::check(foo_itr == foo_end_itr, "Should be the end"); - eosio::check(bar_itr == bar_end_itr, "Should be the end"); + eosio::check(foo_itr == foo_end_itr, "foo should be the end"); + eosio::check(bar_itr == bar_end_itr, "bar should be the end"); --foo_itr; --bar_itr; - eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); - eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + eosio::check(foo_itr != foo_begin_itr, "foo should not be the beginning: 1"); + eosio::check(bar_itr != bar_begin_itr, "bar should not be the beginning: 1"); --foo_itr; --bar_itr; - eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); - eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + eosio::check(foo_itr != foo_begin_itr, "foo should not be the beginning: 2"); + eosio::check(bar_itr != bar_begin_itr, "bar should not be the beginning: 2"); --foo_itr; --bar_itr; - eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); - eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + eosio::check(foo_itr != foo_begin_itr, "foo should not be the beginning: 3"); + eosio::check(bar_itr != bar_begin_itr, "bar should not be the beginning: 3"); --foo_itr; --bar_itr; - eosio::check(foo_itr != foo_begin_itr, "Should not be the beginning"); - eosio::check(bar_itr != bar_begin_itr, "Should not be the beginning"); + eosio::check(foo_itr != foo_begin_itr, "foo should not be the beginning: 4"); + eosio::check(bar_itr != bar_begin_itr, "bar should not be the beginning: 4"); --foo_itr; --bar_itr; - eosio::check(foo_itr == foo_begin_itr, "Should be the beginning"); - eosio::check(bar_itr == bar_begin_itr, "Should be the beginning"); + eosio::check(foo_itr == foo_begin_itr, "foo should be the beginning"); + eosio::check(bar_itr == bar_begin_itr, "bar should be the beginning"); } [[eosio::action]] @@ -209,12 +210,12 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { std::vector expected{s1, s5, s4}; auto vals = t.non_unique_name.range({"Bob Smith", 0}, {"Bob Smith", UINT_MAX}); - eosio::check(vals == expected, "Range did not return the expected vector."); + eosio::check(vals == expected, "Range did not return the expected vector: {s1, s5, s4}"); expected = {s1, s5}; vals = t.non_unique_name.range({"Bob Smith", 0}, {"Bob Smith", 27}); - eosio::check(vals == expected, "Range did not return the expected vector."); + eosio::check(vals == expected, "Range did not return the expected vector: {s1, s5}"); } [[eosio::action]] diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index cd62027e29..43c5829172 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -48,23 +48,23 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto itr = t.primary_key.find("bob"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key: bob"); itr = t.primary_key.find("joe"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key: joe"); itr = t.primary_key.find("alice"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong primary_key: alice"); itr = t.primary_key.find("john"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "john"_n, "Got the wrong primary_key: john"); itr = t.primary_key.find("billy"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong primary_key: billy"); } [[eosio::action]] @@ -93,22 +93,22 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { auto itr = t.primary_key.lower_bound("bob"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key: lower_bound - bob"); itr = t.primary_key.lower_bound("catherine"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key: lower_bound - joe"); itr = t.primary_key.lower_bound("william"_n); eosio::check(itr == end_itr, "Should be the end"); itr = t.primary_key.upper_bound("billy"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong primary_key: upper_bound - bob"); itr = t.primary_key.upper_bound("ian"_n); eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong primary_key: upper_bound - joe"); itr = t.primary_key.upper_bound("john"_n); eosio::check(itr == end_itr, "Should be the end"); @@ -127,29 +127,29 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { eosio::check(itr.value().primary_key == "alice"_n, "Got the wrong beginning"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "billy"_n, "Got the wrong value: billy"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "bob"_n, "Got the wrong value: bob"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "joe"_n, "Got the wrong value: joe"); ++itr; eosio::check(itr != end_itr, "Should not be the end"); - eosio::check(itr.value().primary_key == "john"_n, "Got the wrong value"); + eosio::check(itr.value().primary_key == "john"_n, "Got the wrong value: john"); ++itr; eosio::check(itr == end_itr, "Should be the end"); // operator-- // ---------- --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); + eosio::check(itr != begin_itr, "Should not be the beginning: 1"); --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); + eosio::check(itr != begin_itr, "Should not be the beginning: 2"); --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); + eosio::check(itr != begin_itr, "Should not be the beginning: 3"); --itr; - eosio::check(itr != begin_itr, "Should not be the beginning"); + eosio::check(itr != begin_itr, "Should not be the beginning: 4"); --itr; eosio::check(itr == begin_itr, "Should be the beginning"); } @@ -178,15 +178,15 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { expected = {}; vals = t.primary_key.range("bob"_n, "bob"_n); - eosio::check(vals == expected, "range did not return expected vector"); + eosio::check(vals == expected, "range did not return expected vector: {} - 1"); vals = t.primary_key.range("chris"_n, "joe"_n); - eosio::check(vals == expected, "range did not return expected vector"); + eosio::check(vals == expected, "range did not return expected vector: {} - 2"); vals = t.primary_key.range("joe"_n, "alice"_n); - eosio::check(vals == expected, "range did not return expected vector"); + eosio::check(vals == expected, "range did not return expected vector: {} - 3"); expected = {s2, s5, s, s4, s3}; vals = t.primary_key.range("alice"_n, "william"_n); - eosio::check(vals == expected, "range did not return expected vector"); + eosio::check(vals == expected, "range did not return expected vector: {s2, s5, s, s4, s3}"); } [[eosio::action]] From de8f5f6741af0f75f9589927129edec53bf09cd1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 6 Mar 2020 16:45:15 -0500 Subject: [PATCH 263/659] Cleanup --- libraries/eosiolib/contracts/eosio/key_value.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index fcc2ba2111..aaa347bc63 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -68,7 +68,7 @@ /** * @brief Macro to define a table. - * @details The resulting table will have a member `index` that has fields on it that match 1-1 with the names of the + * @details The resulting table will have member fields on it that match 1-1 with the names of the * fields passed into the list. See example for further clarification. * * @param table_class - The name of the class of the user defined table that inherits from eosio::kv_table From 8f3f47eb35e9a7258e886c4a1e9b3a411296c391 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 6 Mar 2020 17:10:42 -0500 Subject: [PATCH 264/659] Cleanup tests --- tests/integration/kv_make_key_tests.cpp | 43 ------------------------- tests/integration/kv_tests.cpp | 18 +++++++++-- 2 files changed, 16 insertions(+), 45 deletions(-) delete mode 100644 tests/integration/kv_make_key_tests.cpp diff --git a/tests/integration/kv_make_key_tests.cpp b/tests/integration/kv_make_key_tests.cpp deleted file mode 100644 index a001296afa..0000000000 --- a/tests/integration/kv_make_key_tests.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -using namespace eosio; -using namespace eosio::testing; - -using mvo = fc::mutable_variant_object; - -BOOST_AUTO_TEST_SUITE(key_value_tests) - -void make_key_test(name test_name) { - tester t; - - t.create_accounts( { N(kvtest) } ); - t.produce_block(); - t.set_code( N(kvtest), contracts::kv_make_key_tests_wasm() ); - t.set_abi( N(kvtest), contracts::kv_make_key_tests_abi().data() ); - t.produce_blocks(); - - t.set_code(config::system_account_name, contracts::kv_bios_wasm()); - t.set_abi(config::system_account_name, contracts::kv_bios_abi().data()); - - auto data = mvo()("k", 1024)("v", 1024*1024)("i", 256); - t.push_action(config::system_account_name, N(ramkvlimits), config::system_account_name, data); - t.push_action(N(kvtest), N(setup), N(kvtest), {}); - t.push_action(N(kvtest), test_name, N(kvtest), {}); -} - -std::vector data_set{ - N(makekeyname), N(makekeystr), N(makekeyistr), N(makekeyuill), N(makekeyil), N(makekeyuilll), - N(makekeyflt), N(makekeydbl), N(makekeystct), N(makekeytup) -}; - -BOOST_DATA_TEST_CASE(makekeytests, data_set) { try { - make_key_test(sample); -} FC_LOG_AND_RETHROW() } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 8ebb8b01fc..87ac194d8d 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -125,8 +126,8 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_update, tester) try { eosio_assert_message_is("Attempted to store an existing secondary index.")); } FC_LOG_AND_RETHROW() -// Multi -// ----- +// Variant +// ------- BOOST_FIXTURE_TEST_CASE(multi_tests_variant, tester) try { TESTER tester; setup(tester, contracts::kv_variant_tests_wasm(), contracts::kv_variant_tests_abi()); @@ -134,4 +135,17 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_variant, tester) try { tester.push_action(N(kvtest), N(vriantupgrd), N(kvtest), {}); } FC_LOG_AND_RETHROW() +// Make Key +// -------- +std::vector data_set{ + N(makekeyname), N(makekeystr), N(makekeyistr), N(makekeyuill), N(makekeyil), N(makekeyuilll), + N(makekeyflt), N(makekeydbl), N(makekeystct), N(makekeytup) +}; + +BOOST_DATA_TEST_CASE(makekeytests, data_set) { try { + TESTER tester; + setup(tester, contracts::kv_make_key_tests_wasm(), contracts::kv_make_key_tests_abi()); + tester.push_action(N(kvtest), sample, N(kvtest), {}); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() From 2d133026f9ca6a16d65df64c3f570f8bf8d64ded Mon Sep 17 00:00:00 2001 From: iamveritas Date: Mon, 9 Mar 2020 10:04:58 +0200 Subject: [PATCH 265/659] resolves #815 fixes typos "and and" -> "and" --- .../02_multi-index/how-to-instantiate-a-multi-index-table.md | 2 +- libraries/boost/include/boost/hana/fwd/type.hpp | 2 +- libraries/boost/include/boost/move/algo/adaptive_sort.hpp | 2 +- libraries/eosiolib/core/eosio/time.hpp | 2 +- tools/external/wabt/src/wast-parser.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md index 9a33cf0abb..9ab286ef0a 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-instantiate-a-multi-index-table.md @@ -22,7 +22,7 @@ using namespace eosio; + uint64_t datum; }; ``` -4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t, it must be unique and and it must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error saying it can't find the field to use as the primary key: +4. Add definition of the primary index for the multi index table. The primary index type must be uint64_t, it must be unique and it must be named `primary_key()`, if you don't have this the compiler (eosio-cpp) will generate an error saying it can't find the field to use as the primary key: ```diff // the data structure which defines each row of the table struct [[eosio::table]] test_table { diff --git a/libraries/boost/include/boost/hana/fwd/type.hpp b/libraries/boost/include/boost/hana/fwd/type.hpp index c3c220db78..2f3e84cf3d 100644 --- a/libraries/boost/include/boost/hana/fwd/type.hpp +++ b/libraries/boost/include/boost/hana/fwd/type.hpp @@ -165,7 +165,7 @@ BOOST_HANA_NAMESPACE_BEGIN //! ### Rationale for stripping the references //! The rules for template argument deduction are such that a perfect //! solution that always matches `decltype` is impossible. Hence, we - //! have to settle on a solution that's good and and consistent enough + //! have to settle on a solution that's good and consistent enough //! for our needs. One case where matching `decltype`'s behavior is //! impossible is when the argument is a plain, unparenthesized variable //! or function parameter. In that case, `decltype_`'s argument will be diff --git a/libraries/boost/include/boost/move/algo/adaptive_sort.hpp b/libraries/boost/include/boost/move/algo/adaptive_sort.hpp index 2026f9c1b5..696d21078c 100644 --- a/libraries/boost/include/boost/move/algo/adaptive_sort.hpp +++ b/libraries/boost/include/boost/move/algo/adaptive_sort.hpp @@ -261,7 +261,7 @@ bool adaptive_sort_combine_all_blocks // Implies l_block == l_intbuf && use_internal_buf == true //If l_intbuf is zero, see if half keys can be reused as a reduced emergency buffer, // Implies l_block == n_keys/2 && use_internal_buf == true - //Otherwise, just give up and and use all keys to merge using rotations (use_internal_buf = false) + //Otherwise, just give up and use all keys to merge using rotations (use_internal_buf = false) bool use_internal_buf = false; size_type const l_block = lblock_for_combine(l_intbuf, n_keys, 2*l_merged, use_internal_buf); BOOST_ASSERT(!l_intbuf || (l_block == l_intbuf)); diff --git a/libraries/eosiolib/core/eosio/time.hpp b/libraries/eosiolib/core/eosio/time.hpp index 3cea71733c..88e0acb80d 100644 --- a/libraries/eosiolib/core/eosio/time.hpp +++ b/libraries/eosiolib/core/eosio/time.hpp @@ -165,7 +165,7 @@ namespace eosio { /** * This class is used in the block headers to represent the block time * It is a parameterised class that takes an Epoch in milliseconds and - * and an interval in milliseconds and computes the number of slots. + * an interval in milliseconds and computes the number of slots. * * @ingroup time **/ diff --git a/tools/external/wabt/src/wast-parser.h b/tools/external/wabt/src/wast-parser.h index 3a9f0413a9..2f94883785 100644 --- a/tools/external/wabt/src/wast-parser.h +++ b/tools/external/wabt/src/wast-parser.h @@ -56,7 +56,7 @@ class WastParser { Result ErrorExpected(const std::vector& expected, const char* example = nullptr); - // Print an error message, and and return Result::Error if the next token is + // Print an error message, and return Result::Error if the next token is // '('. This is commonly used after parsing a sequence of s-expressions -- if // no more can be parsed, we know that a following '(' is invalid. This // function consumes the '(' so a better error message can be provided From 4c1e3a0ccbda051e3044f11aad7a4a41400b4cd6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 10:04:34 -0400 Subject: [PATCH 266/659] Add constants for ram and disk names --- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index aaa347bc63..6386f49aeb 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -82,7 +82,7 @@ EOSIO_CDT_CREATE_KV_INDICES(value_class, __VA_ARGS__) \ \ table_class(eosio::name contract_name) { \ - init(contract_name, table_name##_n, db_name##_n EOSIO_CDT_LIST_KV_INDICES(__VA_ARGS__)); \ + init(contract_name, table_name##_n, db_name EOSIO_CDT_LIST_KV_INDICES(__VA_ARGS__)); \ } \ }; @@ -393,6 +393,8 @@ inline key_type make_insensitive(const std::string& val) { return make_key(val, true); } +static const eosio::name KV_RAM = "eosio.kvram"_n; +static const eosio::name KV_DISK = "eosio.kvdisk"_n; /** * @defgroup keyvalue Key Value Table From 8566f916158cf9f7861067d972f1d78062ab8e30 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 10:07:05 -0400 Subject: [PATCH 267/659] Constants are not upper case --- libraries/eosiolib/contracts/eosio/key_value.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 6386f49aeb..7fe1085c44 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -393,8 +393,8 @@ inline key_type make_insensitive(const std::string& val) { return make_key(val, true); } -static const eosio::name KV_RAM = "eosio.kvram"_n; -static const eosio::name KV_DISK = "eosio.kvdisk"_n; +static const eosio::name kv_ram = "eosio.kvram"_n; +static const eosio::name kv_disk = "eosio.kvdisk"_n; /** * @defgroup keyvalue Key Value Table From 576cacadb43c6741b6962ddb8506c6371afa678b Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Mon, 9 Mar 2020 10:29:29 -0400 Subject: [PATCH 268/659] update KV_NAMED_INDEX macro to use less args --- libraries/eosiolib/contracts/eosio/key_value.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 7fe1085c44..9520950bab 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -97,8 +97,8 @@ * @param value_class - The class the table stores. * @parma member_name - The name of the member pointer used for the index. */ -#define NAMED_INDEX(variable_name, index_name, value_class, member_name) \ - index variable_name{index_name, &value_class::member_name}; +#define KV_NAMED_INDEX(index_name, member_name) \ + index member_name{index_name ## _n, &value_type::member_name}; namespace eosio { namespace internal_use_do_not_use { @@ -595,6 +595,7 @@ class kv_table { public: using iterator = kv_table::iterator; + using value_type = T; /** * @ingroup keyvalue From 8fe2be352a288fa45ece98368269e01d19e9f4a5 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 10:36:57 -0400 Subject: [PATCH 269/659] Update KV_NAMED_INDEX documentation --- libraries/eosiolib/contracts/eosio/key_value.hpp | 8 +++----- tests/unit/test_contracts/kv_multiple_indices_tests.cpp | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 9520950bab..bf47f9a8a6 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -87,17 +87,15 @@ }; /** - * @brief Macro to define a table. + * @brief Macro to define an index. * @details In the case where the autogenerated index names created by DEFINE_TABLE are not enough, a user can instead * manually define the table and indices. This macro allows users to conveniently define an index without having to specify * the index template type, as those can be large/unwieldy to type out. * - * @param variable_name - The variable name in code of the index. * @param index_name - The index name. - * @param value_class - The class the table stores. - * @parma member_name - The name of the member pointer used for the index. + * @param member_name - The name of the member pointer used for the index. This also defines the index's C++ variable name. */ -#define KV_NAMED_INDEX(index_name, member_name) \ +#define KV_NAMED_INDEX(index_name, member_name) \ index member_name{index_name ## _n, &value_type::member_name}; namespace eosio { diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 571640d959..175e50f4d5 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -42,8 +42,8 @@ struct my_table2 : eosio::kv_table { }; struct my_table_idx : eosio::kv_table { - NAMED_INDEX(primary_key, "prim"_n, my_struct, primary_key) - NAMED_INDEX(foo, "f"_n, my_struct, foo) + KV_NAMED_INDEX("prim", primary_key) + KV_NAMED_INDEX("f", foo) my_table_idx(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); From 8dcf90f121c93f36782060bd3483148d20e8dee9 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 11:53:16 -0400 Subject: [PATCH 270/659] Code cleanup. --- .../eosiolib/contracts/eosio/key_value.hpp | 129 +++++++++--------- tests/integration/kv_tests.cpp | 2 +- .../unit/test_contracts/kv_make_key_tests.cpp | 11 +- .../test_contracts/kv_single_index_tests.cpp | 2 +- .../unit/test_contracts/kv_variant_tests.cpp | 2 +- 5 files changed, 65 insertions(+), 81 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index bf47f9a8a6..abee547a1d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -156,28 +156,22 @@ namespace detail { * The key_type struct is used to store the binary representation of a key. */ struct key_type : private std::string { - key_type() : std::string() {} + key_type() = default; key_type(const char* c, size_t s) : std::string(c, s) {} - key_type operator+(const key_type& b) const { - size_t buffer_size = size() + b.size(); - void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); - - memcpy(buffer, data(), size()); - memcpy(((char*)buffer) + size(), b.data(), b.size()); - return {(char*)buffer, buffer_size}; + key_type ret = *this; + ret += b; + return ret; } bool operator==(const key_type& b) const { - if (size() != b.size()) { - return false; - } - return memcmp(data(), b.data(), b.size()) == 0; + return size() != b.size() && memcmp(data(), b.data(), b.size()) == 0; } using std::string::data; using std::string::size; + using std::string::resize; }; /* @cond PRIVATE */ @@ -185,22 +179,17 @@ inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint auto bige_table = swap_endian(table_name.value); auto bige_index = swap_endian(index_name.value); - size_t size_name = sizeof(index_name); - - size_t buffer_size = (2 * size_name) + sizeof(status); - void* buffer = buffer_size > detail::max_stack_buffer_size ? malloc(buffer_size) : alloca(buffer_size); + constexpr size_t index_name_size = sizeof(index_name); + constexpr size_t buffer_size = (2 * index_name_size) + sizeof(status); - memcpy(buffer, &status, sizeof(status)); - memcpy(((char*)buffer) + sizeof(status), &bige_table, size_name); - memcpy(((char*)buffer) + sizeof(status) + size_name, &bige_index, size_name); + key_type ret; + ret.resize(buffer_size); - key_type s((const char*)buffer, buffer_size); + memcpy(ret.data(), &status, sizeof(status)); + memcpy(ret.data() + sizeof(status), &bige_table, index_name_size); + memcpy(ret.data() + sizeof(status) + index_name_size, &bige_index, index_name_size); - if (buffer_size > detail::max_stack_buffer_size) { - free(buffer); - } - - return s; + return ret; } inline key_type table_key(const key_type& prefix, const key_type& key) { @@ -380,17 +369,6 @@ inline key_type make_key(T val) { #endif -/** - * Used to return the appropriate representation of a case insensitive string for the EOSIO Key Value database. - * This is only valid for ASCII strings. - * - * @param val - The string to be made case-insensitive - * @return The binary representation of the case-insensitive string - */ -inline key_type make_insensitive(const std::string& val) { - return make_key(val, true); -} - static const eosio::name kv_ram = "eosio.kvram"_n; static const eosio::name kv_disk = "eosio.kvdisk"_n; @@ -409,12 +387,6 @@ static const eosio::name kv_disk = "eosio.kvdisk"_n; template class kv_table { - enum class kv_it_stat { - iterator_ok = 0, // Iterator is positioned at a key-value pair - iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased - iterator_end = -2, // Iterator is out-of-bounds - }; - struct index_config { uint64_t db_name; eosio::name contract_name; @@ -425,7 +397,13 @@ class kv_table { class iterator { public: - iterator(uint32_t itr, kv_it_stat itr_stat, const index_config& config) : itr{itr}, itr_stat{itr_stat}, config{config} {} + enum class status { + iterator_ok = 0, // Iterator is positioned at a key-value pair + iterator_erased = -1, // The key-value pair that the iterator used to be positioned at was erased + iterator_end = -2, // Iterator is out-of-bounds + }; + + iterator(uint32_t itr, status itr_stat, const index_config& config) : itr{itr}, itr_stat{itr_stat}, config{config} {} iterator(iterator&& other) : itr(std::exchange(other.itr, 0)), @@ -456,10 +434,11 @@ class kv_table { T value() const { using namespace detail; - eosio::check(itr_stat != kv_it_stat::iterator_end, "Cannot read end iterator"); + eosio::check(itr_stat != status::iterator_end, "Cannot read end iterator"); uint32_t value_size; uint32_t actual_value_size; + uint32_t actual_data_size; uint32_t offset = 0; // call once to get the value_size @@ -468,13 +447,14 @@ class kv_table { void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); auto stat = internal_use_do_not_use::kv_it_value(itr, offset, (char*)buffer, value_size, actual_value_size); - eosio::check(static_cast(stat) == kv_it_stat::iterator_ok, "Error reading value"); + eosio::check(static_cast(stat) == status::iterator_ok, "Error reading value"); void* deserialize_buffer = buffer; size_t deserialize_size = actual_value_size; - if (config.index_name != config.primary_index_name) { - uint32_t actual_data_size; + bool is_primary = config.index_name != config.primary_index_name; + + if (is_primary) { auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, actual_value_size, actual_data_size); eosio::check(success, "failure getting primary key"); @@ -487,12 +467,20 @@ class kv_table { T val; deserialize(val, deserialize_buffer, deserialize_size); + + if (value_size > detail::max_stack_buffer_size) { + free(buffer); + } + + if (is_primary && actual_data_size > detail::max_stack_buffer_size) { + free(deserialize_buffer); + } return val; } iterator& operator++() { - eosio::check(itr_stat != kv_it_stat::iterator_end, "cannot increment end iterator"); - itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); + eosio::check(itr_stat != status::iterator_end, "cannot increment end iterator"); + itr_stat = static_cast(internal_use_do_not_use::kv_it_next(itr)); return *this; } @@ -500,8 +488,8 @@ class kv_table { if (!itr) { itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); } - itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); - eosio::check(itr_stat != kv_it_stat::iterator_end, "decremented past the beginning"); + itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); + eosio::check(itr_stat != status::iterator_end, "decremented past the beginning"); return *this; } @@ -535,13 +523,13 @@ class kv_table { private: uint32_t itr; - kv_it_stat itr_stat; + status itr_stat; index_config config; int compare(const iterator& b) const { - bool a_is_end = !itr || itr_stat == kv_it_stat::iterator_end; - bool b_is_end = !b.itr || b.itr_stat == kv_it_stat::iterator_end; + bool a_is_end = !itr || itr_stat == status::iterator_end; + bool b_is_end = !b.itr || b.itr_stat == status::iterator_end; if (a_is_end && b_is_end) { return 0; } else if (a_is_end && b.itr) { @@ -557,7 +545,7 @@ class kv_table { class kv_index { public: - eosio::name index_name{0}; + eosio::name index_name; eosio::name table_name; eosio::name contract_name; @@ -636,7 +624,7 @@ class kv_table { * @param key - The key to search for. * @return An iterator to the found object OR the `end` iterator if the given key was not found. */ - iterator find(const K& key) { + iterator find(const K& key) const { auto t_key = table_key(config.prefix, make_key(key)); uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); @@ -649,7 +637,7 @@ class kv_table { return end(); } - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), config}; } /** @@ -659,8 +647,9 @@ class kv_table { * @param key - The key to search for. * @return A std::optional of the value corresponding to the key. */ - std::optional get(const K& key) { + std::optional get(const K& key) const { uint32_t value_size; + uint32_t actual_data_size; std::optional ret_val; auto t_key = table_key(config.prefix, make_key(key)); @@ -676,8 +665,8 @@ class kv_table { void* deserialize_buffer = buffer; size_t deserialize_size = copy_size; - if (config.index_name != config.primary_index_name) { - uint32_t actual_data_size; + bool is_primary = config.index_name != config.primary_index_name; + if (is_primary) { auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, copy_size, actual_data_size); eosio::check(success, "failure getting primary key"); @@ -695,6 +684,10 @@ class kv_table { free(buffer); } + if (is_primary && actual_data_size > detail::max_stack_buffer_size) { + free(deserialize_buffer); + } + return ret_val; } @@ -704,11 +697,11 @@ class kv_table { * * @return An iterator to the object with the lowest key (by this index) in the table. */ - iterator begin() { + iterator begin() const { uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), config}; } /** @@ -717,8 +710,8 @@ class kv_table { * * @return An iterator pointing past the end. */ - iterator end() { - return {0, kv_it_stat::iterator_end, config}; + iterator end() const { + return {0, iterator::status::iterator_end, config}; } /** @@ -727,13 +720,13 @@ class kv_table { * * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. */ - iterator lower_bound(const K& key) { + iterator lower_bound(const K& key) const { auto t_key = table_key(config.prefix, make_key(key)); uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), config}; } /** @@ -742,7 +735,7 @@ class kv_table { * * @return An iterator pointing to the first element greater than the given key. */ - iterator upper_bound(const K& key) { + iterator upper_bound(const K& key) const { auto t_key = table_key(config.prefix, make_key(key)); auto it = lower_bound(key); @@ -762,7 +755,7 @@ class kv_table { * @param end - The end of the range (exclusive). * @return A vector containing all the objects that fall between the range. */ - std::vector range(const K& b, const K& e) { + std::vector range(const K& b, const K& e) const { std::vector return_values; for(auto itr = lower_bound(b), end_itr = lower_bound(e); itr < end_itr; ++itr) { diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 87ac194d8d..7cce761c90 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -138,7 +138,7 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_variant, tester) try { // Make Key // -------- std::vector data_set{ - N(makekeyname), N(makekeystr), N(makekeyistr), N(makekeyuill), N(makekeyil), N(makekeyuilll), + N(makekeyname), N(makekeystr), N(makekeyuill), N(makekeyil), N(makekeyuilll), N(makekeyflt), N(makekeydbl), N(makekeystct), N(makekeytup) }; diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index e00d3be746..6fc4b17357 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -31,8 +31,6 @@ struct my_struct { tstruct == rhs.tstruct && ttuple == rhs.ttuple; } - - auto itstring() const { return eosio::make_insensitive(tstring); } }; struct my_table : eosio::kv_table { @@ -45,10 +43,9 @@ struct my_table : eosio::kv_table { index tdouble{&my_struct::tdouble}; index tstruct{&my_struct::tstruct}; index> ttuple{&my_struct::ttuple}; - index itstring{&my_struct::itstring}; my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &tname, &tstring, &tui64, &ti32, &tui128, &tfloat, &tdouble, &tstruct, &ttuple, &itstring); + init(contract_name, "testtable"_n, "eosio.kvram"_n, &tname, &tstring, &tui64, &ti32, &tui128, &tfloat, &tdouble, &tstruct, &ttuple); } }; @@ -148,12 +145,6 @@ class [[eosio::contract]] kv_make_key_tests : public eosio::contract { check_index(t.tstring, {s2, s5, s1, s3, s4}); } - [[eosio::action]] - void makekeyistr() { - my_table t{"kvtest"_n}; - check_index(t.itstring, {s1, s2, s3, s4, s5}); - } - [[eosio::action]] void makekeyuill() { my_table t{"kvtest"_n}; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 43c5829172..c218745572 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -8,7 +8,7 @@ struct my_struct { } }; -DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", primary_key) +DEFINE_TABLE(my_table, my_struct, "testtable", eosio::kv_ram, primary_key) class [[eosio::contract]] kv_single_index_tests : public eosio::contract { public: diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp index c4160febe7..72b5b94370 100644 --- a/tests/unit/test_contracts/kv_variant_tests.cpp +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -11,7 +11,7 @@ struct my_struct_v2 { uint64_t age; }; -DEFINE_TABLE(my_table, my_struct_v, "testtable", "eosio.kvram", age, full_name) +DEFINE_TABLE(my_table, my_struct_v, "testtable", eosio::kv_ram, age, full_name) struct my_table_v : eosio::kv_table> { index primary_key{[](const auto& obj) { From 9740bb4ec07869f826d4ea18aa6467257039cf9e Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Mon, 9 Mar 2020 11:57:39 -0400 Subject: [PATCH 271/659] adding exists function and [] to index --- libraries/eosiolib/contracts/eosio/key_value.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index abee547a1d..75b2a491ee 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -640,6 +640,20 @@ class kv_table { return {itr, static_cast(itr_stat), config}; } + bool exists( const K& key ) { + return find(key) != end(); + uint32_t value_size; + auto t_key = table_key(config.prefix, make_key(key)); + + return internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, t_key.data(), t_key.size(), value_size); + } + + T operator[]( const K& key ) { + auto opt = get(key); + eosio::check( opt, "key not found" ); + return *opt; + } + /** * Get the value for an existing object in a table by the index, using the given key. * @ingroup keyvalue From 191df430b8e302930962667389c7d296c8168079 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 12:43:39 -0400 Subject: [PATCH 272/659] Add tests for exists and [] --- libraries/eosiolib/contracts/eosio/key_value.hpp | 7 +++---- tests/integration/kv_tests.cpp | 4 ++++ tests/unit/test_contracts/kv_single_index_tests.cpp | 12 ++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 75b2a491ee..545828cde5 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -640,17 +640,16 @@ class kv_table { return {itr, static_cast(itr_stat), config}; } - bool exists( const K& key ) { - return find(key) != end(); + bool exists( const K& key ) const { uint32_t value_size; auto t_key = table_key(config.prefix, make_key(key)); return internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, t_key.data(), t_key.size(), value_size); } - T operator[]( const K& key ) { + T operator[]( const K& key ) const { auto opt = get(key); - eosio::check( opt, "key not found" ); + eosio::check( opt.has_value(), "key not found" ); return *opt; } diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 7cce761c90..551e7d1fd0 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -52,6 +52,10 @@ BOOST_AUTO_TEST_CASE(single_tests_get) try { TESTER tester; setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); tester.push_action(N(kvtest), N(get), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(geterror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("key not found")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index c218745572..c776fe183f 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -84,6 +84,18 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { val = t.primary_key.get("william"_n); eosio::check(!val, "Should not have gotten a value"); + + eosio::check(t.primary_key.exists("bob"_n), "Exists should return true"); + eosio::check(!t.primary_key.exists("william"_n), "Exists should return false"); + + auto vval = t.primary_key["bob"_n]; + eosio::check(vval.primary_key == "bob"_n, "Got the wrong value"); + } + + [[eosio::action]] + void geterror() { + my_table t{"kvtest"_n}; + auto val = t.primary_key["william"_n]; } [[eosio::action]] From 3899c3a4c0979ccb71dd67ca4b21a953bb40efc7 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 10 Mar 2020 11:11:17 +0200 Subject: [PATCH 273/659] remove '$' chars from shell commands --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 950e2ce10f..ce7e787fb9 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ brew remove eosio.cdt ### Debian Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb -$ sudo apt install ./eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb +wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb +sudo apt install ./eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb ``` ### Debian Package Uninstall @@ -39,8 +39,8 @@ sudo apt remove eosio.cdt ### RPM Package Install ```sh -$ wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt-1.7.0-1.el7.x86_64.rpm -$ sudo yum install ./eosio.cdt-1.7.0-1.el7.x86_64.rpm +wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt-1.7.0-1.el7.x86_64.rpm +sudo yum install ./eosio.cdt-1.7.0-1.el7.x86_64.rpm ``` ### RPM Package Uninstall From 5900ab3fd9b082413609191e980d56605502a2cd Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 9 Mar 2020 15:54:28 -0400 Subject: [PATCH 274/659] Remove DEFINE_TABLE and require all indexes to be named. Remove case insensitive. rb --- .../eosiolib/contracts/eosio/key_value.hpp | 143 +++--------------- tests/integration/kv_tests.cpp | 13 -- .../unit/test_contracts/kv_make_key_tests.cpp | 18 +-- .../kv_multiple_indices_tests.cpp | 61 +------- .../test_contracts/kv_single_index_tests.cpp | 8 +- .../unit/test_contracts/kv_variant_tests.cpp | 9 +- 6 files changed, 51 insertions(+), 201 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 545828cde5..300e01b7c6 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -1,7 +1,6 @@ #pragma once #include "../../core/eosio/datastream.hpp" #include "../../core/eosio/name.hpp" -#include "../../core/eosio/print.hpp" #include "../../core/eosio/utility.hpp" #include "../../core/eosio/varint.hpp" @@ -15,77 +14,8 @@ #include #include -#define EOSIO_CDT_KV_INDEXnullptr - -#define EOSIO_CDT_KV_INDEX_TEST() 1 -#define EOSIO_CDT_KV_INDEX_TEST_EOSIO_CDT_KV_INDEX_TEST 0, -#define EOSIO_CDT_KV_INDEX_TEST_1 1, ignore -#define EOSIO_CDT_EXPAND(x) x -#define EOSIO_CDT_CAT2(x, y) x ## y -#define EOSIO_CDT_CAT(x, y) EOSIO_CDT_CAT2(x, y) -#define EOSIO_CDT_APPLY(f, args) f args - #define EOSIO_CDT_GET_RETURN_T(value_class, index_name) std::decay_t()))> -#define EOSIO_CDT_KV_FIX_INDEX_NAME_0(index_name, i) index_name -#define EOSIO_CDT_KV_FIX_INDEX_NAME_1(index_name, i) index_name ## i -#define EOSIO_CDT_KV_FIX_INDEX_NAME(x, i) EOSIO_CDT_KV_FIX_INDEX_NAME_ ## x - -#define EOSIO_CDT_KV_FIX_INDEX_TYPE_0(index_name) index -#define EOSIO_CDT_KV_FIX_INDEX_TYPE_1(index_name) null_index -#define EOSIO_CDT_KV_FIX_INDEX_TYPE(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_TYPE_ ## iskeyword - -#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_0(value_class, index_name) {&value_class::index_name} -#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_1(value_class, index_name) -#define EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT(iskeyword, garbage) EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT_ ## iskeyword - -#define EOSIO_CDT_KV_INDEX_NAME(index_name, i) \ - EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_NAME, \ - (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(index_name, i) - -#define EOSIO_CDT_KV_INDEX_TYPE(index_name) \ - EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_TYPE, \ - (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(index_name) - -#define EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name) \ - EOSIO_CDT_APPLY(EOSIO_CDT_KV_FIX_INDEX_CONSTRUCT, \ - (EOSIO_CDT_CAT(EOSIO_CDT_KV_INDEX_TEST_, \ - EOSIO_CDT_EXPAND(EOSIO_CDT_KV_INDEX_TEST EOSIO_CDT_KV_INDEX ## index_name ()))))(value_class, index_name) - -#define EOSIO_CDT_CREATE_KV_INDEX(r, value_class, i, index_name) \ - EOSIO_CDT_KV_INDEX_TYPE(index_name) EOSIO_CDT_KV_INDEX_NAME(index_name, i) EOSIO_CDT_KV_INDEX_CONSTRUCT(value_class, index_name); - -#define EOSIO_CDT_CREATE_KV_INDICES(value_class, ...) \ - BOOST_PP_SEQ_FOR_EACH_I(EOSIO_CDT_CREATE_KV_INDEX, value_class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) - -#define EOSIO_CDT_LIST_KV_INDEX(r, data, index_name) \ - ,&index_name - -#define EOSIO_CDT_LIST_KV_INDICES(...) \ - BOOST_PP_SEQ_FOR_EACH(EOSIO_CDT_LIST_KV_INDEX, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) - -/** - * @brief Macro to define a table. - * @details The resulting table will have member fields on it that match 1-1 with the names of the - * fields passed into the list. See example for further clarification. - * - * @param table_class - The name of the class of the user defined table that inherits from eosio::kv_table - * @param value_class - The name of the class of the data stored as the value of the table - * @param table_name - The name of the table - * @param db_name - The type of the EOSIO Key Value database. Defaulted to eosio.kvram - * @param ... - A variadic list of 1 or more indexes to define on the table. - */ -#define DEFINE_TABLE(table_class, value_class, table_name, db_name, /*indices*/...) \ - struct table_class : eosio::kv_table { \ - EOSIO_CDT_CREATE_KV_INDICES(value_class, __VA_ARGS__) \ - \ - table_class(eosio::name contract_name) { \ - init(contract_name, table_name##_n, db_name EOSIO_CDT_LIST_KV_INDICES(__VA_ARGS__)); \ - } \ - }; - /** * @brief Macro to define an index. * @details In the case where the autogenerated index names created by DEFINE_TABLE are not enough, a user can instead @@ -96,7 +26,7 @@ * @param member_name - The name of the member pointer used for the index. This also defines the index's C++ variable name. */ #define KV_NAMED_INDEX(index_name, member_name) \ - index member_name{index_name ## _n, &value_type::member_name}; + index member_name{eosio::name{index_name}, &value_type::member_name}; namespace eosio { namespace internal_use_do_not_use { @@ -255,15 +185,11 @@ inline key_type make_key(double val) { return make_floating_key(val); } -inline key_type make_key(const char* str, size_t size, bool case_insensitive=false) { +inline key_type make_key(const char* str, size_t size) { size_t data_size = size + 3; void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - if (case_insensitive) { - std::transform(str, str + size, (char*)data_buffer, [](unsigned char c) -> unsigned char { return std::toupper(c); }); - } else { - memcpy(data_buffer, str, size); - } + memcpy(data_buffer, str, size); ((char*)data_buffer)[data_size - 3] = 0x01; ((char*)data_buffer)[data_size - 2] = 0x00; @@ -277,16 +203,16 @@ inline key_type make_key(const char* str, size_t size, bool case_insensitive=fal return s; } -inline key_type make_key(const std::string& val, bool case_insensitive=false) { - return make_key(val.data(), val.size(), case_insensitive); +inline key_type make_key(const std::string& val) { + return make_key(val.data(), val.size()); } -inline key_type make_key(const std::string_view& val, bool case_insensitive=false) { - return make_key(val.data(), val.size(), case_insensitive); +inline key_type make_key(const std::string_view& val) { + return make_key(val.data(), val.size()); } -inline key_type make_key(const char* str, bool case_insensitive=false) { - return make_key(std::string_view{str}, case_insensitive); +inline key_type make_key(const char* str) { + return make_key(std::string_view{str}); } inline key_type make_key(eosio::name n) { @@ -791,15 +717,6 @@ class kv_table { } }; - /** - * @ingroup keyvalue - * - * @brief Defines a deleted index on an EOSIO Key Value Table - * @details Due to the way indexes are named, when deleting an index a "placeholder" index needs to be created instead. - * A null_index should be created in this case. If using DEFINE_TABLE, just passing in nullptr will handle this. - */ - class null_index{}; - /** * @ingroup keyvalue * Puts a value into the table. If the value already exists, it updates the existing entry. @@ -894,57 +811,34 @@ class kv_table { protected: kv_table() = default; - void setup_indices(uint64_t index_name, bool is_named) {} - - template - void setup_indices(uint64_t index_name, bool is_named, null_index* index, Indices... indices) { - ++index_name; - setup_indices(index_name, is_named, indices...); - } + void setup_indices() {} template - void setup_indices(uint64_t index_name, bool is_named, I index, Indices... indices) { - if (is_named) { - eosio::check(index->index_name.value > 0, "All indices must be named if one is named."); - } else { - eosio::check(index->index_name.value == 0, "All indices must be named if one is named."); - index->index_name = eosio::name{index_name}; - } - + void setup_indices(I index, Indices... indices) { index->contract_name = contract_name; index->table_name = table_name; index->tbl = this; index->setup(); secondary_indices.push_back(index); - ++index_name; - setup_indices(index_name, is_named, indices...); + setup_indices(indices...); } template void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex prim_index, SecondaryIndices... indices) { + validate_types(prim_index, indices...); contract_name = contract; table_name = table; db_name = db.value; - bool is_named = false; - uint64_t index_name = 1; - primary_index = prim_index; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; - if (primary_index->index_name.value > 0) { - is_named = true; - } else { - primary_index->index_name = eosio::name{index_name}; - ++index_name; - } - primary_index->setup(); - setup_indices(index_name, is_named, indices...); + setup_indices(indices...); } private: @@ -955,6 +849,15 @@ class kv_table { kv_index* primary_index; std::vector secondary_indices; + constexpr void validate_types() {} + + template + constexpr void validate_types(Type t, Types... ts) { + constexpr bool is_kv_index = std::is_base_of_v>; + static_assert(is_kv_index, "Incorrect index type passed to init. Must be an index."); + validate_types(ts...); + } + template static void serialize(const V& value, void* buffer, size_t size) { datastream ds((char*)buffer, size); diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 551e7d1fd0..255ae764e3 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -92,19 +92,6 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { // Multi // ----- -BOOST_FIXTURE_TEST_CASE(multi_tests_idx, tester) try { - TESTER tester; - setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); - tester.push_action(N(kvtest), N(indices), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(indiceserr), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("All indices must be named if one is named.")); - BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(indiceserr2), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("All indices must be named if one is named.")); -} FC_LOG_AND_RETHROW() - BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { TESTER tester; setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index 6fc4b17357..e62bd5aa63 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -34,15 +34,15 @@ struct my_struct { }; struct my_table : eosio::kv_table { - index tname{&my_struct::tname}; - index tstring{&my_struct::tstring}; - index tui64{&my_struct::tui64}; - index ti32{&my_struct::ti32}; - index tui128{&my_struct::tui128}; - index tfloat{&my_struct::tfloat}; - index tdouble{&my_struct::tdouble}; - index tstruct{&my_struct::tstruct}; - index> ttuple{&my_struct::ttuple}; + KV_NAMED_INDEX("t1"_n, tname) + KV_NAMED_INDEX("t2"_n, tstring) + KV_NAMED_INDEX("t3"_n, tui64) + KV_NAMED_INDEX("t4"_n, ti32) + KV_NAMED_INDEX("t5"_n, tui128) + KV_NAMED_INDEX("t11"_n, tfloat) + KV_NAMED_INDEX("t12"_n, tdouble) + KV_NAMED_INDEX("t13"_n, tstruct) + KV_NAMED_INDEX("t14"_n, ttuple) my_table(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, &tname, &tstring, &tui64, &ti32, &tui128, &tfloat, &tdouble, &tstruct, &ttuple); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 175e50f4d5..77309e0b50 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -20,54 +20,16 @@ struct my_struct { }; struct my_table : eosio::kv_table { - index primary_key{&my_struct::primary_key}; - index foo{&my_struct::foo}; - index bar{&my_struct::bar}; - - index> non_unique_name{&my_struct::non_unique_name}; + KV_NAMED_INDEX("primarykey"_n, primary_key) + KV_NAMED_INDEX("foo"_n, foo) + KV_NAMED_INDEX("bar"_n, bar) + KV_NAMED_INDEX("nonuniqnme"_n, non_unique_name) my_table(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo, &bar, &non_unique_name); } }; -struct my_table2 : eosio::kv_table { - index primary_key{&my_struct::primary_key}; - null_index nullptr_2; - index bar{&my_struct::bar}; - - my_table2(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &nullptr_2, &bar); - } -}; - -struct my_table_idx : eosio::kv_table { - KV_NAMED_INDEX("prim", primary_key) - KV_NAMED_INDEX("f", foo) - - my_table_idx(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); - } -}; - -struct my_table_idx_err : eosio::kv_table { - index primary_key{"prim"_n, &my_struct::primary_key}; - index foo{&my_struct::foo}; - - my_table_idx_err(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); - } -}; - -struct my_table_idx_err_2 : eosio::kv_table { - index primary_key{&my_struct::primary_key}; - index foo{"f"_n, &my_struct::foo}; - - my_table_idx_err_2(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo); - } -}; - class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { public: using contract::contract; @@ -118,21 +80,6 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { t.put(s5); } - [[eosio::action]] - void indices() { - my_table_idx t{"kvtest"_n}; - } - - [[eosio::action]] - void indiceserr() { - my_table_idx_err t{"kvtest"_n}; - } - - [[eosio::action]] - void indiceserr2() { - my_table_idx_err_2 t{"kvtest"_n}; - } - [[eosio::action]] void iteration() { my_table t{"kvtest"_n}; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index c776fe183f..29c738f316 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -8,7 +8,13 @@ struct my_struct { } }; -DEFINE_TABLE(my_table, my_struct, "testtable", eosio::kv_ram, primary_key) +struct my_table : eosio::kv_table { + KV_NAMED_INDEX("primary"_n, primary_key); + + my_table(eosio::name contract_name) { + init(contract_name, "testtable"_n, eosio::kv_ram, &primary_key); + } +}; class [[eosio::contract]] kv_single_index_tests : public eosio::contract { public: diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp index 72b5b94370..c7212a78d4 100644 --- a/tests/unit/test_contracts/kv_variant_tests.cpp +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -11,7 +11,14 @@ struct my_struct_v2 { uint64_t age; }; -DEFINE_TABLE(my_table, my_struct_v, "testtable", eosio::kv_ram, age, full_name) +struct my_table : eosio::kv_table { + KV_NAMED_INDEX("age"_n, age); + KV_NAMED_INDEX("fullname"_n, full_name); + + my_table(eosio::name contract_name) { + init(contract_name, "testtable"_n, eosio::kv_ram, &age, &full_name); + } +}; struct my_table_v : eosio::kv_table> { index primary_key{[](const auto& obj) { From 97393aaf1b7b4a26d192683583ecd43d94643f70 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 11 Mar 2020 10:38:31 -0400 Subject: [PATCH 275/659] Update how to guides --- .../06_key_value/01_key_value_examples.md | 117 +++++------------- 1 file changed, 29 insertions(+), 88 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index a3cb70a64e..b17a18367d 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -1,30 +1,3 @@ -### DEFINE_TABLE Example: -```cpp -struct myrecord { - std::string primary_key; - uint64_t secondary_1; - std::tuple secondary_2; -} - -DEFINE_TABLE(mytable, myrecord, "testtable", "eosio.kvram", - primary_key, - secondary_1, - secondary_2 -) - -// The above macro results in the following class. - -struct mytable : kv_table { - index primary_key{&myrecord::primary_key}; - index secondary_1{&myrecord::secondary_1}; - index> secondary_2{&myrecord::secondary_2}; - - mytable(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &secondary_1, &secondary_2); - } -} -``` - ### kv_table Example: ```cpp #include @@ -41,9 +14,9 @@ struct address { auto full_name() { return first_name + " " + last_name; } } -struct address_table : kv_table { - index account_name{&myrecord::account_name}; - index full_name{&myrecord::full_name}; +struct address_table : kv_table
{ + index account_name{"accname"_n, &myrecord::account_name}; + index full_name{"fullname"_n, &myrecord::full_name}; address_table(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, &account_name, &full_name); @@ -58,6 +31,19 @@ class addressbook : contract { } ``` +### KV_NAMED_INDEX Example: +```cpp +// Assume the address definition above +struct address_table : kv_table
{ + KV_NAMED_INDEX("accname"_n, account_name) + KV_NAMED_INDEX("fullname"_n, full_name) + + address_table(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, &account_name, &full_name); + } +} +``` + ### Using RAM vs DISK example: ```cpp struct myrecord { @@ -66,8 +52,19 @@ struct myrecord { std::tuple secondary_2; } -DEFINE_TABLE(myramtable, myrecord, "testramtbl", "eosio.kvram", primary_key, secondary_1, secondary_2) -DEFINE_TABLE(mydisktable, myrecord, "testdisktbl", "eosio.kvdisk", primary_key, secondary_1, secondary_2) +struct myramtable : kv_table { + // Assume some indexes + myramtable(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvram"_n, ...) + } +} + +struct mydisktable : kv_table { + // Assume some indexes + mydisktable(eosio::name contract_name) { + init(contract_name, "testtable"_n, "eosio.kvdisk"_n, ...) + } +} ``` ### kv_table::put Example: @@ -165,59 +162,3 @@ void myaction() { eosio::check(values == expected_values, "Did not get the expected values"); } ``` - -### Deleted Index Example: -```cpp -// Original table: -DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - primary_key, - secondary_1, - secondary_2 -) - -struct my_table : kv_table { - index primary_key ...; - index secondary_1 ...; - index secondary_2 ...; - - my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &secondary_1, &secondary_2); - } -} - -// Table with secondary_1 deleted: -DEFINE_TABLE(my_table, my_struct, "testtable", "eosio.kvram", - primary_key, - nullptr - secondary_2 -) - -struct my_table : kv_table { - kv_index primary_key ...; - null_index nullptr2; - kv_index secondary_2 ...; - - my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &nullptr2, &secondary_2); - } -} -``` - -### make_insensitive Example: - -```cpp -struct location { - std::string city; - std::string state; - uint64_t zip_code; - - auto icity() { return eosio::make_insensitive(city); } - auto istate() { return eosio::make_insensitive(state); } -} - -DEFINE_TABLE(my_table, location, "testtable", "eosio.kvram", - icity, - istate, - zip_code -) -``` \ No newline at end of file From aecb6d58397a36fcd46a0017019777d1133d345c Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 11 Mar 2020 11:40:06 -0400 Subject: [PATCH 276/659] Remove non-named constructor and fix variant tests. --- libraries/eosiolib/contracts/eosio/key_value.hpp | 11 ++--------- tests/integration/kv_tests.cpp | 7 ++++++- tests/unit/test_contracts/kv_variant_tests.cpp | 8 ++++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 300e01b7c6..b4280100bb 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -378,9 +378,9 @@ class kv_table { void* deserialize_buffer = buffer; size_t deserialize_size = actual_value_size; - bool is_primary = config.index_name != config.primary_index_name; + bool is_primary = config.index_name == config.primary_index_name; - if (is_primary) { + if (!is_primary) { auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, actual_value_size, actual_data_size); eosio::check(success, "failure getting primary key"); @@ -478,13 +478,6 @@ class kv_table { protected: kv_index() = default; - template - kv_index(KF&& kf) { - key_function = [=](const T& t) { - return make_key(std::invoke(kf, &t)); - }; - } - template kv_index(eosio::name index_name, KF&& kf) : index_name{index_name} { key_function = [=](const T& t) { diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 255ae764e3..8504fcb312 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -119,10 +119,15 @@ BOOST_FIXTURE_TEST_CASE(multi_tests_update, tester) try { // Variant // ------- -BOOST_FIXTURE_TEST_CASE(multi_tests_variant, tester) try { +BOOST_FIXTURE_TEST_CASE(variant_tests, tester) try { TESTER tester; setup(tester, contracts::kv_variant_tests_wasm(), contracts::kv_variant_tests_abi()); tester.push_action(N(kvtest), N(vriant), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(variant_upgrade_tests, tester) try { + TESTER tester; + setup(tester, contracts::kv_variant_tests_wasm(), contracts::kv_variant_tests_abi()); tester.push_action(N(kvtest), N(vriantupgrd), N(kvtest), {}); } FC_LOG_AND_RETHROW() diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp index c7212a78d4..e5b655a876 100644 --- a/tests/unit/test_contracts/kv_variant_tests.cpp +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -12,16 +12,16 @@ struct my_struct_v2 { }; struct my_table : eosio::kv_table { - KV_NAMED_INDEX("age"_n, age); KV_NAMED_INDEX("fullname"_n, full_name); + KV_NAMED_INDEX("age"_n, age); my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, eosio::kv_ram, &age, &full_name); + init(contract_name, "testtable"_n, eosio::kv_ram, &full_name, &age); } }; struct my_table_v : eosio::kv_table> { - index primary_key{[](const auto& obj) { + index primary_key{"fullname"_n, [](const auto& obj) { return std::visit([&](auto&& a) { using V = std::decay_t; if constexpr(std::is_same_v) { @@ -34,7 +34,7 @@ struct my_table_v : eosio::kv_table> { } }, *obj); }}; - index age{[](const auto& obj) { + index age{"age"_n, [](const auto& obj) { return std::visit([&](auto&& a) { return a.age; }, *obj); From 155fd9d668ac06d37f45ae9c5df00182314453b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 11 Mar 2020 15:55:06 -0400 Subject: [PATCH 277/659] init accepts references now and further code cleanup --- .../eosiolib/contracts/eosio/key_value.hpp | 40 ++++++++----------- .../unit/test_contracts/kv_make_key_tests.cpp | 2 +- .../kv_multiple_indices_tests.cpp | 2 +- .../test_contracts/kv_single_index_tests.cpp | 2 +- .../unit/test_contracts/kv_variant_tests.cpp | 4 +- 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index b4280100bb..de0a87c002 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -8,12 +8,6 @@ #include #include -#include -#include -#include -#include -#include - #define EOSIO_CDT_GET_RETURN_T(value_class, index_name) std::decay_t()))> /** @@ -804,34 +798,32 @@ class kv_table { protected: kv_table() = default; - void setup_indices() {} - template - void setup_indices(I index, Indices... indices) { - index->contract_name = contract_name; - index->table_name = table_name; - index->tbl = this; - - index->setup(); - secondary_indices.push_back(index); - setup_indices(indices...); + void setup_indices(I&& index, Indices&&... indices) { + kv_index* idx = &index; + idx->contract_name = contract_name; + idx->table_name = table_name; + idx->tbl = this; + + idx->setup(); + secondary_indices.push_back(idx); } template - void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex prim_index, SecondaryIndices... indices) { - validate_types(prim_index, indices...); + void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex&& prim_index, SecondaryIndices&&... indices) { + (validate_types(prim_index, indices), ...); contract_name = contract; table_name = table; db_name = db.value; - primary_index = prim_index; + primary_index = &prim_index; primary_index->contract_name = contract_name; primary_index->table_name = table_name; primary_index->tbl = this; primary_index->setup(); - setup_indices(indices...); + (setup_indices(indices), ...); } private: @@ -845,10 +837,10 @@ class kv_table { constexpr void validate_types() {} template - constexpr void validate_types(Type t, Types... ts) { - constexpr bool is_kv_index = std::is_base_of_v>; - static_assert(is_kv_index, "Incorrect index type passed to init. Must be an index."); - validate_types(ts...); + constexpr void validate_types(Type&& t, Types&&... ts) { + constexpr bool is_kv_index = std::is_base_of_v>; + constexpr bool is_ref = std::is_reference_v; + static_assert(is_kv_index && is_ref, "Incorrect index type passed to init. Must be a reference to an index."); } template diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index e62bd5aa63..e17b20b6b5 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -45,7 +45,7 @@ struct my_table : eosio::kv_table { KV_NAMED_INDEX("t14"_n, ttuple) my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &tname, &tstring, &tui64, &ti32, &tui128, &tfloat, &tdouble, &tstruct, &ttuple); + init(contract_name, "testtable"_n, "eosio.kvram"_n, tname, tstring, tui64, ti32, tui128, tfloat, tdouble, tstruct, ttuple); } }; diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 77309e0b50..8afff3f532 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -26,7 +26,7 @@ struct my_table : eosio::kv_table { KV_NAMED_INDEX("nonuniqnme"_n, non_unique_name) my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &foo, &bar, &non_unique_name); + init(contract_name, "testtable"_n, "eosio.kvram"_n, primary_key, foo, bar, non_unique_name); } }; diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index 29c738f316..abb69ced43 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -12,7 +12,7 @@ struct my_table : eosio::kv_table { KV_NAMED_INDEX("primary"_n, primary_key); my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, eosio::kv_ram, &primary_key); + init(contract_name, "testtable"_n, eosio::kv_ram, primary_key); } }; diff --git a/tests/unit/test_contracts/kv_variant_tests.cpp b/tests/unit/test_contracts/kv_variant_tests.cpp index e5b655a876..c70163f1b6 100644 --- a/tests/unit/test_contracts/kv_variant_tests.cpp +++ b/tests/unit/test_contracts/kv_variant_tests.cpp @@ -16,7 +16,7 @@ struct my_table : eosio::kv_table { KV_NAMED_INDEX("age"_n, age); my_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, eosio::kv_ram, &full_name, &age); + init(contract_name, "testtable"_n, eosio::kv_ram, full_name, age); } }; @@ -41,7 +41,7 @@ struct my_table_v : eosio::kv_table> { }}; my_table_v(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &primary_key, &age); + init(contract_name, "testtable"_n, "eosio.kvram"_n, primary_key, age); } }; From 0ec249add323863f5c345c97b9746b0364c13956 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 09:53:52 -0400 Subject: [PATCH 278/659] Remove index_config and pass around an index pointer instead. --- .../eosiolib/contracts/eosio/key_value.hpp | 87 ++++++++----------- tests/integration/kv_tests.cpp | 6 ++ .../kv_multiple_indices_tests.cpp | 9 ++ 3 files changed, 53 insertions(+), 49 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index de0a87c002..f7d0107a92 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -307,13 +307,7 @@ static const eosio::name kv_disk = "eosio.kvdisk"_n; template class kv_table { - struct index_config { - uint64_t db_name; - eosio::name contract_name; - eosio::name index_name; - eosio::name primary_index_name; - key_type prefix; - }; + class kv_index; class iterator { public: @@ -323,12 +317,13 @@ class kv_table { iterator_end = -2, // Iterator is out-of-bounds }; - iterator(uint32_t itr, status itr_stat, const index_config& config) : itr{itr}, itr_stat{itr_stat}, config{config} {} + iterator() = default; + + iterator(uint32_t itr, status itr_stat, const kv_index* index) : itr{itr}, itr_stat{itr_stat}, index{index} {} iterator(iterator&& other) : itr(std::exchange(other.itr, 0)), - itr_stat(std::move(other.itr_stat)), - config(std::move(other.config)) + itr_stat(std::move(other.itr_stat)) {} ~iterator() { @@ -338,10 +333,11 @@ class kv_table { } iterator& operator=(iterator&& other) { - itr = std::exchange(other.itr, itr); + if (itr) { + internal_use_do_not_use::kv_it_destroy(itr); + } + itr = std::exchange(other.itr, 0); itr_stat = std::move(other.itr_stat); - config = std::move(other.config); - return *this; } @@ -372,14 +368,13 @@ class kv_table { void* deserialize_buffer = buffer; size_t deserialize_size = actual_value_size; - bool is_primary = config.index_name == config.primary_index_name; - + bool is_primary = index->index_name == index->tbl->primary_index_name; if (!is_primary) { - auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, actual_value_size, actual_data_size); - eosio::check(success, "failure getting primary key"); + auto success = internal_use_do_not_use::kv_get(index->tbl->db_name, index->contract_name.value, (char*)buffer, actual_value_size, actual_data_size); + eosio::check(success, "failure getting primary key in `value()`"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)pk_buffer, actual_data_size); + internal_use_do_not_use::kv_get_data(index->tbl->db_name, 0, (char*)pk_buffer, actual_data_size); deserialize_buffer = pk_buffer; deserialize_size = actual_data_size; @@ -406,7 +401,7 @@ class kv_table { iterator& operator--() { if (!itr) { - itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + itr = internal_use_do_not_use::kv_it_create(index->tbl->db_name, index->contract_name.value, index->prefix.data(), index->prefix.size()); } itr_stat = static_cast(internal_use_do_not_use::kv_it_prev(itr)); eosio::check(itr_stat != status::iterator_end, "decremented past the beginning"); @@ -445,7 +440,7 @@ class kv_table { uint32_t itr; status itr_stat; - index_config config; + const kv_index* index; int compare(const iterator& b) const { bool a_is_end = !itr || itr_stat == status::iterator_end; @@ -509,8 +504,6 @@ class kv_table { */ template class index : public kv_index { - index_config config; - public: using kv_table::kv_index::tbl; using kv_table::kv_index::table_name; @@ -538,9 +531,9 @@ class kv_table { * @return An iterator to the found object OR the `end` iterator if the given key was not found. */ iterator find(const K& key) const { - auto t_key = table_key(config.prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(key)); - uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); auto cmp = internal_use_do_not_use::kv_it_key_compare(itr, t_key.data(), t_key.size()); @@ -550,14 +543,14 @@ class kv_table { return end(); } - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), reinterpret_cast(this)}; } bool exists( const K& key ) const { uint32_t value_size; - auto t_key = table_key(config.prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(key)); - return internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, t_key.data(), t_key.size(), value_size); + return internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); } T operator[]( const K& key ) const { @@ -578,26 +571,26 @@ class kv_table { uint32_t actual_data_size; std::optional ret_val; - auto t_key = table_key(config.prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(key)); - auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, t_key.data(), t_key.size(), value_size); + auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); if (!success) { return ret_val; } void* buffer = value_size > detail::max_stack_buffer_size ? malloc(value_size) : alloca(value_size); - auto copy_size = internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)buffer, value_size); + auto copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)buffer, value_size); void* deserialize_buffer = buffer; size_t deserialize_size = copy_size; - bool is_primary = config.index_name != config.primary_index_name; - if (is_primary) { - auto success = internal_use_do_not_use::kv_get(config.db_name, config.contract_name.value, (char*)buffer, copy_size, actual_data_size); + bool is_primary = index_name == tbl->primary_index_name; + if (!is_primary) { + auto success = internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, (char*)buffer, copy_size, actual_data_size); eosio::check(success, "failure getting primary key"); void* pk_buffer = actual_data_size > detail::max_stack_buffer_size ? malloc(actual_data_size) : alloca(actual_data_size); - auto pk_copy_size = internal_use_do_not_use::kv_get_data(config.db_name, 0, (char*)pk_buffer, actual_data_size); + auto pk_copy_size = internal_use_do_not_use::kv_get_data(tbl->db_name, 0, (char*)pk_buffer, actual_data_size); deserialize_buffer = pk_buffer; deserialize_size = pk_copy_size; @@ -624,10 +617,10 @@ class kv_table { * @return An iterator to the object with the lowest key (by this index) in the table. */ iterator begin() const { - uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), reinterpret_cast(this)}; } /** @@ -637,7 +630,7 @@ class kv_table { * @return An iterator pointing past the end. */ iterator end() const { - return {0, iterator::status::iterator_end, config}; + return {0, iterator::status::iterator_end, reinterpret_cast(this)}; } /** @@ -647,12 +640,12 @@ class kv_table { * @return An iterator pointing to the element with the lowest key greater than or equal to the given key. */ iterator lower_bound(const K& key) const { - auto t_key = table_key(config.prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(key)); - uint32_t itr = internal_use_do_not_use::kv_it_create(config.db_name, config.contract_name.value, config.prefix.data(), config.prefix.size()); + uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - return {itr, static_cast(itr_stat), config}; + return {itr, static_cast(itr_stat), reinterpret_cast(this)}; } /** @@ -662,7 +655,7 @@ class kv_table { * @return An iterator pointing to the first element greater than the given key. */ iterator upper_bound(const K& key) const { - auto t_key = table_key(config.prefix, make_key(key)); + auto t_key = table_key(prefix, make_key(key)); auto it = lower_bound(key); auto cmp = it.key_compare(t_key); @@ -693,14 +686,6 @@ class kv_table { void setup() override { prefix = make_prefix(table_name, index_name); - config = { - .db_name = tbl->db_name, - .contract_name = contract_name, - .index_name = index_name, - .primary_index_name = tbl->primary_index->index_name, - .prefix = prefix - }; - } }; @@ -823,6 +808,8 @@ class kv_table { primary_index->setup(); + primary_index_name = primary_index->index_name; + (setup_indices(indices), ...); } @@ -831,6 +818,8 @@ class kv_table { eosio::name table_name; uint64_t db_name; + eosio::name primary_index_name; + kv_index* primary_index; std::vector secondary_indices; diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 8504fcb312..f5731ccd0d 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -92,6 +92,12 @@ BOOST_FIXTURE_TEST_CASE(single_tests_erase, tester) try { // Multi // ----- +BOOST_FIXTURE_TEST_CASE(multi_tests_get, tester) try { + TESTER tester; + setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); + tester.push_action(N(kvtest), N(get), N(kvtest), {}); +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(multi_tests_iteration, tester) try { TESTER tester; setup(tester, contracts::kv_multi_tests_wasm(), contracts::kv_multi_tests_abi()); diff --git a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp index 8afff3f532..d390e0d8f0 100644 --- a/tests/unit/test_contracts/kv_multiple_indices_tests.cpp +++ b/tests/unit/test_contracts/kv_multiple_indices_tests.cpp @@ -80,6 +80,15 @@ class [[eosio::contract]] kv_multiple_indices_tests : public eosio::contract { t.put(s5); } + [[eosio::action]] + void get() { + my_table t{"kvtest"_n}; + auto end_itr = t.foo.end(); + + auto val = t.foo.get("g"); + eosio::check(val->primary_key == "joe"_n, "Got the wrong value"); + } + [[eosio::action]] void iteration() { my_table t{"kvtest"_n}; From e16a790da09522cb44ce376c6c324fcd10afc6f6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 12:39:51 -0400 Subject: [PATCH 279/659] Code cleanup --- .../eosiolib/contracts/eosio/key_value.hpp | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index f7d0107a92..d52f5e6e79 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -288,9 +288,8 @@ inline key_type make_key(T val) { } #endif - -static const eosio::name kv_ram = "eosio.kvram"_n; -static const eosio::name kv_disk = "eosio.kvdisk"_n; +static constexpr eosio::name kv_ram = "eosio.kvram"_n; +static constexpr eosio::name kv_disk = "eosio.kvdisk"_n; /** * @defgroup keyvalue Key Value Table @@ -408,8 +407,12 @@ class kv_table { return *this; } - uint32_t key_compare(key_type kt) const { - return internal_use_do_not_use::kv_it_key_compare(itr, kt.data(), kt.size()); + int32_t key_compare(key_type kt) const { + if (itr == 0 || itr_stat == status::iterator_end) { + return 1; + } else { + return internal_use_do_not_use::kv_it_key_compare(itr, kt.data(), kt.size()); + } } bool operator==(const iterator& b) const { @@ -511,12 +514,6 @@ class kv_table { using kv_table::kv_index::index_name; using kv_table::kv_index::prefix; - template - explicit index(KF&& kf) : kv_index{kf} { - static_assert(std::is_same_v()))>>>, - "Make sure the variable/function passed to the constructor returns the same type as the template parameter."); - } - template index(eosio::name name, KF&& kf) : kv_index{name, kf} { static_assert(std::is_same_v()))>>>, @@ -546,19 +543,6 @@ class kv_table { return {itr, static_cast(itr_stat), reinterpret_cast(this)}; } - bool exists( const K& key ) const { - uint32_t value_size; - auto t_key = table_key(prefix, make_key(key)); - - return internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); - } - - T operator[]( const K& key ) const { - auto opt = get(key); - eosio::check( opt.has_value(), "key not found" ); - return *opt; - } - /** * Get the value for an existing object in a table by the index, using the given key. * @ingroup keyvalue @@ -783,8 +767,8 @@ class kv_table { protected: kv_table() = default; - template - void setup_indices(I&& index, Indices&&... indices) { + template + void setup_indices(I& index) { kv_index* idx = &index; idx->contract_name = contract_name; idx->table_name = table_name; @@ -795,8 +779,10 @@ class kv_table { } template - void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex&& prim_index, SecondaryIndices&&... indices) { - (validate_types(prim_index, indices), ...); + void init(eosio::name contract, eosio::name table, eosio::name db, PrimaryIndex& prim_index, SecondaryIndices&... indices) { + validate_types(prim_index); + (validate_types(indices), ...); + contract_name = contract; table_name = table; db_name = db.value; @@ -825,11 +811,10 @@ class kv_table { constexpr void validate_types() {} - template - constexpr void validate_types(Type&& t, Types&&... ts) { + template + constexpr void validate_types(Type& t) { constexpr bool is_kv_index = std::is_base_of_v>; - constexpr bool is_ref = std::is_reference_v; - static_assert(is_kv_index && is_ref, "Incorrect index type passed to init. Must be a reference to an index."); + static_assert(is_kv_index, "Incorrect type passed to init. Must be a reference to an index."); } template From 2eed8a2951d74a454d4d57172b160d45dce7219a Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 14:16:51 -0400 Subject: [PATCH 280/659] Remove old tests --- tests/integration/kv_tests.cpp | 4 ---- tests/unit/test_contracts/kv_single_index_tests.cpp | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index f5731ccd0d..3a7ea0b83d 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -52,10 +52,6 @@ BOOST_AUTO_TEST_CASE(single_tests_get) try { TESTER tester; setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); tester.push_action(N(kvtest), N(get), N(kvtest), {}); - - BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(geterror), N(kvtest), {}), - eosio_assert_message_exception, - eosio_assert_message_is("key not found")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index abb69ced43..a70e3969b6 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -90,18 +90,6 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { val = t.primary_key.get("william"_n); eosio::check(!val, "Should not have gotten a value"); - - eosio::check(t.primary_key.exists("bob"_n), "Exists should return true"); - eosio::check(!t.primary_key.exists("william"_n), "Exists should return false"); - - auto vval = t.primary_key["bob"_n]; - eosio::check(vval.primary_key == "bob"_n, "Got the wrong value"); - } - - [[eosio::action]] - void geterror() { - my_table t{"kvtest"_n}; - auto val = t.primary_key["william"_n]; } [[eosio::action]] From da8fd4187967fad6b0dfa4bca54955e10a2d9587 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 14:32:14 -0400 Subject: [PATCH 281/659] Revert "Remove old tests" These operators were incorrectly deleted and will be added back. This reverts commit 2eed8a2951d74a454d4d57172b160d45dce7219a. --- tests/integration/kv_tests.cpp | 4 ++++ tests/unit/test_contracts/kv_single_index_tests.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index 3a7ea0b83d..f5731ccd0d 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -52,6 +52,10 @@ BOOST_AUTO_TEST_CASE(single_tests_get) try { TESTER tester; setup(tester, contracts::kv_single_tests_wasm(), contracts::kv_single_tests_abi()); tester.push_action(N(kvtest), N(get), N(kvtest), {}); + + BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(geterror), N(kvtest), {}), + eosio_assert_message_exception, + eosio_assert_message_is("key not found")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { diff --git a/tests/unit/test_contracts/kv_single_index_tests.cpp b/tests/unit/test_contracts/kv_single_index_tests.cpp index a70e3969b6..abb69ced43 100644 --- a/tests/unit/test_contracts/kv_single_index_tests.cpp +++ b/tests/unit/test_contracts/kv_single_index_tests.cpp @@ -90,6 +90,18 @@ class [[eosio::contract]] kv_single_index_tests : public eosio::contract { val = t.primary_key.get("william"_n); eosio::check(!val, "Should not have gotten a value"); + + eosio::check(t.primary_key.exists("bob"_n), "Exists should return true"); + eosio::check(!t.primary_key.exists("william"_n), "Exists should return false"); + + auto vval = t.primary_key["bob"_n]; + eosio::check(vval.primary_key == "bob"_n, "Got the wrong value"); + } + + [[eosio::action]] + void geterror() { + my_table t{"kvtest"_n}; + auto val = t.primary_key["william"_n]; } [[eosio::action]] From 0cffe2f4e692d3309cda02f6102b83a6abc91eb8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 14:38:26 -0400 Subject: [PATCH 282/659] Add back incorrectly deleted functions --- .../eosiolib/contracts/eosio/key_value.hpp | 27 +++++++++++++++++++ tests/integration/kv_tests.cpp | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index d52f5e6e79..d5af9bb974 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -543,6 +543,33 @@ class kv_table { return {itr, static_cast(itr_stat), reinterpret_cast(this)}; } + /** + * Check if a given key exists in the index. + * @ingroup keyvalue + * + * @param key - The key to check for. + * @return If the key exists or not. + */ + bool exists(const K& key) const { + uint32_t value_size; + auto t_key = table_key(prefix, make_key(key)); + + return internal_use_do_not_use::kv_get(tbl->db_name, contract_name.value, t_key.data(), t_key.size(), value_size); + } + + /** + * Get the value for an existing object in a table by the index, using the given key. + * @ingroup keyvalue + * + * @param key - The key to search for. + * @return The value corresponding to the key. + */ + T operator[](const K& key) const { + auto opt = get(key); + eosio::check(opt.has_value(), "Key not found in `[]`"); + return *opt; + } + /** * Get the value for an existing object in a table by the index, using the given key. * @ingroup keyvalue diff --git a/tests/integration/kv_tests.cpp b/tests/integration/kv_tests.cpp index f5731ccd0d..fa12706bac 100644 --- a/tests/integration/kv_tests.cpp +++ b/tests/integration/kv_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(single_tests_get) try { BOOST_CHECK_EXCEPTION(tester.push_action(N(kvtest), N(geterror), N(kvtest), {}), eosio_assert_message_exception, - eosio_assert_message_is("key not found")); + eosio_assert_message_is("Key not found in `[]`")); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(single_tests_bounds, tester) try { From 172d38f36b604f724df162b97129860400d471b1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 15:32:33 -0400 Subject: [PATCH 283/659] Remove unnecessary reinterpret_cast --- libraries/eosiolib/contracts/eosio/key_value.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index d5af9bb974..9211adf2e7 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -540,7 +540,7 @@ class kv_table { return end(); } - return {itr, static_cast(itr_stat), reinterpret_cast(this)}; + return {itr, static_cast(itr_stat), this}; } /** @@ -631,7 +631,7 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, "", 0); - return {itr, static_cast(itr_stat), reinterpret_cast(this)}; + return {itr, static_cast(itr_stat), this}; } /** @@ -641,7 +641,7 @@ class kv_table { * @return An iterator pointing past the end. */ iterator end() const { - return {0, iterator::status::iterator_end, reinterpret_cast(this)}; + return {0, iterator::status::iterator_end, this}; } /** @@ -656,7 +656,7 @@ class kv_table { uint32_t itr = internal_use_do_not_use::kv_it_create(tbl->db_name, contract_name.value, prefix.data(), prefix.size()); int32_t itr_stat = internal_use_do_not_use::kv_it_lower_bound(itr, t_key.data(), t_key.size()); - return {itr, static_cast(itr_stat), reinterpret_cast(this)}; + return {itr, static_cast(itr_stat), this}; } /** From 6b83b7aec96336ebfd8a1c2c53ccea19be61b7b4 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 16 Mar 2020 13:32:14 -0400 Subject: [PATCH 284/659] Fix move constructor/assignment and setup should be private --- libraries/eosiolib/contracts/eosio/key_value.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 9211adf2e7..645a46fd28 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -322,7 +322,8 @@ class kv_table { iterator(iterator&& other) : itr(std::exchange(other.itr, 0)), - itr_stat(std::move(other.itr_stat)) + itr_stat(std::move(other.itr_stat)), + index(std::move(other.index)) {} ~iterator() { @@ -337,6 +338,7 @@ class kv_table { } itr = std::exchange(other.itr, 0); itr_stat = std::move(other.itr_stat); + index = std::move(other.index); return *this; } @@ -695,6 +697,7 @@ class kv_table { return return_values; } + private: void setup() override { prefix = make_prefix(table_name, index_name); } From 19f90ae3d50d12e48f24cd9a1c514dadce43f913 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 19 Mar 2020 17:54:06 -0600 Subject: [PATCH 285/659] Add commandline option -no-missing-ricardian-clause. Whitespace cleanup. --- libraries/CMakeLists.txt | 4 +-- modules/EosioWasmToolchain.cmake.in | 6 ++-- tests/CMakeLists.txt | 2 ++ tools/cc/eosio-cpp.cpp.in | 5 ++-- tools/include/compiler_options.hpp.in | 42 +++++++++++++++------------ tools/include/eosio/abigen.hpp | 10 ++++--- tools/include/eosio/gen.hpp | 13 +++++++-- 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 0649c46049..ddf4b6ad4c 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -11,8 +11,8 @@ endif() list(APPEND CMAKE_MODULE_PATH ${EOSIO_CDT_BIN}) include(EosioCDTMacros) -set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -O3 -Wall ") -set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -O3 -Wall ") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall -no-missing-ricardian-clause") add_subdirectory(libc) add_subdirectory(libc++) diff --git a/modules/EosioWasmToolchain.cmake.in b/modules/EosioWasmToolchain.cmake.in index acdb8928af..d2a0fb1d3e 100644 --- a/modules/EosioWasmToolchain.cmake.in +++ b/modules/EosioWasmToolchain.cmake.in @@ -15,9 +15,9 @@ set(CMAKE_C_COMPILER "@CDT_ROOT_DIR@/bin/eosio-cc") set(CMAKE_CXX_COMPILER "@CDT_ROOT_DIR@/bin/eosio-cpp") set(CMAKE_ASM_COMPILER "@CDT_ROOT_DIR@/bin/eosio-cc") -set(CMAKE_C_FLAGS " -O3 ") -set(CMAKE_CXX_FLAGS " -O3 ") -set(CMAKE_ASM_FLAGS " -fnative -fasm ") +set(CMAKE_C_FLAGS "-O3") +set(CMAKE_CXX_FLAGS "-O3") +set(CMAKE_ASM_FLAGS "-fnative -fasm") set(WASM_LINKER "@CDT_ROOT_DIR@/bin/eosio-ld") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9094d77b7c..987ea7b6af 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,8 @@ else() endif() endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-missing-ricardian-clause") + add_test( asset_tests ${CMAKE_BINARY_DIR}/tests/unit/asset_tests ) set_property(TEST asset_tests PROPERTY LABELS unit_tests) add_test( binary_extension_tests ${CMAKE_BINARY_DIR}/tests/unit/binary_extension_tests ) diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index cedc25d0b6..d4266e678c 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -107,7 +107,7 @@ namespace eosio { namespace cdt { }; }} // ns eosio::cdt -void generate(const std::vector& base_options, std::string input, std::string contract_name, const std::vector& resource_paths, const std::pair& abi_version, bool abigen) { +void generate(const std::vector& base_options, std::string input, std::string contract_name, const std::vector& resource_paths, const std::pair& abi_version, bool abigen, bool suppress_ricardian_warning) { std::vector options; options.push_back("eosio-cpp"); options.push_back(input); // don't remove oddity of CommonOptionsParser? @@ -131,6 +131,7 @@ void generate(const std::vector& base_options, std::string input, s get_abigen_ref().set_contract_name(contract_name); get_abigen_ref().set_resource_dirs(resource_paths); get_abigen_ref().set_abi_version(std::get<0>(abi_version), std::get<1>(abi_version)); + get_abigen_ref().set_suppress_ricardian_warning(suppress_ricardian_warning); codegen::get().set_contract_name(contract_name); EosioMethodMatcher eosio_method_matcher; @@ -190,7 +191,7 @@ int main(int argc, const char **argv) { tool_opts.erase(std::remove_if(tool_opts.begin(), tool_opts.end(), [&](const auto& opt){ return non_tool_opts.count(opt); }), tool_opts.end()); - generate(tool_opts, input, opts.abigen_contract, opts.abigen_resources, opts.abi_version, opts.abigen); + generate(tool_opts, input, opts.abigen_contract, opts.abigen_resources, opts.abi_version, opts.abigen, opts.suppress_ricardian_warning); auto src = SmallString<64>(input); llvm::sys::path::remove_filename(src); diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 20ea092420..d3ba9e8074 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -34,6 +34,11 @@ static cl::opt no_abigen_opt( "no-abigen", cl::desc("Disable ABI file generation"), cl::cat(LD_CAT)); +static cl::opt no_missing_ricardian_clause_opt( + "no-missing-ricardian-clause", + cl::desc("Disable warnings for missing Ricardian clauses"), + cl::init(false), + cl::cat(LD_CAT)); static cl::opt fquery_opt( "fquery", cl::desc("Produce binaries for wasmql"), @@ -172,22 +177,22 @@ static cl::opt abigen_output_opt( cl::cat(EosioCompilerToolCategory)); // ignore for now static cl::opt g_opt( - "g", - cl::desc("debug build "), - cl::Hidden, - cl::ZeroOrMore, - cl::cat(EosioCompilerToolCategory)); + "g", + cl::desc("debug build "), + cl::Hidden, + cl::ZeroOrMore, + cl::cat(EosioCompilerToolCategory)); static cl::opt x_opt( - "x", - cl::desc(""), - cl::Hidden, - cl::Prefix, - cl::cat(EosioCompilerToolCategory)); + "x", + cl::desc(""), + cl::Hidden, + cl::Prefix, + cl::cat(EosioCompilerToolCategory)); static cl::opt pch_opt( - "fpch-preprocess", - cl::desc(""), - cl::Hidden, - cl::cat(EosioCompilerToolCategory)); + "fpch-preprocess", + cl::desc(""), + cl::Hidden, + cl::cat(EosioCompilerToolCategory)); static cl::opt CC_opt( "CC", cl::desc("Include comments from within macros in preprocessed output"), @@ -359,6 +364,7 @@ struct Options { std::vector inputs; bool link; bool abigen; + bool suppress_ricardian_warning; bool pp_only; std::string eosio_pp_dir; std::string abigen_output; @@ -374,7 +380,6 @@ struct Options { static void GetCompDefaults(std::vector& copts) { const char* eosio_apply_suff = "${CMAKE_SHARED_LIBRARY_SUFFIX}"; - std::string apply_lib; // add the define for whether this is compiling with CDT and version macros copts.emplace_back("-D__eosio_cdt__"); copts.emplace_back(std::string("-D__eosio_cdt_major__=")+"${VERSION_MAJOR}"); @@ -624,8 +629,9 @@ static Options CreateOptions(bool add_defaults=true) { link = false; copts.emplace_back("-E"); } - if(g_opt) + if(g_opt) { copts.emplace_back("-g"); + } if (!x_opt.empty()) { // x_opt should precede input files copts.insert(copts.begin(), "-x"+x_opt); @@ -884,8 +890,8 @@ static Options CreateOptions(bool add_defaults=true) { } #ifndef ONLY_LD - return {output_fn, inputs, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; + return {output_fn, inputs, link, abigen, no_missing_ricardian_clause_opt, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; #else - return {output_fn, {}, link, abigen, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; + return {output_fn, {}, link, abigen, no_missing_ricardian_clause_opt, pp_only, pp_dir, abigen_output, abigen_contract, copts, ldopts, agopts, agresources, debug, fnative_opt, {abi_version_major, abi_version_minor}}; #endif } diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index 5a8e17e017..df58718560 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -57,8 +57,9 @@ namespace eosio { namespace cdt { abi_action ret; auto action_name = decl->getEosioActionAttr()->getName(); - if (rcs[get_action_name(decl)].empty()) - std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; + if (!suppress_ricardian_warnings) + if (rcs[get_action_name(decl)].empty()) + std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; ret.ricardian_contract = rcs[get_action_name(decl)]; @@ -89,8 +90,9 @@ namespace eosio { namespace cdt { auto action_name = decl->getEosioActionAttr()->getName(); - if (rcs[get_action_name(decl)].empty()) - std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; + if (!suppress_ricardian_warnings) + if (rcs[get_action_name(decl)].empty()) + std::cout << "Warning, action <"+get_action_name(decl)+"> does not have a ricardian contract\n"; ret.ricardian_contract = rcs[get_action_name(decl)]; diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index ee740e8a9a..41d1caf26c 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -104,6 +104,7 @@ struct generation_utils { std::function error_handler; std::vector resource_dirs; std::string contract_name; + bool suppress_ricardian_warnings; generation_utils( std::function err ) : error_handler(err), resource_dirs({"./"}) {} generation_utils( std::function err, const std::vector& paths ) : error_handler(err), resource_dirs(paths) {} @@ -216,6 +217,10 @@ struct generation_utils { return {}; } + inline void set_suppress_ricardian_warning(bool suppress_ricardian_warnings) { + this->suppress_ricardian_warnings = suppress_ricardian_warnings; + } + inline std::string get_ricardian_clauses() { return read_file(get_clauses_filename()); } @@ -228,7 +233,9 @@ struct generation_utils { std::map rcs; simple_ricardian_tokenizer srt(contracts); if (contracts.empty()) { - std::cout << "Warning, empty ricardian clause file\n"; + if (!suppress_ricardian_warnings) { + std::cout << "Warning, empty ricardian clause file\n"; + } return rcs; } @@ -244,7 +251,9 @@ struct generation_utils { std::vector> clause_pairs; simple_ricardian_tokenizer srt(clauses); if (clauses.empty()) { - std::cout << "Warning, empty ricardian clause file\n"; + if (!suppress_ricardian_warnings) { + std::cout << "Warning, empty ricardian clause file\n"; + } return clause_pairs; } From 6bd36523eeb2286764e9cc0e42dd3346619a1139 Mon Sep 17 00:00:00 2001 From: PhillipHamnett <5197377+PhillipHamnett@users.noreply.github.com> Date: Sun, 22 Mar 2020 11:46:58 +0100 Subject: [PATCH 286/659] Update 02_abi-variants.md Fixed small typos --- docs/09_tutorials/02_abi-variants.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/09_tutorials/02_abi-variants.md b/docs/09_tutorials/02_abi-variants.md index 51430b4b08..25ce59c8ff 100644 --- a/docs/09_tutorials/02_abi-variants.md +++ b/docs/09_tutorials/02_abi-variants.md @@ -153,7 +153,7 @@ class [[eosio::contract]] multi_index_example : public contract { ``` [[warning | Not recommended warning]] -| Be aware, it is not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how to ABI gets generated! +| Be aware, it is not recommend to use `eosio::binary_extension` inside variant definition, this can lead to data corruption unless one is very careful in understanding how these two templates work and how the ABI gets generated! -[[Info | Implemenatation location]] -| The implementation for ABI `variants' section can be found [here](https://github.com/EOSIO/eos/pull/5652). \ No newline at end of file +[[Info | Implementation location]] +| The implementation for ABI `variants' can be found [here](https://github.com/EOSIO/eos/pull/5652). From 48674ce2e6c7a4fadc05bbd86d1beca391ae3ce8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 23 Mar 2020 11:25:08 -0400 Subject: [PATCH 287/659] Minor docs update --- docs/06_how-to-guides/06_key_value/01_key_value_examples.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index b17a18367d..97e5338b9c 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -19,7 +19,7 @@ struct address_table : kv_table
{ index full_name{"fullname"_n, &myrecord::full_name}; address_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &account_name, &full_name); + init(contract_name, "testtable"_n, "eosio.kvram"_n, account_name, full_name); } } @@ -39,7 +39,7 @@ struct address_table : kv_table
{ KV_NAMED_INDEX("fullname"_n, full_name) address_table(eosio::name contract_name) { - init(contract_name, "testtable"_n, "eosio.kvram"_n, &account_name, &full_name); + init(contract_name, "testtable"_n, "eosio.kvram"_n, account_name, full_name); } } ``` From 3ed2e6bc6e8a5e04ba2090eec910257eedcdce57 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 23 Mar 2020 11:37:41 -0400 Subject: [PATCH 288/659] Fix KV_NAMED_INDEX documentation --- libraries/eosiolib/contracts/eosio/key_value.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 645a46fd28..46f91bcede 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -12,9 +12,8 @@ /** * @brief Macro to define an index. - * @details In the case where the autogenerated index names created by DEFINE_TABLE are not enough, a user can instead - * manually define the table and indices. This macro allows users to conveniently define an index without having to specify - * the index template type, as those can be large/unwieldy to type out. + * @details This macro allows users to conveniently define an index without having to specify + * the index template type, as those can be large/unwieldy to type out. It can be used for both primary and secondary indexes. * * @param index_name - The index name. * @param member_name - The name of the member pointer used for the index. This also defines the index's C++ variable name. From 12cfcc3be4c1d5158b8993e6facff8100fdc8989 Mon Sep 17 00:00:00 2001 From: Jonathan Giszczak Date: Thu, 26 Mar 2020 17:02:47 -0600 Subject: [PATCH 289/659] Building on macOS with no dependencies installed did not work. --- scripts/eosiocdt_build_darwin.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/eosiocdt_build_darwin.sh b/scripts/eosiocdt_build_darwin.sh index 30bbe2077f..6681b7b04b 100644 --- a/scripts/eosiocdt_build_darwin.sh +++ b/scripts/eosiocdt_build_darwin.sh @@ -119,11 +119,11 @@ fi if [ $COUNT -gt 1 ]; then printf "\\nThe following dependencies are required to install EOSIO:\\n" printf "${DISPLAY}\\n\\n" - if [ $1 == 0 ]; then read -p "Do you wish to install these packages? (y/n) " answer; fi + if [ -z "$1" ]; then read -p "Do you wish to install these packages? (y/n) " answer; fi case ${answer} in 1 | [Yy]* ) "${XCODESELECT}" --install 2>/dev/null; - if [ $1 == 0 ]; then read -p "Do you wish to update homebrew packages first? (y/n) " answer; fi + if [ -z "$1" ]; then read -p "Do you wish to update homebrew packages first? (y/n) " answer; fi case ${answer} in 1 | [Yy]* ) if ! brew update; then From 9c1edfb48071eeb76238d57ea21d6f033b9c353f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 10 Apr 2020 15:47:23 -0400 Subject: [PATCH 290/659] Convert vector to bytes in ABI --- tools/include/eosio/gen.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index 41d1caf26c..205d6ef31d 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -472,7 +472,11 @@ struct generation_utils { } else if ( is_template_specialization( type, {"vector", "set", "deque", "list"} ) ) { auto t =translate_type(get_template_argument( type ).getAsType()); - return t=="int8" ? "bytes" : t+"[]"; + if (t=="int8" || t=="uint8") { + return "bytes"; + } else { + return t+"[]"; + } } else if ( is_template_specialization( type, {"optional"} ) ) return translate_type(get_template_argument( type ).getAsType())+"?"; From a8b71060e83bdac007174ef71620de753a1d1ce7 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 10 Apr 2020 15:49:23 -0400 Subject: [PATCH 291/659] Match surrounding formatting --- tools/include/eosio/gen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index 205d6ef31d..55ce1e12e9 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -472,7 +472,7 @@ struct generation_utils { } else if ( is_template_specialization( type, {"vector", "set", "deque", "list"} ) ) { auto t =translate_type(get_template_argument( type ).getAsType()); - if (t=="int8" || t=="uint8") { + if ( t=="int8" || t=="uint8" ) { return "bytes"; } else { return t+"[]"; From f61b7c71c8bf3286e5723ca1d456a00e444fe796 Mon Sep 17 00:00:00 2001 From: larryk85 Date: Sun, 12 Apr 2020 14:54:42 -0400 Subject: [PATCH 292/659] fixes for non-type template params --- .../build-pass/template_gen_regression.cpp | 54 +++++++++ tools/include/eosio/abigen.hpp | 30 +++-- tools/include/eosio/gen.hpp | 106 ++++++++++-------- tools/include/eosio/utils.hpp | 8 +- 4 files changed, 132 insertions(+), 66 deletions(-) create mode 100644 tests/toolchain/build-pass/template_gen_regression.cpp diff --git a/tests/toolchain/build-pass/template_gen_regression.cpp b/tests/toolchain/build-pass/template_gen_regression.cpp new file mode 100644 index 0000000000..ac38946576 --- /dev/null +++ b/tests/toolchain/build-pass/template_gen_regression.cpp @@ -0,0 +1,54 @@ +#include +#include + +using namespace eosio; + +template +struct baz { + T val1; + U val2; +}; + +template +datastream& operator >> ( datastream& ds, baz& b ) { + ds >> b.val1 >> b.val2; + return ds; +} + +template +datastream& operator<< ( datastream& ds, const baz& b ) { + ds << b.val1; + ds << b.val2; + return ds; +} + +template +struct arg_val { + int a; +}; + +template +datastream& operator >> ( datastream& ds, arg_val<42>& b ) { + ds >> b.a; + return ds; +} + +template +datastream& operator<< ( datastream& ds, const arg_val<42>& b ) { + ds << b.a; + return ds; +} + +struct foo { + fixed_bytes<20> bar; + baz bur; + arg_val<42> av; +}; + + +CONTRACT template_gen_regression : public eosio::contract { + public: + using contract::contract; + + ACTION test( foo f ) {} +}; diff --git a/tools/include/eosio/abigen.hpp b/tools/include/eosio/abigen.hpp index df58718560..dbde262320 100644 --- a/tools/include/eosio/abigen.hpp +++ b/tools/include/eosio/abigen.hpp @@ -137,7 +137,7 @@ namespace eosio { namespace cdt { abi_struct tup; tup.name = get_type(type); for (int i = 0; i < tst->getNumArgs(); ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); + clang::QualType ftype = std::get(get_template_argument(type, i)); add_type(ftype); tup.fields.push_back( {"field_"+std::to_string(i), translate_type(ftype)} ); @@ -147,32 +147,30 @@ namespace eosio { namespace cdt { void add_pair(const clang::QualType& type) { for (int i = 0; i < 2; ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); + clang::QualType ftype = std::get(get_template_argument(type, i)); std::string ty = translate_type(ftype); add_type(ftype); } abi_struct pair; pair.name = get_type(type); - pair.fields.push_back( {"first", translate_type(get_template_argument(type).getAsType())} ); - pair.fields.push_back( {"second", translate_type(get_template_argument(type, 1).getAsType())} ); - add_type(get_template_argument(type).getAsType()); - add_type(get_template_argument(type, 1).getAsType()); + pair.fields.push_back( {"first", get_template_argument_as_string(type)} ); + pair.fields.push_back( {"second", get_template_argument_as_string(type, 1)} ); + add_type(std::get(get_template_argument(type))); + add_type(std::get(get_template_argument(type, 1))); _abi.structs.insert(pair); } void add_map(const clang::QualType& type) { for (int i = 0; i < 2; ++i) { - clang::QualType ftype = get_template_argument(type, i).getAsType(); - std::string ty = translate_type(ftype); - add_type(ftype); + add_type(std::get(get_template_argument(type, i))); } abi_struct kv; std::string name = get_type(type); kv.name = name.substr(0, name.length() - 2); - kv.fields.push_back( {"key", translate_type(get_template_argument(type).getAsType())} ); - kv.fields.push_back( {"value", translate_type(get_template_argument(type, 1).getAsType())} ); - add_type(get_template_argument(type).getAsType()); - add_type(get_template_argument(type, 1).getAsType()); + kv.fields.push_back( {"key", get_template_argument_as_string(type)} ); + kv.fields.push_back( {"value", get_template_argument_as_string(type, 1)} ); + add_type(std::get(get_template_argument(type))); + add_type(std::get(get_template_argument(type, 1))); _abi.structs.insert(kv); } @@ -261,8 +259,8 @@ namespace eosio { namespace cdt { auto tst = llvm::dyn_cast((pt) ? pt->desugar().getTypePtr() : t.getTypePtr()); var.name = get_type(t); for (int i=0; i < tst->getNumArgs(); ++i) { - var.types.push_back(translate_type(get_template_argument( t, i ).getAsType())); - add_type(get_template_argument( t, i ).getAsType()); + var.types.push_back(get_template_argument_as_string( t, i )); + add_type(std::get(get_template_argument( t, i ))); } _abi.variants.insert(var); } @@ -276,7 +274,7 @@ namespace eosio { namespace cdt { if (is_aliasing(type)) add_typedef(type); else if (is_template_specialization(type, {"vector", "set", "deque", "list", "optional", "binary_extension", "ignore"})) { - add_type(get_template_argument(type).getAsType()); + add_type(std::get(get_template_argument(type))); } else if (is_template_specialization(type, {"map"})) add_map(type); diff --git a/tools/include/eosio/gen.hpp b/tools/include/eosio/gen.hpp index 41d1caf26c..e6616501b5 100644 --- a/tools/include/eosio/gen.hpp +++ b/tools/include/eosio/gen.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace eosio { namespace cdt { @@ -299,8 +300,8 @@ struct generation_utils { return true; } else { for ( auto name : names ) - if ( rt->getDecl()->getName().str() == name ) { - return true; + if ( const auto* decl = rt->getDecl() ) { + return decl->getName().str() == name; } } } @@ -316,20 +317,55 @@ struct generation_utils { return is_specialization; } - inline clang::TemplateArgument get_template_argument( const clang::QualType& type, int index = 0 ) { - auto ret = [&](const clang::Type* t) { + + using template_arg_t = std::variant; + + inline template_arg_t get_template_argument( const clang::QualType& type, int index = 0 ) { + template_arg_t ret_val; + + auto resolve = [&](const clang::Type* t) { auto tst = llvm::dyn_cast(t); if (tst) { auto arg = tst->getArg(index); - return arg.getAsType(); + if ( arg.getKind() == clang::TemplateArgument::ArgKind::Type ) { + ret_val = arg.getAsType(); + return; + } else if ( arg.getKind() == clang::TemplateArgument::ArgKind::Integral ) { + ret_val = arg.getAsIntegral(); + return; + } else if ( arg.getKind() == clang::TemplateArgument::ArgKind::Expression ) { + ret_val = arg.getAsExpr(); + return; + } + else + error_handler(); } std::cout << "Internal error, wrong type of template specialization\n"; error_handler(); - return tst->getArg(index).getAsType(); }; + if (auto pt = llvm::dyn_cast(type.getTypePtr())) - return ret(pt->desugar().getTypePtr()); - return ret(type.getTypePtr()); + resolve(pt->desugar().getTypePtr()); + else + resolve(type.getTypePtr()); + + return ret_val; + } + + inline std::string get_template_argument_as_string( const clang::QualType& type, int index = 0 ) { + auto arg = get_template_argument( type, index ); + if (std::holds_alternative(arg)) + return translate_type(std::get(arg)); + else if (std::holds_alternative(arg)) { + if (auto ce = llvm::dyn_cast(std::get(arg))) { + auto il = llvm::dyn_cast(ce->getSubExpr()); + return std::to_string(il->getValue().getLimitedValue()); + } + } else { + return std::get(arg).toString(10); + } + error_handler(); + __builtin_unreachable(); } std::string get_base_type_name( const clang::QualType& type ) { @@ -421,7 +457,7 @@ struct generation_utils { {"fixed_bytes_32", "checksum256"}, {"fixed_bytes_64", "checksum512"} }; - + auto ret = translation_table[t]; if (ret == "") @@ -444,46 +480,34 @@ struct generation_utils { auto tst = llvm::dyn_cast(pt ? pt->desugar().getTypePtr() : type.getTypePtr()); std::string ret = tst->getTemplateName().getAsTemplateDecl()->getName().str()+"_"; for (int i=0; i < tst->getNumArgs(); ++i) { - auto arg = get_template_argument(type,i); - if (arg.getAsExpr()) { - auto ce = llvm::dyn_cast(arg.getAsExpr()); - if (ce) { - auto il = llvm::dyn_cast(ce->getSubExpr()); - ret += std::to_string(il->getValue().getLimitedValue()); - if ( i < tst->getNumArgs()-1 ) - ret += "_"; - } - } - else { - ret += _translate_type(get_template_argument( type, i ).getAsType()); - if ( i < tst->getNumArgs()-1 ) - ret += "_"; - } + ret += get_template_argument_as_string(type,i); + if ( i < tst->getNumArgs()-1 ) + ret += "_"; } return _translate_type(replace_in_name(ret)); } inline std::string translate_type( const clang::QualType& type ) { if ( is_template_specialization( type, {"ignore"} ) ) - return translate_type(get_template_argument( type ).getAsType() ); + return get_template_argument_as_string( type ); else if ( is_template_specialization( type, {"binary_extension"} ) ) { - auto t = translate_type(get_template_argument( type ).getAsType()); + auto t = get_template_argument_as_string( type ); return t+"$"; } else if ( is_template_specialization( type, {"vector", "set", "deque", "list"} ) ) { - auto t =translate_type(get_template_argument( type ).getAsType()); + auto t = get_template_argument_as_string( type ); return t=="int8" ? "bytes" : t+"[]"; } else if ( is_template_specialization( type, {"optional"} ) ) - return translate_type(get_template_argument( type ).getAsType())+"?"; + return get_template_argument_as_string( type )+"?"; else if ( is_template_specialization( type, {"map"} )) { - auto t0 = translate_type(get_template_argument( type ).getAsType()); - auto t1 = translate_type(get_template_argument( type, 1).getAsType()); + auto t0 = get_template_argument_as_string( type ); + auto t1 = get_template_argument_as_string( type, 1); return replace_in_name("pair_" + t0 + "_" + t1 + "[]"); } else if ( is_template_specialization( type, {"pair"} )) { - auto t0 = translate_type(get_template_argument( type ).getAsType()); - auto t1 = translate_type(get_template_argument( type, 1).getAsType()); + auto t0 = get_template_argument_as_string( type ); + auto t1 = get_template_argument_as_string( type, 1); return replace_in_name("pair_" + t0 + "_" + t1); } else if ( is_template_specialization( type, {"tuple"} )) { @@ -491,7 +515,7 @@ struct generation_utils { auto tst = llvm::dyn_cast( pt ? pt->desugar().getTypePtr() : type.getTypePtr() ); std::string ret = "tuple_"; for (int i=0; i < tst->getNumArgs(); ++i) { - ret += _translate_type(get_template_argument( type, i ).getAsType()); + ret += get_template_argument_as_string( type, i ); if ( i < tst->getNumArgs()-1 ) ret += "_"; } @@ -502,19 +526,9 @@ struct generation_utils { auto tst = llvm::dyn_cast(pt ? pt->desugar().getTypePtr() : type.getTypePtr() ); std::string ret = tst->getTemplateName().getAsTemplateDecl()->getName().str()+"_"; for (int i=0; i < tst->getNumArgs(); ++i) { - auto arg = get_template_argument(type,i); - if (auto ce = arg.getKind() == clang::TemplateArgument::ArgKind::Expression - ? llvm::dyn_cast(arg.getAsExpr()) : nullptr) { - auto il = llvm::dyn_cast(ce->getSubExpr()); - ret += std::to_string(il->getValue().getLimitedValue()); - if ( i < tst->getNumArgs()-1 ) - ret += "_"; - } - else { - ret += translate_type(get_template_argument( type, i ).getAsType()); - if ( i < tst->getNumArgs()-1 ) - ret += "_"; - } + ret += get_template_argument_as_string(type,i); + if ( i < tst->getNumArgs()-1 ) + ret += "_"; } return _translate_type(replace_in_name(ret)); } diff --git a/tools/include/eosio/utils.hpp b/tools/include/eosio/utils.hpp index 7ec624a093..953c3c68fd 100644 --- a/tools/include/eosio/utils.hpp +++ b/tools/include/eosio/utils.hpp @@ -47,7 +47,7 @@ uint64_t string_to_name( const char* str ) template void validate_name( const std::string& str, Lambda&& error_handler ) { const auto len = str.length(); - if ( len > 13 ) { + if ( len > 13 ) { std::cout << "Error, name {" << str << "} is more than 13 characters long\n"; return error_handler(); } @@ -62,7 +62,7 @@ void validate_name( const std::string& str, Lambda&& error_handler ) { str2[12-i] = c; tmp >>= (i == 0 ? 4 : 5); } - + auto trim = [](std::string& s) { int i; for (i = s.length()-1; i >= 0; i--) @@ -140,12 +140,12 @@ struct environment { std::string find_path = eosio::cdt::whereami::where(); if (root) find_path = "/usr/bin"; - if ( auto path = llvm::sys::findProgramByName(prog.c_str(), {find_path}) ) { + if ( const auto& path = llvm::sys::findProgramByName(prog.c_str(), {find_path}) ) { return llvm::sys::ExecuteAndWait(*path, args, {}, {}, 0, 0, nullptr, nullptr) == 0; } else return false; - return true; + return true; } }; From 0369ff3c37a4a3af092ce2996d08985c21752231 Mon Sep 17 00:00:00 2001 From: larryk85 Date: Sun, 12 Apr 2020 15:04:48 -0400 Subject: [PATCH 293/659] finishing up regression test --- tests/toolchain/build-pass/template_gen_regression.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/toolchain/build-pass/template_gen_regression.json diff --git a/tests/toolchain/build-pass/template_gen_regression.json b/tests/toolchain/build-pass/template_gen_regression.json new file mode 100644 index 0000000000..d6cd240ccd --- /dev/null +++ b/tests/toolchain/build-pass/template_gen_regression.json @@ -0,0 +1,9 @@ +{ + "tests": [ + { + "expected": { + "exit-code": 0 + } + } + ] +} From 4f82ea9a58114028eb29b09c870f3bc12fcb4b32 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 15 Apr 2020 23:56:25 -0400 Subject: [PATCH 294/659] Bump Catalina version. --- .cicd/pipeline.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 86317dff39..743be7d3cd 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -55,9 +55,8 @@ steps: - "cd eosio.cdt && ./.cicd/build.sh" - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" plugins: - - EOSIO/anka#v0.5.7: + - EOSIO/anka#v0.6.0: no-volume: true - pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -84,7 +83,7 @@ steps: - EOSIO/anka#v0.6.0: no-volume: true inherit-environment-vars: true - vm-name: 10.15.3_6C_14G_40G + vm-name: 10.15.4_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -151,9 +150,8 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/tests.sh" plugins: - - EOSIO/anka#v0.5.7: + - EOSIO/anka#v0.6.0: no-volume: true - pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -180,7 +178,7 @@ steps: - EOSIO/anka#v0.6.0: no-volume: true inherit-environment-vars: true - vm-name: 10.15.3_6C_14G_40G + vm-name: 10.15.4_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -244,9 +242,8 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/toolchain-tests.sh" plugins: - - EOSIO/anka#v0.5.7: + - EOSIO/anka#v0.6.0: no-volume: true - pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -259,7 +256,7 @@ steps: cd: ~ agents: - "queue=mac-anka-large-node-fleet" - skip: ${SKIP_MOJAVE}${SKIP_TOOLCHAIN_TESTS} + skip: ${SKIP_MACOS_10_14}${SKIP_TOOLCHAIN_TESTS} - wait: continue_on_failure: true From 4f2b0abda489764796189dcfda0f40fc54b7b594 Mon Sep 17 00:00:00 2001 From: Han Liu <667070+dixia@users.noreply.github.com> Date: Wed, 22 Apr 2020 15:10:32 +0800 Subject: [PATCH 295/659] Update kv_table example Update kv_table example including: * use up-to-date header * fix C++ syntax --- .../06_key_value/01_key_value_examples.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index 97e5338b9c..4f70e9c37f 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -1,7 +1,8 @@ ### kv_table Example: ```cpp -#include +#include using namespace eosio; +using namespace std; struct address { uint64_t account_name; @@ -12,7 +13,7 @@ struct address { string state; auto full_name() { return first_name + " " + last_name; } -} +}; struct address_table : kv_table
{ index account_name{"accname"_n, &myrecord::account_name}; @@ -21,14 +22,14 @@ struct address_table : kv_table
{ address_table(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, account_name, full_name); } -} +}; class addressbook : contract { public: void myaction() { address_table addresses{"mycontract"_n}; } -} +}; ``` ### KV_NAMED_INDEX Example: From 5713089a616b0bc4292fcba6a1251dac3ac3549f Mon Sep 17 00:00:00 2001 From: Han Liu <667070+dixia@users.noreply.github.com> Date: Wed, 22 Apr 2020 16:45:47 +0800 Subject: [PATCH 296/659] points to the member of struct points to the member of struct --- docs/06_how-to-guides/06_key_value/01_key_value_examples.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index 4f70e9c37f..f845bf7d5e 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -16,8 +16,8 @@ struct address { }; struct address_table : kv_table
{ - index account_name{"accname"_n, &myrecord::account_name}; - index full_name{"fullname"_n, &myrecord::full_name}; + index account_name{"accname"_n, &address::account_name}; + index full_name{"fullname"_n, &address::full_name}; address_table(eosio::name contract_name) { init(contract_name, "testtable"_n, "eosio.kvram"_n, account_name, full_name); From 9bc60ddf0587ed9ad6575f9d93385f3e939002bd Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Sat, 25 Apr 2020 17:49:02 -0400 Subject: [PATCH 297/659] Add allow names flag --- tools/include/compiler_options.hpp.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index d3ba9e8074..65180b93c9 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -136,6 +136,10 @@ static cl::opt allow_sse_opt( cl::desc("Should not be used, except for build libc"), cl::Hidden, cl::cat(LD_CAT)); +static cl::opt allow_names( + "allow-names", + cl::desc("Allows name section to be created"), + cl::cat(LD_CAT)); /// End of ld options #ifndef ONLY_LD @@ -449,7 +453,8 @@ static void GetCompDefaults(std::vector& copts) { static void GetLdDefaults(std::vector& ldopts) { if (!fnative_opt) { ldopts.emplace_back("--gc-sections"); - ldopts.emplace_back("--strip-all"); + if (!allow_names_opt) + ldopts.emplace_back("--strip-all"); ldopts.emplace_back("--merge-data-segments"); if (fquery_opt || fquery_server_opt || fquery_client_opt) { ldopts.emplace_back("--export-table"); From a57a319e4c67085adfe184a846c0a3d343dd523f Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Sat, 25 Apr 2020 18:30:15 -0400 Subject: [PATCH 298/659] Forgot some bits --- tools/include/compiler_options.hpp.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 65180b93c9..e77b359735 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -452,9 +452,10 @@ static void GetCompDefaults(std::vector& copts) { #ifdef ONLY_LD static void GetLdDefaults(std::vector& ldopts) { if (!fnative_opt) { - ldopts.emplace_back("--gc-sections"); - if (!allow_names_opt) + if (!allow_names_opt) { + ldopts.emplace_back("--gc-sections"); ldopts.emplace_back("--strip-all"); + } ldopts.emplace_back("--merge-data-segments"); if (fquery_opt || fquery_server_opt || fquery_client_opt) { ldopts.emplace_back("--export-table"); @@ -563,6 +564,10 @@ static Options CreateOptions(bool add_defaults=true) { ldopts.emplace_back("-fquery-server"); if (fquery_client_opt) ldopts.emplace_back("-fquery-client"); + if (allow_names_opt) { + ldopts.emplace_back("-fno-post-pass"); + ldopts.emplace_back("--allow-names"); + } #endif if (!pp_path_opt.empty()) From 6342c984093f2fc51d453bb0cf52f7e9b6d763d7 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Sat, 25 Apr 2020 19:55:48 -0400 Subject: [PATCH 299/659] Update compiler_options.hpp.in --- tools/include/compiler_options.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index e77b359735..4e06aa74f0 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -136,7 +136,7 @@ static cl::opt allow_sse_opt( cl::desc("Should not be used, except for build libc"), cl::Hidden, cl::cat(LD_CAT)); -static cl::opt allow_names( +static cl::opt allow_names_opt ( "allow-names", cl::desc("Allows name section to be created"), cl::cat(LD_CAT)); From c7af8215c9c5975444f7cfb5184ac6d39f99421a Mon Sep 17 00:00:00 2001 From: Han Liu <667070+dixia@users.noreply.github.com> Date: Mon, 27 Apr 2020 17:33:06 +0800 Subject: [PATCH 300/659] fix the index and change name type fix the index and change name type --- docs/06_how-to-guides/06_key_value/01_key_value_examples.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md index f845bf7d5e..1b62fceade 100644 --- a/docs/06_how-to-guides/06_key_value/01_key_value_examples.md +++ b/docs/06_how-to-guides/06_key_value/01_key_value_examples.md @@ -5,18 +5,18 @@ using namespace eosio; using namespace std; struct address { - uint64_t account_name; + name account_name; string first_name; string last_name; string street; string city; string state; - auto full_name() { return first_name + " " + last_name; } + auto full_name() const { return first_name + " " + last_name; } }; struct address_table : kv_table
{ - index account_name{"accname"_n, &address::account_name}; + index account_name{"accname"_n, &address::account_name}; index full_name{"fullname"_n, &address::full_name}; address_table(eosio::name contract_name) { From 9442fda9f9140011ad6d757b63ed914e57f4e4c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 13 May 2020 09:16:09 -0400 Subject: [PATCH 301/659] Remove scripts that are no longer needed --- scripts/eosiocdt_build.sh | 185 --------------------------- scripts/eosiocdt_build_amazon.sh | 135 -------------------- scripts/eosiocdt_build_centos.sh | 197 ----------------------------- scripts/eosiocdt_build_darwin.sh | 158 ----------------------- scripts/eosiocdt_build_darwin_deps | 5 - scripts/eosiocdt_build_fedora.sh | 137 -------------------- scripts/eosiocdt_build_ubuntu.sh | 161 ----------------------- scripts/eosiocdt_install.sh | 85 ------------- scripts/eosiocdt_uninstall.sh | 100 --------------- 9 files changed, 1163 deletions(-) delete mode 100755 scripts/eosiocdt_build.sh delete mode 100644 scripts/eosiocdt_build_amazon.sh delete mode 100644 scripts/eosiocdt_build_centos.sh delete mode 100644 scripts/eosiocdt_build_darwin.sh delete mode 100644 scripts/eosiocdt_build_darwin_deps delete mode 100644 scripts/eosiocdt_build_fedora.sh delete mode 100644 scripts/eosiocdt_build_ubuntu.sh delete mode 100755 scripts/eosiocdt_install.sh delete mode 100755 scripts/eosiocdt_uninstall.sh diff --git a/scripts/eosiocdt_build.sh b/scripts/eosiocdt_build.sh deleted file mode 100755 index ba7e2ab64a..0000000000 --- a/scripts/eosiocdt_build.sh +++ /dev/null @@ -1,185 +0,0 @@ -#!/bin/bash - -printf "=========== eosio.cdt ===========\n\n" - -VERSION=2.1 # Build script version -CMAKE_BUILD_TYPE=Release -export DISK_MIN=20 -DOXYGEN=false -ENABLE_COVERAGE_TESTING=false -CORE_SYMBOL_NAME="SYS" -START_MAKE=true - -TIME_BEGIN=$( date -u +%s ) -txtbld=$(tput bold) -bldred=${txtbld}$(tput setaf 1) -txtrst=$(tput sgr0) - -export SRC_LOCATION=${HOME}/src -export OPT_LOCATION=${HOME}/opt -export VAR_LOCATION=${HOME}/var -export ETC_LOCATION=${HOME}/etc -export BIN_LOCATION=${HOME}/bin -export DATA_LOCATION=${HOME}/data -export CMAKE_VERSION_MAJOR=3 -export CMAKE_VERSION_MINOR=13 -export CMAKE_VERSION_PATCH=2 -export CMAKE_VERSION=${CMAKE_VERSION_MAJOR}.${CMAKE_VERSION_MINOR}.${CMAKE_VERSION_PATCH} -export BOOST_VERSION_MAJOR=1 -export BOOST_VERSION_MINOR=67 -export BOOST_VERSION_PATCH=0 -export BOOST_VERSION=${BOOST_VERSION_MAJOR}_${BOOST_VERSION_MINOR}_${BOOST_VERSION_PATCH} -export BOOST_ROOT=${SRC_LOCATION}/boost_${BOOST_VERSION} -export BOOST_LINK_LOCATION=${OPT_LOCATION}/boost -export TINI_VERSION=0.18.0 - -export PATH=$HOME/bin:$PATH:$HOME/opt/llvm/bin - -# Setup directories -mkdir -p $SRC_LOCATION -mkdir -p $OPT_LOCATION -mkdir -p $VAR_LOCATION -mkdir -p $BIN_LOCATION -mkdir -p $VAR_LOCATION/log -mkdir -p $ETC_LOCATION - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -REPO_ROOT="${SCRIPT_DIR}/.." -BUILD_DIR="${REPO_ROOT}/build" - -# Use current directory's tmp directory if noexec is enabled for /tmp -if (mount | grep "/tmp " | grep --quiet noexec); then - mkdir -p $REPO_ROOT/tmp - TEMP_DIR="${REPO_ROOT}/tmp" - rm -rf $REPO_ROOT/tmp/* -else # noexec wasn't found - TEMP_DIR="/tmp" -fi - -if [ ! -d "${REPO_ROOT}/.git" ]; then - printf "\\nThis build script only works with sources cloned from git\\n" - printf "Please clone a new eos directory with 'git clone https://github.com/EOSIO/eos --recursive'\\n" - printf "See the wiki for instructions: https://github.com/EOSIO/eos/wiki\\n" - exit 1 -fi - -cd $REPO_ROOT - -STALE_SUBMODS=$(( $(git submodule status --recursive | grep -c "^[+\-]") )) -if [ $STALE_SUBMODS -gt 0 ]; then - printf "\\ngit submodules are not up to date.\\n" - printf "Please run the command 'git submodule update --init --recursive'.\\n" - exit 1 -fi - -printf "Beginning build version: %s\\n" "${VERSION}" -printf "%s\\n" "$( date -u )" -printf "User: %s\\n" "$( whoami )" -# printf "git head id: %s\\n" "$( cat .git/refs/heads/master )" -printf "Current branch: %s\\n" "$( git rev-parse --abbrev-ref HEAD )" - -ARCH=$( uname ) -printf "\\nARCHITECTURE: %s\\n" "${ARCH}" - -# Find and use existing CMAKE -export CMAKE=$(command -v cmake 2>/dev/null) - -if [ "$ARCH" == "Linux" ]; then - # Check if cmake is already installed or not and use source install location - if [ -z $CMAKE ]; then export CMAKE=$HOME/bin/cmake; fi - export OS_NAME=$( cat /etc/os-release | grep ^NAME | cut -d'=' -f2 | sed 's/\"//gI' ) - case "$OS_NAME" in - "Amazon Linux AMI"|"Amazon Linux") - FILE="./scripts/eosiocdt_build_amazon.sh" - CXX_COMPILER=g++ - C_COMPILER=gcc - ;; - "CentOS Linux") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_centos.sh" - CXX_COMPILER=g++ - C_COMPILER=gcc - ;; - "elementary OS") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" - CXX_COMPILER=clang++-4.0 - C_COMPILER=clang-4.0 - ;; - "Fedora") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_fedora.sh" - CXX_COMPILER=g++ - C_COMPILER=gcc - ;; - "Linux Mint") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" - CXX_COMPILER=clang++-4.0 - C_COMPILER=clang-4.0 - ;; - "Ubuntu") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" - CXX_COMPILER=clang++-4.0 - C_COMPILER=clang-4.0 - ;; - "Debian GNU/Linux") - FILE="${REPO_ROOT}/scripts/eosiocdt_build_ubuntu.sh" - CXX_COMPILER=clang++-4.0 - C_COMPILER=clang-4.0 - ;; - *) - printf "\\nUnsupported Linux Distribution. Exiting now.\\n\\n" - exit 1 - esac -fi - -if [ "$ARCH" == "Darwin" ]; then - # Check if cmake is already installed or not and use source install location - if [ -z $CMAKE ]; then export CMAKE=/usr/local/bin/cmake; fi - FILE="${REPO_ROOT}/scripts/eosiocdt_build_darwin.sh" - FREE_MEM=`vm_stat | grep "Pages free:"` - read -ra FREE_MEM <<< "$FREE_MEM" - FREE_MEM=$((${FREE_MEM[2]%?}*(4096))) # free pages * page size -else - FREE_MEM=`LC_ALL=C free | grep "Mem:" | awk '{print $7}'` -fi - -cd $SRC_LOCATION -. "$FILE" # Execute OS specific build file - -CORES_AVAIL=`getconf _NPROCESSORS_ONLN` -MEM_CORES=$(( ${FREE_MEM}/4000000 )) # 4 gigabytes per core -MEM_CORES=$(( $MEM_CORES > 0 ? $MEM_CORES : 1 )) -CORES=$(( $CORES_AVAIL < $MEM_CORES ? $CORES_AVAIL : $MEM_CORES )) - -mkdir -p $BUILD_DIR -cd $BUILD_DIR - -printf "\\n========================================================================\\n" -printf "======================= Starting EOSIO.CDT Build =======================\\n" - -$CMAKE -DCMAKE_INSTALL_PREFIX=$OPT_LOCATION/eosio.cdt "${REPO_ROOT}" -if [ $? -ne 0 ]; then exit -1; fi -make -j$CORES -if [ $? -ne 0 ]; then exit -1; fi - -TIME_END=$(( $(date -u +%s) - $TIME_BEGIN )) - -printf "\n${bldred}\t ___ ___ ___ ___\n" -printf "\t / /\\ / /\\ / /\\ ___ / /\\ \n" -printf "\t / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" -printf "\t / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" -printf "\t / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" -printf "\t /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" -printf "\t \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" -printf "\t \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" -printf "\t \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" -printf "\t \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" -printf "\t \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n${txtrst}" - -printf "\\nEOSIO.CDT has been successfully built. %02d:%02d:%02d\\n\\n" $(($TIME_END/3600)) $(($TIME_END%3600/60)) $(($TIME_END%60)) -printf "${txtrst}==============================================================================================\\n" - -printf "For more information:\\n" -printf "EOSIO website: https://eos.io\\n" -printf "EOSIO Telegram channel @ https://t.me/EOSProject\\n" -printf "EOSIO resources: https://eos.io/resources/\\n" -printf "EOSIO Stack Exchange: https://eosio.stackexchange.com\\n" -printf "EOSIO wiki: https://github.com/EOSIO/eos/wiki\\n\\n\\n" diff --git a/scripts/eosiocdt_build_amazon.sh b/scripts/eosiocdt_build_amazon.sh deleted file mode 100644 index 31fd0ab945..0000000000 --- a/scripts/eosiocdt_build_amazon.sh +++ /dev/null @@ -1,135 +0,0 @@ -OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' | cut -d'.' -f1 ) - -MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) -CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) -CPU_CORE=$( nproc ) -MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) -export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - -DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) -DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) -DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) -DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) -DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - -DEP_ARRAY=( - sudo procps which gcc72 gcc72-c++ autoconf automake libtool make \ - bzip2 bzip2-devel openssl-devel gmp gmp-devel libstdc++72 python27 python27-devel python34 python34-devel \ - libedit-devel ncurses-devel swig wget file -) -COUNT=1 -DISPLAY="" -DEP="" - -printf "\\nOS name: %s\\n" "${OS_NAME}" -printf "OS Version: %s\\n" "${OS_VER}" -printf "CPU speed: %sMhz\\n" "${CPU_SPEED}" -printf "CPU cores: %s\\n" "${CPU_CORE}" -printf "Physical Memory: %sMgb\\n" "${MEM_MEG}" -printf "Disk space total: %sGb\\n" "${DISK_TOTAL}" -printf "Disk space available: %sG\\n" "${DISK_AVAIL}" - -if [ "${MEM_MEG}" -lt 7000 ]; then - printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "exiting now.\\n" - exit 1 -fi - -if [[ "${OS_NAME}" == "Amazon Linux AMI" && "${OS_VER}" -lt 2017 ]]; then - printf "You must be running Amazon Linux 2017.09 or higher to install EOSIO.\\n" - printf "exiting now.\\n" - exit 1 -fi - -if [ "${DISK_AVAIL}" -lt "${DISK_MIN}" ]; then - printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "exiting now.\\n" - exit 1 -fi - -printf "\\nChecking Yum installation.\\n" -if ! YUM=$( command -v yum 2>/dev/null ) -then - printf "\\nYum must be installed to compile EOS.IO.\\n" - printf "\\nExiting now.\\n" - exit 1 -fi -printf "Yum installation found at ${YUM}.\\n" - -printf "\\nDo you wish to update YUM repositories?\\n\\n" -select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\nUpdating...\\n\\n" - if ! sudo $YUM -y update; then - printf "\\nYUM update failed.\\n" - printf "\\nExiting now.\\n\\n" - exit 1; - else - printf "\\nYUM update complete.\\n" - fi - break;; - [Nn]* ) echo "Proceeding without update!" - break;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac -done - -printf "Checking RPM for installed dependencies...\\n" -for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) - if [[ -z $pkg ]]; then - DEP=$DEP" ${DEP_ARRAY[$i]} " - DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" - printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi -done -printf "\\n" -if [ "${COUNT}" -gt 1 ]; then - printf "The following dependencies are required to install EOSIO.\\n" - printf "${DISPLAY}\\n\\n" - printf "Do you wish to install these dependencies?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "Installing dependencies\\n\\n" - if ! sudo $YUM -y install ${DEP}; then - printf "!! YUM dependency installation failed !!\\n" - printf "Exiting now.\\n" - exit 1; - else - printf "YUM dependencies installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf " - No required YUM dependencies to install.\\n" -fi - - -printf "\\n" - - -printf "Checking CMAKE installation...\\n" -if [ -z $CMAKE ]; then - printf "Installing CMAKE...\\n" - curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ - && tar -xzf cmake-$CMAKE_VERSION.tar.gz \ - && cd cmake-$CMAKE_VERSION \ - && ./bootstrap --prefix=$HOME \ - && make -j"${JOBS}" \ - && make install \ - && cd .. \ - && rm -f cmake-$CMAKE_VERSION.tar.gz \ - || exit 1 - printf " - CMAKE successfully installed @ ${CMAKE}.\\n" -else - printf " - CMAKE found @ ${CMAKE}.\\n" -fi diff --git a/scripts/eosiocdt_build_centos.sh b/scripts/eosiocdt_build_centos.sh deleted file mode 100644 index 0f2f70de53..0000000000 --- a/scripts/eosiocdt_build_centos.sh +++ /dev/null @@ -1,197 +0,0 @@ -OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' \ -| cut -d'.' -f1 ) - -MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) -CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) -CPU_CORE=$( nproc ) -MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) -export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - -DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) -DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) -DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) -DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) -DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - -printf "\\nOS name: ${OS_NAME}\\n" -printf "OS Version: ${OS_VER}\\n" -printf "CPU speed: ${CPU_SPEED}Mhz\\n" -printf "CPU cores: ${CPU_CORE}\\n" -printf "Physical Memory: ${MEM_MEG}Mgb\\n" -printf "Disk install: ${DISK_INSTALL}\\n" -printf "Disk space total: ${DISK_TOTAL%.*}G\\n" -printf "Disk space available: ${DISK_AVAIL%.*}G\\n" -printf "Concurrent Jobs (make -j): ${JOBS}\\n" - -if [ "${MEM_MEG}" -lt 7000 ]; then - printf "\\nYour system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "Exiting now.\\n\\n" - exit 1; -fi - -if [ "${OS_VER}" -lt 7 ]; then - printf "\\nYou must be running Centos 7 or higher to install EOSIO.\\n" - printf "Exiting now.\\n\\n" - exit 1; -fi - -if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "\\nYou must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "Exiting now.\\n\\n" - exit 1; -fi - -printf "\\n" - -printf "Checking Yum installation...\\n" -if ! YUM=$( command -v yum 2>/dev/null ); then - printf "!! Yum must be installed to compile EOS.IO !!\\n" - printf "Exiting now.\\n" - exit 1; -fi -printf " - Yum installation found at %s.\\n" "${YUM}" - -printf "\\nDo you wish to update YUM repositories?\\n\\n" -select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\nUpdating...\\n\\n" - if ! sudo $YUM -y update; then - printf "\\nYUM update failed.\\n" - printf "\\nExiting now.\\n\\n" - exit 1; - else - printf "\\nYUM update complete.\\n" - fi - break;; - [Nn]* ) - echo "Proceeding without update!" - break;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac -done - -printf "Checking installation of Centos Software Collections Repository...\\n" -SCL=$( rpm -qa | grep -E 'centos-release-scl-[0-9].*' ) -if [ -z "${SCL}" ]; then - printf " - Do you wish to install and enable this repository?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "Installing SCL...\\n" - if ! sudo $YUM -y --enablerepo=extras install centos-release-scl; then - printf "!! Centos Software Collections Repository installation failed !!\\n" - printf "Exiting now.\\n\\n" - exit 1; - else - printf "Centos Software Collections Repository installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required Centos Software Collections Repository, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf " - ${SCL} found.\\n" -fi - -printf "Checking installation of devtoolset-7...\\n" -DEVTOOLSET=$( rpm -qa | grep -E 'devtoolset-7-[0-9].*' ) -if [ -z "${DEVTOOLSET}" ]; then - printf "Do you wish to install devtoolset-7?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "Installing devtoolset-7...\\n" - if ! sudo $YUM install -y devtoolset-7 2>/dev/null; then - printf "!! Centos devtoolset-7 installation failed !!\\n" - printf "Exiting now.\\n" - exit 1; - else - printf "Centos devtoolset installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of devtoolset-7. Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf " - ${DEVTOOLSET} found.\\n" -fi -printf "Enabling Centos devtoolset-7...\\n" -if ! source "/opt/rh/devtoolset-7/enable" 2>/dev/null; then - printf "!! Unable to enable Centos devtoolset-7 at this time !!\\n" - printf "Exiting now.\\n\\n" - exit 1; -fi -printf "Centos devtoolset-7 successfully enabled.\\n" - -printf "\\n" - -DEP_ARRAY=( - git autoconf automake libtool make bzip2 \ - bzip2-devel openssl-devel gmp-devel \ - ocaml libicu-devel python python-devel python33 \ - gettext-devel file sudo -) -COUNT=1 -DISPLAY="" -DEP="" -printf "Checking RPM for installed dependencies...\\n" -for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) - if [[ -z $pkg ]]; then - DEP=$DEP" ${DEP_ARRAY[$i]} " - DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" - printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi -done -printf "\\n" -if [ "${COUNT}" -gt 1 ]; then - printf "The following dependencies are required to install EOSIO.\\n" - printf "${DISPLAY}\\n\\n" - printf "Do you wish to install these dependencies?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "Installing dependencies\\n\\n" - if ! sudo $YUM -y install ${DEP}; then - printf "!! YUM dependency installation failed !!\\n" - printf "Exiting now.\\n" - exit 1; - else - printf "YUM dependencies installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf " - No required YUM dependencies to install.\\n" -fi - - -printf "\\n" - - -printf "Checking CMAKE installation...\\n" -if [ -z $CMAKE ]; then - printf "Installing CMAKE...\\n" - curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ - && tar -xzf cmake-$CMAKE_VERSION.tar.gz \ - && cd cmake-$CMAKE_VERSION \ - && ./bootstrap --prefix=$HOME \ - && make -j"${JOBS}" \ - && make install \ - && cd .. \ - && rm -f cmake-$CMAKE_VERSION.tar.gz \ - || exit 1 - printf " - CMAKE successfully installed @ ${CMAKE}.\\n" -else - printf " - CMAKE found @ ${CMAKE}.\\n" -fi \ No newline at end of file diff --git a/scripts/eosiocdt_build_darwin.sh b/scripts/eosiocdt_build_darwin.sh deleted file mode 100644 index 6681b7b04b..0000000000 --- a/scripts/eosiocdt_build_darwin.sh +++ /dev/null @@ -1,158 +0,0 @@ -OS_VER=$(sw_vers -productVersion) -OS_MAJ=$(echo "${OS_VER}" | cut -d'.' -f1) -OS_MIN=$(echo "${OS_VER}" | cut -d'.' -f2) -OS_PATCH=$(echo "${OS_VER}" | cut -d'.' -f3) -MEM_GIG=$(bc <<< "($(sysctl -in hw.memsize) / 1024000000)") -CPU_SPEED=$(bc <<< "scale=2; ($(sysctl -in hw.cpufrequency) / 10^8) / 10") -CPU_CORE=$( sysctl -in machdep.cpu.core_count ) -export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - -DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) -blksize=$(df . | head -1 | awk '{print $2}' | cut -d- -f1) -gbfactor=$(( 1073741824 / blksize )) -total_blks=$(df . | tail -1 | awk '{print $2}') -avail_blks=$(df . | tail -1 | awk '{print $4}') -DISK_TOTAL=$((total_blks / gbfactor )) -DISK_AVAIL=$((avail_blks / gbfactor )) - -export HOMEBREW_NO_AUTO_UPDATE=1 - -COUNT=1 -DISPLAY="" -DEPS="" - -printf "\\nOS name: ${OS_NAME}\\n" -printf "OS Version: ${OS_VER}\\n" -printf "CPU speed: ${CPU_SPEED}Mhz\\n" -printf "CPU cores: %s\\n" "${CPU_CORE}" -printf "Physical Memory: ${MEM_GIG} Gbytes\\n" -printf "Disk install: ${DISK_INSTALL}\\n" -printf "Disk space total: ${DISK_TOTAL}G\\n" -printf "Disk space available: ${DISK_AVAIL}G\\n" - -if [ "${MEM_GIG}" -lt 7 ]; then - echo "Your system must have 7 or more Gigabytes of physical memory installed." - echo "Exiting now." - exit 1 -fi - -if [ "${OS_MIN}" -lt 12 ]; then - echo "You must be running Mac OS 10.12.x or higher to install EOSIO." - echo "Exiting now." - exit 1 -fi - -if [ "${DISK_AVAIL}" -lt "$DISK_MIN" ]; then - echo "You must have at least ${DISK_MIN}GB of available storage to install EOSIO." - echo "Exiting now." - exit 1 -fi - -printf "Checking xcode-select installation\\n" -if ! XCODESELECT=$( command -v xcode-select) -then - printf "\\nXCode must be installed in order to proceed.\\n\\n" - printf "Exiting now.\\n" - exit 1 -fi -printf "xcode-select installation found @ ${XCODESELECT}\\n" - -printf "Checking Ruby installation.\\n" -if ! RUBY=$( command -v ruby) -then - printf "\\nRuby must be installed in order to proceed.\\n\\n" - printf "Exiting now.\\n" - exit 1 -fi -printf "Ruby installation found @ ${RUBY}\\n" - -printf "Checking Home Brew installation...\\n" -if ! BREW=$( command -v brew ) -then - printf "Homebrew must be installed to compile EOS.IO!\\n" - if [ $1 == 0 ]; then read -p "Do you wish to install HomeBrew? (y/n)? " answer; fi - case ${answer} in - 1 | [Yy]* ) - "${XCODESELECT}" --install 2>/dev/null; - if ! "${RUBY}" -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; then - echo " - Unable to install homebrew at this time." - exit 1; - else - BREW=$( command -v brew ) - fi - ;; - [Nn]* ) echo "User aborted homebrew installation. Exiting now."; exit 1;; - * ) echo "Please type 'y' for yes or 'n' for no.";; - esac - -fi -printf " - Home Brew installation found @ ${BREW}\\n" - -printf "\\nChecking dependencies...\\n" -var_ifs="${IFS}" -IFS="," -while read -r name tester testee brewname uri; do - if [ "${tester}" "${testee}" ]; then - printf " - %s found\\n" "${name}" - continue - fi - # resolve conflict with homebrew glibtool and apple/gnu installs of libtool - if [ "${testee}" == "/usr/local/bin/glibtool" ]; then - if [ "${tester}" "/usr/local/bin/libtool" ]; then - printf " - %s found\\n" "${name}" - continue - fi - fi - DEPS=$DEPS"${brewname}," - DISPLAY="${DISPLAY}${COUNT}. ${name}\\n" - printf " - %s ${bldred}NOT${txtrst} found.\\n" "${name}" - (( COUNT++ )) -done < "${REPO_ROOT}/scripts/eosiocdt_build_darwin_deps" -IFS="${var_ifs}" - -if [ ! -d /usr/local/Frameworks ]; then - printf "\\n${bldred}/usr/local/Frameworks is necessary to brew install python@3. Run the following commands as sudo and try again:${txtrst}\\n" - printf "sudo mkdir /usr/local/Frameworks && sudo chown $(whoami):admin /usr/local/Frameworks\\n\\n" - exit 1; -fi - -if [ $COUNT -gt 1 ]; then - printf "\\nThe following dependencies are required to install EOSIO:\\n" - printf "${DISPLAY}\\n\\n" - if [ -z "$1" ]; then read -p "Do you wish to install these packages? (y/n) " answer; fi - case ${answer} in - 1 | [Yy]* ) - "${XCODESELECT}" --install 2>/dev/null; - if [ -z "$1" ]; then read -p "Do you wish to update homebrew packages first? (y/n) " answer; fi - case ${answer} in - 1 | [Yy]* ) - if ! brew update; then - printf " - Brew update failed.\\n" - exit 1; - else - printf " - Brew update complete.\\n" - fi - ;; - [Nn]* ) echo "Proceeding without update!";; - * ) echo "Please type 'y' for yes or 'n' for no."; exit;; - esac - brew tap eosio/eosio - printf "\\nInstalling Dependencies...\\n" - # DON'T INSTALL llvm@4 WITH --force! - OIFS="$IFS" - IFS=$',' - for DEP in $DEPS; do - # Eval to support string/arguments with $DEP - if ! eval $BREW install $DEP; then - printf " - Homebrew exited with the above errors!\\n" - exit 1; - fi - done - IFS="$OIFS" - ;; - [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; - * ) echo "Please type 'y' for yes or 'n' for no."; exit;; - esac -else - printf "\\n - No required Home Brew dependencies to install.\\n" -fi \ No newline at end of file diff --git a/scripts/eosiocdt_build_darwin_deps b/scripts/eosiocdt_build_darwin_deps deleted file mode 100644 index 9aadb88cce..0000000000 --- a/scripts/eosiocdt_build_darwin_deps +++ /dev/null @@ -1,5 +0,0 @@ -automake,-x,/usr/local/bin/automake,automake,http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz -Libtool,-x,/usr/local/bin/glibtool,libtool,http://gnu.askapache.com/libtool/libtool-2.4.6.tar.gz -OpenSSL,-f,/usr/local/opt/openssl/lib/libssl.a,openssl,https://www.openssl.org/source/openssl-1.0.2n.tar.gz -GMP,-f,/usr/local/opt/gmp/include/gmpxx.h,gmp,https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2 -cmake,-f,/usr/local/bin/cmake,cmake,https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4.tar.gz diff --git a/scripts/eosiocdt_build_fedora.sh b/scripts/eosiocdt_build_fedora.sh deleted file mode 100644 index e22a57c025..0000000000 --- a/scripts/eosiocdt_build_fedora.sh +++ /dev/null @@ -1,137 +0,0 @@ -OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) - -MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 ) -CPU_SPEED=$( lscpu | grep "MHz" | tr -s ' ' | cut -d\ -f3 | cut -d'.' -f1 ) -CPU_CORE=$( nproc ) -MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) -export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - -DISK_INSTALL=$( df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 ) -DISK_TOTAL_KB=$( df . | tail -1 | awk '{print $2}' ) -DISK_AVAIL_KB=$( df . | tail -1 | awk '{print $4}' ) -DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) -DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - -DEP_ARRAY=( - git sudo procps-ng which gcc gcc-c++ autoconf automake libtool make \ - bzip2-devel wget bzip2 compat-openssl10 \ - openssl-devel gmp-devel libstdc++-devel python2 python2-devel python3 python3-devel \ - libedit ncurses-devel swig -) -COUNT=1 -DISPLAY="" -DEP="" - -printf "\\nOS name: ${OS_NAME}\\n" -printf "OS Version: ${OS_VER}\\n" -printf "CPU speed: ${CPU_SPEED}Mhz\\n" -printf "CPU cores: %s\\n" "${CPU_CORE}" -printf "Physical Memory: ${MEM_MEG} Mgb\\n" -printf "Disk install: ${DISK_INSTALL}\\n" -printf "Disk space total: ${DISK_TOTAL%.*}G\\n" -printf "Disk space available: ${DISK_AVAIL%.*}G\\n" - -if [ "${MEM_MEG}" -lt 7000 ]; then - printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "Exiting now.\\n" - exit 1; -fi - -if [ "${OS_VER}" -lt 25 ]; then - printf "You must be running Fedora 25 or higher to install EOSIO.\\n" - printf "Exiting now.\\n" - exit 1; -fi - -if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "Exiting now.\\n" - exit 1; -fi - -printf "\\nChecking Yum installation...\\n" -if ! YUM=$( command -v yum 2>/dev/null ); then - printf "!! Yum must be installed to compile EOS.IO !!\\n" - printf "Exiting now.\\n" - exit 1; -fi -printf " - Yum installation found at %s.\\n" "${YUM}" - -printf "\\nDo you wish to update YUM repositories?\\n\\n" -select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\nUpdating...\\n\\n" - if ! sudo $YUM -y update; then - printf "\\nYUM update failed.\\n" - printf "\\nExiting now.\\n\\n" - exit 1; - else - printf "\\nYUM update complete.\\n" - fi - break;; - [Nn]* ) echo "Proceeding without update!" - break;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac -done - -printf "\\n" - -printf "Checking RPM for installed dependencies...\\n" -for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( rpm -qi "${DEP_ARRAY[$i]}" 2>/dev/null | grep Name ) - if [[ -z $pkg ]]; then - DEP=$DEP" ${DEP_ARRAY[$i]} " - DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" - printf "!! Package %s ${bldred} NOT ${txtrst} found !!\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf " - Package %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi -done -if [ "${COUNT}" -gt 1 ]; then - printf "The following dependencies are required to install EOSIO.\\n" - printf "${DISPLAY}\\n" - printf "Do you wish to install these dependencies?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "Installing dependencies\\n\\n" - if ! sudo $YUM -y install ${DEP}; then - printf "!! YUM dependency installation failed !!\\n" - printf "Exiting now.\\n" - exit 1; - else - printf "YUM dependencies installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf " - No required YUM dependencies to install.\\n" -fi - - -printf "\\n" - - -printf "Checking CMAKE installation...\\n" -if [ -z $CMAKE ]; then - printf "Installing CMAKE...\\n" - curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ - && tar xf cmake-$CMAKE_VERSION.tar.gz \ - && cd cmake-$CMAKE_VERSION \ - && ./bootstrap --prefix=$HOME \ - && make -j"${JOBS}" \ - && make install \ - && cd .. \ - && rm -f cmake-$CMAKE_VERSION.tar.gz \ - || exit 1 - printf " - CMAKE successfully installed @ ${CMAKE}.\\n" -else - printf " - CMAKE found @ ${CMAKE}.\\n" -fi diff --git a/scripts/eosiocdt_build_ubuntu.sh b/scripts/eosiocdt_build_ubuntu.sh deleted file mode 100644 index aadf8ef04c..0000000000 --- a/scripts/eosiocdt_build_ubuntu.sh +++ /dev/null @@ -1,161 +0,0 @@ -OS_VER=$( grep VERSION_ID /etc/os-release | cut -d'=' -f2 | sed 's/[^0-9\.]//gI' ) -OS_MAJ=$(echo "${OS_VER}" | cut -d'.' -f1) -OS_MIN=$(echo "${OS_VER}" | cut -d'.' -f2) - -MEM_MEG=$( free -m | sed -n 2p | tr -s ' ' | cut -d\ -f2 || cut -d' ' -f2 ) -CPU_SPEED=$( lscpu | grep -m1 "MHz" | tr -s ' ' | cut -d\ -f3 || cut -d' ' -f3 | cut -d'.' -f1 ) -CPU_CORE=$( nproc ) -MEM_GIG=$(( ((MEM_MEG / 1000) / 2) )) -export JOBS=$(( MEM_GIG > CPU_CORE ? CPU_CORE : MEM_GIG )) - -DISK_INSTALL=$(df -h . | tail -1 | tr -s ' ' | cut -d\ -f1 || cut -d' ' -f1) -DISK_TOTAL_KB=$(df . | tail -1 | awk '{print $2}') -DISK_AVAIL_KB=$(df . | tail -1 | awk '{print $4}') -DISK_TOTAL=$(( DISK_TOTAL_KB / 1048576 )) -DISK_AVAIL=$(( DISK_AVAIL_KB / 1048576 )) - -printf "\\nOS name: ${OS_NAME}\\n" -printf "OS Version: ${OS_VER}\\n" -printf "CPU speed: ${CPU_SPEED}Mhz\\n" -printf "CPU cores: %s\\n" "${CPU_CORE}" -printf "Physical Memory: ${MEM_MEG} Mgb\\n" -printf "Disk install: ${DISK_INSTALL}\\n" -printf "Disk space total: ${DISK_TOTAL%.*}G\\n" -printf "Disk space available: ${DISK_AVAIL%.*}G\\n" - -if [ "${MEM_MEG}" -lt 7000 ]; then - printf "Your system must have 7 or more Gigabytes of physical memory installed.\\n" - printf "Exiting now.\\n" - exit 1 -fi - -case "${OS_NAME}" in - "Linux Mint") - if [ "${OS_MAJ}" -lt 18 ]; then - printf "You must be running Linux Mint 18.x or higher to install EOSIO.\\n" - printf "Exiting now.\\n" - exit 1 - fi - ;; - "Ubuntu") - if [ "${OS_MAJ}" -lt 16 ]; then - printf "You must be running Ubuntu 16.04.x or higher to install EOSIO.\\n" - printf "Exiting now.\\n" - exit 1 - fi - # UBUNTU 18 doesn't have MONGODB 3.6.3 - if [ $OS_MAJ -gt 16 ]; then - export MONGODB_VERSION=4.1.1 - fi - # We have to re-set this with the new version - export MONGODB_ROOT=${OPT_LOCATION}/mongodb-${MONGODB_VERSION} - ;; - "Debian") - if [ $OS_MAJ -lt 10 ]; then - printf "You must be running Debian 10 to install EOSIO, and resolve missing dependencies from unstable (sid).\n" - printf "Exiting now.\n" - exit 1 - fi - ;; -esac - -if [ "${DISK_AVAIL%.*}" -lt "${DISK_MIN}" ]; then - printf "You must have at least %sGB of available storage to install EOSIO.\\n" "${DISK_MIN}" - printf "Exiting now.\\n" - exit 1 -fi - -# llvm-4.0 is installed into /usr/lib/llvm-4.0 -DEP_ARRAY=( - git llvm-4.0 clang-4.0 libclang-4.0-dev make automake libbz2-dev libssl-dev \ - libgmp3-dev autotools-dev build-essential libicu-dev python2.7 python2.7-dev python3 python3-dev \ - autoconf libtool curl zlib1g-dev sudo ruby -) -COUNT=1 -DISPLAY="" -DEP="" - -if [[ "${ENABLE_CODE_COVERAGE}" == true ]]; then - DEP_ARRAY+=(lcov) -fi - -printf "Do you wish to update repositories with apt-get update?\\n\\n" -select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\nUpdating...\\n\\n" - if ! sudo apt-get update; then - printf "\\nAPT update failed.\\n" - printf "\\nExiting now.\\n\\n" - exit 1; - else - printf "\\nAPT update complete.\\n" - fi - break;; - [Nn]* ) echo "Proceeding without update!" - break;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac -done - -printf "\\nChecking for installed dependencies.\\n\\n" - -for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); -do - pkg=$( dpkg -s "${DEP_ARRAY[$i]}" 2>/dev/null | grep Status | tr -s ' ' | cut -d\ -f4 ) - if [ -z "$pkg" ]; then - DEP=$DEP" ${DEP_ARRAY[$i]} " - DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n" - printf "Package %s ${bldred} NOT ${txtrst} found.\\n" "${DEP_ARRAY[$i]}" - (( COUNT++ )) - else - printf "Package %s found.\\n" "${DEP_ARRAY[$i]}" - continue - fi -done - -if [ "${COUNT}" -gt 1 ]; then - printf "\\nThe following dependencies are required to install EOSIO.\\n" - printf "\\n${DISPLAY}\\n\\n" - printf "Do you wish to install these packages?\\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - printf "\\n\\nInstalling dependencies\\n\\n" - if ! sudo apt-get -y install ${DEP} - then - printf "\\nDPKG dependency failed.\\n" - printf "\\nExiting now.\\n" - exit 1 - else - printf "\\nDPKG dependencies installed successfully.\\n" - fi - break;; - [Nn]* ) echo "User aborting installation of required dependencies, Exiting now."; exit;; - * ) echo "Please type 1 for yes or 2 for no.";; - esac - done -else - printf "\\nNo required dpkg dependencies to install." -fi - - -printf "\\n" - - -printf "Checking CMAKE installation...\\n" -if [ ! -d $SRC_LOCATION/cmake-$CMAKE_VERSION ]; then - printf "Installing CMAKE...\\n" - curl -LO https://cmake.org/files/v$CMAKE_VERSION_MAJOR.$CMAKE_VERSION_MINOR/cmake-$CMAKE_VERSION.tar.gz \ - && tar xf cmake-$CMAKE_VERSION.tar.gz \ - && cd cmake-$CMAKE_VERSION \ - && ./bootstrap --prefix=$HOME \ - && make -j"${JOBS}" \ - && make install \ - && cd .. \ - && rm -f cmake-$CMAKE_VERSION.tar.gz \ - || exit 1 - printf " - CMAKE successfully installed @ ${CMAKE}.\\n" -else - printf " - CMAKE found @ ${CMAKE}.\\n" -fi diff --git a/scripts/eosiocdt_install.sh b/scripts/eosiocdt_install.sh deleted file mode 100755 index 959cf20841..0000000000 --- a/scripts/eosiocdt_install.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -########################################################################## -# This is the EOSIO automated install script for Linux and Mac OS. -# This file was downloaded from https://github.com/EOSIO/eos -# -# Copyright (c) 2017, Respective Authors all rights reserved. -# -# After June 1, 2018 this software is available under the following terms: -# -# The MIT License -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# https://github.com/EOSIO/eos/blob/master/LICENSE.txt -########################################################################## - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -REPO_ROOT="${SCRIPT_DIR}/.." -BUILD_DIR="${REPO_ROOT}/build" - -OPT_LOCATION=$HOME/opt -BIN_LOCATION=$HOME/bin -LIB_LOCATION=$HOME/lib - -CMAKE_BUILD_TYPE=Release -TIME_BEGIN=$( date -u +%s ) -VERSION=2.0 - -txtbld=$(tput bold) -bldred=${txtbld}$(tput setaf 1) -txtrst=$(tput sgr0) - -if [ ! -d "${BUILD_DIR}" ]; then - printf "\\n\Error, build.sh has not run successfully. Please run ./build.sh first!\\n\\n" - exit -1 -fi - -if ! pushd "${BUILD_DIR}" &> /dev/null; then - printf "Unable to enter build directory ${BUILD_DIR}.\\n Exiting now.\\n" - exit 1; -fi - -if ! make install; then - printf "\\nMAKE installing EOSIO has exited with the above error.\\n\\n" - exit -1 -fi -popd &> /dev/null - -printf "\n${bldred} ___ ___ ___ ___\n" -printf " / /\\ / /\\ / /\\ ___ / /\\ \n" -printf " / /:/_ / /::\\ / /:/_ / /\\ / /::\\ \n" -printf " / /:/ /\\ / /:/\\:\\ / /:/ /\\ / /:/ / /:/\\:\\ \n" -printf " / /:/ /:/_ / /:/ \\:\\ / /:/ /::\\ /__/::\\ / /:/ \\:\\ \n" -printf " /__/:/ /:/ /\\ /__/:/ \\__\\:\\ /__/:/ /:/\\:\\ \\__\\/\\:\\__ /__/:/ \\__\\:\\ \n" -printf " \\ \\:\\/:/ /:/ \\ \\:\\ / /:/ \\ \\:\\/:/~/:/ \\ \\:\\/\\ \\ \\:\\ / /:/ \n" -printf " \\ \\::/ /:/ \\ \\:\\ /:/ \\ \\::/ /:/ \\__\\::/ \\ \\:\\ /:/ \n" -printf " \\ \\:\\/:/ \\ \\:\\/:/ \\__\\/ /:/ /__/:/ \\ \\:\\/:/ \n" -printf " \\ \\::/ \\ \\::/ /__/:/ \\__\\/ \\ \\::/ \n" -printf " \\__\\/ \\__\\/ \\__\\/ \\__\\/ \n\n${txtrst}" - -printf "==============================================================================================\\n" -printf "EOSIO has been installed into ${OPT_LOCATION}/eosio.cdt/bin!\\n" -printf "If you need to, you can fully uninstall using eosiocdt_uninstall.sh.\\n" -printf "==============================================================================================\\n\\n" - -printf "For more information:\\n" -printf "EOSIO website: https://eos.io\\n" -printf "EOSIO resources: https://eos.io/resources/\\n" -printf "EOSIO Stack Exchange: https://eosio.stackexchange.com\\n" diff --git a/scripts/eosiocdt_uninstall.sh b/scripts/eosiocdt_uninstall.sh deleted file mode 100755 index f2ec7d71f6..0000000000 --- a/scripts/eosiocdt_uninstall.sh +++ /dev/null @@ -1,100 +0,0 @@ -#! /bin/bash - -OPT_LOCATION=$HOME/opt - -binaries=( - eosio-ranlib - eosio-ar - eosio-objdump - eosio-readelf - eosio-abigen - eosio-wasm2wast - eosio-wast2wasm - eosio-pp - eosio-cc - eosio-cpp - eosio-ld - eosio-abidiff - eosio-init - llvm-readelf - llvm-objdump - llvm-ar - llvm-ranlib -) - -if [ -d "/usr/local/eosio.cdt" ]; then - printf "Do you wish to remove this install? (requires sudo)\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - if [ "$(id -u)" -ne 0 ]; then - printf "\nThis requires sudo, please run ./uninstall.sh with sudo\n\n" - exit -1 - fi - pushd /usr/local &> /dev/null - rm -rf eosio.cdt - pushd bin &> /dev/null - for binary in ${binaries[@]}; do - rm ${binary} - done - popd &> /dev/null - pushd lib/cmake &> /dev/null - rm -rf eosio.cdt - popd &> /dev/null - break;; - [Nn]* ) - printf "Aborting uninstall\n\n" - exit -1;; - esac - done -fi - -if [ -d "/usr/local/eosio.wasmsdk" ]; then - printf "Do you wish to remove this install? (requires sudo)\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - if [ "$(id -u)" -ne 0 ]; then - printf "\nThis requires sudo, please run ./uninstall.sh with sudo\n\n" - exit -1 - fi - pushd /usr/local &> /dev/null - rm -rf eosio.wasmsdk - pushd bin &> /dev/null - for binary in ${binaries[@]}; do - rm ${binary} - done - popd &> /dev/null - break;; - - [Nn]* ) - printf "Aborting uninstall\n\n" - exit -1;; - esac - done -fi - -if [ -d $OPT_LOCATION/eosio.cdt ] || [[ $1 == "force-new" ]]; then - printf "Do you wish to remove this install?\n" - select yn in "Yes" "No"; do - case $yn in - [Yy]* ) - pushd $HOME &> /dev/null - pushd opt &> /dev/null - rm -rf eosio.cdt - popd &> /dev/null - pushd bin &> /dev/null - for binary in ${binaries[@]}; do - rm ${binary} - done - popd &> /dev/null - pushd lib/cmake &> /dev/null - rm -rf eosio.cdt - popd &> /dev/null - break;; - [Nn]* ) - printf "\tAborting uninstall\n\n" - exit -1;; - esac - done -fi \ No newline at end of file From 7aaa0e910e0f9b08474619c4511f3943bb631487 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 14 May 2020 08:45:00 -0400 Subject: [PATCH 302/659] Increase package timeout --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 743be7d3cd..3c5e2073df 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -323,7 +323,7 @@ steps: cd: ~ agents: - "queue=mac-anka-node-fleet" - timeout: 10 + timeout: 20 skip: ${SKIP_MACOS_10_14}${SKIP_PACKAGE_BUILDER} - label: ":darwin: Catalina - Package Builder" From e4d3f4c9245ebb1dfcaf51229da0124dafe44281 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 14 May 2020 09:59:51 -0400 Subject: [PATCH 303/659] Set timeout back to normal, seemed to be due to a network issue? --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 3c5e2073df..743be7d3cd 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -323,7 +323,7 @@ steps: cd: ~ agents: - "queue=mac-anka-node-fleet" - timeout: 20 + timeout: 10 skip: ${SKIP_MACOS_10_14}${SKIP_PACKAGE_BUILDER} - label: ":darwin: Catalina - Package Builder" From a72c7b77f7546a59066cfac4320ac547ce56395d Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 18 May 2020 13:26:38 -0400 Subject: [PATCH 304/659] Fix use-after-free --- libraries/eosiolib/contracts/eosio/multi_index.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/multi_index.hpp b/libraries/eosiolib/contracts/eosio/multi_index.hpp index 0f03a6585d..c0b17bd74d 100644 --- a/libraries/eosiolib/contracts/eosio/multi_index.hpp +++ b/libraries/eosiolib/contracts/eosio/multi_index.hpp @@ -1894,8 +1894,6 @@ class multi_index eosio::check( itr2 != _items_vector.rend(), "attempt to remove object that was not in multi_index" ); - _items_vector.erase(--(itr2.base())); - internal_use_do_not_use::db_remove_i64( objitem.__primary_itr ); hana::for_each( _indices, [&]( auto& idx ) { @@ -1909,6 +1907,8 @@ class multi_index if( i >= 0 ) secondary_index_db_functions::db_idx_remove( i ); }); + + _items_vector.erase(--(itr2.base())); } }; From c3394dade2fa3fd8531755d5f6d2dd61d7cb5592 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Mon, 18 May 2020 23:43:57 +0300 Subject: [PATCH 305/659] Resolves 883, correction for eosio-init example. --- docs/03_command-reference/eosio-init.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/03_command-reference/eosio-init.md b/docs/03_command-reference/eosio-init.md index 271f28de5e..c5fa03308e 100644 --- a/docs/03_command-reference/eosio-init.md +++ b/docs/03_command-reference/eosio-init.md @@ -4,13 +4,14 @@ content_title: eosio-init tool This tool is used to generate a skeleton smart contract and directory structure. To generate a new smart contract project you can either generate a "bare" project (no CMake) or the default is to generate a CMake project. + Example: ```bash -$ eosio-abigen hello.cpp --contract=hello --output=hello.abi +$ eosio-init --path=\destination\path\where\to\generate\project\ --project=hello_contract_folder ``` -This will generate one file: -* The generated ABI file (hello.abi) +This will generate a project folder `hello_contract_folder` in the path `\destination\path\where\to\generate\project\` containing the skeleton smart contract and directory structure. + ``` USAGE: eosio-init [options] From c788108eca0a4044b7ec571b1747770d86e59150 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 22 May 2020 14:56:44 -0400 Subject: [PATCH 306/659] Add timeout bump back --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 743be7d3cd..627f407263 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -344,7 +344,7 @@ steps: wait-network: true agents: - "queue=mac-anka-node-fleet" - timeout: 10 + timeout: 20 skip: ${SKIP_MACOS_10_15}${SKIP_PACKAGE_BUILDER} - label: ":git: Git Submodule Regression Check" From 1a9a6a1e1ded5c635c0d37b436ab83ddea060f35 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Thu, 14 Nov 2019 20:15:10 -0500 Subject: [PATCH 307/659] updates for llvm9 bump --- eosio_llvm | 2 +- libraries/libc++/libcxx | 2 +- libraries/libc/musl | 2 +- modules/InstallCDT.cmake | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/eosio_llvm b/eosio_llvm index 3c026f8b78..d8e69fb88e 160000 --- a/eosio_llvm +++ b/eosio_llvm @@ -1 +1 @@ -Subproject commit 3c026f8b7813ad693749d3551353a554c5ca33e7 +Subproject commit d8e69fb88e5211d9055b9aa6371eb21bd4ce1107 diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index fb4b3725ab..8ccb1fa7c2 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit fb4b3725ab993d85384e67c4d634d2a404c0c381 +Subproject commit 8ccb1fa7c224bd1ccff65b46393c59181517c3d3 diff --git a/libraries/libc/musl b/libraries/libc/musl index 7941d81911..7f6ced8142 160000 --- a/libraries/libc/musl +++ b/libraries/libc/musl @@ -1 +1 @@ -Subproject commit 7941d8191103ce94fb86c2c518878aef474165b5 +Subproject commit 7f6ced814233ba86709a10d6b7923672a95dbc61 diff --git a/modules/InstallCDT.cmake b/modules/InstallCDT.cmake index a762d4d71f..66b3dfb351 100644 --- a/modules/InstallCDT.cmake +++ b/modules/InstallCDT.cmake @@ -63,7 +63,7 @@ eosio_clang_install(llc) eosio_clang_install(lld) eosio_clang_install(ld.lld) eosio_clang_install(ld64.lld) -eosio_clang_install(clang-7) +eosio_clang_install(clang-9) eosio_clang_install(wasm-ld) eosio_tool_install_and_symlink(eosio-pp eosio-pp) @@ -77,7 +77,6 @@ eosio_tool_install_and_symlink(eosio-init eosio-init) eosio_clang_install(../lib/LLVMEosioApply${CMAKE_SHARED_LIBRARY_SUFFIX}) eosio_clang_install(../lib/LLVMEosioSoftfloat${CMAKE_SHARED_LIBRARY_SUFFIX}) -eosio_clang_install(../lib/eosio_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}) eosio_cmake_install_and_symlink(eosio.cdt-config.cmake eosio.cdt-config.cmake) eosio_cmake_install_and_symlink(EosioWasmToolchain.cmake EosioWasmToolchain.cmake) From dadcb312859d6d741ebe59aaf9e895185009cc42 Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Fri, 15 Nov 2019 18:47:43 -0500 Subject: [PATCH 308/659] more changes for llvm9 --- CMakeLists.txt | 3 ++ libraries/CMakeLists.txt | 5 +- libraries/eosiolib/CMakeLists.txt | 19 ++++---- libraries/eosiolib/malloc.cpp | 8 ++-- libraries/eosiolib/simple_malloc.cpp | 14 +++--- libraries/libc++/CMakeLists.txt | 34 ++++++------- libraries/libc/CMakeLists.txt | 71 +++++++++++++++------------- libraries/rt/CMakeLists.txt | 13 +++-- modules/ClangExternalProject.txt | 2 +- modules/LibrariesExternalProject.txt | 2 +- modules/ToolsExternalProject.txt | 2 +- tools/cc/eosio-cc.cpp.in | 2 +- tools/cc/eosio-cpp.cpp.in | 2 +- 13 files changed, 98 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e59580995c..5aacff5dd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,9 @@ endif() set(CDT_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/eosio.cdt) +option(ENABLE_NATIVE_COMPILER "enable native builds with the eosio.cdt toolchain" ON) +option(ENABLE_TESTS "enable building tests" ON) + include(GNUInstallDirs) include(modules/ClangExternalProject.txt) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index ddf4b6ad4c..b99ea475b0 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -18,5 +18,8 @@ add_subdirectory(libc) add_subdirectory(libc++) add_subdirectory(eosiolib) add_subdirectory(boost) -add_subdirectory(native) add_subdirectory(rt) + +if (ENABLE_NATIVE_COMPILER) + add_subdirectory(native) +endif() diff --git a/libraries/eosiolib/CMakeLists.txt b/libraries/eosiolib/CMakeLists.txt index 6622b9f4f4..345506346d 100644 --- a/libraries/eosiolib/CMakeLists.txt +++ b/libraries/eosiolib/CMakeLists.txt @@ -18,11 +18,6 @@ add_library(eosio_cmem memory.cpp ${HEADERS}) -add_native_library(native_eosio - eosiolib.cpp - crypto.cpp - malloc.cpp - ${HEADERS}) set_target_properties(eosio_malloc PROPERTIES LINKER_LANGUAGE C) @@ -36,12 +31,20 @@ target_include_directories(eosio PUBLIC ${CMAKE_SOURCE_DIR}/boost/include) target_link_libraries( eosio c c++ ) -add_dependencies( native_eosio eosio ) - add_custom_command( TARGET eosio POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) add_custom_command( TARGET eosio_malloc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) add_custom_command( TARGET eosio_dsm POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) add_custom_command( TARGET eosio_cmem POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) -add_custom_command( TARGET native_eosio POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) + +if (ENABLE_NATIVE_COMPILER) + add_native_library(native_eosio + eosiolib.cpp + crypto.cpp + malloc.cpp + ${HEADERS}) + + add_dependencies( native_eosio eosio ) + add_custom_command( TARGET native_eosio POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) +endif() file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../eosiolib DESTINATION ${BASE_BINARY_DIR}/include FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp") diff --git a/libraries/eosiolib/malloc.cpp b/libraries/eosiolib/malloc.cpp index 3adc4bb6fd..2f3585baa9 100644 --- a/libraries/eosiolib/malloc.cpp +++ b/libraries/eosiolib/malloc.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include "core/eosio/check.hpp" #include "core/eosio/print.hpp" @@ -11,8 +11,8 @@ #define CURRENT_MEMORY _current_memory() #define GROW_MEMORY(X) _grow_memory(X) #else -#define CURRENT_MEMORY __builtin_wasm_current_memory() -#define GROW_MEMORY(X) __builtin_wasm_grow_memory(X) +#define CURRENT_MEMORY __builtin_wasm_memory_size(0) +#define GROW_MEMORY(X) __builtin_wasm_memory_grow(0, X) #endif namespace eosio { @@ -520,7 +520,7 @@ namespace eosio { size_t _active_free_heap; static const size_t _alloc_memory_mask = size_t(1) << 31; }; - + memory_manager memory_heap; } /// namespace eosio diff --git a/libraries/eosiolib/simple_malloc.cpp b/libraries/eosiolib/simple_malloc.cpp index 15ad69e368..4cd6e27f64 100644 --- a/libraries/eosiolib/simple_malloc.cpp +++ b/libraries/eosiolib/simple_malloc.cpp @@ -9,11 +9,11 @@ #define CURRENT_MEMORY _current_memory() #define GROW_MEMORY(X) _grow_memory(X) #else -#define CURRENT_MEMORY __builtin_wasm_current_memory() -#define GROW_MEMORY(X) __builtin_wasm_grow_memory(X) +#define CURRENT_MEMORY __builtin_wasm_memory_size(0) +#define GROW_MEMORY(X) __builtin_wasm_memory_grow(0, X) #endif -namespace eosio { +namespace eosio { struct dsmalloc { inline char* align(char* ptr, uint8_t align_amt) { return (char*)((((size_t)ptr) + align_amt-1) & ~(align_amt-1)); @@ -32,7 +32,7 @@ namespace eosio { next_page = CURRENT_MEMORY; } - + char* operator()(size_t sz, uint8_t align_amt=16) { if (sz == 0) return NULL; @@ -45,8 +45,8 @@ namespace eosio { if ((next_page << 16) <= (size_t)last_ptr) { next_page++; pages_to_alloc++; - } - eosio::check(GROW_MEMORY(pages_to_alloc) != -1, "failed to allocate pages"); + } + eosio::check(GROW_MEMORY(pages_to_alloc) != -1, "failed to allocate pages"); return ret; } @@ -54,7 +54,7 @@ namespace eosio { char* last_ptr; size_t offset; size_t next_page; - }; + }; dsmalloc _dsmalloc; } // ns eosio diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index 0a511d4524..c8cc4d063f 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -14,19 +14,9 @@ set(CMAKE_BUILD_TYPE "Release") add_library(c++ ${SRC_FILES}) -add_native_library(native_c++ - ${SRC_FILES}) target_include_directories(c++ - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/libcxx/include - ${CMAKE_SOURCE_DIR}/libc/musl/include - ${CMAKE_SOURCE_DIR}/libc/musl/src/internal - ${CMAKE_SOURCE_DIR}/libc/musl/src/crypt - ${CMAKE_SOURCE_DIR}/libc/musl/arch/eos) - -target_include_directories(native_c++ - PUBLIC + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libcxx/include ${CMAKE_SOURCE_DIR}/libc/musl/include ${CMAKE_SOURCE_DIR}/libc/musl/src/internal @@ -34,12 +24,24 @@ target_include_directories(native_c++ ${CMAKE_SOURCE_DIR}/libc/musl/arch/eos) target_link_libraries(c++ c) -target_link_libraries(native_c++ native_c) - -target_compile_options(native_c++ PUBLIC -allow-sse) - +target_compile_definitions(c++ PUBLIC -D_LIBCPP_BUILDING_LIBRARY) add_custom_command( TARGET c++ POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) -add_custom_command( TARGET native_c++ POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) +if (ENABLE_NATIVE_COMPILER) + add_native_library(native_c++ + ${SRC_FILES}) + + target_include_directories(native_c++ + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/libcxx/include + ${CMAKE_SOURCE_DIR}/libc/musl/include + ${CMAKE_SOURCE_DIR}/libc/musl/src/internal + ${CMAKE_SOURCE_DIR}/libc/musl/src/crypt + ${CMAKE_SOURCE_DIR}/libc/musl/arch/eos) + + target_link_libraries(native_c++ native_c) + target_compile_options(native_c++ PUBLIC -allow-sse) + add_custom_command( TARGET native_c++ POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) +endif() file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/libcxx/include/ DESTINATION ${BASE_BINARY_DIR}/include/libcxx) diff --git a/libraries/libc/CMakeLists.txt b/libraries/libc/CMakeLists.txt index acff253149..a3bd42e358 100644 --- a/libraries/libc/CMakeLists.txt +++ b/libraries/libc/CMakeLists.txt @@ -27,8 +27,8 @@ file(GLOB HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/musl/include/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/musl/arch/eos/*.h") -add_library(c - ${CRYPT_SOURCES} +add_library(c + ${CRYPT_SOURCES} ${CTYPE_SOURCES} ${ENV_SOURCES} ${ERRNO_SOURCES} @@ -48,37 +48,9 @@ add_library(c "musl/src/malloc/memalign.c" ${HEADERS}) -add_native_library(native_c - ${CRYPT_SOURCES} - ${CTYPE_SOURCES} - ${ENV_SOURCES} - ${ERRNO_SOURCES} - ${EXIT_SOURCES} - ${INTERNAL_SOURCES} - ${LOCALE_SOURCES} - ${MATH_SOURCES} - ${MBYTE_SOURCES} - ${MISC_SOURCES} - ${SEARCH_SOURCES} - ${STDIO_SOURCES} - ${STDLIB_SOURCES} - ${STRING_SOURCES} - ${TIME_SOURCES} - ${THREAD_SOURCES} - "musl/src/malloc/posix_memalign.c" - "musl/src/malloc/memalign.c" - ${HEADERS}) - -target_include_directories(c - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/musl/include - ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal - ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/crypt - ${CMAKE_CURRENT_SOURCE_DIR}/musl/arch/eos - ${CMAKE_SOURCE_DIR}) -target_include_directories(native_c - PUBLIC +target_include_directories(c + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/musl/include ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/crypt @@ -86,7 +58,40 @@ target_include_directories(native_c ${CMAKE_SOURCE_DIR}) add_custom_command( TARGET c POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) -add_custom_command( TARGET native_c POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) + +if (ENABLE_NATIVE_COMPILER) + add_native_library(native_c + ${CRYPT_SOURCES} + ${CTYPE_SOURCES} + ${ENV_SOURCES} + ${ERRNO_SOURCES} + ${EXIT_SOURCES} + ${INTERNAL_SOURCES} + ${LOCALE_SOURCES} + ${MATH_SOURCES} + ${MBYTE_SOURCES} + ${MISC_SOURCES} + ${SEARCH_SOURCES} + ${STDIO_SOURCES} + ${STDLIB_SOURCES} + ${STRING_SOURCES} + ${TIME_SOURCES} + ${THREAD_SOURCES} + "musl/src/malloc/posix_memalign.c" + "musl/src/malloc/memalign.c" + ${HEADERS}) + + target_include_directories(native_c + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/musl/include + ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal + ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/crypt + ${CMAKE_CURRENT_SOURCE_DIR}/musl/arch/eos + ${CMAKE_SOURCE_DIR}) + + + add_custom_command( TARGET native_c POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) +endif() file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/musl/include/ DESTINATION ${BASE_BINARY_DIR}/include/libc/) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/musl/src/internal/ DESTINATION ${BASE_BINARY_DIR}/include/libc/) diff --git a/libraries/rt/CMakeLists.txt b/libraries/rt/CMakeLists.txt index f65bf53e91..708c730075 100644 --- a/libraries/rt/CMakeLists.txt +++ b/libraries/rt/CMakeLists.txt @@ -18,13 +18,16 @@ file ( GLOB builtins_headers "${CMAKE_CURRENT_SOURCE_DIR}*.h" ) list( APPEND builtins_sources ${builtins_headers} ) add_library ( rt STATIC ${builtins_sources} ) -add_native_library ( native_rt STATIC ${builtins_sources} ) target_include_directories( rt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../native/softfloat/source/include" ) -target_include_directories( native_rt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/../native/softfloat/source/include" ) - add_custom_command( TARGET rt POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) -add_custom_command( TARGET native_rt POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) + +if (ENABLE_NATIVE_COMPILER) + add_native_library ( native_rt STATIC ${builtins_sources} ) + target_include_directories( native_rt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/../native/softfloat/source/include" ) + + add_custom_command( TARGET native_rt POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) +endif() diff --git a/modules/ClangExternalProject.txt b/modules/ClangExternalProject.txt index f3d0cd01f1..60302efa67 100644 --- a/modules/ClangExternalProject.txt +++ b/modules/ClangExternalProject.txt @@ -4,7 +4,7 @@ include(GNUInstallDirs) ExternalProject_Add( EosioClang - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_BUILD_TYPE=Debug -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools SOURCE_DIR "${CMAKE_SOURCE_DIR}/eosio_llvm" BINARY_DIR "${CMAKE_BINARY_DIR}/eosio_llvm" diff --git a/modules/LibrariesExternalProject.txt b/modules/LibrariesExternalProject.txt index 07506528fd..08dcc139c2 100644 --- a/modules/LibrariesExternalProject.txt +++ b/modules/LibrariesExternalProject.txt @@ -6,7 +6,7 @@ ExternalProject_Add( EosioWasmLibraries SOURCE_DIR "${CMAKE_SOURCE_DIR}/libraries" BINARY_DIR "${CMAKE_BINARY_DIR}/libraries" - CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/EosioWasmToolchain.cmake -DEOSIO_CDT_BIN=${CMAKE_BINARY_DIR}/lib/cmake/eosio.cdt/ -DBASE_BINARY_DIR=${CMAKE_BINARY_DIR} -D__APPLE=${APPLE} -DENABLE_NATIVE_COMPILER=${ENABLE_NATIVE_COMPILER} UPDATE_COMMAND "" PATCH_COMMAND "" TEST_COMMAND "" diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index 139afed94b..2c25ed193e 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_PATCH=${VERSION_PATCH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Debug -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DENABLE_NATIVE_COMPILER=${ENABLE_NATIVE_COMPILER} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" diff --git a/tools/cc/eosio-cc.cpp.in b/tools/cc/eosio-cc.cpp.in index 1d8e220103..b1ee3e152b 100644 --- a/tools/cc/eosio-cc.cpp.in +++ b/tools/cc/eosio-cc.cpp.in @@ -60,7 +60,7 @@ int main(int argc, const char **argv) { new_opts.insert(new_opts.begin(), "-o"+output); outputs.push_back(output); - if (!eosio::cdt::environment::exec_subprogram("clang-7", new_opts)) { + if (!eosio::cdt::environment::exec_subprogram("clang-9", new_opts)) { llvm::sys::fs::remove(tmp_file); return -1; } diff --git a/tools/cc/eosio-cpp.cpp.in b/tools/cc/eosio-cpp.cpp.in index d4266e678c..7f99a063e4 100644 --- a/tools/cc/eosio-cpp.cpp.in +++ b/tools/cc/eosio-cpp.cpp.in @@ -215,7 +215,7 @@ int main(int argc, const char **argv) { if (llvm::sys::path::extension(input).equals(".c")) new_opts.insert(new_opts.begin(), "-xc++"); - if (!eosio::cdt::environment::exec_subprogram("clang-7", new_opts)) { + if (!eosio::cdt::environment::exec_subprogram("clang-9", new_opts)) { llvm::sys::fs::remove(tmp_file); return -1; } From 97a312febbba63f3598a3d61002c9d6276af0efe Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Mon, 18 Nov 2019 18:04:36 -0500 Subject: [PATCH 309/659] updates to submods for llvm9 update --- libraries/libc++/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index c8cc4d063f..e46d479156 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -40,6 +40,7 @@ if (ENABLE_NATIVE_COMPILER) ${CMAKE_SOURCE_DIR}/libc/musl/arch/eos) target_link_libraries(native_c++ native_c) + target_compile_definitions(native_c++ PUBLIC -D_LIBCPP_BUILDING_LIBRARY) target_compile_options(native_c++ PUBLIC -allow-sse) add_custom_command( TARGET native_c++ POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${BASE_BINARY_DIR}/lib ) endif() From bf12e4acc73fda1ef20f4f3d0b7718e4e99d415c Mon Sep 17 00:00:00 2001 From: Bucky Kittinger Date: Mon, 27 Jan 2020 18:59:27 -0500 Subject: [PATCH 310/659] some temporary changes --- CMakeLists.txt | 6 ++--- libraries/CMakeLists.txt | 4 ++++ tests/CMakeLists.txt | 47 +++++++++++++++------------------------- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5aacff5dd7..05d2234887 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ endif() set(CDT_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/eosio.cdt) option(ENABLE_NATIVE_COMPILER "enable native builds with the eosio.cdt toolchain" ON) -option(ENABLE_TESTS "enable building tests" ON) +option(ENABLE_TESTS "enable building tests" OFF) include(GNUInstallDirs) @@ -96,8 +96,8 @@ configure_file(${CMAKE_SOURCE_DIR}/tools/external/wabt/LICENSE ${CMAKE_BINARY_DI configure_file(${CMAKE_SOURCE_DIR}/tools/jsoncons/LICENSE ${CMAKE_BINARY_DIR}/licenses/jsoncons.license COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/licenses/eosio.cdt.license COPYONLY) -include(modules/TestsExternalProject.txt) +#include(modules/TestsExternalProject.txt) include(CTest) enable_testing() -add_subdirectory(tests) +#add_subdirectory(tests) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index b99ea475b0..5743cae464 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -14,12 +14,16 @@ include(EosioCDTMacros) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall -no-missing-ricardian-clause") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_EXTENSIONS ON) + add_subdirectory(libc) add_subdirectory(libc++) add_subdirectory(eosiolib) add_subdirectory(boost) add_subdirectory(rt) +set(ENABLE_NATIVE_COMPILER 0) if (ENABLE_NATIVE_COMPILER) add_subdirectory(native) endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 987ea7b6af..5e4d0c1cf6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,36 +10,25 @@ else() endif() endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-missing-ricardian-clause") +macro(add_unit_test TEST_NAME) + add_test( ${TEST_NAME} ${CMAKE_BINARY_DIR}/tests/unit/${TEST_NAME} ) + set_property(TEST ${TEST_NAME} PROPERTY LABELS unit_tests) +endmacro() -add_test( asset_tests ${CMAKE_BINARY_DIR}/tests/unit/asset_tests ) -set_property(TEST asset_tests PROPERTY LABELS unit_tests) -add_test( binary_extension_tests ${CMAKE_BINARY_DIR}/tests/unit/binary_extension_tests ) -set_property(TEST binary_extension_tests PROPERTY LABELS unit_tests) -add_test( crypto_tests ${CMAKE_BINARY_DIR}/tests/unit/crypto_tests ) -set_property(TEST crypto_tests PROPERTY LABELS unit_tests) -add_test( datastream_tests ${CMAKE_BINARY_DIR}/tests/unit/datastream_tests ) -set_property(TEST datastream_tests PROPERTY LABELS unit_tests) -add_test( fixed_bytes_tests ${CMAKE_BINARY_DIR}/tests/unit/fixed_bytes_tests ) -set_property(TEST fixed_bytes_tests PROPERTY LABELS unit_tests) -add_test( name_tests ${CMAKE_BINARY_DIR}/tests/unit/name_tests ) -set_property(TEST name_tests PROPERTY LABELS unit_tests) -add_test( rope_tests ${CMAKE_BINARY_DIR}/tests/unit/rope_tests ) -set_property(TEST rope_tests PROPERTY LABELS unit_tests) -add_test( print_tests ${CMAKE_BINARY_DIR}/tests/unit/print_tests ) -set_property(TEST print_tests PROPERTY LABELS unit_tests) -add_test( serialize_tests ${CMAKE_BINARY_DIR}/tests/unit/serialize_tests ) -set_property(TEST serialize_tests PROPERTY LABELS unit_tests) -add_test( string_tests ${CMAKE_BINARY_DIR}/tests/unit/string_tests ) -set_property(TEST string_tests PROPERTY LABELS unit_tests) -add_test( symbol_tests ${CMAKE_BINARY_DIR}/tests/unit/symbol_tests ) -set_property(TEST symbol_tests PROPERTY LABELS unit_tests) -add_test( system_tests ${CMAKE_BINARY_DIR}/tests/unit/system_tests ) -set_property(TEST system_tests PROPERTY LABELS unit_tests) -add_test( time_tests ${CMAKE_BINARY_DIR}/tests/unit/time_tests ) -set_property(TEST time_tests PROPERTY LABELS unit_tests) -add_test( varint_tests ${CMAKE_BINARY_DIR}/tests/unit/varint_tests ) -set_property(TEST varint_tests PROPERTY LABELS unit_tests) +add_unit_test( asset_tests ) +add_unit_test( binary_extension_tests ) +add_unit_test( crypto_tests ) +add_unit_test( datastream_tests ) +add_unit_test( fixed_bytes_tests ) +add_unit_test( name_tests ) +add_unit_test( rope_tests ) +add_unit_test( print_tests ) +add_unit_test( serialize_tests ) +add_unit_test( string_tests ) +add_unit_test( symbol_tests ) +add_unit_test( system_tests ) +add_unit_test( time_tests ) +add_unit_test( varint_tests ) add_test( NAME toolchain_tests COMMAND ${CMAKE_BINARY_DIR}/tools/toolchain-tester/toolchain-tester ${CMAKE_SOURCE_DIR}/tests/toolchain --cdt ${CMAKE_BINARY_DIR}/bin ) set_property(TEST toolchain_tests PROPERTY LABELS toolchain_tests) From 16f29a66d3d1d881a9cd3f657efb33d197c56e49 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 18 May 2020 10:20:45 -0400 Subject: [PATCH 311/659] Add -mllvm flag --- tools/include/compiler_options.hpp.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/include/compiler_options.hpp.in b/tools/include/compiler_options.hpp.in index 4e06aa74f0..b05bc95b77 100644 --- a/tools/include/compiler_options.hpp.in +++ b/tools/include/compiler_options.hpp.in @@ -140,6 +140,11 @@ static cl::opt allow_names_opt ( "allow-names", cl::desc("Allows name section to be created"), cl::cat(LD_CAT)); +static cl::opt mllvm_opt( + "mllvm", + cl::desc("Pass arguments to llvm"), + cl::ZeroOrMore, + cl::cat(LD_CAT)); /// End of ld options #ifndef ONLY_LD @@ -512,6 +517,11 @@ static void GetLdDefaults(std::vector& ldopts) { ldopts.emplace_back(only_export_opt); } + if (!mllvm_opt.empty()) { + ldopts.emplace_back("-mllvm"); + ldopts.emplace_back(mllvm_opt); + } + } else { #ifdef __APPLE__ ldopts.insert(ldopts.end(), {"-arch", "x86_64", "-macosx_version_min", "10.13", "-framework", "Foundation", "-framework", "System"}); From e17d37a458e1272fbf8f4afdd50abe05f9654602 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 1 Jun 2020 08:27:10 -0400 Subject: [PATCH 312/659] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3febf9557f..cf5b76f453 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ __pycache__/ # Editor Files .vscode/ +.idea/ From d28274add3e5eb54da0b7d489ddad4679bbbd013 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 1 Jun 2020 08:29:43 -0400 Subject: [PATCH 313/659] Add better messaging around linker failure --- tools/ld/eosio-ld.cpp.in | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/ld/eosio-ld.cpp.in b/tools/ld/eosio-ld.cpp.in index 290be5981c..5396df24ed 100644 --- a/tools/ld/eosio-ld.cpp.in +++ b/tools/ld/eosio-ld.cpp.in @@ -30,10 +30,13 @@ int main(int argc, const char **argv) { #endif return -1; } else { - if (!eosio::cdt::environment::exec_subprogram("wasm-ld", opts.ld_options)) + if (!eosio::cdt::environment::exec_subprogram("wasm-ld", opts.ld_options)) { + std::cout << "Exit due to wasm-ld failure" << std::endl; return -1; + } } if ( !llvm::sys::fs::exists( opts.output_fn ) ) { + std::cout << "Exit due to failure to write file" << std::endl; return -1; } @@ -43,9 +46,14 @@ int main(int argc, const char **argv) { std::cout << "Error: eosio.pp not found! (Try reinstalling eosio.wasmsdk)" << std::endl; return -1; } - if (!eosio::cdt::environment::exec_subprogram("eosio-pp", {opts.output_fn})) + + if (!eosio::cdt::environment::exec_subprogram("eosio-pp", {opts.output_fn})) { + std::cout << "eosio-pp failed" << std::endl; return -1; + } + if ( !llvm::sys::fs::exists( opts.output_fn ) ) { + std::cout << "Exit due to failure to write file" << std::endl; return -1; } } From ec8c9a61764ded6fe2b660bfa65dd7e80cb6a757 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 1 Jun 2020 08:33:36 -0400 Subject: [PATCH 314/659] Fix native compilation --- libraries/CMakeLists.txt | 1 - libraries/libc++/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 5743cae464..39c68b2698 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -23,7 +23,6 @@ add_subdirectory(eosiolib) add_subdirectory(boost) add_subdirectory(rt) -set(ENABLE_NATIVE_COMPILER 0) if (ENABLE_NATIVE_COMPILER) add_subdirectory(native) endif() diff --git a/libraries/libc++/CMakeLists.txt b/libraries/libc++/CMakeLists.txt index e46d479156..b13071fee2 100644 --- a/libraries/libc++/CMakeLists.txt +++ b/libraries/libc++/CMakeLists.txt @@ -1,4 +1,4 @@ -SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp chrono.cpp condition_variable.cpp functional.cpp +SET(SRC_FILENAMES algorithm.cpp any.cpp bind.cpp charconv.cpp chrono.cpp condition_variable.cpp functional.cpp future.cpp hash.cpp ios.cpp iostream.cpp locale.cpp memory.cpp mutex.cpp new.cpp optional.cpp regex.cpp stdexcept.cpp string.cpp strstream.cpp system_error.cpp exception.cpp typeinfo.cpp utility.cpp valarray.cpp variant.cpp vector.cpp eosio.cpp) From d48bd7883ea63655238913c57db9537d8d43c438 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 2 Jun 2020 10:44:00 -0400 Subject: [PATCH 315/659] Debugging stuff --- eosio_llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eosio_llvm b/eosio_llvm index d8e69fb88e..4c09a2a16f 160000 --- a/eosio_llvm +++ b/eosio_llvm @@ -1 +1 @@ -Subproject commit d8e69fb88e5211d9055b9aa6371eb21bd4ce1107 +Subproject commit 4c09a2a16f47495e3ceca87686cde23f63cb35ae From e466ab74d9444869987991d6b81dc74e2dfe2d2e Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 3 Jun 2020 13:09:24 -0400 Subject: [PATCH 316/659] Add tests back (except datastream due to PFR issue) --- CMakeLists.txt | 4 ++-- tests/unit/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05d2234887..043239fc9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,8 +96,8 @@ configure_file(${CMAKE_SOURCE_DIR}/tools/external/wabt/LICENSE ${CMAKE_BINARY_DI configure_file(${CMAKE_SOURCE_DIR}/tools/jsoncons/LICENSE ${CMAKE_BINARY_DIR}/licenses/jsoncons.license COPYONLY) configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/licenses/eosio.cdt.license COPYONLY) -#include(modules/TestsExternalProject.txt) +include(modules/TestsExternalProject.txt) include(CTest) enable_testing() -#add_subdirectory(tests) +add_subdirectory(tests) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index c6f165e2d5..339d296e02 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -6,7 +6,7 @@ include( EosioCDTMacros ) add_native_executable( asset_tests asset_tests.cpp ) add_native_executable( binary_extension_tests binary_extension_tests.cpp ) add_native_executable( crypto_tests crypto_tests.cpp ) -add_native_executable( datastream_tests datastream_tests.cpp ) +#add_native_executable( datastream_tests datastream_tests.cpp ) add_native_executable( fixed_bytes_tests fixed_bytes_tests.cpp ) add_native_executable( name_tests name_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) From efd1d29a4feec4f20edff1a44d391ef5eee539e3 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 3 Jun 2020 13:32:10 -0400 Subject: [PATCH 317/659] Eliminate fallthrough warnings --- .../include/jsoncons/detail/unicode_traits.hpp | 12 ++++++++++++ tools/jsoncons/include/jsoncons/json.hpp | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp b/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp index affbb9b792..58371da4a4 100644 --- a/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp +++ b/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp @@ -261,10 +261,12 @@ is_legal_utf8(Iterator first, size_t length) if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; // FALLTHRU + LLVM_FALLTHROUGH; case 3: if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; // FALLTHRU + LLVM_FALLTHROUGH; case 2: if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; @@ -280,6 +282,7 @@ is_legal_utf8(Iterator first, size_t length) } // FALLTHRU + LLVM_FALLTHROUGH; case 1: if (static_cast(*first) >= 0x80 && static_cast(*first) < 0xC2) return conv_errc::source_illegal; @@ -373,8 +376,11 @@ convert(InputIt first, InputIt last, OutputIt target, conv_flags flags=conv_flag switch (length) { case 4: *target++ = (static_cast(*first++)); + LLVM_FALLTHROUGH; case 3: *target++ = (static_cast(*first++)); + LLVM_FALLTHROUGH; case 2: *target++ = (static_cast(*first++)); + LLVM_FALLTHROUGH; case 1: *target++ = (static_cast(*first++)); } } @@ -744,12 +750,15 @@ convert(InputIt first, InputIt last, case 4: byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 1: byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); } @@ -984,12 +993,15 @@ class sequence case 4: ch += static_cast(*it++); ch <<= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 3: ch += static_cast(*it++); ch <<= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 2: ch += static_cast(*it++); ch <<= 6; // FALLTHRU + LLVM_FALLTHROUGH; case 1: ch += static_cast(*it++); ch -= offsets_from_utf8[length_ - 1]; diff --git a/tools/jsoncons/include/jsoncons/json.hpp b/tools/jsoncons/include/jsoncons/json.hpp index 0c2b07d86c..72c20553ba 100644 --- a/tools/jsoncons/include/jsoncons/json.hpp +++ b/tools/jsoncons/include/jsoncons/json.hpp @@ -2683,6 +2683,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return json_proxy(*this, key_storage_type(name.begin(),name.end(),char_allocator_type(object_value().get_allocator()))); break; @@ -3714,6 +3715,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().insert_or_assign(name, std::forward(val)); default: @@ -3731,6 +3733,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().try_emplace(name, std::forward(args)...); default: @@ -3748,6 +3751,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: object_value().set_(std::forward(name), std::forward(val)); break; @@ -3767,6 +3771,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(source.object_value()); default: @@ -3783,6 +3788,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(std::move(source.object_value())); default: @@ -3799,6 +3805,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(hint, source.object_value()); default: @@ -3815,6 +3822,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(hint, std::move(source.object_value())); default: @@ -3833,6 +3841,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(source.object_value()); default: @@ -3849,6 +3858,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(std::move(source.object_value())); default: @@ -3865,6 +3875,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(hint, source.object_value()); default: @@ -3881,6 +3892,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(hint, std::move(source.object_value())); default: @@ -3906,6 +3918,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().insert_or_assign(hint, name, std::forward(val)); default: @@ -3923,6 +3936,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().try_emplace(hint, name, std::forward(args)...); default: @@ -3940,6 +3954,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().set_(hint, std::forward(name), std::forward(val)); break; @@ -4488,6 +4503,7 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return var_.object_data_cast()->value(); default: @@ -4503,6 +4519,7 @@ class basic_json case json_major_type::empty_object_t: const_cast(this)->create_object_implicitly(); // HERE // FALLTHRU + LLVM_FALLTHROUGH; case json_major_type::object_t: return var_.object_data_cast()->value(); default: From 5de78ea46d2f9039d637fe83ac3bd59582380436 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 3 Jun 2020 13:33:48 -0400 Subject: [PATCH 318/659] Working linker on llvm9 --- eosio_llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eosio_llvm b/eosio_llvm index 4c09a2a16f..ba0fe38ea2 160000 --- a/eosio_llvm +++ b/eosio_llvm @@ -1 +1 @@ -Subproject commit 4c09a2a16f47495e3ceca87686cde23f63cb35ae +Subproject commit ba0fe38ea2be2a6886787e6b90887890e5500a75 From a467ecd7bb0b84445de332da742abf010f55f689 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 3 Jun 2020 15:15:04 -0400 Subject: [PATCH 319/659] turn off Werror for wabt --- tools/external/wabt/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/external/wabt/CMakeLists.txt b/tools/external/wabt/CMakeLists.txt index 12aa8c9aae..cda05652d7 100644 --- a/tools/external/wabt/CMakeLists.txt +++ b/tools/external/wabt/CMakeLists.txt @@ -101,7 +101,7 @@ else () # interfaces, etc. # disable -Wpointer-arith: this is a GCC extension, and doesn't work in MSVC. add_definitions( - -Wall -Wextra -Werror -Wno-unused-parameter -Wpointer-arith -g -std=c++11 + -Wall -Wextra -Wno-unused-parameter -Wpointer-arith -g -std=c++11 -Wold-style-cast -Wuninitialized ) From 423713732a359f8ca8befc6964fbb5a0f88906d0 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 3 Jun 2020 16:00:54 -0400 Subject: [PATCH 320/659] Fix PFR errors by switching to use cpp17 --- libraries/boost/include/boost/pfr/detail/config.hpp | 2 +- tests/unit/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/boost/include/boost/pfr/detail/config.hpp b/libraries/boost/include/boost/pfr/detail/config.hpp index 5a36de47d1..339df5e952 100644 --- a/libraries/boost/include/boost/pfr/detail/config.hpp +++ b/libraries/boost/include/boost/pfr/detail/config.hpp @@ -24,7 +24,7 @@ # define BOOST_PFR_USE_LOOPHOLE 1 #endif -#define BOOST_PFR_USE_CPP17 0 +#define BOOST_PFR_USE_CPP17 1 #ifndef BOOST_PFR_USE_CPP17 # ifdef __cpp_structured_bindings diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 339d296e02..c6f165e2d5 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -6,7 +6,7 @@ include( EosioCDTMacros ) add_native_executable( asset_tests asset_tests.cpp ) add_native_executable( binary_extension_tests binary_extension_tests.cpp ) add_native_executable( crypto_tests crypto_tests.cpp ) -#add_native_executable( datastream_tests datastream_tests.cpp ) +add_native_executable( datastream_tests datastream_tests.cpp ) add_native_executable( fixed_bytes_tests fixed_bytes_tests.cpp ) add_native_executable( name_tests name_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) From 6c8df5c9b0f8f257859aa811d85c2c32adb6a9d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 4 Jun 2020 15:54:59 -0400 Subject: [PATCH 321/659] Use cerr correctly --- tools/ld/eosio-ld.cpp.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/ld/eosio-ld.cpp.in b/tools/ld/eosio-ld.cpp.in index 5396df24ed..f1df961db2 100644 --- a/tools/ld/eosio-ld.cpp.in +++ b/tools/ld/eosio-ld.cpp.in @@ -31,29 +31,29 @@ int main(int argc, const char **argv) { return -1; } else { if (!eosio::cdt::environment::exec_subprogram("wasm-ld", opts.ld_options)) { - std::cout << "Exit due to wasm-ld failure" << std::endl; + std::cerr << "Exit due to wasm-ld failure" << std::endl; return -1; } } if ( !llvm::sys::fs::exists( opts.output_fn ) ) { - std::cout << "Exit due to failure to write file" << std::endl; + std::cerr << "Exit due to failure to write file" << std::endl; return -1; } // finally any post processing if (!fno_post_pass_opt && !opts.native) { if ( !llvm::sys::fs::exists( opts.eosio_pp_dir+"/eosio-pp" ) ) { - std::cout << "Error: eosio.pp not found! (Try reinstalling eosio.wasmsdk)" << std::endl; + std::cerr << "Error: eosio.pp not found! (Try reinstalling eosio.cdt)" << std::endl; return -1; } if (!eosio::cdt::environment::exec_subprogram("eosio-pp", {opts.output_fn})) { - std::cout << "eosio-pp failed" << std::endl; + std::cerr << "eosio-pp failed" << std::endl; return -1; } if ( !llvm::sys::fs::exists( opts.output_fn ) ) { - std::cout << "Exit due to failure to write file" << std::endl; + std::cerr << "Exit due to failure to write file" << std::endl; return -1; } } From 61155461a817ca0e6521f60996c83a2adba37753 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 4 Jun 2020 15:55:58 -0400 Subject: [PATCH 322/659] Pass BUILD_TYPE to tests and eosio_llvm --- modules/ClangExternalProject.txt | 2 +- modules/ToolsExternalProject.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ClangExternalProject.txt b/modules/ClangExternalProject.txt index 60302efa67..500d6685d8 100644 --- a/modules/ClangExternalProject.txt +++ b/modules/ClangExternalProject.txt @@ -4,7 +4,7 @@ include(GNUInstallDirs) ExternalProject_Add( EosioClang - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_BUILD_TYPE=Debug -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools SOURCE_DIR "${CMAKE_SOURCE_DIR}/eosio_llvm" BINARY_DIR "${CMAKE_BINARY_DIR}/eosio_llvm" diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index 2c25ed193e..a1acbf90f8 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Debug -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DENABLE_NATIVE_COMPILER=${ENABLE_NATIVE_COMPILER} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DENABLE_NATIVE_COMPILER=${ENABLE_NATIVE_COMPILER} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" From 020689e5c34be4a104f5ee56c06b822e281a721d Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 4 Jun 2020 16:43:04 -0400 Subject: [PATCH 323/659] Update libcxx to eosio branch --- libraries/libc++/libcxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index 8ccb1fa7c2..a27e136baa 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit 8ccb1fa7c224bd1ccff65b46393c59181517c3d3 +Subproject commit a27e136baac8000be124e6cb01c3dcab5b56f9e7 From efcfb01e26024bcc32099f450a865254f7b8c9cb Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 4 Jun 2020 16:54:30 -0400 Subject: [PATCH 324/659] Use pragmas to turn off fallthrough warnings --- .../jsoncons/detail/unicode_traits.hpp | 19 +++++++----------- tools/jsoncons/include/jsoncons/json.hpp | 20 +++---------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp b/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp index 58371da4a4..a1a4cd46c8 100644 --- a/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp +++ b/tools/jsoncons/include/jsoncons/detail/unicode_traits.hpp @@ -39,6 +39,13 @@ #include #include +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#else +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#endif + namespace unicons { /* @@ -261,12 +268,10 @@ is_legal_utf8(Iterator first, size_t length) if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; // FALLTHRU - LLVM_FALLTHROUGH; case 3: if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; // FALLTHRU - LLVM_FALLTHROUGH; case 2: if (((a = (*--srcptr))& 0xC0) != 0x80) return conv_errc::expected_continuation_byte; @@ -282,7 +287,6 @@ is_legal_utf8(Iterator first, size_t length) } // FALLTHRU - LLVM_FALLTHROUGH; case 1: if (static_cast(*first) >= 0x80 && static_cast(*first) < 0xC2) return conv_errc::source_illegal; @@ -376,11 +380,8 @@ convert(InputIt first, InputIt last, OutputIt target, conv_flags flags=conv_flag switch (length) { case 4: *target++ = (static_cast(*first++)); - LLVM_FALLTHROUGH; case 3: *target++ = (static_cast(*first++)); - LLVM_FALLTHROUGH; case 2: *target++ = (static_cast(*first++)); - LLVM_FALLTHROUGH; case 1: *target++ = (static_cast(*first++)); } } @@ -750,15 +751,12 @@ convert(InputIt first, InputIt last, case 4: byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 1: byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); } @@ -993,15 +991,12 @@ class sequence case 4: ch += static_cast(*it++); ch <<= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 3: ch += static_cast(*it++); ch <<= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 2: ch += static_cast(*it++); ch <<= 6; // FALLTHRU - LLVM_FALLTHROUGH; case 1: ch += static_cast(*it++); ch -= offsets_from_utf8[length_ - 1]; diff --git a/tools/jsoncons/include/jsoncons/json.hpp b/tools/jsoncons/include/jsoncons/json.hpp index 72c20553ba..60014fc3ad 100644 --- a/tools/jsoncons/include/jsoncons/json.hpp +++ b/tools/jsoncons/include/jsoncons/json.hpp @@ -36,6 +36,9 @@ #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#else +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" #endif namespace jsoncons { @@ -2683,7 +2686,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return json_proxy(*this, key_storage_type(name.begin(),name.end(),char_allocator_type(object_value().get_allocator()))); break; @@ -3715,7 +3717,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().insert_or_assign(name, std::forward(val)); default: @@ -3733,7 +3734,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().try_emplace(name, std::forward(args)...); default: @@ -3751,7 +3751,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: object_value().set_(std::forward(name), std::forward(val)); break; @@ -3771,7 +3770,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(source.object_value()); default: @@ -3788,7 +3786,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(std::move(source.object_value())); default: @@ -3805,7 +3802,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(hint, source.object_value()); default: @@ -3822,7 +3818,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge(hint, std::move(source.object_value())); default: @@ -3841,7 +3836,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(source.object_value()); default: @@ -3858,7 +3852,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(std::move(source.object_value())); default: @@ -3875,7 +3868,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(hint, source.object_value()); default: @@ -3892,7 +3884,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().merge_or_update(hint, std::move(source.object_value())); default: @@ -3918,7 +3909,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().insert_or_assign(hint, name, std::forward(val)); default: @@ -3936,7 +3926,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().try_emplace(hint, name, std::forward(args)...); default: @@ -3954,7 +3943,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return object_value().set_(hint, std::forward(name), std::forward(val)); break; @@ -4503,7 +4491,6 @@ class basic_json case json_major_type::empty_object_t: create_object_implicitly(); // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return var_.object_data_cast()->value(); default: @@ -4519,7 +4506,6 @@ class basic_json case json_major_type::empty_object_t: const_cast(this)->create_object_implicitly(); // HERE // FALLTHRU - LLVM_FALLTHROUGH; case json_major_type::object_t: return var_.object_data_cast()->value(); default: From 5a20efac9c40f59bfb63182311d931bc16d025bb Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 5 Jun 2020 00:16:38 +0300 Subject: [PATCH 325/659] fixes #898 --- libraries/eosiolib/contracts/eosio/multi_index.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/multi_index.hpp b/libraries/eosiolib/contracts/eosio/multi_index.hpp index c0b17bd74d..f66c39f29b 100644 --- a/libraries/eosiolib/contracts/eosio/multi_index.hpp +++ b/libraries/eosiolib/contracts/eosio/multi_index.hpp @@ -866,7 +866,7 @@ class multi_index * // This assumes the code from the constructor example. Replace myaction() {...} * * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope + * address_index addresses("dan"_n, "dan"_n.value); // code, scope * eosio::check(addresses.get_code() == "dan"_n, "Codes don't match."); * } * } @@ -887,8 +887,8 @@ class multi_index * // This assumes the code from the constructor example. Replace myaction() {...} * * void myaction() { - * address_index addresses("dan"_n, "dan"_n); // code, scope - * eosio::check(addresses.get_code() == "dan"_n, "Scopes don't match"); + * address_index addresses("dan"_n, "dan"_n.value); // code, scope + * eosio::check(addresses.get_scope() == "dan"_n.value, "Scopes don't match"); * } * } * EOSIO_DISPATCH( addressbook, (myaction) ) From 549acac4be4c0cf94ea20334780aea4fcdf8f4a4 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Fri, 5 Jun 2020 10:28:55 -0400 Subject: [PATCH 326/659] Bump to 10.15.5 and Anka plugin 0.6.1 --- .cicd/pipeline.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 627f407263..36e8965c39 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -55,7 +55,7 @@ steps: - "cd eosio.cdt && ./.cicd/build.sh" - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G @@ -80,10 +80,10 @@ steps: - "cd eosio.cdt && ./.cicd/build.sh" - "cd eosio.cdt && tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.4_6C_14G_40G + vm-name: 10.15.5_6C_14G_50G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -150,7 +150,7 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/tests.sh" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G @@ -175,10 +175,10 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/tests.sh" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.4_6C_14G_40G + vm-name: 10.15.5_6C_14G_50G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -242,7 +242,7 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/toolchain-tests.sh" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G @@ -310,9 +310,8 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.14 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/package.sh" plugins: - - EOSIO/anka#v0.5.7: + - EOSIO/anka#v0.6.1: no-volume: true - pre-execute-ping-sleep: "8.8.8.8" inherit-environment-vars: true vm-name: 10.14.6_6C_14G_40G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" @@ -334,10 +333,10 @@ steps: - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" - "cd eosio.cdt && ./.cicd/package.sh" plugins: - - EOSIO/anka#v0.6.0: + - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.3_6C_14G_40G + vm-name: 10.15.5_6C_14G_50G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" always-pull: true debug: true From acdc4c055924b1ccc763a540b786ed61c7c06431 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 5 Jun 2020 10:34:22 -0400 Subject: [PATCH 327/659] Remove timespec_get in libcxx --- libraries/libc++/libcxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libc++/libcxx b/libraries/libc++/libcxx index a27e136baa..dd2d7b0ffe 160000 --- a/libraries/libc++/libcxx +++ b/libraries/libc++/libcxx @@ -1 +1 @@ -Subproject commit a27e136baac8000be124e6cb01c3dcab5b56f9e7 +Subproject commit dd2d7b0ffea485690e75f4381432be243bf1fb3a From 4675a7be1a791c9e679bc7d20e042206baa6cd37 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Sun, 7 Jun 2020 10:50:50 -0400 Subject: [PATCH 328/659] Bump to 80G disk. --- .cicd/pipeline.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 36e8965c39..1519482fdf 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -58,7 +58,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.6_6C_14G_40G + vm-name: 10.14.6_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -83,7 +83,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.5_6C_14G_50G + vm-name: 10.15.5_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -153,7 +153,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.6_6C_14G_40G + vm-name: 10.14.6_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -178,7 +178,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.5_6C_14G_50G + vm-name: 10.15.5_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -245,7 +245,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.6_6C_14G_40G + vm-name: 10.14.6_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" modify-cpu: 12 modify-ram: 24 @@ -313,7 +313,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.14.6_6C_14G_40G + vm-name: 10.14.6_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" always-pull: true debug: true @@ -336,7 +336,7 @@ steps: - EOSIO/anka#v0.6.1: no-volume: true inherit-environment-vars: true - vm-name: 10.15.5_6C_14G_50G + vm-name: 10.15.5_6C_14G_80G vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" always-pull: true debug: true From c81fe3805098757254adfe24184d5d3596b6cae2 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 8 Jun 2020 09:18:00 -0400 Subject: [PATCH 329/659] Add missing toolchain tests for Catalina. --- .cicd/pipeline.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 1519482fdf..1518f08bdc 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -258,6 +258,31 @@ steps: - "queue=mac-anka-large-node-fleet" skip: ${SKIP_MACOS_10_14}${SKIP_TOOLCHAIN_TESTS} + - label: ":darwin: macOS 10.15 - Toolchain Tests" + command: + - "brew install git automake libtool wget cmake gmp gettext doxygen graphviz lcov python@3" + - "git clone $BUILDKITE_REPO eosio.cdt" + - "cd eosio.cdt && if [[ $BUILDKITE_BRANCH =~ ^pull/[0-9]+/head: ]]; then git fetch -v --prune origin refs/pull/$(echo $BUILDKITE_BRANCH | cut -d/ -f2)/head; fi" + - "cd eosio.cdt && git checkout -f $BUILDKITE_COMMIT && git submodule update --init --recursive" + - "cd eosio.cdt && buildkite-agent artifact download build.tar.gz . --step ':darwin: macOS 10.15 - Build' && tar -xzf build.tar.gz" + - "cd eosio.cdt && ./.cicd/toolchain-tests.sh" + plugins: + - EOSIO/anka#v0.6.1: + no-volume: true + inherit-environment-vars: true + vm-name: 10.15.5_6C_14G_80G + vm-registry-tag: "clean::cicd::git-ssh::nas::brew::buildkite-agent" + modify-cpu: 12 + modify-ram: 24 + always-pull: true + debug: true + wait-network: true + - EOSIO/skip-checkout#v0.1.1: + cd: ~ + agents: + - "queue=mac-anka-large-node-fleet" + skip: ${SKIP_MACOS_10_14}${SKIP_TOOLCHAIN_TESTS} + - wait: continue_on_failure: true From 9af4c7de87376e5e63959c0380f6043500b3f7ef Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 8 Jun 2020 10:20:31 -0400 Subject: [PATCH 330/659] revert bad merge in lld --- eosio_llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eosio_llvm b/eosio_llvm index ba0fe38ea2..41c8bc5dee 160000 --- a/eosio_llvm +++ b/eosio_llvm @@ -1 +1 @@ -Subproject commit ba0fe38ea2be2a6886787e6b90887890e5500a75 +Subproject commit 41c8bc5dee4815a7d213018509eed1eea0f9bf16 From 83cf2e508b4ce2d1d85bd05c3b6c54e48149cf9f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 8 Jun 2020 11:54:42 -0400 Subject: [PATCH 331/659] Build in release mode, should drastically reduce size --- .cicd/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index fcedffbf24..68db55efdd 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -8,7 +8,7 @@ if [[ $(uname) == 'Darwin' ]]; then # You can't use chained commands in execute cd $BUILD_DIR - cmake .. + cmake .. -DCMAKE_BUILD_TYPE=Release make -j$JOBS else # Linux @@ -19,7 +19,7 @@ else # Linux # PRE_COMMANDS: Executed pre-cmake PRE_COMMANDS="cd $MOUNTED_DIR/build" - BUILD_COMMANDS="cmake .. && make -j$JOBS" + BUILD_COMMANDS="cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$JOBS" [[ $IMAGE_TAG == 'centos-7.7' ]] && PRE_COMMANDS="$PRE_COMMANDS && source /opt/rh/devtoolset-7/enable" # Docker Commands @@ -40,4 +40,4 @@ else # Linux eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" -fi \ No newline at end of file +fi From eac3c41e98d1f226810780d9ff66cd9f4a13a8d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 12 Mar 2020 11:52:10 -0400 Subject: [PATCH 332/659] Switch make_key over to using abieos. --- .../eosiolib/contracts/eosio/key_value.hpp | 160 ++---------------- 1 file changed, 11 insertions(+), 149 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 46f91bcede..2c2532af1f 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -4,6 +4,8 @@ #include "../../core/eosio/utility.hpp" #include "../../core/eosio/varint.hpp" +#include + #include #include #include @@ -82,6 +84,9 @@ struct key_type : private std::string { key_type() = default; key_type(const char* c, size_t s) : std::string(c, s) {} + template + key_type(Iter begin, Iter end) : std::string(begin, end) {} + key_type operator+(const key_type& b) const { key_type ret = *this; ret += b; @@ -119,158 +124,15 @@ inline key_type table_key(const key_type& prefix, const key_type& key) { return prefix + key; } -template -inline I flip_msb(I val) { - constexpr static size_t bits = sizeof(I) * 8; - return val ^ (static_cast(1) << (bits - 1)); -} - -template -inline I get_msb(I val) { - constexpr static size_t bits = sizeof(I) * 8; - return val >> (bits - 1); -} - -template ::value, int> = 0> -inline key_type make_key(I val) { - if (std::is_signed::value) { - val = flip_msb(val); - } - - auto big_endian = swap_endian(val); - - const char* bytes = reinterpret_cast(&big_endian); - constexpr size_t size = sizeof(big_endian); - key_type s(bytes, size); - return s; -} - -template -inline key_type make_floating_key(F val) { - if (val == -0) { - val = +0; - } - - auto* ival = reinterpret_cast(&val); - I bit_val; - auto msb = get_msb(*ival); - if (msb) { - // invert all the bits - bit_val = ~(*ival); - } else { - // invert just msb - bit_val = flip_msb(*ival); - } - - auto big_endian = swap_endian(bit_val); - - const char* bytes = reinterpret_cast(&big_endian); - constexpr size_t size = sizeof(big_endian); - key_type s(bytes, size); - return s; -} - -inline key_type make_key(float val) { - return make_floating_key(val); -} - -inline key_type make_key(double val) { - return make_floating_key(val); -} - -inline key_type make_key(const char* str, size_t size) { - size_t data_size = size + 3; - void* data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - - memcpy(data_buffer, str, size); - - ((char*)data_buffer)[data_size - 3] = 0x01; - ((char*)data_buffer)[data_size - 2] = 0x00; - ((char*)data_buffer)[data_size - 1] = 0x00; - - key_type s((const char*)data_buffer, data_size); - - if (data_size > detail::max_stack_buffer_size) { - free(data_buffer); - } - return s; -} - -inline key_type make_key(const std::string& val) { - return make_key(val.data(), val.size()); -} - -inline key_type make_key(const std::string_view& val) { - return make_key(val.data(), val.size()); -} - -inline key_type make_key(const char* str) { - return make_key(std::string_view{str}); -} - -inline key_type make_key(eosio::name n) { - return make_key(n.value); -} - -inline key_type make_key(key_type&& val) { - return std::move(val); -} - -inline key_type make_key(const key_type& val) { - return val; -} - -template ::value, int> = 0> -inline key_type make_key(const S& val) { - size_t data_size = 0; - size_t pos = 0; - void* data_buffer; - - boost::pfr::for_each_field(val, [&](auto& field) { - data_size += sizeof(field); - }); - - data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - - boost::pfr::for_each_field(val, [&](auto& field) { - auto kt = make_key(field); - memcpy((char*)data_buffer + pos, kt.data(), kt.size()); - pos += kt.size(); - }); - - key_type s((const char*)data_buffer, data_size); +template +inline key_type make_key(const T& t) { + auto bytes = convert_to_key(t); + + eosio::check(bytes, "There was a failure converting to a key."); - if (data_size > detail::max_stack_buffer_size) { - free(data_buffer); - } - return s; + return key_type(bytes.value().begin(), bytes.value().end()); } -template -inline key_type make_key(const std::tuple& val) { - size_t data_size = 0; - size_t pos = 0; - void* data_buffer; - - boost::fusion::for_each(val, [&](auto& field) { - data_size += sizeof(field); - }); - - data_buffer = data_size > detail::max_stack_buffer_size ? malloc(data_size) : alloca(data_size); - - boost::fusion::for_each(val, [&](auto& field) { - auto kt = make_key(field); - memcpy((char*)data_buffer + pos, kt.data(), kt.size()); - pos += kt.size(); - }); - - key_type s((const char*)data_buffer, data_size); - - if (data_size > detail::max_stack_buffer_size) { - free(data_buffer); - } - return s; -} /* @endcond */ // This is the "best" way to document a function that does not technically exist using Doxygen. From eb056dfaee0b749e96c3d2cf97350edfe5fe7167 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 11:25:14 -0400 Subject: [PATCH 333/659] Change key_type to vector to reduce copying from abieos results. --- .../eosiolib/contracts/eosio/key_value.hpp | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 2c2532af1f..c3f43f7d4d 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -80,12 +80,10 @@ namespace detail { /** * The key_type struct is used to store the binary representation of a key. */ -struct key_type : private std::string { +struct key_type : private std::vector { key_type() = default; - key_type(const char* c, size_t s) : std::string(c, s) {} - template - key_type(Iter begin, Iter end) : std::string(begin, end) {} + key_type(std::vector&& v) : std::vector(v) {} key_type operator+(const key_type& b) const { key_type ret = *this; @@ -93,6 +91,12 @@ struct key_type : private std::string { return ret; } + key_type& operator+=(const key_type& b) const { + this->resize(this->size()+b->size()); + this->insert(this->end(), b.begin(), b.end()); + return *this; + } + bool operator==(const key_type& b) const { return size() != b.size() && memcmp(data(), b.data(), b.size()) == 0; } @@ -103,36 +107,20 @@ struct key_type : private std::string { }; /* @cond PRIVATE */ -inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { - auto bige_table = swap_endian(table_name.value); - auto bige_index = swap_endian(index_name.value); - - constexpr size_t index_name_size = sizeof(index_name); - constexpr size_t buffer_size = (2 * index_name_size) + sizeof(status); - - key_type ret; - ret.resize(buffer_size); - - memcpy(ret.data(), &status, sizeof(status)); - memcpy(ret.data() + sizeof(status), &bige_table, index_name_size); - memcpy(ret.data() + sizeof(status) + index_name_size, &bige_index, index_name_size); - - return ret; -} - -inline key_type table_key(const key_type& prefix, const key_type& key) { - return prefix + key; -} - template inline key_type make_key(const T& t) { auto bytes = convert_to_key(t); - - eosio::check(bytes, "There was a failure converting to a key."); + eosio::check((bool)bytes, "There was a failure converting to a key."); + return key_type(std::move(bytes.value())); +} - return key_type(bytes.value().begin(), bytes.value().end()); +inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { + return make_key(std::make_tuple(status, table_name, index_name)); } +inline key_type table_key(const key_type& prefix, const key_type& key) { + return prefix + key; +} /* @endcond */ // This is the "best" way to document a function that does not technically exist using Doxygen. From 1bce089a7bfc3bc645e1afceae82f44fecd22b62 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 12:35:49 -0400 Subject: [PATCH 334/659] Improve key_type --- libraries/eosiolib/contracts/eosio/key_value.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index c3f43f7d4d..887b62d5e0 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -83,7 +83,7 @@ namespace detail { struct key_type : private std::vector { key_type() = default; - key_type(std::vector&& v) : std::vector(v) {} + explicit key_type(std::vector&& v) : std::vector(v) {} key_type operator+(const key_type& b) const { key_type ret = *this; @@ -92,7 +92,6 @@ struct key_type : private std::vector { } key_type& operator+=(const key_type& b) const { - this->resize(this->size()+b->size()); this->insert(this->end(), b.begin(), b.end()); return *this; } From cf2fe34bc982c615738e5cb252c8866523506c04 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 13 Mar 2020 14:02:05 -0400 Subject: [PATCH 335/659] Remove unneeded headers --- .../eosiolib/contracts/eosio/key_value.hpp | 1 - libraries/eosiolib/core/eosio/utility.hpp | 31 ------------------- 2 files changed, 32 deletions(-) delete mode 100644 libraries/eosiolib/core/eosio/utility.hpp diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 887b62d5e0..2d3401efb6 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -1,7 +1,6 @@ #pragma once #include "../../core/eosio/datastream.hpp" #include "../../core/eosio/name.hpp" -#include "../../core/eosio/utility.hpp" #include "../../core/eosio/varint.hpp" #include diff --git a/libraries/eosiolib/core/eosio/utility.hpp b/libraries/eosiolib/core/eosio/utility.hpp deleted file mode 100644 index e1c0a632c8..0000000000 --- a/libraries/eosiolib/core/eosio/utility.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -namespace eosio { - /* utility function to swap the endianness of a variable */ - template - inline T swap_endian(T val) { - static_assert(sizeof(T) <= 16); - if constexpr (sizeof(T) == 1) - return val; - else if constexpr (sizeof(T) == 2) - return (val << 8) | (val >> 8); - else if constexpr (sizeof(T) == 4) { - T value; - auto swapped = __builtin_bswap32(val); - memcpy((char*)&value, (char*)&swapped, sizeof(T)); - return value; - } else if constexpr (sizeof(T) == 8) { - T value; - auto swapped = __builtin_bswap64(val); - memcpy((char*)&value, (char*)&swapped, sizeof(T)); - return value; - } else { - T value; - uint128_t swapped_high = __builtin_bswap64((uint64_t)val); - uint64_t swapped_low = __builtin_bswap64((uint64_t)(val >> 64)); - T swapped = (swapped_high << 64) | swapped_low; - memcpy((char*)&value, (char*)&swapped, sizeof(T)); - return value; - } - } -} From bdf9eeaedf6e28e581a69a45fe3472ced40cc1d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 8 Jun 2020 16:56:01 -0400 Subject: [PATCH 336/659] Pull in minimal abieos dependencies for key serialization --- .../eosiolib/contracts/eosio/key_value.hpp | 15 +- libraries/eosiolib/contracts/eosio/to_key.hpp | 298 ++++++++++++++++++ libraries/eosiolib/core/eosio/check.hpp | 20 +- .../eosiolib/core/eosio/for_each_field.hpp | 51 +++ libraries/eosiolib/core/eosio/map_macro.h | 64 ++++ libraries/eosiolib/core/eosio/name.hpp | 2 + libraries/eosiolib/core/eosio/reflection.hpp | 61 ++++ libraries/eosiolib/core/eosio/stream.hpp | 231 ++++++++++++++ .../unit/test_contracts/kv_make_key_tests.cpp | 3 + 9 files changed, 737 insertions(+), 8 deletions(-) create mode 100644 libraries/eosiolib/contracts/eosio/to_key.hpp create mode 100644 libraries/eosiolib/core/eosio/for_each_field.hpp create mode 100644 libraries/eosiolib/core/eosio/map_macro.h create mode 100644 libraries/eosiolib/core/eosio/reflection.hpp create mode 100644 libraries/eosiolib/core/eosio/stream.hpp diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 2d3401efb6..42b5235d7c 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -3,7 +3,7 @@ #include "../../core/eosio/name.hpp" #include "../../core/eosio/varint.hpp" -#include +#include "to_key.hpp" #include #include @@ -84,13 +84,15 @@ struct key_type : private std::vector { explicit key_type(std::vector&& v) : std::vector(v) {} + explicit key_type(char* str, size_t size) : std::vector(str, str+size) {} + key_type operator+(const key_type& b) const { key_type ret = *this; ret += b; return ret; } - key_type& operator+=(const key_type& b) const { + key_type& operator+=(const key_type& b) { this->insert(this->end(), b.begin(), b.end()); return *this; } @@ -99,17 +101,16 @@ struct key_type : private std::vector { return size() != b.size() && memcmp(data(), b.data(), b.size()) == 0; } - using std::string::data; - using std::string::size; - using std::string::resize; + using std::vector::data; + using std::vector::size; + using std::vector::resize; }; /* @cond PRIVATE */ template inline key_type make_key(const T& t) { auto bytes = convert_to_key(t); - eosio::check((bool)bytes, "There was a failure converting to a key."); - return key_type(std::move(bytes.value())); + return key_type(std::move(bytes)); } inline key_type make_prefix(eosio::name table_name, eosio::name index_name, uint8_t status = 1) { diff --git a/libraries/eosiolib/contracts/eosio/to_key.hpp b/libraries/eosiolib/contracts/eosio/to_key.hpp new file mode 100644 index 0000000000..5e674af271 --- /dev/null +++ b/libraries/eosiolib/contracts/eosio/to_key.hpp @@ -0,0 +1,298 @@ +#pragma once + +#include +#include "../../core/eosio/for_each_field.hpp" +#include "../../core/eosio/stream.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eosio { + +template +void to_key(const std::tuple& obj, S& stream); + +// to_key defines a conversion from a type to a sequence of bytes whose lexicograpical +// ordering is the same as the ordering of the original type. +// +// For any two objects of type T, a and b: +// +// - key(a) < key(b) iff a < b +// - key(a) is not a prefix of key(b) +// +// Overloads of to_key for user-defined types can be found by Koenig lookup. +// +// Abieos provides specializations of to_key for the following types +// - std::string and std::string_view +// - std::vector, std::list, std::deque +// - std::tuple +// - std::array +// - std::optional +// - std::variant +// - Arithmetic types +// - Scoped enumeration types +// - Reflected structs +// - All smart-contract related types defined by abieos +template +void to_key(const T& obj, S& stream); + +template +void to_key_tuple(const T& obj, S& stream) { + if constexpr (i < std::tuple_size_v) { + to_key(std::get(obj), stream); + to_key_tuple(obj, stream); + } +} + +template +void to_key(const std::tuple& obj, S& stream) { + to_key_tuple<0>(obj, stream); +} + +template +void to_key(const std::array& obj, S& stream) { + for (const T& elem : obj) { to_key(elem, stream); } +} + +template +void to_key_optional(const bool* obj, S& stream) { + if (obj == nullptr) + stream.write('\0'); + else if (!*obj) + stream.write('\1'); + else + stream.write('\2'); +} + +template +void to_key_optional(const T* obj, S& stream) { + if constexpr (has_bitwise_serialization() && sizeof(T) == 1) { + if (obj == nullptr) + stream.write("\0", 2); + else { + char buf[1]; + fixed_buf_stream tmp_stream(buf, 1); + to_key(*obj, tmp_stream); + stream.write(buf[0]); + if (buf[0] == '\0') + stream.write('\1'); + } + } else { + if (obj) { + stream.write('\1'); + to_key(*obj, stream); + } else { + stream.write('\0'); + } + } +} + +template +void to_key(const std::pair& obj, S& stream) { + to_key(obj.first, stream); + to_key(obj.second, stream); +} + +template +void to_key_range(const T& obj, S& stream) { + for (const auto& elem : obj) { to_key_optional(&elem, stream); } + to_key_optional((decltype(&*std::begin(obj))) nullptr, stream); +} + +template +void to_key(const std::vector& obj, S& stream) { + for (const T& elem : obj) { to_key_optional(&elem, stream); } + to_key_optional((const T*)nullptr, stream); +} + +template +void to_key(const std::list& obj, S& stream) { + to_key_range(obj, stream); +} + +template +void to_key(const std::deque& obj, S& stream) { + to_key_range(obj, stream); +} + +template +void to_key(const std::set& obj, S& stream) { + to_key_range(obj, stream); +} + +template +void to_key(const std::map& obj, S& stream) { + to_key_range(obj, stream); +} + +template +void to_key(const std::optional& obj, S& stream) { + to_key_optional(obj ? &*obj : nullptr, stream); +} + +// The first byte holds: +// 0-4 1's (number of additional bytes) 0 (terminator) bits +// +// The number is represented as big-endian using the low order +// bits of the first byte and all of the remaining bytes. +// +// Notes: +// - values must be encoded using the minimum number of bytes, +// as non-canonical representations will break the sort order. +template +void to_key_varuint32(std::uint32_t obj, S& stream) { + int num_bytes; + if (obj < 0x80u) { + num_bytes = 1; + } else if (obj < 0x4000u) { + num_bytes = 2; + } else if (obj < 0x200000u) { + num_bytes = 3; + } else if (obj < 0x10000000u) { + num_bytes = 4; + } else { + num_bytes = 5; + } + + stream.write( + static_cast(~(0xFFu >> (num_bytes - 1)) | (num_bytes == 5 ? 0 : (obj >> ((num_bytes - 1) * 8))))); + for (int i = num_bytes - 2; i >= 0; --i) { stream.write(static_cast((obj >> i * 8) & 0xFFu)); } +} + +// for non-negative values +// The first byte holds: +// 1 (signbit) 0-4 1's (number of additional bytes) 0 (terminator) bits +// The value is represented as big endian +// for negative values +// The first byte holds: +// 0 (signbit) 0-4 0's (number of additional bytes) 1 (terminator) bits +// The value is adjusted to be positive based on the range that can +// be represented with this number of bytes and then encoded as big endian. +// +// Notes: +// - negative values must sort before positive values +// - For negative value, numbers that need more bytes are smaller, hence +// the encoding of the width must be opposite the encoding used for +// non-negative values. +// - A 5-byte varint can represent values in $[-2^34, 2^34)$. In this case, +// the argument will be sign-extended. +template +void to_key_varint32(std::int32_t obj, S& stream) { + static_assert(std::is_same_v, "to_key for varint32 has been temporarily disabled"); + int num_bytes; + bool sign = (obj < 0); + if (obj < 0x40 && obj >= -0x40) { + num_bytes = 1; + } else if (obj < 0x2000 && obj >= -0x2000) { + num_bytes = 2; + } else if (obj < 0x100000 && obj >= -0x100000) { + num_bytes = 3; + } else if (obj < 0x08000000 && obj >= -0x08000000) { + num_bytes = 4; + } else { + num_bytes = 5; + } + + unsigned char width_field; + if (sign) { + width_field = 0x80u >> num_bytes; + } else { + width_field = 0x80u | ~(0xFFu >> num_bytes); + } + auto uobj = static_cast(obj); + unsigned char value_mask = (0xFFu >> (num_bytes + 1)); + unsigned char high_byte = (num_bytes == 5 ? (sign ? 0xFF : 0) : (uobj >> ((num_bytes - 1) * 8))); + stream.write(width_field | (high_byte & value_mask)); + for (int i = num_bytes - 2; i >= 0; --i) { stream.write(static_cast((uobj >> i * 8) & 0xFFu)); } +} + +template +void to_key(const std::variant& obj, S& stream) { + to_key_varuint32(static_cast(obj.index()), stream); + std::visit([&](const auto& item) { to_key(item, stream); }, obj); +} + +template +void to_key(std::string_view obj, S& stream) { + for (char ch : obj) { + stream.write(ch); + if (ch == '\0') { + stream.write('\1'); + } + } + stream.write("\0", 2); +} + +template +void to_key(const std::string& obj, S& stream) { + to_key(std::string_view(obj), stream); +} + +template +void to_key(bool obj, S& stream) { + stream.write(static_cast(obj ? 1 : 0)); +} + +template +UInt float_to_key(T value) { + static_assert(sizeof(T) == sizeof(UInt), "Expected unsigned int of the same size"); + UInt result; + std::memcpy(&result, &value, sizeof(T)); + UInt signbit = (static_cast(1) << (std::numeric_limits::digits - 1)); + UInt mask = 0; + if (result == signbit) + result = 0; + if (result & signbit) + mask = ~mask; + return result ^ (mask | signbit); +} + +template +void to_key(const T& obj, S& stream) { + if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + to_key(float_to_key(obj), stream); + } else { + static_assert(sizeof(T) == 8, "Unknown floating point type"); + to_key(float_to_key(obj), stream); + } + } else if constexpr (std::is_integral_v) { + auto v = static_cast>(obj); + v -= static_cast>(std::numeric_limits::min()); + std::reverse(reinterpret_cast(&v), reinterpret_cast(&v + 1)); + stream.write_raw(v); + } else if constexpr (std::is_enum_v) { + static_assert(!std::is_convertible_v>, "Serializing unscoped enum"); + to_key(static_cast>(obj), stream); + } else { + eosio::for_each_field(obj, [&](const auto& member) { + to_key(member, stream); + }); + } +} + +template +void convert_to_key(const T& t, std::vector& bin) { + size_stream ss; + to_key(t, ss); + auto orig_size = bin.size(); + bin.resize(orig_size + ss.size); + fixed_buf_stream fbs(bin.data() + orig_size, ss.size); + to_key(t, fbs); + check( fbs.pos == fbs.end, convert_stream_error(stream_error::underrun) ); +} + +template +std::vector convert_to_key(const T& t) { + std::vector result; + convert_to_key(t, result); + return result; +} + +} // namespace eosio diff --git a/libraries/eosiolib/core/eosio/check.hpp b/libraries/eosiolib/core/eosio/check.hpp index 236b718b5f..9f4b1738fe 100644 --- a/libraries/eosiolib/core/eosio/check.hpp +++ b/libraries/eosiolib/core/eosio/check.hpp @@ -4,8 +4,9 @@ */ #pragma once -#include +//#include #include +#include namespace eosio { @@ -28,6 +29,22 @@ namespace eosio { * @brief Defines wrappers over eosio_assert */ + + /** + * Assert if the predicate fails and use the supplied message. + * + * @ingroup system + * + * Example: + * @code + * eosio::check(a == b, "a does not equal b"); + * @endcode + */ + inline void check(bool pred, std::string_view msg) { + if (!pred) + internal_use_do_not_use::eosio_assert_message(false, msg.data(), msg.size()); + } + /** * Assert if the predicate fails and use the supplied message. * @@ -76,6 +93,7 @@ namespace eosio { } } + /** * Assert if the predicate fails and use a subset of the supplied message. * diff --git a/libraries/eosiolib/core/eosio/for_each_field.hpp b/libraries/eosiolib/core/eosio/for_each_field.hpp new file mode 100644 index 0000000000..9669e291d5 --- /dev/null +++ b/libraries/eosiolib/core/eosio/for_each_field.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "../../core/eosio/reflection.hpp" +#include + +// This causes compilation erros, but everything builds fine without it. +#if 0 +#if __has_include() + +#include + +namespace eosio { +template +constexpr auto for_each_field(T&& t, F&& f) -> std::enable_if_t>> { + return boost::pfr::for_each_field(static_cast(t), static_cast(f)); + +// namespace eosio +#endif +#endif + +namespace eosio { + +template +constexpr auto for_each_field(T&& t, F&& f) -> std::enable_if_t>> { + eosio_for_each_field((std::decay_t*)nullptr, [&](const char*, auto member) { + if constexpr (std::is_member_object_pointer_v) { + f(t.*member(&t)); + } + }); +} + +template +constexpr void for_each_field(F&& f) { + eosio_for_each_field((T*)nullptr, [&f](const char* name, auto member) { + if constexpr (std::is_member_object_pointer_v) { + f(name, [member](auto p) -> decltype((p->*member(p))) { return p->*member(p); }); + } + }); +} + +// Calls f(#fn_name, &T::fn_name) for every reflected member function of T. +template +constexpr void for_each_method(F&& f) { + eosio_for_each_field((T*)nullptr, [&f](const char* name, auto member) { + if constexpr (std::is_member_function_pointer_v) { + f(name, member((T*)nullptr)); + } + }); +} + +} // namespace eosio diff --git a/libraries/eosiolib/core/eosio/map_macro.h b/libraries/eosiolib/core/eosio/map_macro.h new file mode 100644 index 0000000000..c8fd54188b --- /dev/null +++ b/libraries/eosiolib/core/eosio/map_macro.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 William Swanson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or + * their institutions shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization from the authors. + */ + +/* + * This file has been modified by block.one + */ + +#ifndef EOSIO_MAP_MACRO_H_INCLUDED +#define EOSIO_MAP_MACRO_H_INCLUDED + +#define EOSIO_EVAL0(...) __VA_ARGS__ +#define EOSIO_EVAL1(...) EOSIO_EVAL0(EOSIO_EVAL0(EOSIO_EVAL0(__VA_ARGS__))) +#define EOSIO_EVAL2(...) EOSIO_EVAL1(EOSIO_EVAL1(EOSIO_EVAL1(__VA_ARGS__))) +#define EOSIO_EVAL3(...) EOSIO_EVAL2(EOSIO_EVAL2(EOSIO_EVAL2(__VA_ARGS__))) +#define EOSIO_EVAL4(...) EOSIO_EVAL3(EOSIO_EVAL3(EOSIO_EVAL3(__VA_ARGS__))) +#define EOSIO_EVAL(...) EOSIO_EVAL4(EOSIO_EVAL4(EOSIO_EVAL4(__VA_ARGS__))) + +#define EOSIO_MAP_END(...) +#define EOSIO_MAP_OUT + +#define EOSIO_MAP_GET_END2() 0, EOSIO_MAP_END +#define EOSIO_MAP_GET_END1(...) EOSIO_MAP_GET_END2 +#define EOSIO_MAP_GET_END(...) EOSIO_MAP_GET_END1 +#define EOSIO_MAP_NEXT0(test, next, ...) next EOSIO_MAP_OUT +#define EOSIO_MAP_NEXT1(test, next) EOSIO_MAP_NEXT0(test, next, 0) +#define EOSIO_MAP_NEXT(test, next) EOSIO_MAP_NEXT1(EOSIO_MAP_GET_END test, next) + +// Macros below this point added by block.one + +#define EOSIO_MAP_REUSE_ARG0_0(f, arg0, x, peek, ...) \ + f(arg0, x) EOSIO_MAP_NEXT(peek, EOSIO_MAP_REUSE_ARG0_1)(f, arg0, peek, __VA_ARGS__) +#define EOSIO_MAP_REUSE_ARG0_1(f, arg0, x, peek, ...) \ + f(arg0, x) EOSIO_MAP_NEXT(peek, EOSIO_MAP_REUSE_ARG0_0)(f, arg0, peek, __VA_ARGS__) +// Handle 0 arguments +#define EOSIO_MAP_REUSE_ARG0_I(f, arg0, peek, ...) \ + EOSIO_MAP_NEXT(peek, EOSIO_MAP_REUSE_ARG0_1)(f, arg0, peek, __VA_ARGS__) +#define EOSIO_MAP_REUSE_ARG0(f, ...) EOSIO_EVAL(EOSIO_MAP_REUSE_ARG0_I(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#endif diff --git a/libraries/eosiolib/core/eosio/name.hpp b/libraries/eosiolib/core/eosio/name.hpp index b635ee8b68..c972c8a90e 100644 --- a/libraries/eosiolib/core/eosio/name.hpp +++ b/libraries/eosiolib/core/eosio/name.hpp @@ -5,6 +5,7 @@ #pragma once #include "check.hpp" +#include "reflection.hpp" #include "serialize.hpp" #include @@ -309,6 +310,7 @@ namespace eosio { static constexpr const char value[] = {Str...}; }; } /// namespace detail + EOSIO_REFLECT(name, value); } /// namespace eosio /// @cond IMPLEMENTATIONS diff --git a/libraries/eosiolib/core/eosio/reflection.hpp b/libraries/eosiolib/core/eosio/reflection.hpp new file mode 100644 index 0000000000..0761274493 --- /dev/null +++ b/libraries/eosiolib/core/eosio/reflection.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include "map_macro.h" +#include + +namespace eosio { namespace reflection { + + template + struct has_for_each_field { + private: + struct F { + template + void operator()(const A&, const B&); + }; + + template + static char test(decltype(eosio_for_each_field((C*)nullptr, std::declval()))*); + + template + static long test(...); + + public: + static constexpr bool value = sizeof(test((void*)nullptr)) == sizeof(char); + }; + + template + inline constexpr bool has_for_each_field_v = has_for_each_field::value; + +#define EOSIO_REFLECT_MEMBER(STRUCT, FIELD) \ + f(#FIELD, [](auto p) -> decltype(&std::decay_t::FIELD) { return &std::decay_t::FIELD; }); + +#define EOSIO_REFLECT_STRIP_BASEbase +#define EOSIO_REFLECT_BASE(STRUCT, BASE) \ + static_assert(std::is_base_of_v, #BASE " is not a base class of " #STRUCT); \ + eosio_for_each_field((EOSIO_REFLECT_STRIP_BASE##BASE*)nullptr, f); + +#define EOSIO_REFLECT_SIGNATURE(STRUCT, ...) \ + [[maybe_unused]] inline const char* get_type_name(STRUCT*) { return #STRUCT; } \ + template \ + constexpr void eosio_for_each_field(STRUCT*, F f) + +/** + * EOSIO_REFLECT(, ...) + * Each parameter should be either the keyword 'base' followed by a base class of the struct or + * an identifier which names a non-static data member of the struct. + */ +#define EOSIO_REFLECT(...) \ + EOSIO_REFLECT_SIGNATURE(__VA_ARGS__) { EOSIO_MAP_REUSE_ARG0(EOSIO_REFLECT_INTERNAL, __VA_ARGS__) } + +// Identity the keyword 'base' followed by at least one token +#define EOSIO_REFLECT_SELECT_I(a, b, c, d, ...) EOSIO_REFLECT_##d +#define EOSIO_REFLECT_IS_BASE() ~, ~ +#define EOSIO_REFLECT_IS_BASE_TESTbase ~, EOSIO_REFLECT_IS_BASE + +#define EOSIO_APPLY(m, x) m x +#define EOSIO_CAT(x, y) x##y +#define EOSIO_REFLECT_INTERNAL(STRUCT, FIELD) \ + EOSIO_APPLY(EOSIO_REFLECT_SELECT_I, (EOSIO_CAT(EOSIO_REFLECT_IS_BASE_TEST, FIELD()), MEMBER, BASE, MEMBER)) \ + (STRUCT, FIELD) + +}} // namespace eosio::reflection diff --git a/libraries/eosiolib/core/eosio/stream.hpp b/libraries/eosiolib/core/eosio/stream.hpp new file mode 100644 index 0000000000..f21cb9f7fe --- /dev/null +++ b/libraries/eosiolib/core/eosio/stream.hpp @@ -0,0 +1,231 @@ +#pragma once + +#include "../../core/eosio/check.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eosio { + +enum class stream_error { + no_error, + overrun, + underrun, + float_error, + varuint_too_big, + invalid_varuint_encoding, + bad_variant_index, + invalid_asset_format, + array_size_mismatch, + invalid_name_char, + invalid_name_char13, + name_too_long, + json_writer_error, // !!! +}; // stream_error + +constexpr inline std::string_view convert_stream_error(stream_error e) { + switch (e) { + // clang-format off + case stream_error::no_error: return "No error"; + case stream_error::overrun: return "Stream overrun"; + case stream_error::underrun: return "Stream underrun"; + case stream_error::float_error: return "Float error"; + case stream_error::varuint_too_big: return "Varuint too big"; + case stream_error::invalid_varuint_encoding: return "Invalid varuint encoding"; + case stream_error::bad_variant_index: return "Bad variant index"; + case stream_error::invalid_asset_format: return "Invalid asset format"; + case stream_error::array_size_mismatch: return "T[] size and unpacked size don't match"; + case stream_error::invalid_name_char: return "character is not in allowed character set for names"; + case stream_error::invalid_name_char13: return "thirteenth character in name cannot be a letter that comes after j"; + case stream_error::name_too_long: return "string is too long to be a valid name"; + case stream_error::json_writer_error: return "Error writing json"; + // clang-format on + + default: return "unknown"; + } +} + +template +constexpr bool has_bitwise_serialization() { + if constexpr (std::is_arithmetic_v) { + return true; + } else if constexpr (std::is_enum_v) { + static_assert(!std::is_convertible_v>, "Serializing unscoped enum"); + return true; + } else { + return false; + } +} + +template +struct small_buffer { + char data[max_size]; + char* pos{ data }; + + void reverse() { std::reverse(data, pos); } +}; + +struct vector_stream { + std::vector& data; + vector_stream(std::vector& data) : data(data) {} + + void write(char c) { + data.push_back(c); + } + void write(const void* src, std::size_t sz) { + auto s = reinterpret_cast(src); + data.insert( data.end(), s, s + sz ); + } + template + void write_raw(const T& v) { + write(&v, sizeof(v)); + } +}; + +struct fixed_buf_stream { + char* pos; + char* end; + + fixed_buf_stream(char* pos, size_t size) : pos{ pos }, end{ pos + size } {} + + void write(char c) { + check( pos < end, convert_stream_error(stream_error::overrun) ); + *pos++ = c; + } + + void write(const void* src, std::size_t sz) { + check( pos + sz <= end, convert_stream_error(stream_error::overrun) ); + memcpy(pos, src, sz); + pos += sz; + } + + template + void write(const char (&src)[Size]) { + write(src, Size); + } + + template + void write_raw(const T& v) { + write(&v, sizeof(v)); + } +}; + +struct size_stream { + size_t size = 0; + + void write(char c) { + ++size; + } + + void write(const void* src, std::size_t sz) { + size += sz; + } + + template + void write(const char (&src)[Size]) { + size += Size; + } + + template + void write_raw(const T& v) { + size += sizeof(v); + } +}; + +template +void increase_indent(S&) { +} + +template +void decrease_indent(S&) { +} + +template +void write_colon(S& s) { + s.write(':'); +} + +template +void write_newline(S&) { +} + +template +struct pretty_stream : Base { + using Base::Base; + int indent_size = 4; + std::vector current_indent; +}; + +template +void increase_indent(pretty_stream& s) { + s.current_indent.resize(s.current_indent.size() + s.indent_size, ' '); +} + +template +void decrease_indent(pretty_stream& s) { + check( s.current_indent.size() >= s.indent_size, + convert_stream_error(stream_error::overrun) ); + s.current_indent.resize(s.current_indent.size() - s.indent_size); +} + +template +void write_colon(pretty_stream& s) { + s.write(": ", 2); +} + +template +void write_newline(pretty_stream& s) { + s.write('\n'); + s.write(s.current_indent.data(), s.current_indent.size()); +} + +struct input_stream { + const char* pos; + const char* end; + + input_stream() : pos{ nullptr }, end{ nullptr } {} + input_stream(const char* pos, size_t size) : pos{ pos }, end{ pos + size } {} + input_stream(const char* pos, const char* end) : pos{ pos }, end{ end } {} + input_stream(const std::vector& v) : pos{ v.data() }, end{ v.data() + v.size() } {} + input_stream(std::string_view v) : pos{ v.data() }, end{ v.data() + v.size() } {} + input_stream(const input_stream&) = default; + + input_stream& operator=(const input_stream&) = default; + + size_t remaining() const { return end - pos; } + + void check_available(size_t size) const { + check( size <= std::size_t(end-pos), convert_stream_error(stream_error::overrun) ); + } + + auto get_pos()const { return pos; } + + void read(void* dest, size_t size) { + check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); + memcpy(dest, pos, size); + pos += size; + } + + template + void read_raw(T& dest) { + read(&dest, sizeof(dest)); + } + + void skip(size_t size) { + check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); + pos += size; + } + + void read_reuse_storage(const char*& result, size_t size) { + check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); + result = pos; + pos += size; + } +}; + +} // namespace eosio diff --git a/tests/unit/test_contracts/kv_make_key_tests.cpp b/tests/unit/test_contracts/kv_make_key_tests.cpp index e17b20b6b5..8915f3492a 100644 --- a/tests/unit/test_contracts/kv_make_key_tests.cpp +++ b/tests/unit/test_contracts/kv_make_key_tests.cpp @@ -33,6 +33,9 @@ struct my_struct { } }; +EOSIO_REFLECT(testing_struct, a, b); +EOSIO_REFLECT(my_struct, tname, tstring, tui64, ti32, tui128, tfloat, tdouble, tstruct, ttuple); + struct my_table : eosio::kv_table { KV_NAMED_INDEX("t1"_n, tname) KV_NAMED_INDEX("t2"_n, tstring) From 933c879c14697a6175e77b2d1415b49b4b2ca5c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 9 Jun 2020 15:31:55 -0400 Subject: [PATCH 337/659] Update intrinsics for latest develop --- libraries/eosiolib/contracts/eosio/key_value.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 42b5235d7c..a57d69d4b7 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -56,13 +56,13 @@ namespace eosio { int32_t kv_it_move_to_end(uint32_t itr); __attribute__((eosio_wasm_import)) - int32_t kv_it_next(uint32_t itr); + int32_t kv_it_next(uint32_t itr, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) - int32_t kv_it_prev(uint32_t itr); + int32_t kv_it_prev(uint32_t itr, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) - int32_t kv_it_lower_bound(uint32_t itr, const char* key, uint32_t size); + int32_t kv_it_lower_bound(uint32_t itr, const char* key, uint32_t size, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) int32_t kv_it_key(uint32_t itr, uint32_t offset, char* dest, uint32_t size, uint32_t& actual_size); From 229a5ba41d70e662d72b2fd24ca0cbf8241c70ec Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Tue, 9 Jun 2020 15:32:47 -0400 Subject: [PATCH 338/659] Update to_key to use datastream rather than stream --- libraries/eosiolib/contracts/eosio/to_key.hpp | 80 +++--- libraries/eosiolib/core/eosio/datastream.hpp | 43 ++++ libraries/eosiolib/core/eosio/stream.hpp | 231 ------------------ 3 files changed, 90 insertions(+), 264 deletions(-) delete mode 100644 libraries/eosiolib/core/eosio/stream.hpp diff --git a/libraries/eosiolib/contracts/eosio/to_key.hpp b/libraries/eosiolib/contracts/eosio/to_key.hpp index 5e674af271..0f75fc1ef4 100644 --- a/libraries/eosiolib/contracts/eosio/to_key.hpp +++ b/libraries/eosiolib/contracts/eosio/to_key.hpp @@ -1,8 +1,6 @@ #pragma once #include -#include "../../core/eosio/for_each_field.hpp" -#include "../../core/eosio/stream.hpp" #include #include #include @@ -13,10 +11,25 @@ #include #include +#include "../../core/eosio/datastream.hpp" +#include "../../core/eosio/for_each_field.hpp" + namespace eosio { +template +constexpr bool has_bitwise_serialization() { + if constexpr (std::is_arithmetic_v) { + return true; + } else if constexpr (std::is_enum_v) { + static_assert(!std::is_convertible_v>, "Serializing unscoped enum"); + return true; + } else { + return false; + } +} + template -void to_key(const std::tuple& obj, S& stream); +void to_key(const std::tuple& obj, datastream& stream); // to_key defines a conversion from a type to a sequence of bytes whose lexicograpical // ordering is the same as the ordering of the original type. @@ -40,10 +53,10 @@ void to_key(const std::tuple& obj, S& stream); // - Reflected structs // - All smart-contract related types defined by abieos template -void to_key(const T& obj, S& stream); +void to_key(const T& obj, datastream& stream); template -void to_key_tuple(const T& obj, S& stream) { +void to_key_tuple(const T& obj, datastream& stream) { if constexpr (i < std::tuple_size_v) { to_key(std::get(obj), stream); to_key_tuple(obj, stream); @@ -51,33 +64,34 @@ void to_key_tuple(const T& obj, S& stream) { } template -void to_key(const std::tuple& obj, S& stream) { +void to_key(const std::tuple& obj, datastream& stream) { to_key_tuple<0>(obj, stream); } template -void to_key(const std::array& obj, S& stream) { +void to_key(const std::array& obj, datastream& stream) { for (const T& elem : obj) { to_key(elem, stream); } } template -void to_key_optional(const bool* obj, S& stream) { +void to_key_optional(const bool* obj, datastream& stream) { if (obj == nullptr) stream.write('\0'); else if (!*obj) stream.write('\1'); - else - stream.write('\2'); + else { + stream.write("\2", 2); + } } template -void to_key_optional(const T* obj, S& stream) { +void to_key_optional(const T* obj, datastream& stream) { if constexpr (has_bitwise_serialization() && sizeof(T) == 1) { if (obj == nullptr) stream.write("\0", 2); else { char buf[1]; - fixed_buf_stream tmp_stream(buf, 1); + datastream tmp_stream(buf, 1); to_key(*obj, tmp_stream); stream.write(buf[0]); if (buf[0] == '\0') @@ -94,45 +108,45 @@ void to_key_optional(const T* obj, S& stream) { } template -void to_key(const std::pair& obj, S& stream) { +void to_key(const std::pair& obj, datastream& stream) { to_key(obj.first, stream); to_key(obj.second, stream); } template -void to_key_range(const T& obj, S& stream) { +void to_key_range(const T& obj, datastream& stream) { for (const auto& elem : obj) { to_key_optional(&elem, stream); } to_key_optional((decltype(&*std::begin(obj))) nullptr, stream); } template -void to_key(const std::vector& obj, S& stream) { +void to_key(const std::vector& obj, datastream& stream) { for (const T& elem : obj) { to_key_optional(&elem, stream); } to_key_optional((const T*)nullptr, stream); } template -void to_key(const std::list& obj, S& stream) { +void to_key(const std::list& obj, datastream& stream) { to_key_range(obj, stream); } template -void to_key(const std::deque& obj, S& stream) { +void to_key(const std::deque& obj, datastream& stream) { to_key_range(obj, stream); } template -void to_key(const std::set& obj, S& stream) { +void to_key(const std::set& obj, datastream& stream) { to_key_range(obj, stream); } template -void to_key(const std::map& obj, S& stream) { +void to_key(const std::map& obj, datastream& stream) { to_key_range(obj, stream); } template -void to_key(const std::optional& obj, S& stream) { +void to_key(const std::optional& obj, datastream& stream) { to_key_optional(obj ? &*obj : nullptr, stream); } @@ -146,7 +160,7 @@ void to_key(const std::optional& obj, S& stream) { // - values must be encoded using the minimum number of bytes, // as non-canonical representations will break the sort order. template -void to_key_varuint32(std::uint32_t obj, S& stream) { +void to_key_varuint32(std::uint32_t obj, datastream& stream) { int num_bytes; if (obj < 0x80u) { num_bytes = 1; @@ -183,7 +197,7 @@ void to_key_varuint32(std::uint32_t obj, S& stream) { // - A 5-byte varint can represent values in $[-2^34, 2^34)$. In this case, // the argument will be sign-extended. template -void to_key_varint32(std::int32_t obj, S& stream) { +void to_key_varint32(std::int32_t obj, datastream& stream) { static_assert(std::is_same_v, "to_key for varint32 has been temporarily disabled"); int num_bytes; bool sign = (obj < 0); @@ -213,15 +227,15 @@ void to_key_varint32(std::int32_t obj, S& stream) { } template -void to_key(const std::variant& obj, S& stream) { +void to_key(const std::variant& obj, datastream& stream) { to_key_varuint32(static_cast(obj.index()), stream); std::visit([&](const auto& item) { to_key(item, stream); }, obj); } template -void to_key(std::string_view obj, S& stream) { +void to_key(std::string_view obj, datastream& stream) { for (char ch : obj) { - stream.write(ch); + stream.write(&ch, 1); if (ch == '\0') { stream.write('\1'); } @@ -230,12 +244,12 @@ void to_key(std::string_view obj, S& stream) { } template -void to_key(const std::string& obj, S& stream) { +void to_key(const std::string& obj, datastream& stream) { to_key(std::string_view(obj), stream); } template -void to_key(bool obj, S& stream) { +void to_key(bool obj, datastream& stream) { stream.write(static_cast(obj ? 1 : 0)); } @@ -254,7 +268,7 @@ UInt float_to_key(T value) { } template -void to_key(const T& obj, S& stream) { +void to_key(const T& obj, datastream& stream) { if constexpr (std::is_floating_point_v) { if constexpr (sizeof(T) == 4) { to_key(float_to_key(obj), stream); @@ -266,7 +280,7 @@ void to_key(const T& obj, S& stream) { auto v = static_cast>(obj); v -= static_cast>(std::numeric_limits::min()); std::reverse(reinterpret_cast(&v), reinterpret_cast(&v + 1)); - stream.write_raw(v); + stream.write(&v, sizeof(v)); } else if constexpr (std::is_enum_v) { static_assert(!std::is_convertible_v>, "Serializing unscoped enum"); to_key(static_cast>(obj), stream); @@ -279,13 +293,13 @@ void to_key(const T& obj, S& stream) { template void convert_to_key(const T& t, std::vector& bin) { - size_stream ss; + datastream ss; to_key(t, ss); auto orig_size = bin.size(); - bin.resize(orig_size + ss.size); - fixed_buf_stream fbs(bin.data() + orig_size, ss.size); + bin.resize(orig_size + ss.tellp()); + datastream fbs(bin.data() + orig_size, ss.tellp()); to_key(t, fbs); - check( fbs.pos == fbs.end, convert_stream_error(stream_error::underrun) ); + check( fbs.valid(), "Stream overrun" ); } template diff --git a/libraries/eosiolib/core/eosio/datastream.hpp b/libraries/eosiolib/core/eosio/datastream.hpp index acbdbf3b47..e2e64f665e 100644 --- a/libraries/eosiolib/core/eosio/datastream.hpp +++ b/libraries/eosiolib/core/eosio/datastream.hpp @@ -85,6 +85,33 @@ class datastream { return true; } + /** + * Writes a specified number of bytes into the stream from a buffer + * + * @param d - The pointer to the source buffer + * @param s - The number of bytes to write + * @return true + */ + inline bool write( char d ) { + eosio::check( _end - _pos >= 1, "write" ); + *_pos++ = d; + return true; + } + + /** + * Writes a specified number of bytes into the stream from a buffer + * + * @param d - The pointer to the source buffer + * @param s - The number of bytes to write + * @return true + */ + inline bool write( const void* d, size_t s ) { + eosio::check( _end - _pos >= (int32_t)s, "write" ); + memcpy( (void*)_pos, d, s ); + _pos += s; + return true; + } + /** * Writes a byte into the stream * @@ -207,6 +234,22 @@ class datastream { */ inline bool write( const char* ,size_t s ) { _size += s; return true; } + /** + * Increment the size by s. This behaves the same as skip( size_t s ) + * + * @param s - The amount of size to increase + * @return true + */ + inline bool write( char ) { _size++; return true; } + + /** + * Increment the size by s. This behaves the same as skip( size_t s ) + * + * @param s - The amount of size to increase + * @return true + */ + inline bool write( const void* ,size_t s ) { _size += s; return true; } + /** * Increment the size by one * diff --git a/libraries/eosiolib/core/eosio/stream.hpp b/libraries/eosiolib/core/eosio/stream.hpp deleted file mode 100644 index f21cb9f7fe..0000000000 --- a/libraries/eosiolib/core/eosio/stream.hpp +++ /dev/null @@ -1,231 +0,0 @@ -#pragma once - -#include "../../core/eosio/check.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace eosio { - -enum class stream_error { - no_error, - overrun, - underrun, - float_error, - varuint_too_big, - invalid_varuint_encoding, - bad_variant_index, - invalid_asset_format, - array_size_mismatch, - invalid_name_char, - invalid_name_char13, - name_too_long, - json_writer_error, // !!! -}; // stream_error - -constexpr inline std::string_view convert_stream_error(stream_error e) { - switch (e) { - // clang-format off - case stream_error::no_error: return "No error"; - case stream_error::overrun: return "Stream overrun"; - case stream_error::underrun: return "Stream underrun"; - case stream_error::float_error: return "Float error"; - case stream_error::varuint_too_big: return "Varuint too big"; - case stream_error::invalid_varuint_encoding: return "Invalid varuint encoding"; - case stream_error::bad_variant_index: return "Bad variant index"; - case stream_error::invalid_asset_format: return "Invalid asset format"; - case stream_error::array_size_mismatch: return "T[] size and unpacked size don't match"; - case stream_error::invalid_name_char: return "character is not in allowed character set for names"; - case stream_error::invalid_name_char13: return "thirteenth character in name cannot be a letter that comes after j"; - case stream_error::name_too_long: return "string is too long to be a valid name"; - case stream_error::json_writer_error: return "Error writing json"; - // clang-format on - - default: return "unknown"; - } -} - -template -constexpr bool has_bitwise_serialization() { - if constexpr (std::is_arithmetic_v) { - return true; - } else if constexpr (std::is_enum_v) { - static_assert(!std::is_convertible_v>, "Serializing unscoped enum"); - return true; - } else { - return false; - } -} - -template -struct small_buffer { - char data[max_size]; - char* pos{ data }; - - void reverse() { std::reverse(data, pos); } -}; - -struct vector_stream { - std::vector& data; - vector_stream(std::vector& data) : data(data) {} - - void write(char c) { - data.push_back(c); - } - void write(const void* src, std::size_t sz) { - auto s = reinterpret_cast(src); - data.insert( data.end(), s, s + sz ); - } - template - void write_raw(const T& v) { - write(&v, sizeof(v)); - } -}; - -struct fixed_buf_stream { - char* pos; - char* end; - - fixed_buf_stream(char* pos, size_t size) : pos{ pos }, end{ pos + size } {} - - void write(char c) { - check( pos < end, convert_stream_error(stream_error::overrun) ); - *pos++ = c; - } - - void write(const void* src, std::size_t sz) { - check( pos + sz <= end, convert_stream_error(stream_error::overrun) ); - memcpy(pos, src, sz); - pos += sz; - } - - template - void write(const char (&src)[Size]) { - write(src, Size); - } - - template - void write_raw(const T& v) { - write(&v, sizeof(v)); - } -}; - -struct size_stream { - size_t size = 0; - - void write(char c) { - ++size; - } - - void write(const void* src, std::size_t sz) { - size += sz; - } - - template - void write(const char (&src)[Size]) { - size += Size; - } - - template - void write_raw(const T& v) { - size += sizeof(v); - } -}; - -template -void increase_indent(S&) { -} - -template -void decrease_indent(S&) { -} - -template -void write_colon(S& s) { - s.write(':'); -} - -template -void write_newline(S&) { -} - -template -struct pretty_stream : Base { - using Base::Base; - int indent_size = 4; - std::vector current_indent; -}; - -template -void increase_indent(pretty_stream& s) { - s.current_indent.resize(s.current_indent.size() + s.indent_size, ' '); -} - -template -void decrease_indent(pretty_stream& s) { - check( s.current_indent.size() >= s.indent_size, - convert_stream_error(stream_error::overrun) ); - s.current_indent.resize(s.current_indent.size() - s.indent_size); -} - -template -void write_colon(pretty_stream& s) { - s.write(": ", 2); -} - -template -void write_newline(pretty_stream& s) { - s.write('\n'); - s.write(s.current_indent.data(), s.current_indent.size()); -} - -struct input_stream { - const char* pos; - const char* end; - - input_stream() : pos{ nullptr }, end{ nullptr } {} - input_stream(const char* pos, size_t size) : pos{ pos }, end{ pos + size } {} - input_stream(const char* pos, const char* end) : pos{ pos }, end{ end } {} - input_stream(const std::vector& v) : pos{ v.data() }, end{ v.data() + v.size() } {} - input_stream(std::string_view v) : pos{ v.data() }, end{ v.data() + v.size() } {} - input_stream(const input_stream&) = default; - - input_stream& operator=(const input_stream&) = default; - - size_t remaining() const { return end - pos; } - - void check_available(size_t size) const { - check( size <= std::size_t(end-pos), convert_stream_error(stream_error::overrun) ); - } - - auto get_pos()const { return pos; } - - void read(void* dest, size_t size) { - check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); - memcpy(dest, pos, size); - pos += size; - } - - template - void read_raw(T& dest) { - read(&dest, sizeof(dest)); - } - - void skip(size_t size) { - check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); - pos += size; - } - - void read_reuse_storage(const char*& result, size_t size) { - check( size <= size_t(end-pos), convert_stream_error(stream_error::overrun) ); - result = pos; - pos += size; - } -}; - -} // namespace eosio From 6c8a41e0d7b7c4d16fe7fe73e25647b1b3436785 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 4 Jun 2020 16:09:59 -0400 Subject: [PATCH 339/659] Fix CI build for 16.04 --- .cicd/build.sh | 5 ++++- .cicd/docker/ubuntu-16.04.dockerfile | 16 +++++++++++++--- modules/ClangExternalProject.txt | 2 +- modules/ToolsExternalProject.txt | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index fcedffbf24..84e476378f 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -21,6 +21,9 @@ else # Linux PRE_COMMANDS="cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake .. && make -j$JOBS" + BUILD_COMMANDS_1604="cmake .. -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_FLAGS=\"-stdlib=libc++\" && make -j$JOBS" + [[ $IMAGE_TAG == 'ubuntu-16.04' ]] && BUILD_COMMANDS="$BUILD_COMMANDS_1604" + [[ $IMAGE_TAG == 'centos-7.7' ]] && PRE_COMMANDS="$PRE_COMMANDS && source /opt/rh/devtoolset-7/enable" # Docker Commands if [[ $BUILDKITE == true ]]; then @@ -40,4 +43,4 @@ else # Linux eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" -fi \ No newline at end of file +fi diff --git a/.cicd/docker/ubuntu-16.04.dockerfile b/.cicd/docker/ubuntu-16.04.dockerfile index f049e4a387..68031e381f 100644 --- a/.cicd/docker/ubuntu-16.04.dockerfile +++ b/.cicd/docker/ubuntu-16.04.dockerfile @@ -1,11 +1,11 @@ FROM ubuntu:16.04 # install dependencies RUN apt-get update && apt-get upgrade -y && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y git clang-4.0 \ - lldb-4.0 libclang-4.0-dev make automake libbz2-dev libssl-dev \ + DEBIAN_FRONTEND=noninteractive apt-get install -y git \ + lldb-4.0 make automake libbz2-dev libssl-dev \ libgmp3-dev autotools-dev build-essential libicu-dev python2.7-dev \ autoconf libtool curl zlib1g-dev doxygen graphviz \ - wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev + wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev xz-utils # install cmake RUN curl -LO https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz && \ @@ -25,3 +25,13 @@ RUN curl -LO https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && \ make -j$(nproc) altinstall && \ cd .. && \ rm -rf Python-3.7.4 && rm -rf Python-3.7.4.tar.gz + +# install clang 9 +RUN curl -LO https://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz && \ + tar -xvf clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz && \ + cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/* /usr/local/bin && \ + cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/include/* /usr/local/include && \ + cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/lib/* /usr/local/lib && \ + mkdir -p /usr/local/libexec && cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/libexec/* /usr/local/libexec && \ + cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/share/* /usr/local/share && \ + cp -R clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-16.04/lib/libc++* /usr/lib diff --git a/modules/ClangExternalProject.txt b/modules/ClangExternalProject.txt index f3d0cd01f1..214599f731 100644 --- a/modules/ClangExternalProject.txt +++ b/modules/ClangExternalProject.txt @@ -4,7 +4,7 @@ include(GNUInstallDirs) ExternalProject_Add( EosioClang - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/llvm -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=Release -DEOSIO_TOOL_DIR=${CMAKE_SOURCE_DIR}/tools -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} SOURCE_DIR "${CMAKE_SOURCE_DIR}/eosio_llvm" BINARY_DIR "${CMAKE_BINARY_DIR}/eosio_llvm" diff --git a/modules/ToolsExternalProject.txt b/modules/ToolsExternalProject.txt index 139afed94b..ef53ee56f9 100644 --- a/modules/ToolsExternalProject.txt +++ b/modules/ToolsExternalProject.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) set(LLVM_BINDIR ${CMAKE_BINARY_DIR}/eosio_llvm) ExternalProject_Add( EosioTools - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_PATCH=${VERSION_PATCH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DVERSION_FULL=${VERSION_FULL} -DLLVM_SRCDIR=${CMAKE_SOURCE_DIR}/eosio_llvm -DLLVM_BINDIR=${LLVM_BINDIR} -DLLVM_DIR=${LLVM_BINDIR}/lib/cmake/llvm -DCMAKE_INSTALL_BINDIR=${CMAKE_INSTALL_BINDIR} -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_PATCH=${VERSION_PATCH} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} SOURCE_DIR "${CMAKE_SOURCE_DIR}/tools" BINARY_DIR "${CMAKE_BINARY_DIR}/tools" From 3a2b496e3d9a4bcd821fa055a04500133d3b7ce8 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 11 Jun 2020 13:39:07 +0300 Subject: [PATCH 340/659] fixes #905 [eosio.cdt:issue:905] [docs] as of eosio 2.0-rc1 deferred transaction are deprecated --- docs/05_best-practices/09_deferred_transactions.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md index 63ca63c2aa..c2d4a7eb11 100644 --- a/docs/05_best-practices/09_deferred_transactions.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -6,5 +6,7 @@ Deferred communication conceptually takes the form of action notifications sent As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. -[[warning | Warning about deferred transaction usage]] -| Because of the above, it is not recommended to use `deferred transactions`. There is consideration to deprecate deferred transactions in a future version. +Because all of the above it is not recommended to use `deferred transactions`. + +[[warning | Deferred Transactions Are Deprecated]] +| As of [EOSIO 2.0 RC1](https://github.com/EOSIO/eos/releases/tag/v2.0.0-rc1) deferred transactions are deprecated. From 60e03fb5b1e5074b96f557a8c0a1a0ddf51f5092 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 11 Jun 2020 09:39:18 -0400 Subject: [PATCH 341/659] Update intrinsics for latest develop --- libraries/eosiolib/contracts/eosio/key_value.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index 46f91bcede..a1fbd6a84f 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -55,13 +55,13 @@ namespace eosio { int32_t kv_it_move_to_end(uint32_t itr); __attribute__((eosio_wasm_import)) - int32_t kv_it_next(uint32_t itr); + int32_t kv_it_next(uint32_t itr, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) - int32_t kv_it_prev(uint32_t itr); + int32_t kv_it_prev(uint32_t itr, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) - int32_t kv_it_lower_bound(uint32_t itr, const char* key, uint32_t size); + int32_t kv_it_lower_bound(uint32_t itr, const char* key, uint32_t size, uint32_t& found_key_size = (uint32_t&)std::move(uint32_t(0)), uint32_t& found_value_size = (uint32_t&)std::move(uint32_t(0))); __attribute__((eosio_wasm_import)) int32_t kv_it_key(uint32_t itr, uint32_t offset, char* dest, uint32_t size, uint32_t& actual_size); From 6126d1cdfc998b3bdb3a25c9217087210d01a668 Mon Sep 17 00:00:00 2001 From: Damon Revoe Date: Thu, 11 Jun 2020 12:27:17 -0400 Subject: [PATCH 342/659] Split monolith string_tests into many small tests In some environments, the single huge unit test in string_tests.cpp either failed to compile or consumed ridiculous amounts of memory and CPU time. Because the test comprised of many independent small cases, lumped together to avoid having to list them in the main function, it was easy to split the single test into individual test cases, which helped the compilation speed and memory consumption. --- tests/unit/string_tests.cpp | 2718 ++++++++++++++++++----------------- 1 file changed, 1422 insertions(+), 1296 deletions(-) diff --git a/tests/unit/string_tests.cpp b/tests/unit/string_tests.cpp index 9bcda8a272..05c0bf646f 100644 --- a/tests/unit/string_tests.cpp +++ b/tests/unit/string_tests.cpp @@ -14,1484 +14,1483 @@ using eosio::datastream; using eosio::string; // Definitions found in `eosio.cdt/libraries/eosiolib/core/eosio/string.hpp` -EOSIO_TEST_BEGIN(string_test) - //// template - //// string(const char (&str)[N]) - { - static const string eostr0{"a"}; - static const string eostr1{"abcdef"}; - - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 1 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "a"), 0 ) - - CHECK_EQUAL( eostr1.size(), 6 ) - CHECK_EQUAL( eostr1.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "abcdef"), 0) - } - //// string() - { - static const string eostr{}; +//// template +//// string(const char (&str)[N]) +EOSIO_TEST_BEGIN(string_test_1) + static const string eostr0{"a"}; + static const string eostr1{"abcdef"}; - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( eostr.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0) - } + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "a"), 0 ) - //// constexpr string(const char* str, const size_t n) - { - static const char* str0{""}; - static const char* str1{"abc"}; - static const char* str2{"abcdef"}; + CHECK_EQUAL( eostr1.size(), 6 ) + CHECK_EQUAL( eostr1.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "abcdef"), 0) +EOSIO_TEST_END - static const string eostr0(str0, 0); - static const string eostr1(str1, 1); - static const string eostr2(str2, 6); +//// string() +EOSIO_TEST_BEGIN(string_test_2) + static const string eostr{}; - CHECK_EQUAL( eostr0.size(), 0 ) - CHECK_EQUAL( eostr0.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0) +EOSIO_TEST_END - CHECK_EQUAL( eostr1.size(), 1 ) - CHECK_EQUAL( eostr1.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) +//// constexpr string(const char* str, const size_t n) +EOSIO_TEST_BEGIN(string_test_3) + static const char* str0{""}; + static const char* str1{"abc"}; + static const char* str2{"abcdef"}; - CHECK_EQUAL( eostr2.size(), 6 ) - CHECK_EQUAL( eostr2.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) - } + static const string eostr0(str0, 0); + static const string eostr1(str1, 1); + static const string eostr2(str2, 6); - //// string(const size_t n, const char c) - { - static const string eostr0(0, 'c'); - static const string eostr1(1, 'c'); - static const string eostr2(3, 'c'); + CHECK_EQUAL( eostr0.size(), 0 ) + CHECK_EQUAL( eostr0.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) - CHECK_EQUAL( eostr0.size(), 0 ) - CHECK_EQUAL( eostr0.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + CHECK_EQUAL( eostr1.size(), 1 ) + CHECK_EQUAL( eostr1.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) - CHECK_EQUAL( eostr1.size(), 1 ) - CHECK_EQUAL( eostr1.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "c"), 0) + CHECK_EQUAL( eostr2.size(), 6 ) + CHECK_EQUAL( eostr2.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) +EOSIO_TEST_END - CHECK_EQUAL( eostr2.size(), 3 ) - CHECK_EQUAL( eostr2.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "ccc"), 0) - } +//// string(const size_t n, const char c) +EOSIO_TEST_BEGIN(string_test_4) + static const string eostr0(0, 'c'); + static const string eostr1(1, 'c'); + static const string eostr2(3, 'c'); - //// string(const string& str, const size_t pos, const size_t n = string::npos) - { - static const string eostr{"abcdef"}; - static const string eostr0_sub(eostr, 0, 0); - static const string eostr1_sub(eostr, 1, 0); - static const string eostr2_sub(eostr, 0, 1); - static const string eostr3_sub(eostr, 0, 3); - static const string eostr4_sub(eostr, 0, 8); - static const string eostr5_sub(eostr, 0, 7); - static const string eostr6_sub(eostr, 0, 6); - static const string eostr7_sub(eostr, 3, 3); - static const string eostr8_sub(eostr, 3, 2); - - CHECK_EQUAL( eostr0_sub.size(), 0 ) - CHECK_EQUAL( eostr0_sub.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0_sub.c_str(), ""), 0) - - CHECK_EQUAL( eostr1_sub.size(), 0 ) - CHECK_EQUAL( eostr1_sub.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr1_sub.c_str(), ""), 0) - - CHECK_EQUAL( eostr2_sub.size(), 1 ) - CHECK_EQUAL( eostr2_sub.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr2_sub.c_str(), "a"), 0) - - CHECK_EQUAL( eostr3_sub.size(), 3 ) - CHECK_EQUAL( eostr3_sub.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr3_sub.c_str(), "abc"), 0) - - CHECK_EQUAL( eostr4_sub.size(), 6 ) - CHECK_EQUAL( eostr4_sub.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr4_sub.c_str(), "abcdef"), 0) - - CHECK_EQUAL( eostr5_sub.size(), 6 ) - CHECK_EQUAL( eostr5_sub.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr5_sub.c_str(), "abcdef"), 0) - - CHECK_EQUAL( eostr6_sub.size(), 6 ) - CHECK_EQUAL( eostr6_sub.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr6_sub.c_str(), "abcdef"), 0 ) - - CHECK_EQUAL( eostr7_sub.size(), 3 ) - CHECK_EQUAL( eostr7_sub.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr7_sub.c_str(), "def"), 0 ) - - CHECK_EQUAL( eostr8_sub.size(), 2 ) - CHECK_EQUAL( eostr8_sub.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr8_sub.c_str(), "de"), 0) - } + CHECK_EQUAL( eostr0.size(), 0 ) + CHECK_EQUAL( eostr0.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) - //// constexpr string(const string& str) - { - static const string eostr0{""}; - static const string eostr1{"a"}; - static const string eostr2{"abcdef"}; - static const string eostr0_cpy{eostr0}; - static const string eostr1_cpy{eostr1}; - static const string eostr2_cpy{eostr2}; - - CHECK_EQUAL( eostr0_cpy.size(), 0 ) - CHECK_EQUAL( eostr0_cpy.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), ""), 0) - - CHECK_EQUAL( eostr1_cpy.size(), 1 ) - CHECK_EQUAL( eostr1_cpy.capacity(), 1 ) - CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "a"), 0) - - CHECK_EQUAL( eostr2_cpy.size(), 6 ) - CHECK_EQUAL( eostr2_cpy.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr2_cpy.c_str(), "abcdef"), 0) - } + CHECK_EQUAL( eostr1.size(), 1 ) + CHECK_EQUAL( eostr1.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "c"), 0) - { - static string eostr0{""}; - eostr0 += "a"; - static string eostr1{"abc"}; - eostr1 += "def"; - static string eostr0_cpy{eostr0}; - static string eostr1_cpy{eostr1}; - - CHECK_EQUAL( eostr0_cpy.size(), 1 ) - CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) - - CHECK_EQUAL( eostr1_cpy.size(), 6 ) - CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) - } + CHECK_EQUAL( eostr2.size(), 3 ) + CHECK_EQUAL( eostr2.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "ccc"), 0) +EOSIO_TEST_END - //// constexpr string(const string&& str) - { - static string eostr0{""}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static const string eostr0_mv{move(eostr0)}; - static const string eostr1_mv{move(eostr1)}; - static const string eostr2_mv{move(eostr2)}; - - CHECK_EQUAL( eostr0_mv.size(), 0 ) - CHECK_EQUAL( eostr0_mv.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) - - CHECK_EQUAL( eostr1_mv.size(), 1 ) - CHECK_EQUAL( eostr1_mv.capacity(), 1 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) - - CHECK_EQUAL( eostr2_mv.size(), 6 ) - CHECK_EQUAL( eostr2_mv.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) - } +//// string(const string& str, const size_t pos, const size_t n = string::npos) +EOSIO_TEST_BEGIN(string_test_5) + static const string eostr{"abcdef"}; + static const string eostr0_sub(eostr, 0, 0); + static const string eostr1_sub(eostr, 1, 0); + static const string eostr2_sub(eostr, 0, 1); + static const string eostr3_sub(eostr, 0, 3); + static const string eostr4_sub(eostr, 0, 8); + static const string eostr5_sub(eostr, 0, 7); + static const string eostr6_sub(eostr, 0, 6); + static const string eostr7_sub(eostr, 3, 3); + static const string eostr8_sub(eostr, 3, 2); + + CHECK_EQUAL( eostr0_sub.size(), 0 ) + CHECK_EQUAL( eostr0_sub.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_sub.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_sub.size(), 0 ) + CHECK_EQUAL( eostr1_sub.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr1_sub.c_str(), ""), 0) + + CHECK_EQUAL( eostr2_sub.size(), 1 ) + CHECK_EQUAL( eostr2_sub.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr2_sub.c_str(), "a"), 0) + + CHECK_EQUAL( eostr3_sub.size(), 3 ) + CHECK_EQUAL( eostr3_sub.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr3_sub.c_str(), "abc"), 0) + + CHECK_EQUAL( eostr4_sub.size(), 6 ) + CHECK_EQUAL( eostr4_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr4_sub.c_str(), "abcdef"), 0) + + CHECK_EQUAL( eostr5_sub.size(), 6 ) + CHECK_EQUAL( eostr5_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr5_sub.c_str(), "abcdef"), 0) + + CHECK_EQUAL( eostr6_sub.size(), 6 ) + CHECK_EQUAL( eostr6_sub.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr6_sub.c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( eostr7_sub.size(), 3 ) + CHECK_EQUAL( eostr7_sub.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr7_sub.c_str(), "def"), 0 ) + + CHECK_EQUAL( eostr8_sub.size(), 2 ) + CHECK_EQUAL( eostr8_sub.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr8_sub.c_str(), "de"), 0) +EOSIO_TEST_END - { - static string eostr0{""}; - eostr0 += "a"; - static string eostr1{"abc"}; - eostr1 += "def"; - static string eostr0_cpy{move(eostr0)}; - static string eostr1_cpy{move(eostr1)}; - - CHECK_EQUAL( eostr0_cpy.size(), 1 ) - CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) - - CHECK_EQUAL( eostr1_cpy.size(), 6 ) - CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) - } +//// constexpr string(const string& str) +EOSIO_TEST_BEGIN(string_test_6) + static const string eostr0{""}; + static const string eostr1{"a"}; + static const string eostr2{"abcdef"}; + static const string eostr0_cpy{eostr0}; + static const string eostr1_cpy{eostr1}; + static const string eostr2_cpy{eostr2}; + + CHECK_EQUAL( eostr0_cpy.size(), 0 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 1 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_cpy.size(), 6 ) + CHECK_EQUAL( eostr2_cpy.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_cpy.c_str(), "abcdef"), 0) +EOSIO_TEST_END - //// string& operator=(const string& str); - { - static const string eostr0{""}; - static const string eostr1{"a"}; - static const string eostr2{"abcdef"}; - static string eostr0_cpy_assig{}; - static string eostr1_cpy_assig{}; - static string eostr2_cpy_assig{}; - eostr0_cpy_assig = eostr0; - eostr1_cpy_assig = eostr1; - eostr2_cpy_assig = eostr2; - - CHECK_EQUAL( eostr0_cpy_assig.size(), 0 ) - CHECK_EQUAL( eostr0_cpy_assig.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), ""), 0) - - CHECK_EQUAL( eostr1_cpy_assig.size(), 1 ) - CHECK_EQUAL( eostr1_cpy_assig.capacity(), 1 ) - CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "a"), 0) - - CHECK_EQUAL( eostr2_cpy_assig.size(), 6 ) - CHECK_EQUAL( eostr2_cpy_assig.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr2_cpy_assig.c_str(), "abcdef"), 0) - } +EOSIO_TEST_BEGIN(string_test_7) + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy{eostr0}; + static string eostr1_cpy{eostr1}; + + CHECK_EQUAL( eostr0_cpy.size(), 1 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 6 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) +EOSIO_TEST_END - { - static string eostr0{""}; - eostr0 += "a"; - static string eostr1{"abc"}; - eostr1 += "def"; - static string eostr0_cpy_assig{}; - static string eostr1_cpy_assig{}; - eostr0_cpy_assig = eostr0; - eostr1_cpy_assig = eostr1; - - CHECK_EQUAL( eostr0_cpy_assig.size(), 1 ) - CHECK_EQUAL( eostr0_cpy_assig.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), "a"), 0) - - CHECK_EQUAL( eostr1_cpy_assig.size(), 6 ) - CHECK_EQUAL( eostr1_cpy_assig.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "abcdef"), 0) - } +//// constexpr string(const string&& str) +EOSIO_TEST_BEGIN(string_test_8) + static string eostr0{""}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static const string eostr0_mv{move(eostr0)}; + static const string eostr1_mv{move(eostr1)}; + static const string eostr2_mv{move(eostr2)}; + + CHECK_EQUAL( eostr0_mv.size(), 0 ) + CHECK_EQUAL( eostr0_mv.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_mv.size(), 1 ) + CHECK_EQUAL( eostr1_mv.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_mv.size(), 6 ) + CHECK_EQUAL( eostr2_mv.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdef"), 0) +EOSIO_TEST_END - //// string& operator=(string&& str) - { - static string eostr0{""}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static string eostr0_mv_assig{}; - static string eostr1_mv_assig{}; - static string eostr2_mv_assig{}; - eostr0_mv_assig = move(eostr0); - eostr1_mv_assig = move(eostr1); - eostr2_mv_assig = move(eostr2); - - CHECK_EQUAL( eostr0_mv_assig.size(), 0 ) - CHECK_EQUAL( eostr0_mv_assig.capacity(), 0 ) - CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), ""), 0) - - CHECK_EQUAL( eostr1_mv_assig.size(), 1 ) - CHECK_EQUAL( eostr1_mv_assig.capacity(), 1 ) - CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "a"), 0) - - CHECK_EQUAL( eostr2_mv_assig.size(), 6 ) - CHECK_EQUAL( eostr2_mv_assig.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr2_mv_assig.c_str(), "abcdef"), 0) - } +EOSIO_TEST_BEGIN(string_test_9) + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy{move(eostr0)}; + static string eostr1_cpy{move(eostr1)}; + + CHECK_EQUAL( eostr0_cpy.size(), 1 ) + CHECK_EQUAL( eostr0_cpy.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy.size(), 6 ) + CHECK_EQUAL( eostr1_cpy.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy.c_str(), "abcdef"), 0) +EOSIO_TEST_END - { - static string eostr0{""}; - eostr0 += "a"; - static string eostr1{"abc"}; - eostr1 += "def"; - static string eostr0_mv_assig{}; - static string eostr1_mv_assig{}; - eostr0_mv_assig = move(eostr0); - eostr1_mv_assig = move(eostr1); - - CHECK_EQUAL( eostr0_mv_assig.size(), 1 ) - CHECK_EQUAL( eostr0_mv_assig.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), "a"), 0) - - CHECK_EQUAL( eostr1_mv_assig.size(), 6 ) - CHECK_EQUAL( eostr1_mv_assig.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "abcdef"), 0) - } +//// string& operator=(const string& str); +EOSIO_TEST_BEGIN(string_test_10) + static const string eostr0{""}; + static const string eostr1{"a"}; + static const string eostr2{"abcdef"}; + static string eostr0_cpy_assig{}; + static string eostr1_cpy_assig{}; + static string eostr2_cpy_assig{}; + eostr0_cpy_assig = eostr0; + eostr1_cpy_assig = eostr1; + eostr2_cpy_assig = eostr2; + + CHECK_EQUAL( eostr0_cpy_assig.size(), 0 ) + CHECK_EQUAL( eostr0_cpy_assig.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_cpy_assig.size(), 1 ) + CHECK_EQUAL( eostr1_cpy_assig.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_cpy_assig.size(), 6 ) + CHECK_EQUAL( eostr2_cpy_assig.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_cpy_assig.c_str(), "abcdef"), 0) +EOSIO_TEST_END - //// string& operator=(const char* str) - { - static string eostr{}; - eostr = "abcdef"; +EOSIO_TEST_BEGIN(string_test_11) + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_cpy_assig{}; + static string eostr1_cpy_assig{}; + eostr0_cpy_assig = eostr0; + eostr1_cpy_assig = eostr1; + + CHECK_EQUAL( eostr0_cpy_assig.size(), 1 ) + CHECK_EQUAL( eostr0_cpy_assig.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_cpy_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_cpy_assig.size(), 6 ) + CHECK_EQUAL( eostr1_cpy_assig.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_cpy_assig.c_str(), "abcdef"), 0) +EOSIO_TEST_END - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +//// string& operator=(string&& str) +EOSIO_TEST_BEGIN(string_test_12) + static string eostr0{""}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr0_mv_assig{}; + static string eostr1_mv_assig{}; + static string eostr2_mv_assig{}; + eostr0_mv_assig = move(eostr0); + eostr1_mv_assig = move(eostr1); + eostr2_mv_assig = move(eostr2); + + CHECK_EQUAL( eostr0_mv_assig.size(), 0 ) + CHECK_EQUAL( eostr0_mv_assig.capacity(), 0 ) + CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), ""), 0) + + CHECK_EQUAL( eostr1_mv_assig.size(), 1 ) + CHECK_EQUAL( eostr1_mv_assig.capacity(), 1 ) + CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr2_mv_assig.size(), 6 ) + CHECK_EQUAL( eostr2_mv_assig.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr2_mv_assig.c_str(), "abcdef"), 0) +EOSIO_TEST_END - eostr = eostr; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_13) + static string eostr0{""}; + eostr0 += "a"; + static string eostr1{"abc"}; + eostr1 += "def"; + static string eostr0_mv_assig{}; + static string eostr1_mv_assig{}; + eostr0_mv_assig = move(eostr0); + eostr1_mv_assig = move(eostr1); + + CHECK_EQUAL( eostr0_mv_assig.size(), 1 ) + CHECK_EQUAL( eostr0_mv_assig.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0_mv_assig.c_str(), "a"), 0) + + CHECK_EQUAL( eostr1_mv_assig.size(), 6 ) + CHECK_EQUAL( eostr1_mv_assig.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr1_mv_assig.c_str(), "abcdef"), 0) +EOSIO_TEST_END - { - static string eostr{}; - eostr = ""; - eostr += "abcdef"; +//// string& operator=(const char* str) +EOSIO_TEST_BEGIN(string_test_14) + static string eostr{}; + eostr = "abcdef"; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - eostr = eostr; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - } + eostr = eostr; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - //// char& operator[](const size_t n) - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr[0], 'a' ) - CHECK_EQUAL( eostr[5], 'f' ) - } +EOSIO_TEST_BEGIN(string_test_15) + static string eostr{}; + eostr = ""; + eostr += "abcdef"; - { - static string eostr{"abc"}; - eostr += "def"; - CHECK_EQUAL( eostr[0], 'a' ) - CHECK_EQUAL( eostr[5], 'f' ) - } + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - //// const char& operator[](const size_t n) const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( eostr[0], 'a' ) - CHECK_EQUAL( eostr[5], 'f' ) - } + eostr = eostr; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - //// char& at(const size_t n) - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.at(0), 'a' ) - CHECK_EQUAL( eostr.at(5), 'f' ) +//// char& operator[](const size_t n) +EOSIO_TEST_BEGIN(string_test_16) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) +EOSIO_TEST_END - CHECK_ASSERT( "eosio::string::at", []() {eostr.at(6);} ) - } +EOSIO_TEST_BEGIN(string_test_17) + static string eostr{"abc"}; + eostr += "def"; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) +EOSIO_TEST_END - //// const char& at(const size_t n) const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( eostr.at(0), 'a' ) - CHECK_EQUAL( eostr.at(5), 'f' ) +//// const char& operator[](const size_t n) const +EOSIO_TEST_BEGIN(string_test_18) + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr[0], 'a' ) + CHECK_EQUAL( eostr[5], 'f' ) +EOSIO_TEST_END - CHECK_ASSERT( "eosio::string::at const", []() {eostr.at(6);} ) - } +//// char& at(const size_t n) +EOSIO_TEST_BEGIN(string_test_19) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.at(0), 'a' ) + CHECK_EQUAL( eostr.at(5), 'f' ) - { - static string eostr{""}; - eostr += "abcdef"; - const char c0{eostr.at(0)}; - const char c1{eostr.at(5)}; - CHECK_EQUAL( c0, 'a' ) - CHECK_EQUAL( c1, 'f' ) - } + CHECK_ASSERT( "eosio::string::at", []() {eostr.at(6);} ) +EOSIO_TEST_END - //// char& front() - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.front(), 'a' ) +//// const char& at(const size_t n) const +EOSIO_TEST_BEGIN(string_test_20) + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.at(0), 'a' ) + CHECK_EQUAL( eostr.at(5), 'f' ) - static string empty_str; - CHECK_EQUAL( eostr.front(), 'a' ) - } + CHECK_ASSERT( "eosio::string::at const", []() {eostr.at(6);} ) +EOSIO_TEST_END - //// const char& front() const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( eostr.front(), 'a' ) - } +EOSIO_TEST_BEGIN(string_test_21) + static string eostr{""}; + eostr += "abcdef"; + const char c0{eostr.at(0)}; + const char c1{eostr.at(5)}; + CHECK_EQUAL( c0, 'a' ) + CHECK_EQUAL( c1, 'f' ) +EOSIO_TEST_END - //// char& back() - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.back(), 'f' ) - } +//// char& front() +EOSIO_TEST_BEGIN(string_test_22) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.front(), 'a' ) - //// const char& back() const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( eostr.back(), 'f' ) - } + static string empty_str; + CHECK_EQUAL( eostr.front(), 'a' ) +EOSIO_TEST_END - //// char* data() - { - static string eostr{"abcdef"}; - CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) +//// const char& front() const +EOSIO_TEST_BEGIN(string_test_23) + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.front(), 'a' ) +EOSIO_TEST_END - eostr = "abc"; - CHECK_EQUAL( strcmp(eostr.data(), "abc"), 0 ) - } +//// char& back() +EOSIO_TEST_BEGIN(string_test_24) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.back(), 'f' ) +EOSIO_TEST_END - //// const char* data() const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) - } +//// const char& back() const +EOSIO_TEST_BEGIN(string_test_25) + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.back(), 'f' ) +EOSIO_TEST_END - //// const char* c_str() const - { - static string eostr{"abcdef"}; - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) - } +//// char* data() +EOSIO_TEST_BEGIN(string_test_26) + static string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) - { - static string eostr{""}; - eostr += "abcdef"; - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) - } + eostr = "abc"; + CHECK_EQUAL( strcmp(eostr.data(), "abc"), 0 ) +EOSIO_TEST_END - //// char* begin() - { - static string eostr{"abcdef"}; - char* iter{eostr.begin()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) - } +//// const char* data() const +EOSIO_TEST_BEGIN(string_test_27) + static const string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.data(), "abcdef"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdef"; - char* iter{eostr.begin()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) - } +//// const char* c_str() const +EOSIO_TEST_BEGIN(string_test_28) + static string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) +EOSIO_TEST_END - //// const char* cbegin() const - { - static const string eostr{"abcdef"}; - const char* iter{eostr.cbegin()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) - } +EOSIO_TEST_BEGIN(string_test_29) + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) + CHECK_EQUAL( eostr.c_str()[eostr.size()], '\0' ) +EOSIO_TEST_END - //// char* end() - { - static string eostr{"abcdef"}; - char* iter{eostr.end()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) - } +//// char* begin() +EOSIO_TEST_BEGIN(string_test_30) + static string eostr{"abcdef"}; + char* iter{eostr.begin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdef"; - char* iter{eostr.end()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) - } +EOSIO_TEST_BEGIN(string_test_31) + static string eostr{""}; + eostr += "abcdef"; + char* iter{eostr.begin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) +EOSIO_TEST_END - //// const char* cend() const - { - static const string eostr{"abcdef"}; - const char* iter{eostr.cend()}; - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.data()+eostr.size(), iter), 0 ) - } +//// const char* cbegin() const +EOSIO_TEST_BEGIN(string_test_32) + static const string eostr{"abcdef"}; + const char* iter{eostr.cbegin()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), iter), 0 ) +EOSIO_TEST_END - //// bool string::empty() const - { - static string eostr{}; - CHECK_EQUAL( eostr.empty(), true ) - eostr += 'c'; - CHECK_EQUAL( eostr.empty(), false ) - } +//// char* end() +EOSIO_TEST_BEGIN(string_test_33) + static string eostr{"abcdef"}; + char* iter{eostr.end()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) +EOSIO_TEST_END - //// size_t string::size() const - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.size(), 6 ) - eostr += 'g'; - CHECK_EQUAL( eostr.size(), 7 ) - } +EOSIO_TEST_BEGIN(string_test_34) + static string eostr{""}; + eostr += "abcdef"; + char* iter{eostr.end()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str()+eostr.size(), iter), 0 ) +EOSIO_TEST_END - //// size_t string::length() const - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.length(), 6 ) - eostr += 'g'; - CHECK_EQUAL( eostr.length(), 7 ) - } +//// const char* cend() const +EOSIO_TEST_BEGIN(string_test_35) + static const string eostr{"abcdef"}; + const char* iter{eostr.cend()}; + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.data()+eostr.size(), iter), 0 ) +EOSIO_TEST_END - //// size_t string::capacity() const - { - static string eostr{"abc"}; - CHECK_EQUAL( eostr.capacity(), 3 ) - eostr += 'd', eostr += 'e', eostr += 'f'; - CHECK_EQUAL( eostr.capacity(), 8 ) - eostr += 'g'; - CHECK_EQUAL( eostr.capacity(), 8 ) - } +//// bool string::empty() const +EOSIO_TEST_BEGIN(string_test_36) + static string eostr{}; + CHECK_EQUAL( eostr.empty(), true ) + eostr += 'c'; + CHECK_EQUAL( eostr.empty(), false ) +EOSIO_TEST_END - //// size_t string::max_size() const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( eostr.max_size(), string::npos ) - } +//// size_t string::size() const +EOSIO_TEST_BEGIN(string_test_37) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.size(), 6 ) + eostr += 'g'; + CHECK_EQUAL( eostr.size(), 7 ) +EOSIO_TEST_END - //// void reserve(const size_t n) - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.capacity(), 6 ) - eostr.reserve(10); - CHECK_EQUAL( eostr.capacity(), 10 ) - eostr.reserve(24); - CHECK_EQUAL( eostr.capacity(), 24 ) - eostr.reserve(1); - CHECK_EQUAL( eostr.capacity(), 24 ) - } +//// size_t string::length() const +EOSIO_TEST_BEGIN(string_test_38) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.length(), 6 ) + eostr += 'g'; + CHECK_EQUAL( eostr.length(), 7 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdef"; - CHECK_EQUAL( eostr.capacity(), 12 ) - eostr.reserve(10); - CHECK_EQUAL( eostr.capacity(), 12 ) - eostr.reserve(24); - CHECK_EQUAL( eostr.capacity(), 24 ) - eostr.reserve(1); - CHECK_EQUAL( eostr.capacity(), 24 ) - } +//// size_t string::capacity() const +EOSIO_TEST_BEGIN(string_test_39) + static string eostr{"abc"}; + CHECK_EQUAL( eostr.capacity(), 3 ) + eostr += 'd', eostr += 'e', eostr += 'f'; + CHECK_EQUAL( eostr.capacity(), 8 ) + eostr += 'g'; + CHECK_EQUAL( eostr.capacity(), 8 ) +EOSIO_TEST_END - //// void string::shrink_to_fit() const - { - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - - CHECK_EQUAL( eostr0.capacity(), 0 ) - eostr0.reserve(100); - CHECK_EQUAL( eostr0.capacity(), 100 ) - eostr0.shrink_to_fit(); - CHECK_EQUAL( eostr0.capacity(), 0 ) - - CHECK_EQUAL( eostr1.capacity(), 1 ) - eostr1.reserve(100); - CHECK_EQUAL( eostr1.capacity(), 100 ) - eostr1.shrink_to_fit(); - CHECK_EQUAL( eostr1.capacity(), 1 ) - - CHECK_EQUAL( eostr2.capacity(), 6 ) - eostr2.reserve(100); - CHECK_EQUAL( eostr2.capacity(), 100 ) - eostr2.shrink_to_fit(); - CHECK_EQUAL( eostr2.capacity(), 6 ) - } +//// size_t string::max_size() const +EOSIO_TEST_BEGIN(string_test_40) + static const string eostr{"abcdef"}; + CHECK_EQUAL( eostr.max_size(), string::npos ) +EOSIO_TEST_END - //// void string::clear() - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.empty(), false ) - eostr.clear(); - CHECK_EQUAL( eostr.empty(), true ) - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( eostr.data()[0], '\0' ) - } +//// void reserve(const size_t n) +EOSIO_TEST_BEGIN(string_test_41) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.capacity(), 6 ) + eostr.reserve(10); + CHECK_EQUAL( eostr.capacity(), 10 ) + eostr.reserve(24); + CHECK_EQUAL( eostr.capacity(), 24 ) + eostr.reserve(1); + CHECK_EQUAL( eostr.capacity(), 24 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdef"; - CHECK_EQUAL( eostr.empty(), false ) - eostr.clear(); - CHECK_EQUAL( eostr.empty(), true ) - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( eostr.data()[0], '\0' ) - } +EOSIO_TEST_BEGIN(string_test_42) + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( eostr.capacity(), 12 ) + eostr.reserve(10); + CHECK_EQUAL( eostr.capacity(), 12 ) + eostr.reserve(24); + CHECK_EQUAL( eostr.capacity(), 24 ) + eostr.reserve(1); + CHECK_EQUAL( eostr.capacity(), 24 ) +EOSIO_TEST_END - //// void resize(size_t n) - { - static string eostr{"abcdef"}; +//// void string::shrink_to_fit() const +EOSIO_TEST_BEGIN(string_test_43) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + + CHECK_EQUAL( eostr0.capacity(), 0 ) + eostr0.reserve(100); + CHECK_EQUAL( eostr0.capacity(), 100 ) + eostr0.shrink_to_fit(); + CHECK_EQUAL( eostr0.capacity(), 0 ) + + CHECK_EQUAL( eostr1.capacity(), 1 ) + eostr1.reserve(100); + CHECK_EQUAL( eostr1.capacity(), 100 ) + eostr1.shrink_to_fit(); + CHECK_EQUAL( eostr1.capacity(), 1 ) + + CHECK_EQUAL( eostr2.capacity(), 6 ) + eostr2.reserve(100); + CHECK_EQUAL( eostr2.capacity(), 100 ) + eostr2.shrink_to_fit(); + CHECK_EQUAL( eostr2.capacity(), 6 ) +EOSIO_TEST_END - eostr.resize(3); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +//// void string::clear() +EOSIO_TEST_BEGIN(string_test_44) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.empty(), false ) + eostr.clear(); + CHECK_EQUAL( eostr.empty(), true ) + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.data()[0], '\0' ) +EOSIO_TEST_END - eostr.resize(5); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_BEGIN(string_test_45) + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( eostr.empty(), false ) + eostr.clear(); + CHECK_EQUAL( eostr.empty(), true ) + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( eostr.data()[0], '\0' ) +EOSIO_TEST_END - eostr.resize(13); - CHECK_EQUAL( eostr.size(), 13 ) - CHECK_EQUAL( eostr.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - } +//// void resize(size_t n) +EOSIO_TEST_BEGIN(string_test_46) + static string eostr{"abcdef"}; - { - static string eostr{""}; - eostr += "abcdef"; + eostr.resize(3); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - eostr.resize(3); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + eostr.resize(5); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - eostr.resize(5); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) + eostr.resize(13); + CHECK_EQUAL( eostr.size(), 13 ) + CHECK_EQUAL( eostr.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END - eostr.resize(13); - CHECK_EQUAL( eostr.size(), 13 ) - CHECK_EQUAL( eostr.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_47) + static string eostr{""}; + eostr += "abcdef"; - //// void swap(string& str) - { - static string eostr_swap0{"abc"}; - static string eostr_swap1{"123456"}; + eostr.resize(3); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - eostr_swap0.swap(eostr_swap1); + eostr.resize(5); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - CHECK_EQUAL( eostr_swap0.size(), 6 ) - CHECK_EQUAL( eostr_swap0.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr_swap0.c_str(), "123456"), 0 ) + eostr.resize(13); + CHECK_EQUAL( eostr.size(), 13 ) + CHECK_EQUAL( eostr.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END - CHECK_EQUAL( eostr_swap1.size(), 3 ) - CHECK_EQUAL( eostr_swap1.capacity(), 3 ) - CHECK_EQUAL( strcmp(eostr_swap1.c_str(), "abc"), 0 ) - } +//// void swap(string& str) +EOSIO_TEST_BEGIN(string_test_48) + static string eostr_swap0{"abc"}; + static string eostr_swap1{"123456"}; - //// void push_back(char c) - { - static string eostr{"abcdef"}; - CHECK_EQUAL( eostr.size(), 6 ) - eostr.push_back('g'); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( eostr.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) - } + eostr_swap0.swap(eostr_swap1); - //// void pop_back() - { - static string eostr{"abcdefg"}; - CHECK_EQUAL( eostr.size(), 7 ) - eostr.pop_back(); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - } + CHECK_EQUAL( eostr_swap0.size(), 6 ) + CHECK_EQUAL( eostr_swap0.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr_swap0.c_str(), "123456"), 0 ) - { - static string eostr{"abc"}; - CHECK_EQUAL( eostr.size(), 3 ) - eostr.pop_back(); - eostr.pop_back(); - eostr.pop_back(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - - eostr.pop_back(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } + CHECK_EQUAL( eostr_swap1.size(), 3 ) + CHECK_EQUAL( eostr_swap1.capacity(), 3 ) + CHECK_EQUAL( strcmp(eostr_swap1.c_str(), "abc"), 0 ) +EOSIO_TEST_END - //// string substr(size_t pos = 0, size_t len = npos) const - { - static const string eostr{"abcdef"}; - CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) - - CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) - } +//// void push_back(char c) +EOSIO_TEST_BEGIN(string_test_49) + static string eostr{"abcdef"}; + CHECK_EQUAL( eostr.size(), 6 ) + eostr.push_back('g'); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( eostr.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdef"; - CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) - - CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) - CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) - } +//// void pop_back() +EOSIO_TEST_BEGIN(string_test_50) + static string eostr{"abcdefg"}; + CHECK_EQUAL( eostr.size(), 7 ) + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - //// size_t copy(char* dest, size_t len, size_t pos = 0) const - { - static const string eostr{"abcdef"}; - static char str[7]{}; +EOSIO_TEST_BEGIN(string_test_51) + static string eostr{"abc"}; + CHECK_EQUAL( eostr.size(), 3 ) + eostr.pop_back(); + eostr.pop_back(); + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) + + eostr.pop_back(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - CHECK_EQUAL( eostr.copy(str, 0), 0 ) - CHECK_EQUAL( strcmp(str, ""), 0 ) +//// string substr(size_t pos = 0, size_t len = npos) const +EOSIO_TEST_BEGIN(string_test_52) + static const string eostr{"abcdef"}; + CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) +EOSIO_TEST_END - CHECK_EQUAL( eostr.copy(str, 10), 6 ) - CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) +EOSIO_TEST_BEGIN(string_test_53) + static string eostr{""}; + eostr += "abcdef"; + CHECK_EQUAL( strcmp(eostr.substr(0).c_str(), "abcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,1).c_str(), "a"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,2).c_str(), "ab"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,3).c_str(), "abc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,4).c_str(), "abcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,5).c_str(), "abcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(0,6).c_str(), "abcdef"), 0 ) + + CHECK_EQUAL( strcmp(eostr.substr(1,0).c_str(), ""), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,1).c_str(), "b"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,2).c_str(), "bc"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,3).c_str(), "bcd"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,4).c_str(), "bcde"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,5).c_str(), "bcdef"), 0 ) + CHECK_EQUAL( strcmp(eostr.substr(1,6).c_str(), "bcdef"), 0 ) +EOSIO_TEST_END - CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) - CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) +//// size_t copy(char* dest, size_t len, size_t pos = 0) const +EOSIO_TEST_BEGIN(string_test_54) + static const string eostr{"abcdef"}; + static char str[7]{}; - CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) - CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 0), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) - CHECK_EQUAL( strcmp(str, "cdef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) - CHECK_EQUAL( strcmp(str, "def"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) - CHECK_EQUAL( strcmp(str, "ef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) + CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) - CHECK_EQUAL( strcmp(str, "f"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) + CHECK_EQUAL( strcmp(str, "cdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) - CHECK_EQUAL( strcmp(str, ""), 0 ) - } + CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) + CHECK_EQUAL( strcmp(str, "def"), 0 ) - { - static string eostr{""}; - eostr += "abcdef"; - static char str[7]{}; + CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) + CHECK_EQUAL( strcmp(str, "ef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 0), 0 ) - CHECK_EQUAL( strcmp(str, ""), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) + CHECK_EQUAL( strcmp(str, "f"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10), 6 ) - CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) +EOSIO_TEST_END - CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) - CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) +EOSIO_TEST_BEGIN(string_test_55) + static string eostr{""}; + eostr += "abcdef"; + static char str[7]{}; - CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) - CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 0), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) - CHECK_EQUAL( strcmp(str, "cdef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) - CHECK_EQUAL( strcmp(str, "def"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 0), 6 ) + CHECK_EQUAL( strcmp(str, "abcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) - CHECK_EQUAL( strcmp(str, "ef"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 1), 5 ) + CHECK_EQUAL( strcmp(str, "bcdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) - CHECK_EQUAL( strcmp(str, "f"), 0 ) + CHECK_EQUAL( eostr.copy(str, 10, 2), 4 ) + CHECK_EQUAL( strcmp(str, "cdef"), 0 ) - CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) - CHECK_EQUAL( strcmp(str, ""), 0 ) - } + CHECK_EQUAL( eostr.copy(str, 10, 3), 3 ) + CHECK_EQUAL( strcmp(str, "def"), 0 ) - { - static const string eostr{"abcdef"}; - static char str[7]{}; - CHECK_ASSERT( "eosio::string::copy", []() {eostr.copy(str, 1, eostr.size()+1);} ) - } + CHECK_EQUAL( eostr.copy(str, 10, 4), 2 ) + CHECK_EQUAL( strcmp(str, "ef"), 0 ) - //// string& insert(const size_t pos, const char* str) - { - static string eostr{"iii"}; - static const char* str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) - } + CHECK_EQUAL( eostr.copy(str, 10, 5), 1 ) + CHECK_EQUAL( strcmp(str, "f"), 0 ) - { - static string eostr{"iii"}; - static const char* str{"ooo"}; - eostr.insert(1, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) - } + CHECK_EQUAL( eostr.copy(str, 10, 6), 0 ) + CHECK_EQUAL( strcmp(str, ""), 0 ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const char* str{"ooo"}; - eostr.insert(2, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_56) + static const string eostr{"abcdef"}; + static char str[7]{}; + CHECK_ASSERT( "eosio::string::copy", []() {eostr.copy(str, 1, eostr.size()+1);} ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const char* str{"ooo"}; - eostr.insert(3, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) - } +//// string& insert(const size_t pos, const char* str) +EOSIO_TEST_BEGIN(string_test_57) + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static const char* str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_58) + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static const char* str{"ooo"}; - eostr.insert(1, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_59) + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static const char* str{"ooo"}; - eostr.insert(2, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_60) + static string eostr{"iii"}; + static const char* str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static const char* str{"ooo"}; - eostr.insert(3, str); - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_61) + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - static const char* null_man{nullptr}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(0, null_man, 1);} ) - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, "ooo", 1);} ) - } +EOSIO_TEST_BEGIN(string_test_62) + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii"), 0 ) +EOSIO_TEST_END - //// string& insert(const size_t pos, const string& str) - { - static string eostr{}; - static const string str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_63) + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abc"}; - static const string str{"d"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( eostr.capacity(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_64) + static string eostr{""}; + eostr += "iii"; + static const char* str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abc"}; - static const string str{"def"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_65) + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(0, null_man, 1);} ) + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, "ooo", 1);} ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) - } +//// string& insert(const size_t pos, const string& str) +EOSIO_TEST_BEGIN(string_test_66) + static string eostr{}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(1, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_67) + static string eostr{"abc"}; + static const string str{"d"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(2, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_68) + static string eostr{"abc"}; + static const string str{"def"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) +EOSIO_TEST_END - { - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(3, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_69) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - static const string str{"ooo"}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) - } +EOSIO_TEST_BEGIN(string_test_70) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - static string str{""}; - str += "ooo"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_71) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abc"; - static string str{""}; - str += "d"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_72) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abc"; - static string str{""}; - str += "def"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_73) + static string eostr{"abcdefg"}; + static const string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_74) + static string eostr{""}; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(1, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_75) + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "d"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(2, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_76) + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "def"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(3, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_77) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - static string str{"ooo"}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) - } +EOSIO_TEST_BEGIN(string_test_78) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) +EOSIO_TEST_END - { // Bucky's test for bug he caught; PR #459. - static string eostr = "hello"; - eostr.insert(0, "0", 1); /// `_capacity` is now 12; `_begin` now holds `std::unique_ptr` - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "0hello") , 0 ) - - eostr.insert(0, "h", 1); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "h0hello") , 0 ) - } +EOSIO_TEST_BEGIN(string_test_79) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) +EOSIO_TEST_END - //// string& erase(size_t pos = 0, size_t len = npos) - { - static string eostr{"abcdefgh"}; - eostr.erase(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_80) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(0); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_81) + static string eostr{"abcdefg"}; + static string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(0, string::npos); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_82) + static string eostr = "hello"; + eostr.insert(0, "0", 1); /// `_capacity` is now 12; `_begin` now holds `std::unique_ptr` + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "0hello") , 0 ) + + eostr.insert(0, "h", 1); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "h0hello") , 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(1, string::npos); - CHECK_EQUAL( eostr.size(), 1 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) - } +//// string& erase(size_t pos = 0, size_t len = npos) +EOSIO_TEST_BEGIN(string_test_83) + static string eostr{"abcdefgh"}; + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(2, string::npos); - CHECK_EQUAL( eostr.size(), 2 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_84) + static string eostr{"abcdefgh"}; + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(3, string::npos); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_85) + static string eostr{"abcdefgh"}; + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(4, string::npos); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_86) + static string eostr{"abcdefgh"}; + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(5, string::npos); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_87) + static string eostr{"abcdefgh"}; + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(6, string::npos); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_88) + static string eostr{"abcdefgh"}; + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(7, string::npos); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_89) + static string eostr{"abcdefgh"}; + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(8, string::npos); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_90) + static string eostr{"abcdefgh"}; + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefgh"}; - eostr.erase(8, 0); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_91) + static string eostr{"abcdefgh"}; + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) - } +EOSIO_TEST_BEGIN(string_test_92) + static string eostr{"abcdefgh"}; + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdefgh"; +EOSIO_TEST_BEGIN(string_test_93) + static string eostr{"abcdefgh"}; + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END - eostr.erase(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_94) + static string eostr{"abcdefgh"}; + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END - { - static string eostr{""}; - eostr += "abcdefgh"; +EOSIO_TEST_BEGIN(string_test_95) + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) +EOSIO_TEST_END - eostr.erase(0); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_96) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - eostr.erase(0, string::npos); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) - } +EOSIO_TEST_BEGIN(string_test_97) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - eostr.erase(1, string::npos); - CHECK_EQUAL( eostr.size(), 1 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_98) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END - eostr.erase(2, string::npos); - CHECK_EQUAL( eostr.size(), 2 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_99) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) +EOSIO_TEST_END - eostr.erase(3, string::npos); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_100) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) +EOSIO_TEST_END - eostr.erase(4, string::npos); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_101) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END - eostr.erase(5, string::npos); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_102) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) +EOSIO_TEST_END - eostr.erase(6, string::npos); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_103) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) +EOSIO_TEST_END - eostr.erase(7, string::npos); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_104) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - eostr.erase(8, string::npos); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_105) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{""}; - eostr += "abcdefgh"; + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) +EOSIO_TEST_END - eostr.erase(8, 0); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_106) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{"abcdefg"}; - CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) - } + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END - //// string& append(const char* str) - { - static string eostr{}; - static const char* str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_107) + static string eostr{""}; + eostr += "abcdefgh"; - { - static string eostr{"abcdefg"}; - static const char* str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 10 ) - CHECK_EQUAL( eostr.capacity(), 20 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) - } + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - static const char* null_man{nullptr}; - CHECK_ASSERT( "eosio::string::append", []() {eostr.append(null_man);} ) - } +EOSIO_TEST_BEGIN(string_test_108) + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) +EOSIO_TEST_END - //// string& append(const string& str) - { - static string eostr{}; - static const string str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) - } +//// string& append(const char* str) +EOSIO_TEST_BEGIN(string_test_109) + static string eostr{}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) +EOSIO_TEST_END - { - static string eostr{"abcdefg"}; - static const string str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 10 ) - CHECK_EQUAL( eostr.capacity(), 20 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_110) + static string eostr{"abcdefg"}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) +EOSIO_TEST_END - //// string& operator+=(const char c) - { - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - - eostr0 += 'c'; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += 'c'; - eostr1 += 'c'; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += 'c'; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_111) + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::append", []() {eostr.append(null_man);} ) +EOSIO_TEST_END - //// string& operator+=(const char* rhs) - { - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static string eostr3{"abcdef"}; - - eostr0 += "c"; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += "c"; - eostr1 += "c"; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += "c"; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) - - eostr3 += "ghijklm"; - CHECK_EQUAL( eostr3.size(), 13 ) - CHECK_EQUAL( eostr3.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) - } +//// string& append(const string& str) +EOSIO_TEST_BEGIN(string_test_112) + static string eostr{}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) +EOSIO_TEST_END - //// string& operator+=(const string& rhs) - { - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static string eostr3{"abcdef"}; - - eostr0 += string{"c"}; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += string{"c"}; - eostr1 += string{"c"}; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += string{"c"}; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) - - eostr3 += string{"ghijklm"}; - CHECK_EQUAL( eostr3.size(), 13 ) - CHECK_EQUAL( eostr3.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) - } +EOSIO_TEST_BEGIN(string_test_113) + static string eostr{"abcdefg"}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) +EOSIO_TEST_END - //// string& operator+=(const string& s) - { - static string eostr0{"a"}; - static string eostr1{"b"}; - CHECK_EQUAL( eostr0.size(), 1 ) - eostr0 += eostr1; - CHECK_EQUAL( eostr0.size(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "ab"), 0 ) - } +//// string& operator+=(const char c) +EOSIO_TEST_BEGIN(string_test_114) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + + eostr0 += 'c'; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += 'c'; + eostr1 += 'c'; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += 'c'; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) +EOSIO_TEST_END - { - static string eostr0{"abc"}; - static string eostr1{"def"}; - CHECK_EQUAL( eostr0.size(), 3 ) - eostr0 += eostr1; - CHECK_EQUAL( eostr0.size(), 6 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "abcdef"), 0 ) - } +//// string& operator+=(const char* rhs) +EOSIO_TEST_BEGIN(string_test_115) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += "c"; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += "c"; + eostr1 += "c"; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += "c"; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += "ghijklm"; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) +EOSIO_TEST_END - //// inline void print(eosio::string str) - { - static const string eostr0{""}; - static const string eostr1{"abc"}; - static const string eostr2{"abcdef"}; +//// string& operator+=(const string& rhs) +EOSIO_TEST_BEGIN(string_test_116) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += string{"c"}; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += string{"c"}; + eostr1 += string{"c"}; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += string{"c"}; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += string{"ghijklm"}; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) +EOSIO_TEST_END - CHECK_PRINT( "", [](){ print(eostr0); } ) - CHECK_PRINT( "abc", [](){ print(eostr1); } ) - CHECK_PRINT( "abcdef", [](){ print(eostr2); } ) - } +//// string& operator+=(const string& s) +EOSIO_TEST_BEGIN(string_test_117) + static string eostr0{"a"}; + static string eostr1{"b"}; + CHECK_EQUAL( eostr0.size(), 1 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "ab"), 0 ) +EOSIO_TEST_END - //// friend bool operator< (const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 < eostr0), false ) - CHECK_EQUAL( (eostr1 < eostr1), false ) - CHECK_EQUAL( (eostr0 < eostr1), true ) - } +EOSIO_TEST_BEGIN(string_test_118) + static string eostr0{"abc"}; + static string eostr1{"def"}; + CHECK_EQUAL( eostr0.size(), 3 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 6 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END - //// friend bool operator> (const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 > eostr0), false ) - CHECK_EQUAL( (eostr1 > eostr1), false ) - CHECK_EQUAL( (eostr0 > eostr1), false ) - } +//// inline void print(eosio::string str) +EOSIO_TEST_BEGIN(string_test_119) + static const string eostr0{""}; + static const string eostr1{"abc"}; + static const string eostr2{"abcdef"}; - //// friend bool operator<=(const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 <= eostr0), true ) - CHECK_EQUAL( (eostr1 <= eostr1), true ) - CHECK_EQUAL( (eostr0 <= eostr1), true ) - } + CHECK_PRINT( "", [](){ print(eostr0); } ) + CHECK_PRINT( "abc", [](){ print(eostr1); } ) + CHECK_PRINT( "abcdef", [](){ print(eostr2); } ) +EOSIO_TEST_END - //// friend bool operator>=(const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 >= eostr0), true ) - CHECK_EQUAL( (eostr1 >= eostr1), true ) - CHECK_EQUAL( (eostr0 >= eostr1), false ) - } +//// friend bool operator< (const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_120) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 < eostr0), false ) + CHECK_EQUAL( (eostr1 < eostr1), false ) + CHECK_EQUAL( (eostr0 < eostr1), true ) +EOSIO_TEST_END - //// friend bool operator==(const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 == eostr0), true ) - CHECK_EQUAL( (eostr1 == eostr1), true ) - CHECK_EQUAL( (eostr0 == eostr1), false ) - } +//// friend bool operator> (const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_121) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 > eostr0), false ) + CHECK_EQUAL( (eostr1 > eostr1), false ) + CHECK_EQUAL( (eostr0 > eostr1), false ) +EOSIO_TEST_END - //// friend bool operator!=(const string& lhs, const string& rhs) - { - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 != eostr0), false ) - CHECK_EQUAL( (eostr1 != eostr1), false ) - CHECK_EQUAL( (eostr0 != eostr1), true ) - } +//// friend bool operator<=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_122) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 <= eostr0), true ) + CHECK_EQUAL( (eostr1 <= eostr1), true ) + CHECK_EQUAL( (eostr0 <= eostr1), true ) +EOSIO_TEST_END - //// template - //// DataStream& operator<<(DataStream& ds, const string& str) - //// DataStream& operator>>(DataStream& ds, string& str) - { - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; // Buffer for the datastream to point to - static char buffer[buffer_size]; // Buffer to compare `datastream_buffer` with - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {""}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) - } +//// friend bool operator>=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_123) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 >= eostr0), true ) + CHECK_EQUAL( (eostr1 >= eostr1), true ) + CHECK_EQUAL( (eostr0 >= eostr1), false ) +EOSIO_TEST_END - { - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; - static char buffer[buffer_size]; - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {"a"}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) - } +//// friend bool operator==(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_124) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 == eostr0), true ) + CHECK_EQUAL( (eostr1 == eostr1), true ) + CHECK_EQUAL( (eostr0 == eostr1), false ) +EOSIO_TEST_END - { - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; - static char buffer[buffer_size]; - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {"abcdefghi"}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) - } +//// friend bool operator!=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_125) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 != eostr0), false ) + CHECK_EQUAL( (eostr1 != eostr1), false ) + CHECK_EQUAL( (eostr0 != eostr1), true ) +EOSIO_TEST_END + +//// template +//// DataStream& operator<<(DataStream& ds, const string& str) +//// DataStream& operator>>(DataStream& ds, string& str) +EOSIO_TEST_BEGIN(string_test_126) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; // Buffer for the datastream to point to + static char buffer[buffer_size]; // Buffer to compare `datastream_buffer` with + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {""}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_127) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"a"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_128) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"abcdefghi"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) EOSIO_TEST_END int main(int argc, char* argv[]) { @@ -1501,6 +1500,133 @@ int main(int argc, char* argv[]) { } silence_output(!verbose); - EOSIO_TEST(string_test) + EOSIO_TEST(string_test_1) + EOSIO_TEST(string_test_2) + EOSIO_TEST(string_test_3) + EOSIO_TEST(string_test_4) + EOSIO_TEST(string_test_5) + EOSIO_TEST(string_test_6) + EOSIO_TEST(string_test_7) + EOSIO_TEST(string_test_8) + EOSIO_TEST(string_test_9) + EOSIO_TEST(string_test_10) + EOSIO_TEST(string_test_11) + EOSIO_TEST(string_test_12) + EOSIO_TEST(string_test_13) + EOSIO_TEST(string_test_14) + EOSIO_TEST(string_test_15) + EOSIO_TEST(string_test_16) + EOSIO_TEST(string_test_17) + EOSIO_TEST(string_test_18) + EOSIO_TEST(string_test_19) + EOSIO_TEST(string_test_20) + EOSIO_TEST(string_test_21) + EOSIO_TEST(string_test_22) + EOSIO_TEST(string_test_23) + EOSIO_TEST(string_test_24) + EOSIO_TEST(string_test_25) + EOSIO_TEST(string_test_26) + EOSIO_TEST(string_test_27) + EOSIO_TEST(string_test_28) + EOSIO_TEST(string_test_29) + EOSIO_TEST(string_test_30) + EOSIO_TEST(string_test_31) + EOSIO_TEST(string_test_32) + EOSIO_TEST(string_test_33) + EOSIO_TEST(string_test_34) + EOSIO_TEST(string_test_35) + EOSIO_TEST(string_test_36) + EOSIO_TEST(string_test_37) + EOSIO_TEST(string_test_38) + EOSIO_TEST(string_test_39) + EOSIO_TEST(string_test_40) + EOSIO_TEST(string_test_41) + EOSIO_TEST(string_test_42) + EOSIO_TEST(string_test_43) + EOSIO_TEST(string_test_44) + EOSIO_TEST(string_test_45) + EOSIO_TEST(string_test_46) + EOSIO_TEST(string_test_47) + EOSIO_TEST(string_test_48) + EOSIO_TEST(string_test_49) + EOSIO_TEST(string_test_50) + EOSIO_TEST(string_test_51) + EOSIO_TEST(string_test_52) + EOSIO_TEST(string_test_53) + EOSIO_TEST(string_test_54) + EOSIO_TEST(string_test_55) + EOSIO_TEST(string_test_56) + EOSIO_TEST(string_test_57) + EOSIO_TEST(string_test_58) + EOSIO_TEST(string_test_59) + EOSIO_TEST(string_test_60) + EOSIO_TEST(string_test_61) + EOSIO_TEST(string_test_62) + EOSIO_TEST(string_test_63) + EOSIO_TEST(string_test_64) + EOSIO_TEST(string_test_65) + EOSIO_TEST(string_test_66) + EOSIO_TEST(string_test_67) + EOSIO_TEST(string_test_68) + EOSIO_TEST(string_test_69) + EOSIO_TEST(string_test_70) + EOSIO_TEST(string_test_71) + EOSIO_TEST(string_test_72) + EOSIO_TEST(string_test_73) + EOSIO_TEST(string_test_74) + EOSIO_TEST(string_test_75) + EOSIO_TEST(string_test_76) + EOSIO_TEST(string_test_77) + EOSIO_TEST(string_test_78) + EOSIO_TEST(string_test_79) + EOSIO_TEST(string_test_80) + EOSIO_TEST(string_test_81) + EOSIO_TEST(string_test_82) + EOSIO_TEST(string_test_83) + EOSIO_TEST(string_test_84) + EOSIO_TEST(string_test_85) + EOSIO_TEST(string_test_86) + EOSIO_TEST(string_test_87) + EOSIO_TEST(string_test_88) + EOSIO_TEST(string_test_89) + EOSIO_TEST(string_test_90) + EOSIO_TEST(string_test_91) + EOSIO_TEST(string_test_92) + EOSIO_TEST(string_test_93) + EOSIO_TEST(string_test_94) + EOSIO_TEST(string_test_95) + EOSIO_TEST(string_test_96) + EOSIO_TEST(string_test_97) + EOSIO_TEST(string_test_98) + EOSIO_TEST(string_test_99) + EOSIO_TEST(string_test_100) + EOSIO_TEST(string_test_101) + EOSIO_TEST(string_test_102) + EOSIO_TEST(string_test_103) + EOSIO_TEST(string_test_104) + EOSIO_TEST(string_test_105) + EOSIO_TEST(string_test_106) + EOSIO_TEST(string_test_107) + EOSIO_TEST(string_test_108) + EOSIO_TEST(string_test_109) + EOSIO_TEST(string_test_110) + EOSIO_TEST(string_test_111) + EOSIO_TEST(string_test_112) + EOSIO_TEST(string_test_113) + EOSIO_TEST(string_test_114) + EOSIO_TEST(string_test_115) + EOSIO_TEST(string_test_116) + EOSIO_TEST(string_test_117) + EOSIO_TEST(string_test_118) + EOSIO_TEST(string_test_119) + EOSIO_TEST(string_test_120) + EOSIO_TEST(string_test_121) + EOSIO_TEST(string_test_122) + EOSIO_TEST(string_test_123) + EOSIO_TEST(string_test_124) + EOSIO_TEST(string_test_125) + EOSIO_TEST(string_test_126) + EOSIO_TEST(string_test_127) + EOSIO_TEST(string_test_128) return has_failed(); } From 0b5c7152a06f4bd14a4d1ddf641cffe160132a0e Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 11 Jun 2020 20:37:13 +0300 Subject: [PATCH 343/659] fixes #865 [eosio.cdt:issue:865] Introduce the eosio::check(eosio::has_auth(...)) in the existing how to --- ...to_restrict_access_to_an_action_by_user.md | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 4ec1229724..4002a87446 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -1,13 +1,41 @@ --- -content_title: How to restrict access to an action by a user +content_title: How To Perform Authorization Checks +link_text: How To Perform Authorization Checks --- ## Preconditions -- It is assumed you have the sources for a contract and one of the actions defined is getting as a parameter an account name and it is printing the account name. -To restrict access to the `hi` action, you can do it in two ways: +It is assumed the following: + +1. You have the sources of a contract with one of the actions defined, let's call it `hi` action. +2. The `hi` action has defined one input parameter `user` of type `name`. +3. The `hi` action is printing the name of the `user` account. +4. The `hi` action needs to authorize the `user` account. + +## Authorization Methods + +To restrict access to the `hi` action, you can do it in three ways. + +### 1. Using eosio::check(eosio::has_auth(...)...) + +The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). + +[[info | Error message is custom]] +| Observe that in this case the yielded error message is a custom one and thus it can be used to provide a better experience for the user. + +```cpp +#include + +void hi( name user ) { + check(has_auth(user), "User is not authorized to perform this action."); + print( "Hello, ", name{user} ); +} +``` + +Another example can be found in the [Tic Tac Toe Tutorial](https://developers.eos.io/welcome/latest/tutorials/tic-tac-toe-game-contract/#action-handler---move). + +### 2. Using require_auth -1. Using require_auth The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). ```cpp @@ -17,7 +45,10 @@ void hi( name user ) { } ``` -2. Or using require_auth2 +[[info | Error message is not custom]] +| Note that this time you can not customize the yielded error message, it will be a generic authorization error message. + +### 3. Using require_auth2 The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action and only if the permission used to sign the transaction is the 'active' one. In other words, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. @@ -25,9 +56,10 @@ The below code is enforcing the action `hi` to be executed only by the account t #include void hi( name user ) { - require_auth2(nm.value, "active"_n.value); + require_auth2(user.value, "active"_n.value); print( "Hello, ", name{user} ); } ``` -An example of this contract can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/examples/hello/src/hello.cpp) +[[info | Error message is not custom]] +| Note that this time, as well as previous method, you can not customize the yielded error message, it will be a generic authorization error message. From 516868c14ded9c1ad3436479e78374e02d627c4d Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Thu, 11 Jun 2020 15:03:54 -0400 Subject: [PATCH 344/659] Bump lld --- eosio_llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eosio_llvm b/eosio_llvm index 41c8bc5dee..ca078afbdc 160000 --- a/eosio_llvm +++ b/eosio_llvm @@ -1 +1 @@ -Subproject commit 41c8bc5dee4815a7d213018509eed1eea0f9bf16 +Subproject commit ca078afbdc8bdb966b0f5c3b608553d611524475 From db1f42ff8f2eb37e559d206f6424be8c6ad54177 Mon Sep 17 00:00:00 2001 From: Damon Revoe Date: Thu, 11 Jun 2020 19:29:24 -0400 Subject: [PATCH 345/659] Split string_tests.cpp into two sources Earlier splitting of a single unit test into multiple small tests caused bus error on all platforms. This commit splits the test source into two, which allows the tests to complete without crashing. --- tests/CMakeLists.txt | 6 +- tests/unit/CMakeLists.txt | 3 +- .../{string_tests.cpp => string_tests1.cpp} | 699 ----------------- tests/unit/string_tests2.cpp | 725 ++++++++++++++++++ 4 files changed, 731 insertions(+), 702 deletions(-) rename tests/unit/{string_tests.cpp => string_tests1.cpp} (57%) create mode 100644 tests/unit/string_tests2.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 987ea7b6af..5541502db3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,8 +30,10 @@ add_test( print_tests ${CMAKE_BINARY_DIR}/tests/unit/print_tests ) set_property(TEST print_tests PROPERTY LABELS unit_tests) add_test( serialize_tests ${CMAKE_BINARY_DIR}/tests/unit/serialize_tests ) set_property(TEST serialize_tests PROPERTY LABELS unit_tests) -add_test( string_tests ${CMAKE_BINARY_DIR}/tests/unit/string_tests ) -set_property(TEST string_tests PROPERTY LABELS unit_tests) +add_test( string_tests1 ${CMAKE_BINARY_DIR}/tests/unit/string_tests1 ) +set_property(TEST string_tests1 PROPERTY LABELS unit_tests) +add_test( string_tests2 ${CMAKE_BINARY_DIR}/tests/unit/string_tests2 ) +set_property(TEST string_tests2 PROPERTY LABELS unit_tests) add_test( symbol_tests ${CMAKE_BINARY_DIR}/tests/unit/symbol_tests ) set_property(TEST symbol_tests PROPERTY LABELS unit_tests) add_test( system_tests ${CMAKE_BINARY_DIR}/tests/unit/system_tests ) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index c6f165e2d5..7932679c0f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -11,7 +11,8 @@ add_native_executable( fixed_bytes_tests fixed_bytes_tests.cpp ) add_native_executable( name_tests name_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) add_native_executable( serialize_tests serialize_tests.cpp ) -add_native_executable( string_tests string_tests.cpp ) +add_native_executable( string_tests1 string_tests1.cpp ) +add_native_executable( string_tests2 string_tests2.cpp ) add_native_executable( symbol_tests symbol_tests.cpp ) add_native_executable( system_tests system_tests.cpp ) add_native_executable( rope_tests rope_tests.cpp ) diff --git a/tests/unit/string_tests.cpp b/tests/unit/string_tests1.cpp similarity index 57% rename from tests/unit/string_tests.cpp rename to tests/unit/string_tests1.cpp index 05c0bf646f..351784e80c 100644 --- a/tests/unit/string_tests.cpp +++ b/tests/unit/string_tests1.cpp @@ -858,641 +858,6 @@ EOSIO_TEST_BEGIN(string_test_64) CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo"), 0 ) EOSIO_TEST_END -EOSIO_TEST_BEGIN(string_test_65) - static string eostr{"abcdefg"}; - static const char* null_man{nullptr}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(0, null_man, 1);} ) - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, "ooo", 1);} ) -EOSIO_TEST_END - -//// string& insert(const size_t pos, const string& str) -EOSIO_TEST_BEGIN(string_test_66) - static string eostr{}; - static const string str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_67) - static string eostr{"abc"}; - static const string str{"d"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( eostr.capacity(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_68) - static string eostr{"abc"}; - static const string str{"def"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_69) - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_70) - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(1, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_71) - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(2, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_72) - static string eostr{"iii"}; - static const string str{"ooo"}; - eostr.insert(3, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_73) - static string eostr{"abcdefg"}; - static const string str{"ooo"}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_74) - static string eostr{""}; - static string str{""}; - str += "ooo"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_75) - static string eostr{""}; - eostr += "abc"; - static string str{""}; - str += "d"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_76) - static string eostr{""}; - eostr += "abc"; - static string str{""}; - str += "def"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_77) - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(0, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_78) - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(1, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_79) - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(2, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_80) - static string eostr{""}; - eostr += "iii"; - static string str{""}; - str += "ooo"; - eostr.insert(3, str); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_81) - static string eostr{"abcdefg"}; - static string str{"ooo"}; - CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_82) - static string eostr = "hello"; - eostr.insert(0, "0", 1); /// `_capacity` is now 12; `_begin` now holds `std::unique_ptr` - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "0hello") , 0 ) - - eostr.insert(0, "h", 1); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( eostr.capacity(), 12 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "h0hello") , 0 ) -EOSIO_TEST_END - -//// string& erase(size_t pos = 0, size_t len = npos) -EOSIO_TEST_BEGIN(string_test_83) - static string eostr{"abcdefgh"}; - eostr.erase(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_84) - static string eostr{"abcdefgh"}; - eostr.erase(0); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_85) - static string eostr{"abcdefgh"}; - eostr.erase(0, string::npos); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_86) - static string eostr{"abcdefgh"}; - eostr.erase(1, string::npos); - CHECK_EQUAL( eostr.size(), 1 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_87) - static string eostr{"abcdefgh"}; - eostr.erase(2, string::npos); - CHECK_EQUAL( eostr.size(), 2 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_88) - static string eostr{"abcdefgh"}; - eostr.erase(3, string::npos); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_89) - static string eostr{"abcdefgh"}; - eostr.erase(4, string::npos); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_90) - static string eostr{"abcdefgh"}; - eostr.erase(5, string::npos); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_91) - static string eostr{"abcdefgh"}; - eostr.erase(6, string::npos); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_92) - static string eostr{"abcdefgh"}; - eostr.erase(7, string::npos); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_93) - static string eostr{"abcdefgh"}; - eostr.erase(8, string::npos); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_94) - static string eostr{"abcdefgh"}; - eostr.erase(8, 0); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_95) - static string eostr{"abcdefg"}; - CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_96) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_97) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(0); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_98) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(0, string::npos); - CHECK_EQUAL( eostr.size(), 0 ) - CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_99) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(1, string::npos); - CHECK_EQUAL( eostr.size(), 1 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_100) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(2, string::npos); - CHECK_EQUAL( eostr.size(), 2 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_101) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(3, string::npos); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_102) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(4, string::npos); - CHECK_EQUAL( eostr.size(), 4 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_103) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(5, string::npos); - CHECK_EQUAL( eostr.size(), 5 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_104) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(6, string::npos); - CHECK_EQUAL( eostr.size(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_105) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(7, string::npos); - CHECK_EQUAL( eostr.size(), 7 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_106) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(8, string::npos); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_107) - static string eostr{""}; - eostr += "abcdefgh"; - - eostr.erase(8, 0); - CHECK_EQUAL( eostr.size(), 8 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_108) - static string eostr{"abcdefg"}; - CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) -EOSIO_TEST_END - -//// string& append(const char* str) -EOSIO_TEST_BEGIN(string_test_109) - static string eostr{}; - static const char* str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_110) - static string eostr{"abcdefg"}; - static const char* str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 10 ) - CHECK_EQUAL( eostr.capacity(), 20 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_111) - static string eostr{"abcdefg"}; - static const char* null_man{nullptr}; - CHECK_ASSERT( "eosio::string::append", []() {eostr.append(null_man);} ) -EOSIO_TEST_END - -//// string& append(const string& str) -EOSIO_TEST_BEGIN(string_test_112) - static string eostr{}; - static const string str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 3 ) - CHECK_EQUAL( eostr.capacity(), 6 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_113) - static string eostr{"abcdefg"}; - static const string str{"iii"}; - eostr.append(str); - CHECK_EQUAL( eostr.size(), 10 ) - CHECK_EQUAL( eostr.capacity(), 20 ) - CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) -EOSIO_TEST_END - -//// string& operator+=(const char c) -EOSIO_TEST_BEGIN(string_test_114) - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - - eostr0 += 'c'; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += 'c'; - eostr1 += 'c'; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += 'c'; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) -EOSIO_TEST_END - -//// string& operator+=(const char* rhs) -EOSIO_TEST_BEGIN(string_test_115) - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static string eostr3{"abcdef"}; - - eostr0 += "c"; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += "c"; - eostr1 += "c"; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += "c"; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) - - eostr3 += "ghijklm"; - CHECK_EQUAL( eostr3.size(), 13 ) - CHECK_EQUAL( eostr3.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) -EOSIO_TEST_END - -//// string& operator+=(const string& rhs) -EOSIO_TEST_BEGIN(string_test_116) - static string eostr0{}; - static string eostr1{"a"}; - static string eostr2{"abcdef"}; - static string eostr3{"abcdef"}; - - eostr0 += string{"c"}; - CHECK_EQUAL( eostr0.size(), 1 ) - CHECK_EQUAL( eostr0.capacity(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) - - eostr1 += string{"c"}; - eostr1 += string{"c"}; - CHECK_EQUAL( eostr1.size(), 3 ) - CHECK_EQUAL( eostr1.capacity(), 4 ) - CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) - - eostr2 += string{"c"}; - CHECK_EQUAL( eostr2.size(), 7 ) - CHECK_EQUAL( eostr2.capacity(), 14 ) - CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) - - eostr3 += string{"ghijklm"}; - CHECK_EQUAL( eostr3.size(), 13 ) - CHECK_EQUAL( eostr3.capacity(), 26 ) - CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) -EOSIO_TEST_END - -//// string& operator+=(const string& s) -EOSIO_TEST_BEGIN(string_test_117) - static string eostr0{"a"}; - static string eostr1{"b"}; - CHECK_EQUAL( eostr0.size(), 1 ) - eostr0 += eostr1; - CHECK_EQUAL( eostr0.size(), 2 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "ab"), 0 ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_118) - static string eostr0{"abc"}; - static string eostr1{"def"}; - CHECK_EQUAL( eostr0.size(), 3 ) - eostr0 += eostr1; - CHECK_EQUAL( eostr0.size(), 6 ) - CHECK_EQUAL( strcmp(eostr0.c_str(), "abcdef"), 0 ) -EOSIO_TEST_END - -//// inline void print(eosio::string str) -EOSIO_TEST_BEGIN(string_test_119) - static const string eostr0{""}; - static const string eostr1{"abc"}; - static const string eostr2{"abcdef"}; - - CHECK_PRINT( "", [](){ print(eostr0); } ) - CHECK_PRINT( "abc", [](){ print(eostr1); } ) - CHECK_PRINT( "abcdef", [](){ print(eostr2); } ) -EOSIO_TEST_END - -//// friend bool operator< (const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_120) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 < eostr0), false ) - CHECK_EQUAL( (eostr1 < eostr1), false ) - CHECK_EQUAL( (eostr0 < eostr1), true ) -EOSIO_TEST_END - -//// friend bool operator> (const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_121) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 > eostr0), false ) - CHECK_EQUAL( (eostr1 > eostr1), false ) - CHECK_EQUAL( (eostr0 > eostr1), false ) -EOSIO_TEST_END - -//// friend bool operator<=(const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_122) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 <= eostr0), true ) - CHECK_EQUAL( (eostr1 <= eostr1), true ) - CHECK_EQUAL( (eostr0 <= eostr1), true ) -EOSIO_TEST_END - -//// friend bool operator>=(const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_123) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 >= eostr0), true ) - CHECK_EQUAL( (eostr1 >= eostr1), true ) - CHECK_EQUAL( (eostr0 >= eostr1), false ) -EOSIO_TEST_END - -//// friend bool operator==(const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_124) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 == eostr0), true ) - CHECK_EQUAL( (eostr1 == eostr1), true ) - CHECK_EQUAL( (eostr0 == eostr1), false ) -EOSIO_TEST_END - -//// friend bool operator!=(const string& lhs, const string& rhs) -EOSIO_TEST_BEGIN(string_test_125) - static const string eostr0{"abc"}; - static const string eostr1{"def"}; - CHECK_EQUAL( (eostr0 != eostr0), false ) - CHECK_EQUAL( (eostr1 != eostr1), false ) - CHECK_EQUAL( (eostr0 != eostr1), true ) -EOSIO_TEST_END - -//// template -//// DataStream& operator<<(DataStream& ds, const string& str) -//// DataStream& operator>>(DataStream& ds, string& str) -EOSIO_TEST_BEGIN(string_test_126) - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; // Buffer for the datastream to point to - static char buffer[buffer_size]; // Buffer to compare `datastream_buffer` with - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {""}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_127) - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; - static char buffer[buffer_size]; - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {"a"}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) -EOSIO_TEST_END - -EOSIO_TEST_BEGIN(string_test_128) - static constexpr uint16_t buffer_size{256}; - static char datastream_buffer[buffer_size]{}; - static char buffer[buffer_size]; - static datastream ds{datastream_buffer, buffer_size}; - - ds.seekp(0); - fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); - static const string cstr {"abcdefghi"}; - static string str{}; - ds << cstr; - ds.seekp(0); - ds >> str; - CHECK_EQUAL( cstr, str ) -EOSIO_TEST_END - int main(int argc, char* argv[]) { bool verbose = false; if( argc >= 2 && std::strcmp( argv[1], "-v" ) == 0 ) { @@ -1564,69 +929,5 @@ int main(int argc, char* argv[]) { EOSIO_TEST(string_test_62) EOSIO_TEST(string_test_63) EOSIO_TEST(string_test_64) - EOSIO_TEST(string_test_65) - EOSIO_TEST(string_test_66) - EOSIO_TEST(string_test_67) - EOSIO_TEST(string_test_68) - EOSIO_TEST(string_test_69) - EOSIO_TEST(string_test_70) - EOSIO_TEST(string_test_71) - EOSIO_TEST(string_test_72) - EOSIO_TEST(string_test_73) - EOSIO_TEST(string_test_74) - EOSIO_TEST(string_test_75) - EOSIO_TEST(string_test_76) - EOSIO_TEST(string_test_77) - EOSIO_TEST(string_test_78) - EOSIO_TEST(string_test_79) - EOSIO_TEST(string_test_80) - EOSIO_TEST(string_test_81) - EOSIO_TEST(string_test_82) - EOSIO_TEST(string_test_83) - EOSIO_TEST(string_test_84) - EOSIO_TEST(string_test_85) - EOSIO_TEST(string_test_86) - EOSIO_TEST(string_test_87) - EOSIO_TEST(string_test_88) - EOSIO_TEST(string_test_89) - EOSIO_TEST(string_test_90) - EOSIO_TEST(string_test_91) - EOSIO_TEST(string_test_92) - EOSIO_TEST(string_test_93) - EOSIO_TEST(string_test_94) - EOSIO_TEST(string_test_95) - EOSIO_TEST(string_test_96) - EOSIO_TEST(string_test_97) - EOSIO_TEST(string_test_98) - EOSIO_TEST(string_test_99) - EOSIO_TEST(string_test_100) - EOSIO_TEST(string_test_101) - EOSIO_TEST(string_test_102) - EOSIO_TEST(string_test_103) - EOSIO_TEST(string_test_104) - EOSIO_TEST(string_test_105) - EOSIO_TEST(string_test_106) - EOSIO_TEST(string_test_107) - EOSIO_TEST(string_test_108) - EOSIO_TEST(string_test_109) - EOSIO_TEST(string_test_110) - EOSIO_TEST(string_test_111) - EOSIO_TEST(string_test_112) - EOSIO_TEST(string_test_113) - EOSIO_TEST(string_test_114) - EOSIO_TEST(string_test_115) - EOSIO_TEST(string_test_116) - EOSIO_TEST(string_test_117) - EOSIO_TEST(string_test_118) - EOSIO_TEST(string_test_119) - EOSIO_TEST(string_test_120) - EOSIO_TEST(string_test_121) - EOSIO_TEST(string_test_122) - EOSIO_TEST(string_test_123) - EOSIO_TEST(string_test_124) - EOSIO_TEST(string_test_125) - EOSIO_TEST(string_test_126) - EOSIO_TEST(string_test_127) - EOSIO_TEST(string_test_128) return has_failed(); } diff --git a/tests/unit/string_tests2.cpp b/tests/unit/string_tests2.cpp new file mode 100644 index 0000000000..cd75b80b8d --- /dev/null +++ b/tests/unit/string_tests2.cpp @@ -0,0 +1,725 @@ +/** + * @file + * @copyright defined in eosio.cdt/LICENSE.txt + */ + +#include +#include +#include + +using std::fill; +using std::move; + +using eosio::datastream; +using eosio::string; + +// Definitions found in `eosio.cdt/libraries/eosiolib/core/eosio/string.hpp` + +EOSIO_TEST_BEGIN(string_test_65) + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(0, null_man, 1);} ) + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, "ooo", 1);} ) +EOSIO_TEST_END + +//// string& insert(const size_t pos, const string& str) +EOSIO_TEST_BEGIN(string_test_66) + static string eostr{}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_67) + static string eostr{"abc"}; + static const string str{"d"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_68) + static string eostr{"abc"}; + static const string str{"def"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_69) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_70) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_71) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_72) + static string eostr{"iii"}; + static const string str{"ooo"}; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_73) + static string eostr{"abcdefg"}; + static const string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_74) + static string eostr{""}; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ooo"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_75) + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "d"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "dabc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_76) + static string eostr{""}; + eostr += "abc"; + static string str{""}; + str += "def"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "defabc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_77) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(0, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "oooiii") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_78) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(1, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ioooii") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_79) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(2, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iioooi") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_80) + static string eostr{""}; + eostr += "iii"; + static string str{""}; + str += "ooo"; + eostr.insert(3, str); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iiiooo") , 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_81) + static string eostr{"abcdefg"}; + static string str{"ooo"}; + CHECK_ASSERT( "eosio::string::insert", []() {eostr.insert(-1, str);} ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_82) + static string eostr = "hello"; + eostr.insert(0, "0", 1); /// `_capacity` is now 12; `_begin` now holds `std::unique_ptr` + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "0hello") , 0 ) + + eostr.insert(0, "h", 1); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( eostr.capacity(), 12 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "h0hello") , 0 ) +EOSIO_TEST_END + +//// string& erase(size_t pos = 0, size_t len = npos) +EOSIO_TEST_BEGIN(string_test_83) + static string eostr{"abcdefgh"}; + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_84) + static string eostr{"abcdefgh"}; + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_85) + static string eostr{"abcdefgh"}; + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_86) + static string eostr{"abcdefgh"}; + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_87) + static string eostr{"abcdefgh"}; + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_88) + static string eostr{"abcdefgh"}; + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_89) + static string eostr{"abcdefgh"}; + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_90) + static string eostr{"abcdefgh"}; + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_91) + static string eostr{"abcdefgh"}; + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_92) + static string eostr{"abcdefgh"}; + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_93) + static string eostr{"abcdefgh"}; + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_94) + static string eostr{"abcdefgh"}; + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_95) + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_96) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_97) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(0); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_98) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(0, string::npos); + CHECK_EQUAL( eostr.size(), 0 ) + CHECK_EQUAL( strcmp(eostr.c_str(), ""), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_99) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(1, string::npos); + CHECK_EQUAL( eostr.size(), 1 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "a"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_100) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(2, string::npos); + CHECK_EQUAL( eostr.size(), 2 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "ab"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_101) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(3, string::npos); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abc"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_102) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(4, string::npos); + CHECK_EQUAL( eostr.size(), 4 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcd"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_103) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(5, string::npos); + CHECK_EQUAL( eostr.size(), 5 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcde"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_104) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(6, string::npos); + CHECK_EQUAL( eostr.size(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_105) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(7, string::npos); + CHECK_EQUAL( eostr.size(), 7 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefg"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_106) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(8, string::npos); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_107) + static string eostr{""}; + eostr += "abcdefgh"; + + eostr.erase(8, 0); + CHECK_EQUAL( eostr.size(), 8 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgh"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_108) + static string eostr{"abcdefg"}; + CHECK_ASSERT( "eosio::string::erase", []() {eostr.erase(-1, 1);} ) +EOSIO_TEST_END + +//// string& append(const char* str) +EOSIO_TEST_BEGIN(string_test_109) + static string eostr{}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_110) + static string eostr{"abcdefg"}; + static const char* str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_111) + static string eostr{"abcdefg"}; + static const char* null_man{nullptr}; + CHECK_ASSERT( "eosio::string::append", []() {eostr.append(null_man);} ) +EOSIO_TEST_END + +//// string& append(const string& str) +EOSIO_TEST_BEGIN(string_test_112) + static string eostr{}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 3 ) + CHECK_EQUAL( eostr.capacity(), 6 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "iii"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_113) + static string eostr{"abcdefg"}; + static const string str{"iii"}; + eostr.append(str); + CHECK_EQUAL( eostr.size(), 10 ) + CHECK_EQUAL( eostr.capacity(), 20 ) + CHECK_EQUAL( strcmp(eostr.c_str(), "abcdefgiii"), 0 ) +EOSIO_TEST_END + +//// string& operator+=(const char c) +EOSIO_TEST_BEGIN(string_test_114) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + + eostr0 += 'c'; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += 'c'; + eostr1 += 'c'; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += 'c'; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) +EOSIO_TEST_END + +//// string& operator+=(const char* rhs) +EOSIO_TEST_BEGIN(string_test_115) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += "c"; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += "c"; + eostr1 += "c"; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += "c"; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += "ghijklm"; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) +EOSIO_TEST_END + +//// string& operator+=(const string& rhs) +EOSIO_TEST_BEGIN(string_test_116) + static string eostr0{}; + static string eostr1{"a"}; + static string eostr2{"abcdef"}; + static string eostr3{"abcdef"}; + + eostr0 += string{"c"}; + CHECK_EQUAL( eostr0.size(), 1 ) + CHECK_EQUAL( eostr0.capacity(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "c"), 0 ) + + eostr1 += string{"c"}; + eostr1 += string{"c"}; + CHECK_EQUAL( eostr1.size(), 3 ) + CHECK_EQUAL( eostr1.capacity(), 4 ) + CHECK_EQUAL( strcmp(eostr1.c_str(), "acc"), 0 ) + + eostr2 += string{"c"}; + CHECK_EQUAL( eostr2.size(), 7 ) + CHECK_EQUAL( eostr2.capacity(), 14 ) + CHECK_EQUAL( strcmp(eostr2.c_str(), "abcdefc"), 0 ) + + eostr3 += string{"ghijklm"}; + CHECK_EQUAL( eostr3.size(), 13 ) + CHECK_EQUAL( eostr3.capacity(), 26 ) + CHECK_EQUAL( strcmp(eostr3.c_str(), "abcdefghijklm"), 0 ) +EOSIO_TEST_END + +//// string& operator+=(const string& s) +EOSIO_TEST_BEGIN(string_test_117) + static string eostr0{"a"}; + static string eostr1{"b"}; + CHECK_EQUAL( eostr0.size(), 1 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 2 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "ab"), 0 ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_118) + static string eostr0{"abc"}; + static string eostr1{"def"}; + CHECK_EQUAL( eostr0.size(), 3 ) + eostr0 += eostr1; + CHECK_EQUAL( eostr0.size(), 6 ) + CHECK_EQUAL( strcmp(eostr0.c_str(), "abcdef"), 0 ) +EOSIO_TEST_END + +//// inline void print(eosio::string str) +EOSIO_TEST_BEGIN(string_test_119) + static const string eostr0{""}; + static const string eostr1{"abc"}; + static const string eostr2{"abcdef"}; + + CHECK_PRINT( "", [](){ print(eostr0); } ) + CHECK_PRINT( "abc", [](){ print(eostr1); } ) + CHECK_PRINT( "abcdef", [](){ print(eostr2); } ) +EOSIO_TEST_END + +//// friend bool operator< (const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_120) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 < eostr0), false ) + CHECK_EQUAL( (eostr1 < eostr1), false ) + CHECK_EQUAL( (eostr0 < eostr1), true ) +EOSIO_TEST_END + +//// friend bool operator> (const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_121) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 > eostr0), false ) + CHECK_EQUAL( (eostr1 > eostr1), false ) + CHECK_EQUAL( (eostr0 > eostr1), false ) +EOSIO_TEST_END + +//// friend bool operator<=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_122) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 <= eostr0), true ) + CHECK_EQUAL( (eostr1 <= eostr1), true ) + CHECK_EQUAL( (eostr0 <= eostr1), true ) +EOSIO_TEST_END + +//// friend bool operator>=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_123) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 >= eostr0), true ) + CHECK_EQUAL( (eostr1 >= eostr1), true ) + CHECK_EQUAL( (eostr0 >= eostr1), false ) +EOSIO_TEST_END + +//// friend bool operator==(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_124) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 == eostr0), true ) + CHECK_EQUAL( (eostr1 == eostr1), true ) + CHECK_EQUAL( (eostr0 == eostr1), false ) +EOSIO_TEST_END + +//// friend bool operator!=(const string& lhs, const string& rhs) +EOSIO_TEST_BEGIN(string_test_125) + static const string eostr0{"abc"}; + static const string eostr1{"def"}; + CHECK_EQUAL( (eostr0 != eostr0), false ) + CHECK_EQUAL( (eostr1 != eostr1), false ) + CHECK_EQUAL( (eostr0 != eostr1), true ) +EOSIO_TEST_END + +//// template +//// DataStream& operator<<(DataStream& ds, const string& str) +//// DataStream& operator>>(DataStream& ds, string& str) +EOSIO_TEST_BEGIN(string_test_126) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; // Buffer for the datastream to point to + static char buffer[buffer_size]; // Buffer to compare `datastream_buffer` with + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {""}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_127) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"a"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) +EOSIO_TEST_END + +EOSIO_TEST_BEGIN(string_test_128) + static constexpr uint16_t buffer_size{256}; + static char datastream_buffer[buffer_size]{}; + static char buffer[buffer_size]; + static datastream ds{datastream_buffer, buffer_size}; + + ds.seekp(0); + fill(std::begin(datastream_buffer), std::end(datastream_buffer), 0); + static const string cstr {"abcdefghi"}; + static string str{}; + ds << cstr; + ds.seekp(0); + ds >> str; + CHECK_EQUAL( cstr, str ) +EOSIO_TEST_END + +int main(int argc, char* argv[]) { + bool verbose = false; + if( argc >= 2 && std::strcmp( argv[1], "-v" ) == 0 ) { + verbose = true; + } + silence_output(!verbose); + + EOSIO_TEST(string_test_65) + EOSIO_TEST(string_test_66) + EOSIO_TEST(string_test_67) + EOSIO_TEST(string_test_68) + EOSIO_TEST(string_test_69) + EOSIO_TEST(string_test_70) + EOSIO_TEST(string_test_71) + EOSIO_TEST(string_test_72) + EOSIO_TEST(string_test_73) + EOSIO_TEST(string_test_74) + EOSIO_TEST(string_test_75) + EOSIO_TEST(string_test_76) + EOSIO_TEST(string_test_77) + EOSIO_TEST(string_test_78) + EOSIO_TEST(string_test_79) + EOSIO_TEST(string_test_80) + EOSIO_TEST(string_test_81) + EOSIO_TEST(string_test_82) + EOSIO_TEST(string_test_83) + EOSIO_TEST(string_test_84) + EOSIO_TEST(string_test_85) + EOSIO_TEST(string_test_86) + EOSIO_TEST(string_test_87) + EOSIO_TEST(string_test_88) + EOSIO_TEST(string_test_89) + EOSIO_TEST(string_test_90) + EOSIO_TEST(string_test_91) + EOSIO_TEST(string_test_92) + EOSIO_TEST(string_test_93) + EOSIO_TEST(string_test_94) + EOSIO_TEST(string_test_95) + EOSIO_TEST(string_test_96) + EOSIO_TEST(string_test_97) + EOSIO_TEST(string_test_98) + EOSIO_TEST(string_test_99) + EOSIO_TEST(string_test_100) + EOSIO_TEST(string_test_101) + EOSIO_TEST(string_test_102) + EOSIO_TEST(string_test_103) + EOSIO_TEST(string_test_104) + EOSIO_TEST(string_test_105) + EOSIO_TEST(string_test_106) + EOSIO_TEST(string_test_107) + EOSIO_TEST(string_test_108) + EOSIO_TEST(string_test_109) + EOSIO_TEST(string_test_110) + EOSIO_TEST(string_test_111) + EOSIO_TEST(string_test_112) + EOSIO_TEST(string_test_113) + EOSIO_TEST(string_test_114) + EOSIO_TEST(string_test_115) + EOSIO_TEST(string_test_116) + EOSIO_TEST(string_test_117) + EOSIO_TEST(string_test_118) + EOSIO_TEST(string_test_119) + EOSIO_TEST(string_test_120) + EOSIO_TEST(string_test_121) + EOSIO_TEST(string_test_122) + EOSIO_TEST(string_test_123) + EOSIO_TEST(string_test_124) + EOSIO_TEST(string_test_125) + EOSIO_TEST(string_test_126) + EOSIO_TEST(string_test_127) + EOSIO_TEST(string_test_128) + return has_failed(); +} From 28a905da7557d7679d9bd05b45042cac31ae45d5 Mon Sep 17 00:00:00 2001 From: Damon Revoe Date: Thu, 11 Jun 2020 19:39:29 -0400 Subject: [PATCH 346/659] Compile unit tests with -fno-clf-aa Per request on the pull request --- tests/unit/CMakeLists.txt | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 7932679c0f..fe4a528406 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -3,22 +3,27 @@ cmake_minimum_required(VERSION 3.5) list( APPEND CMAKE_MODULE_PATH ${EOSIO_CDT_BIN} ) include( EosioCDTMacros ) -add_native_executable( asset_tests asset_tests.cpp ) -add_native_executable( binary_extension_tests binary_extension_tests.cpp ) -add_native_executable( crypto_tests crypto_tests.cpp ) -add_native_executable( datastream_tests datastream_tests.cpp ) -add_native_executable( fixed_bytes_tests fixed_bytes_tests.cpp ) -add_native_executable( name_tests name_tests.cpp ) -add_native_executable( rope_tests rope_tests.cpp ) -add_native_executable( serialize_tests serialize_tests.cpp ) -add_native_executable( string_tests1 string_tests1.cpp ) -add_native_executable( string_tests2 string_tests2.cpp ) -add_native_executable( symbol_tests symbol_tests.cpp ) -add_native_executable( system_tests system_tests.cpp ) -add_native_executable( rope_tests rope_tests.cpp ) -add_native_executable( print_tests print_tests.cpp ) -add_native_executable( time_tests time_tests.cpp ) -add_native_executable( varint_tests varint_tests.cpp ) +macro(add_cdt_unit_test TEST_NAME) + add_native_executable(${TEST_NAME} ${TEST_NAME}.cpp) + target_compile_options(${TEST_NAME} PRIVATE -fno-cfl-aa) +endmacro() + +add_cdt_unit_test(asset_tests) +add_cdt_unit_test(binary_extension_tests) +add_cdt_unit_test(crypto_tests) +add_cdt_unit_test(datastream_tests) +add_cdt_unit_test(fixed_bytes_tests) +add_cdt_unit_test(name_tests) +add_cdt_unit_test(rope_tests) +add_cdt_unit_test(serialize_tests) +add_cdt_unit_test(string_tests1) +add_cdt_unit_test(string_tests2) +add_cdt_unit_test(symbol_tests) +add_cdt_unit_test(system_tests) +add_cdt_unit_test(rope_tests) +add_cdt_unit_test(print_tests) +add_cdt_unit_test(time_tests) +add_cdt_unit_test(varint_tests) target_compile_options( rope_tests PUBLIC -g ) add_subdirectory(test_contracts) From 64b74c9c57d151359c47e665f8ce9a0fd02e6630 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 13:32:40 +0300 Subject: [PATCH 347/659] fixes #866 [eosio.cdt:issue:866] Corrections are needed on the best practices, securing your contract --- .../05_securing_your_contract.md | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md index 122e5c52d7..a69c136060 100644 --- a/docs/05_best-practices/05_securing_your_contract.md +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -2,16 +2,35 @@ content_title: Securing your contract --- -These are basic recommendations that should be the foundation of securing your smart contract: +## Basic Recommendations -1. The master git branch has the `has_auth`, `require_auth`, `require_auth2` and `require_recipient` methods available in the EOSIO library. They can be found in detail [here](https://eosio.github.io/eosio.cdt/1.6.0-rc1/group__action.html#function-requirerecipient) and implemented [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L144) (they end up calling the methods implemented in the `apply_context` class). +The following are basic recommendations which can be the foundation of securing your smart contract. -2. Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. +### 1. Authorization Checks -3. Have a solid and comprehensive development process that includes security considerations from day one of the product planning and development. +The following methods are available in the `EOSIO` library and they can be used to implemented authorization checks in your smart contracts: -4. Test your smart contracts with every update announced for the blockchain you have deployed to. To ease your work, automate the testing as much as possible so you can run them often, and improve them periodically. +- [`has_auth`](../group__action/#function-has_auth) +- [`require_auth`](../group__action/#function-require_auth) +- [`require_auth2`](../how-to-guides/authorization/how_to_restrict_access_to_an_action_by_user/#3-using-require_auth2) +- [`require_recipient`](../group__action/#function-require_recipient) -5. Conduct independent smart contract audits, at least two from different organizations. +### 2. Resource Management -6. Host periodic bug bounties on your smart contracts and keep a continuous commitment to reward real security problems reported at any time. \ No newline at end of file +Understand how each of your contracts' actions is impacting the RAM, CPU, and NET consumption, and which account ends up paying for these resources. + +### 3. Secure by Default + +Have a solid and comprehensive development process that includes security considerations from day one of the product planning and development. + +### 4. Continuous Integration And Continuous Delivery + +Test your smart contracts with every update announced for the blockchain you have deployed to. To ease your work, automate the testing as much as possible so you can run them often, and improve them periodically. + +### 5. Security Audits + +Conduct independent smart contract audits, at least two from different organizations. + +### 6. Bug Bounties + +Host periodic bug bounties on your smart contracts and keep a continuous commitment to reward real security problems reported at any time. From eb6aac120b2447ec3a00a7572971909127341f99 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 13:40:56 +0300 Subject: [PATCH 348/659] fixes #871 "for the Storage usage of the updated row" lowercase inconsistent --- libraries/eosiolib/contracts/eosio/multi_index.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/multi_index.hpp b/libraries/eosiolib/contracts/eosio/multi_index.hpp index f66c39f29b..bdd7c625b0 100644 --- a/libraries/eosiolib/contracts/eosio/multi_index.hpp +++ b/libraries/eosiolib/contracts/eosio/multi_index.hpp @@ -1571,7 +1571,7 @@ class multi_index * @ingroup multiindex * * @param itr - an iterator pointing to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row + * @param payer - account name of the payer for the storage usage of the updated row * @param updater - lambda function that updates the target object * * @pre itr points to an existing element @@ -1618,7 +1618,7 @@ class multi_index * @ingroup multiindex * * @param obj - a reference to the object to be updated - * @param payer - account name of the payer for the Storage usage of the updated row + * @param payer - account name of the payer for the storage usage of the updated row * @param updater - lambda function that updates the target object * * @pre obj is an existing object in the table From 96b3eba8bd43fbdc33494ea3c15e48ffdd7cf8aa Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 14:10:41 +0300 Subject: [PATCH 349/659] fixes #877 delete duplicated lines in eosio::datastream class documentation --- libraries/eosiolib/core/eosio/datastream.hpp | 45 +------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/libraries/eosiolib/core/eosio/datastream.hpp b/libraries/eosiolib/core/eosio/datastream.hpp index acbdbf3b47..924827148e 100644 --- a/libraries/eosiolib/core/eosio/datastream.hpp +++ b/libraries/eosiolib/core/eosio/datastream.hpp @@ -88,7 +88,6 @@ class datastream { /** * Writes a byte into the stream * - * @brief Writes a byte into the stream * @param c byte to write * @return true */ @@ -102,7 +101,6 @@ class datastream { /** * Reads a byte from the stream * - * @brief Reads a byte from the stream * @param c - The reference to destination byte * @return true */ @@ -111,7 +109,6 @@ class datastream { /** * Reads a byte from the stream * - * @brief Reads a byte from the stream * @param c - The reference to destination byte * @return true */ @@ -126,7 +123,6 @@ class datastream { /** * Retrieves the current position of the stream * - * @brief Retrieves the current position of the stream * @return T - The current position of the stream */ T pos()const { return _pos; } @@ -135,7 +131,6 @@ class datastream { /** * Sets the position within the current stream * - * @brief Sets the position within the current stream * @param p - The offset relative to the origin * @return true if p is within the range * @return false if p is not within the rawnge @@ -145,7 +140,6 @@ class datastream { /** * Gets the position within the current stream * - * @brief Gets the position within the current stream * @return p - The position within the current stream */ inline size_t tellp()const { return size_t(_pos - _start); } @@ -153,27 +147,20 @@ class datastream { /** * Returns the number of remaining bytes that can be read/skipped * - * @brief Returns the number of remaining bytes that can be read/skipped * @return size_t - The number of remaining bytes */ inline size_t remaining()const { return _end - _pos; } private: /** * The start position of the buffer - * - * @brief The start position of the buffer */ T _start; /** * The current position of the buffer - * - * @brief The current position of the buffer */ T _pos; /** * The end position of the buffer - * - * @brief The end position of the buffer */ T _end; }; @@ -224,7 +211,6 @@ class datastream { /** * Set new size * - * @brief Set new size * @param p - The new size * @return true */ @@ -454,7 +440,6 @@ inline datastream& operator<<(datastream& ds, const bool& d) { /** * Deserialize a bool from a stream * - * @brief Deserialize a bool * @param ds - The stream to read * @param d - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -524,7 +509,6 @@ datastream& operator << ( datastream& ds, const std::array& /** * Deserialize a fixed size std::array * - * @brief Deserialize a fixed size std::array * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -543,7 +527,6 @@ namespace _datastream_detail { /** * Check if type T is a pointer * - * @brief Check if type T is a pointer * @tparam T - The type to be checked * @return true if T is a pointer * @return false otherwise @@ -558,7 +541,6 @@ namespace _datastream_detail { /** * Check if type T is a primitive type * - * @brief Check if type T is a primitive type * @tparam T - The type to be checked * @return true if T is a primitive type * @return false otherwise @@ -572,7 +554,6 @@ namespace _datastream_detail { /* * Check if type T is a specialization of datastream * - * @brief Check if type T is a datastream * @tparam T - The type to be checked */ template @@ -582,9 +563,9 @@ namespace _datastream_detail { } /** - * Pointer should not be serialized, so this function will always throws an error + * Deserialize a pointer * - * @brief Deserialize a a pointer + * @brief Pointer should not be serialized, so this function will always throws an error * @param ds - The stream to read * @tparam Stream - Type of datastream buffer * @tparam T - Type of the pointer @@ -600,7 +581,6 @@ datastream& operator >> ( datastream& ds, T ) { /** * Serialize a fixed size C array of non-primitive and non-pointer type * - * @brief Serialize a fixed size C array of non-primitive and non-pointer type * @param ds - The stream to write * @param v - The value to serialize * @tparam Stream - Type of datastream buffer @@ -620,7 +600,6 @@ datastream& operator << ( datastream& ds, const T (&v)[N] ) { /** * Serialize a fixed size C array of primitive type * - * @brief Serialize a fixed size C array of primitive type * @param ds - The stream to write * @param v - The value to serialize * @tparam Stream - Type of datastream buffer @@ -638,7 +617,6 @@ datastream& operator << ( datastream& ds, const T (&v)[N] ) { /** * Deserialize a fixed size C array of non-primitive and non-pointer type * - * @brief Deserialize a fixed size C array of non-primitive and non-pointer type * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam T - Type of the object contained in the array @@ -661,7 +639,6 @@ datastream& operator >> ( datastream& ds, T (&v)[N] ) { /** * Deserialize a fixed size C array of primitive type * - * @brief Deserialize a fixed size C array of primitive type * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam T - Type of the object contained in the array @@ -682,7 +659,6 @@ datastream& operator >> ( datastream& ds, T (&v)[N] ) { /** * Serialize a vector of char * - * @brief Serialize a vector of char * @param ds - The stream to write * @param v - The value to serialize * @tparam Stream - Type of datastream buffer @@ -698,7 +674,6 @@ datastream& operator << ( datastream& ds, const std::vector& operator << ( datastream& ds, const std::vector& /** * Deserialize a vector of char * - * @brief Deserialize a vector of char * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -734,7 +708,6 @@ datastream& operator >> ( datastream& ds, std::vector& v ) /** * Deserialize a vector * - * @brief Deserialize a vector * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -754,7 +727,6 @@ datastream& operator >> ( datastream& ds, std::vector& v ) { /** * Serialize a set * - * @brief Serialize a set * @param ds - The stream to write * @param s - The value to serialize * @tparam Stream - Type of datastream buffer @@ -774,7 +746,6 @@ datastream& operator << ( datastream& ds, const std::set& s ) /** * Deserialize a set * - * @brief Deserialize a set * @param ds - The stream to read * @param s - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -797,7 +768,6 @@ datastream& operator >> ( datastream& ds, std::set& s ) { /** * Serialize a map * - * @brief Serialize a map * @param ds - The stream to write * @param m - The value to serialize * @tparam Stream - Type of datastream buffer @@ -817,7 +787,6 @@ datastream& operator << ( datastream& ds, const std::map& m /** * Deserialize a map * - * @brief Deserialize a map * @param ds - The stream to read * @param m - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -841,7 +810,6 @@ datastream& operator >> ( datastream& ds, std::map& m ) { /** * Serialize a tuple * - * @brief Serialize a tuple * @param ds - The stream to write * @param t - The value to serialize * @tparam Stream - Type of datastream buffer @@ -859,7 +827,6 @@ datastream& operator<<( datastream& ds, const std::tuple& operator>>( datastream& ds, std::tuple& t ) /** * Serialize a class * - * @brief Serialize a class * @param ds - The stream to write * @param v - The value to serialize * @tparam DataStream - Type of datastream @@ -895,7 +861,6 @@ DataStream& operator<<( DataStream& ds, const T& v ) { /** * Deserialize a class * - * @brief Deserialize a class * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam DataStream - Type of datastream @@ -913,7 +878,6 @@ DataStream& operator>>( DataStream& ds, T& v ) { /** * Serialize a primitive type * - * @brief Serialize a primitive type * @param ds - The stream to write * @param v - The value to serialize * @tparam Stream - Type of datastream buffer @@ -929,7 +893,6 @@ datastream& operator<<( datastream& ds, const T& v ) { /** * Deserialize a primitive type * - * @brief Deserialize a primitive type * @param ds - The stream to read * @param v - The destination for deserialized value * @tparam Stream - Type of datastream buffer @@ -946,7 +909,6 @@ datastream& operator>>( datastream& ds, T& v ) { * Unpack data inside a fixed size buffer as T * * @ingroup datastream - * @brief Unpack data inside a fixed size buffer as T * @tparam T - Type of the unpacked data * @param buffer - Pointer to the buffer * @param len - Length of the buffer @@ -964,7 +926,6 @@ T unpack( const char* buffer, size_t len ) { * Unpack data inside a variable size buffer as T * * @ingroup datastream - * @brief Unpack data inside a variable size buffer as T * @tparam T - Type of the unpacked data * @param bytes - Buffer * @return T - The unpacked data @@ -978,7 +939,6 @@ T unpack( const std::vector& bytes ) { * Get the size of the packed data * * @ingroup datastream - * @brief Get the size of the packed data * @tparam T - Type of the data to be packed * @param value - Data to be packed * @return size_t - Size of the packed data @@ -994,7 +954,6 @@ size_t pack_size( const T& value ) { * Get packed data * * @ingroup datastream - * @brief Get packed data * @tparam T - Type of the data to be packed * @param value - Data to be packed * @return bytes - The packed data From efef73e69989c998cfa43d464101282b8419c60b Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 14:42:48 +0300 Subject: [PATCH 350/659] fixes #888 [docs] Suggestion / Change Request for singleton example and docs --- .../how-to-define-a-singleton.md | 36 +++++++++---------- .../include/singleton_example.hpp | 6 ++-- .../src/singleton_example.cpp | 6 +--- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 4729372b53..66d3cb0e9b 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -2,7 +2,7 @@ content_title: How to define a singleton --- -To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`, follow the steps below: +To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `test_table`, follow the steps below: 1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage ``` @@ -13,29 +13,29 @@ using namespace eosio; 2. Define the data structure for the multi index table ```cpp -struct [[eosio::table]] testtable { +struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; }; ``` -3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `testtable` data structure defined above +3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `test_table` data structure defined above ```diff -struct [[eosio::table]] testtable { +struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; }; -+using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; ++using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; ``` 4. Define the singleton table instance declared as a data member of type `singleton_type` defined in the privious step ```diff -struct [[eosio::table]] testtable { +struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; }; -using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; +using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; +singleton_type singleton_instance; ``` @@ -63,17 +63,20 @@ class [[eosio::contract]] singleton_example : public contract { singleton_example( name receiver, name code, datastream ds ) : contract(receiver, code, ds), singleton_instance(receiver, receiver.value) - { } + {} - [[eosio::action]] void set( name user, uint64_t value ); - [[eosio::action]] void get( ); + [[eosio::action]] + void set( name user, uint64_t value ); + [[eosio::action]] + void get( ); - struct [[eosio::table]] testtable { + struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; - } tt; + uint64_t primary_key() const { return primary_value.value; } + } test_table_instance; - using singleton_type = eosio::singleton<"testsingletona"_n, testtable>; + using singleton_type = eosio::singleton<"test_table"_n, test_table>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; @@ -88,11 +91,7 @@ __singleton_example.cpp__ #include [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - if (!singleton_instance.exists()) - { - singleton_instance.get_or_create(user, tt); - } - auto entry_stored = singleton_instance.get(); + auto entry_stored = singleton_instance.get_or_create(user, test_table_instance); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); @@ -111,6 +110,5 @@ __singleton_example.cpp__ } ``` - [[Info | Full example location]] | A full example project demonstrating the instantiation and usage of singleton can be found [here](https://github.com/EOSIO/eosio.cdt/tree/master/examples/singleton_example). diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index 8b67639c62..d82cb52628 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -15,13 +15,13 @@ class [[eosio::contract]] singleton_example : public contract { [[eosio::action]] void get( ); - struct [[eosio::table]] testtable { + struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; uint64_t primary_key() const { return primary_value.value; } - } tt; + } test_table_instance; - using singleton_type = eosio::singleton<"testtable"_n, testtable>; + using singleton_type = eosio::singleton<"test_table"_n, test_table>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp index 4e896bb25a..bc7fd854f3 100644 --- a/examples/singleton_example/src/singleton_example.cpp +++ b/examples/singleton_example/src/singleton_example.cpp @@ -2,11 +2,7 @@ [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - if (!singleton_instance.exists()) - { - singleton_instance.get_or_create(user, tt); - } - auto entry_stored = singleton_instance.get(); + auto entry_stored = singleton_instance.get_or_create(user, test_table_instance); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); From 92e07d6036ea63ec31cd64f044d1929a15989308 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 14:48:41 +0300 Subject: [PATCH 351/659] correct name for type --- .../02_multi-index/how-to-define-a-singleton.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 66d3cb0e9b..b62a229fb7 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -76,7 +76,7 @@ class [[eosio::contract]] singleton_example : public contract { uint64_t primary_key() const { return primary_value.value; } } test_table_instance; - using singleton_type = eosio::singleton<"test_table"_n, test_table>; + using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; From 9725bdfe8ceaadbbc70d36ed210668bc71b9ce06 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 12 Jun 2020 11:55:12 -0400 Subject: [PATCH 352/659] Remove some unnecessary make_prefix calls --- libraries/eosiolib/contracts/eosio/key_value.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/eosiolib/contracts/eosio/key_value.hpp b/libraries/eosiolib/contracts/eosio/key_value.hpp index a57d69d4b7..91f0e78697 100644 --- a/libraries/eosiolib/contracts/eosio/key_value.hpp +++ b/libraries/eosiolib/contracts/eosio/key_value.hpp @@ -564,7 +564,7 @@ class kv_table { T old_value; auto primary_key = primary_index->get_key(value); - auto tbl_key = table_key(make_prefix(table_name, primary_index->index_name), primary_key); + auto tbl_key = table_key(primary_index->prefix, primary_key); auto primary_key_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), value_size); if (primary_key_found) { @@ -579,7 +579,7 @@ class kv_table { } for (const auto& idx : secondary_indices) { - auto sec_tbl_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(value)); + auto sec_tbl_key = table_key(idx->prefix, idx->get_key(value)); auto sec_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), value_size); if (!primary_key_found) { @@ -597,7 +597,7 @@ class kv_table { free(buffer); } } else { - auto old_sec_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(old_value)); + auto old_sec_key = table_key(idx->prefix, idx->get_key(old_value)); internal_use_do_not_use::kv_erase(db_name, contract_name.value, old_sec_key.data(), old_sec_key.size()); internal_use_do_not_use::kv_set(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size(), tbl_key.data(), tbl_key.size()); } @@ -627,7 +627,7 @@ class kv_table { uint32_t value_size; auto primary_key = primary_index->get_key(value); - auto tbl_key = table_key(make_prefix(table_name, primary_index->index_name), primary_key); + auto tbl_key = table_key(primary_index->prefix, primary_key); auto primary_key_found = internal_use_do_not_use::kv_get(db_name, contract_name.value, tbl_key.data(), tbl_key.size(), value_size); if (!primary_key_found) { @@ -635,7 +635,7 @@ class kv_table { } for (const auto& idx : secondary_indices) { - auto sec_tbl_key = table_key(make_prefix(table_name, idx->index_name), idx->get_key(value)); + auto sec_tbl_key = table_key(idx->prefix, idx->get_key(value)); internal_use_do_not_use::kv_erase(db_name, contract_name.value, sec_tbl_key.data(), sec_tbl_key.size()); } From 077c930c53374fd170605ca7bf925dda41750076 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Fri, 12 Jun 2020 11:56:56 -0400 Subject: [PATCH 353/659] Cleanup --- libraries/eosiolib/core/eosio/check.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/eosiolib/core/eosio/check.hpp b/libraries/eosiolib/core/eosio/check.hpp index 9f4b1738fe..e48b36c0a1 100644 --- a/libraries/eosiolib/core/eosio/check.hpp +++ b/libraries/eosiolib/core/eosio/check.hpp @@ -4,7 +4,6 @@ */ #pragma once -//#include #include #include From eef570aec82fec1059f95b38f6c36bc2c548e56f Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 21:21:22 +0300 Subject: [PATCH 354/659] updates based on code PR review comments --- docs/05_best-practices/09_deferred_transactions.md | 4 ++-- .../how_to_restrict_access_to_an_action_by_user.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/05_best-practices/09_deferred_transactions.md b/docs/05_best-practices/09_deferred_transactions.md index c2d4a7eb11..7866fed4cd 100644 --- a/docs/05_best-practices/09_deferred_transactions.md +++ b/docs/05_best-practices/09_deferred_transactions.md @@ -6,7 +6,7 @@ Deferred communication conceptually takes the form of action notifications sent As already mentioned, deferred communication will get scheduled later at the producer's discretion. From the perspective of the originating transaction, i.e., the transaction that creates the deferred transaction, it can only determine whether the create request was submitted successfully or whether it failed (if it fails, it will fail immediately). Deferred transactions carry the authority of the contract that sends them. A transaction can cancel a deferred transaction. -Because all of the above it is not recommended to use `deferred transactions`. - [[warning | Deferred Transactions Are Deprecated]] | As of [EOSIO 2.0 RC1](https://github.com/EOSIO/eos/releases/tag/v2.0.0-rc1) deferred transactions are deprecated. + +Due to the above described behaviors it is not recommended to use `deferred transactions`. diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 4002a87446..3797a7ce61 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -5,7 +5,7 @@ link_text: How To Perform Authorization Checks ## Preconditions -It is assumed the following: +The following conditions are assumed: 1. You have the sources of a contract with one of the actions defined, let's call it `hi` action. 2. The `hi` action has defined one input parameter `user` of type `name`. From 5cbd7862040c7654f68734bbe6f4f44415c2c512 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 12 Jun 2020 22:08:13 +0300 Subject: [PATCH 355/659] got rid of the gerunds (-ing verb terminations) --- .../05_best-practices/05_securing_your_contract.md | 2 +- .../how_to_restrict_access_to_an_action_by_user.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/05_best-practices/05_securing_your_contract.md b/docs/05_best-practices/05_securing_your_contract.md index a69c136060..54a5db5ee5 100644 --- a/docs/05_best-practices/05_securing_your_contract.md +++ b/docs/05_best-practices/05_securing_your_contract.md @@ -4,7 +4,7 @@ content_title: Securing your contract ## Basic Recommendations -The following are basic recommendations which can be the foundation of securing your smart contract. +The following are basic recommendations which can be the foundation for securing your smart contract. ### 1. Authorization Checks diff --git a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md index 3797a7ce61..6e25e60c0f 100644 --- a/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md +++ b/docs/06_how-to-guides/05_authorization/how_to_restrict_access_to_an_action_by_user.md @@ -9,16 +9,16 @@ The following conditions are assumed: 1. You have the sources of a contract with one of the actions defined, let's call it `hi` action. 2. The `hi` action has defined one input parameter `user` of type `name`. -3. The `hi` action is printing the name of the `user` account. +3. The `hi` action prints the name of the `user` account. 4. The `hi` action needs to authorize the `user` account. ## Authorization Methods To restrict access to the `hi` action, you can do it in three ways. -### 1. Using eosio::check(eosio::has_auth(...)...) +### 1. Use eosio::check(eosio::has_auth(...)...) -The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). +The below code enforces the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account uses to sign the transaction (e.g. owner, active, code). [[info | Error message is custom]] | Observe that in this case the yielded error message is a custom one and thus it can be used to provide a better experience for the user. @@ -34,9 +34,9 @@ void hi( name user ) { Another example can be found in the [Tic Tac Toe Tutorial](https://developers.eos.io/welcome/latest/tutorials/tic-tac-toe-game-contract/#action-handler---move). -### 2. Using require_auth +### 2. Use require_auth -The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account is using to sign the transaction (e.g. owner, active, code). +The below code enforces the action `hi` to be executed only by the account that is sent as parameter to the action, no matter what permission the account uses to sign the transaction (e.g. owner, active, code). ```cpp void hi( name user ) { @@ -48,9 +48,9 @@ void hi( name user ) { [[info | Error message is not custom]] | Note that this time you can not customize the yielded error message, it will be a generic authorization error message. -### 3. Using require_auth2 +### 3. Use require_auth2 -The below code is enforcing the action `hi` to be executed only by the account that is sent as parameter to the action and only if the permission used to sign the transaction is the 'active' one. In other words, if the same user is signing the transaction with a different permission (e.g. code, owner) the execution of the action is halted. +The below code is enforces the action `hi` to be executed only by the account that is sent as parameter to the action and only if the permission used to sign the transaction is the 'active' one. In other words, if the same user uses the transaction with a different permission (e.g. code, owner) the execution of the action is halted. ```cpp #include From 3c56e6bba4bead7f0f920afe003dadce5ceb1b1b Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 16 Jun 2020 11:58:27 +0300 Subject: [PATCH 356/659] correct name, it can't have underscores --- examples/singleton_example/include/singleton_example.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index d82cb52628..fdf5d8987d 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -21,7 +21,7 @@ class [[eosio::contract]] singleton_example : public contract { uint64_t primary_key() const { return primary_value.value; } } test_table_instance; - using singleton_type = eosio::singleton<"test_table"_n, test_table>; + using singleton_type = eosio::singleton<"testtable"_n, test_table>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; From 89d88ea7e6d044ed832ed4912073a0e5294903b5 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 16 Jun 2020 12:04:39 +0300 Subject: [PATCH 357/659] correct name, it has to be smaller than 13 chars --- .../02_multi-index/how-to-define-a-singleton.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index b62a229fb7..746f15fa55 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -19,13 +19,13 @@ struct [[eosio::table]] test_table { }; ``` -3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testsingletona"` and the `test_table` data structure defined above +3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testtable"`, which has to respect the EOSIO account name restrictions, and the `test_table` data structure defined above ```diff struct [[eosio::table]] test_table { name primary_value; uint64_t secondary_value; }; -+using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; ++using singleton_type = eosio::singleton<"testtable"_n, test_table>; ``` 4. Define the singleton table instance declared as a data member of type `singleton_type` defined in the privious step @@ -35,11 +35,11 @@ struct [[eosio::table]] test_table { uint64_t secondary_value; }; -using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; +using singleton_type = eosio::singleton<"testtable"_n, test_table>; +singleton_type singleton_instance; ``` -5. Instantiate the data member `singleton_instance` by passing to its constructor the `receiver` and the `code` (in this case `receiver.value`) parameters; these two combined with "testsingletona" provide access to the partition of the RAM cache used by this singleton. In this example you will initialize the `singleton_instance` data member in the smart contract constructor, see below: +5. Instantiate the data member `singleton_instance` by passing to its constructor the `receiver` and the `code` (in this case `receiver.value`) parameters; these two combined with "testtable" provide access to the partition of the RAM cache used by this singleton. In this example you will initialize the `singleton_instance` data member in the smart contract constructor, see below: ```diff // singleton contract constructor singleton_example( name receiver, name code, datastream ds ) : @@ -76,7 +76,7 @@ class [[eosio::contract]] singleton_example : public contract { uint64_t primary_key() const { return primary_value.value; } } test_table_instance; - using singleton_type = eosio::singleton<"testsingletona"_n, test_table>; + using singleton_type = eosio::singleton<"testtable"_n, test_table>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; From a8db6fad0cf5da448b58dc1a4a90d878de28e4c0 Mon Sep 17 00:00:00 2001 From: Emil Guseynov Date: Tue, 16 Jun 2020 14:19:49 +0300 Subject: [PATCH 358/659] Add missing \n --- tools/include/eosio/codegen.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/include/eosio/codegen.hpp b/tools/include/eosio/codegen.hpp index 7b24f9a7a9..c23424a471 100644 --- a/tools/include/eosio/codegen.hpp +++ b/tools/include/eosio/codegen.hpp @@ -405,6 +405,7 @@ namespace eosio { namespace cdt { } // generate apply stub with abi std::stringstream ss; + ss << "\n"; ss << "extern \"C\" {\n"; ss << "__attribute__((eosio_wasm_import))\n"; ss << "void eosio_assert_code(uint32_t, uint64_t);"; From bbb85666838e33688ffe0d25cd9eb60aff2e5ebe Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 17 Jun 2020 15:04:54 -0400 Subject: [PATCH 359/659] Fix duplicate symbol error with hana --- libraries/boost/include/boost/hana/functional/curry.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/boost/include/boost/hana/functional/curry.hpp b/libraries/boost/include/boost/hana/functional/curry.hpp index 74ec09459a..8d98b10fab 100644 --- a/libraries/boost/include/boost/hana/functional/curry.hpp +++ b/libraries/boost/include/boost/hana/functional/curry.hpp @@ -116,7 +116,7 @@ BOOST_HANA_NAMESPACE_BEGIN constexpr make_curry_t curry_or_call{}; template <> - constexpr auto curry_or_call<0> = apply; + inline constexpr auto curry_or_call<0> = apply; } template From 96b4ad865a5f824dfe690e08ecf61f6c9d48c81b Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 18 Jun 2020 15:59:26 +0300 Subject: [PATCH 360/659] correct names --- .../how-to-define-a-singleton.md | 22 +++++++++---------- .../include/singleton_example.hpp | 6 ++--- .../src/singleton_example.cpp | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md index 746f15fa55..2409314af3 100644 --- a/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md +++ b/docs/06_how-to-guides/02_multi-index/how-to-define-a-singleton.md @@ -2,7 +2,7 @@ content_title: How to define a singleton --- -To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `test_table`, follow the steps below: +To define a simple singleton, which is storing an account name as primary value and a uint64_t as secondary value in structure `testtable`, follow the steps below: 1. Include the `eosio.hpp` and `singleton.hpp` headers and declare the `eosio` namespace usage ``` @@ -13,29 +13,29 @@ using namespace eosio; 2. Define the data structure for the multi index table ```cpp -struct [[eosio::table]] test_table { +struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; }; ``` -3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testtable"`, which has to respect the EOSIO account name restrictions, and the `test_table` data structure defined above +3. For ease of use, define a type alias `singleton_type` based on the `eosio::singleton` template type, parametarized with a random name `"testtable"`, which has to respect the EOSIO account name restrictions, and the `testtable` data structure defined above ```diff -struct [[eosio::table]] test_table { +struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; }; -+using singleton_type = eosio::singleton<"testtable"_n, test_table>; ++using singleton_type = eosio::singleton<"testtable"_n, testtable>; ``` 4. Define the singleton table instance declared as a data member of type `singleton_type` defined in the privious step ```diff -struct [[eosio::table]] test_table { +struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; }; -using singleton_type = eosio::singleton<"testtable"_n, test_table>; +using singleton_type = eosio::singleton<"testtable"_n, testtable>; +singleton_type singleton_instance; ``` @@ -70,13 +70,13 @@ class [[eosio::contract]] singleton_example : public contract { [[eosio::action]] void get( ); - struct [[eosio::table]] test_table { + struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; uint64_t primary_key() const { return primary_value.value; } - } test_table_instance; + } testtablerow; - using singleton_type = eosio::singleton<"testtable"_n, test_table>; + using singleton_type = eosio::singleton<"testtable"_n, testtable>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; @@ -91,7 +91,7 @@ __singleton_example.cpp__ #include [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - auto entry_stored = singleton_instance.get_or_create(user, test_table_instance); + auto entry_stored = singleton_instance.get_or_create(user, testtablerow); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); diff --git a/examples/singleton_example/include/singleton_example.hpp b/examples/singleton_example/include/singleton_example.hpp index fdf5d8987d..26de5c5cbe 100644 --- a/examples/singleton_example/include/singleton_example.hpp +++ b/examples/singleton_example/include/singleton_example.hpp @@ -15,13 +15,13 @@ class [[eosio::contract]] singleton_example : public contract { [[eosio::action]] void get( ); - struct [[eosio::table]] test_table { + struct [[eosio::table]] testtable { name primary_value; uint64_t secondary_value; uint64_t primary_key() const { return primary_value.value; } - } test_table_instance; + } testtablerow; - using singleton_type = eosio::singleton<"testtable"_n, test_table>; + using singleton_type = eosio::singleton<"testtable"_n, testtable>; singleton_type singleton_instance; using set_action = action_wrapper<"set"_n, &singleton_example::set>; diff --git a/examples/singleton_example/src/singleton_example.cpp b/examples/singleton_example/src/singleton_example.cpp index bc7fd854f3..01472b4cc2 100644 --- a/examples/singleton_example/src/singleton_example.cpp +++ b/examples/singleton_example/src/singleton_example.cpp @@ -2,7 +2,7 @@ [[eosio::action]] void singleton_example::set( name user, uint64_t value ) { - auto entry_stored = singleton_instance.get_or_create(user, test_table_instance); + auto entry_stored = singleton_instance.get_or_create(user, testtablerow); entry_stored.primary_value = user; entry_stored.secondary_value = value; singleton_instance.set(entry_stored, user); @@ -18,5 +18,5 @@ void singleton_example::get( ) { singleton_instance.get().secondary_value, "\n"); else - eosio::print("Singleton is empty\n"); + eosio::print("Singleton is empty.\n"); } From 6f34e956a85483bb276c13bdb9632547a6da29d6 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 24 Jun 2020 11:39:59 -0400 Subject: [PATCH 361/659] add meta_refl --- libraries/CMakeLists.txt | 2 + libraries/meta_refl/CMakeLists.txt | 77 ++++++ libraries/meta_refl/LICENSE | 21 ++ libraries/meta_refl/README.md | 2 + .../bluegrass/meta/function_traits.hpp | 244 ++++++++++++++++++ .../include/bluegrass/meta/preprocessor.hpp | 78 ++++++ .../meta_refl/include/bluegrass/meta/refl.hpp | 196 ++++++++++++++ .../include/bluegrass/meta/utility.hpp | 63 +++++ libraries/meta_refl/modules/add_project.cmake | 37 +++ .../meta_refl/modules/catch2_install.cmake.in | 30 +++ .../meta_refl/modules/catch2_macro.cmake | 16 ++ .../modules/meta_refl-config-version.cmake.in | 13 + libraries/meta_refl/tests/CMakeLists.txt | 12 + libraries/meta_refl/tests/main.cpp | 2 + libraries/meta_refl/tests/meta_tests.cpp | 107 ++++++++ libraries/meta_refl/tests/traits_tests.cpp | 116 +++++++++ 16 files changed, 1016 insertions(+) create mode 100644 libraries/meta_refl/CMakeLists.txt create mode 100644 libraries/meta_refl/LICENSE create mode 100644 libraries/meta_refl/README.md create mode 100644 libraries/meta_refl/include/bluegrass/meta/function_traits.hpp create mode 100644 libraries/meta_refl/include/bluegrass/meta/preprocessor.hpp create mode 100644 libraries/meta_refl/include/bluegrass/meta/refl.hpp create mode 100644 libraries/meta_refl/include/bluegrass/meta/utility.hpp create mode 100644 libraries/meta_refl/modules/add_project.cmake create mode 100644 libraries/meta_refl/modules/catch2_install.cmake.in create mode 100644 libraries/meta_refl/modules/catch2_macro.cmake create mode 100644 libraries/meta_refl/modules/meta_refl-config-version.cmake.in create mode 100644 libraries/meta_refl/tests/CMakeLists.txt create mode 100644 libraries/meta_refl/tests/main.cpp create mode 100644 libraries/meta_refl/tests/meta_tests.cpp create mode 100644 libraries/meta_refl/tests/traits_tests.cpp diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index ddf4b6ad4c..d69008957f 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -20,3 +20,5 @@ add_subdirectory(eosiolib) add_subdirectory(boost) add_subdirectory(native) add_subdirectory(rt) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/meta_refl/include/bluegrass DESTINATION ${BASE_BINARY_DIR}/include) diff --git a/libraries/meta_refl/CMakeLists.txt b/libraries/meta_refl/CMakeLists.txt new file mode 100644 index 0000000000..82dc59e764 --- /dev/null +++ b/libraries/meta_refl/CMakeLists.txt @@ -0,0 +1,77 @@ +# ################################################################################################## +# Defines the meta_refl library and associated tooling. See docs/cmake.md for instructions on how to +# build meta_refl or integrate with another system with CMake. +# ################################################################################################## +cmake_minimum_required(VERSION 3.8) +set(META_REFL_VERSION_MAJOR 1) +set(META_REFL_VERSION_MINOR 0) +set(META_REFL_VERSION_PATCH 0) +set(META_REFL_VERSION_SUFFIX rc1) +project(meta_refl VERSION ${META_REFL_VERSION_MAJOR}.${META_REFL_VERSION_MINOR}.${META_REFL_VERSION_PATCH}) + +if (META_REFL_VERSION_SUFFIX) + set(VERSION_FULL "${META_REFL_VERSION_MAJOR}.${META_REFL_VERSION_MINOR}.${META_REFL_VERSION_PATCH}-${META_REFL_VERSION_SUFFIX}") +else() + set(VERSION_FULL "${META_REFL_VERSION_MAJOR}.${META_REFL_VERSION_MINOR}.${META_REFL_VERSION_PATCH}") +endif() + +message(STATUS "Building liberror v${VERSION_FULL}...") + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_EXTENSIONS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# ################################################################################################## +# Defined options for building or integrating liberror. +# ################################################################################################## +include(CMakeDependentOption) +option(META_REFL_ENABLE_INSTALL "enable this library to be installed" ON) +option(META_REFL_ENABLE_TESTS "enable building of unit tests" OFF) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/modules") + +# ################################################################################################## +# Create the liberror library. +# ################################################################################################## +add_library(meta_refl INTERFACE) +target_include_directories(meta_refl + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) +add_library(bluegrass::meta_refl ALIAS meta_refl) + +# ################################################################################################## +# Build liberror tests. +# ################################################################################################## +if(META_REFL_ENABLE_TESTS) + include(CTest) + include(catch2_macro) + use_catch2(${CMAKE_BINARY_DIR}) + add_subdirectory(tests) +endif() + +# ################################################################################################## +# Configure version info. +# ################################################################################################## +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/modules/meta_refl-config-version.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/meta_refl-config-version.cmake @ONLY) + +# ################################################################################################## +# Installation. +# ################################################################################################## +if(BLUEGRASS_ENABLE_INSTALL) + include(GNUInstallDirs) + message(STATUS "Installing bluegrass meta_refl ...") + install(TARGETS meta_refl + EXPORT meta_refl_pkg_config + LIBRARY + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT Headers) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/bluegrass + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + install(EXPORT meta_refl_pkg_config + DESTINATION "${CMAKE_INSTALL_DATADIR}/meta_refl/cmake" + NAMESPACE bluegrass::) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/meta_refl-config-version.cmake + DESTINATION "#{CMAKE_INSTALL_DATADIR}/meta_refl/cmake") +endif() + diff --git a/libraries/meta_refl/LICENSE b/libraries/meta_refl/LICENSE new file mode 100644 index 0000000000..a8573975cd --- /dev/null +++ b/libraries/meta_refl/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Bucky Kittinger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libraries/meta_refl/README.md b/libraries/meta_refl/README.md new file mode 100644 index 0000000000..16b3a64ff6 --- /dev/null +++ b/libraries/meta_refl/README.md @@ -0,0 +1,2 @@ +# meta_refl +A very small meta programming and reflection library. diff --git a/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp b/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp new file mode 100644 index 0000000000..a3d4abbb72 --- /dev/null +++ b/libraries/meta_refl/include/bluegrass/meta/function_traits.hpp @@ -0,0 +1,244 @@ +#pragma once + +#include "utility.hpp" + +#include +#include + +#define BLUEGRASS_META_HAS_MEMBER_GENERATOR(NAME, MEMBER) \ + template \ + struct has_member_ ## NAME { \ + template struct sfinae {}; \ + template constexpr static char test(sfinae*); \ + template constexpr static int test(...); \ + constexpr static const bool value = sizeof(test(0)) == sizeof(char); \ + }; + +#define BLUEGRASS_HAS_MEMBER(ARG, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t> && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_MEMBER_TY(TY, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_TEMPLATE_MEMBER(ARG, NAME) \ + bluegrass::meta::overloaded { \ + [&](auto&& f, std::enable_if_t> && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::template NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + +#define BLUEGRASS_HAS_TEMPLATE_MEMBER_TY(TY, NAME) \ + bluegrass::meta::overloaded { \ + [](auto&& f, std::enable_if_t && \ + bluegrass::meta::detail::pass_type< \ + decltype(&std::decay_t::type::template NAME)>(), int> = 0) constexpr { \ + return true; \ + }, [](...) constexpr { return false; } \ + }(bluegrass::meta::detail::wrapper_t{}) + + +// Workaround for compiler bug handling C++g17 auto template parameters. +// The parameter is not treated as being type-dependent in all contexts, +// causing early evaluation of the containing expression. +// Tested at Apple LLVM version 10.0.1 (clang-1001.0.46.4) +#define AUTO_PARAM_WORKAROUND(X) bluegrass::meta::detail::make_dependent(X) + +namespace bluegrass { namespace meta { + + struct freestanding {}; + + namespace detail { + template + constexpr bool pass_type() { return true; } + + template + constexpr bool is_callable_impl(...) { + return false; + } + + template + struct wrapper_t { + using type = T; + constexpr wrapper_t() {} + constexpr wrapper_t(T&&) {} + }; + + template + inline constexpr U&& make_dependent(U&& u) { return static_cast(u); } + } + + template + inline constexpr static bool is_callable_v = BLUEGRASS_HAS_MEMBER(AUTO_PARAM_WORKAROUND(FN), operator()); + + template + constexpr bool is_callable(F&& fn) { return BLUEGRASS_HAS_MEMBER(fn, operator()); } + + namespace detail { + template + constexpr auto get_types(R(Args...)) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)&&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const &) -> std::tuple, Args>...>>; + template + constexpr auto get_types(R (Cls::*)(Args...)const &&) -> std::tuple, Args>...>>; + template + constexpr auto get_types(F&& fn) { + if constexpr (is_callable_v) + return get_types(&F::operator()); + else + return get_types(fn); + } + + template + using get_types_t = decltype(get_types(std::declval())); + + template + struct pack_from; + + template + struct pack_from { + static_assert(Sz > N, "index out of range"); + using type = typename pack_from::type; + }; + + template + struct pack_from { + using type = std::tuple; + }; + + template + using pack_from_t = typename pack_from::type; + + template + constexpr auto parameters_from_impl(R(Args...)) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)&) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)&&) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &) -> pack_from_t; + template + constexpr auto parameters_from_impl(R(Cls::*)(Args...)const &&) -> pack_from_t; + template + constexpr auto parameters_from_impl(F&& fn) { + if constexpr (is_callable_v) + return parameters_from_impl(&F::operator()); + else + return parameters_from_impl(fn); + } + + template + using parameters_from_impl_t = decltype(parameters_from_impl(std::declval())); + } // ns bluegrass::meta::detail + + template + constexpr bool is_function(R(*)(Args...)) { return true; } + + template + constexpr bool is_function(F&&) { return false; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)& ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)&& ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const & ) { return true; } + + template + constexpr bool is_member_function(R(Cls::*)(Args...)const && ) { return true; } + + template + constexpr bool is_member_function(F&&) { return false; } + + template + inline constexpr static bool is_function_v = is_function(AUTO_PARAM_WORKAROUND(FN)); + + template + inline constexpr static bool is_member_function_v = is_member_function(AUTO_PARAM_WORKAROUND(FN)); + + template + constexpr bool is_class(F&&) { return std::is_class_v; } + + template + constexpr auto return_type(F&& fn) -> std::tuple_element_t<0, detail::get_types_t>; + + template + using return_type_t = decltype(return_type(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto class_from_member(F&& fn) -> std::tuple_element_t<1, detail::get_types_t>; + + template + using class_from_member_t = decltype(class_from_member(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t>; + + template + using flatten_parameters_t = decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto decayed_flatten_parameters(F&& fn) -> std::tuple_element_t<2, detail::get_types_t>; + + template + using decayed_flatten_parameters_t = decltype(decayed_flatten_parameters(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto parameter_at(F&& fn) -> std::tuple_element_t()))>; + + template + using parameter_at_t = decltype(parameter_at(AUTO_PARAM_WORKAROUND(FN))); + + template + constexpr auto parameters_from(F&& fn) -> detail::parameters_from_impl_t; + + template + using parameters_from_t = decltype(parameters_from(AUTO_PARAM_WORKAROUND(FN))); + + template + inline constexpr static std::size_t arity(F&& fn) { return std::tuple_size_v; } + + template + inline constexpr static std::size_t arity_v = arity(FN); +}} diff --git a/libraries/meta_refl/include/bluegrass/meta/preprocessor.hpp b/libraries/meta_refl/include/bluegrass/meta/preprocessor.hpp new file mode 100644 index 0000000000..d1248cdc0a --- /dev/null +++ b/libraries/meta_refl/include/bluegrass/meta/preprocessor.hpp @@ -0,0 +1,78 @@ +#pragma once + +#define BLUEGRASS_META_EXPAND(X) X + +#define BLUEGRASS_META_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, NAME, ...) NAME + +#define BLUEGRASS_META_FE0(MAC, ...) +#define BLUEGRASS_META_FE1(MAC, A, B) MAC(A, B) +#define BLUEGRASS_META_FE2(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE1(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE3(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE2(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE4(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE3(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE5(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE4(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE6(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE5(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE7(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE6(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE8(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE7(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE9(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE8(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE10(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE9(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE11(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE10(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE12(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE11(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE13(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE12(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE14(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE13(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE15(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE14(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE16(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE15(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE17(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE16(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE18(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE17(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE19(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE18(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE20(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE19(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE21(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE20(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE22(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE21(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE23(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE22(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE24(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE23(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE25(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE24(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE26(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE25(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE27(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE26(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE28(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE27(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE29(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE28(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE30(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE29(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE31(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE30(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE32(MAC, A, B, ...) MAC(A, B) BLUEGRASS_META_FE31(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA2(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE1(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA3(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA2(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA4(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA3(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA5(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA4(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA6(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA5(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA7(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA6(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA8(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA7(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA9(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA8(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA10(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA9(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA11(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA10(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA12(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA11(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA13(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA12(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA14(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA13(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA15(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA14(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA16(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA15(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA17(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA16(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA18(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA17(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA19(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA18(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA20(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA19(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA21(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA20(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA22(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA21(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA23(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA22(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA24(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA23(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA25(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA24(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA26(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA25(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA27(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA26(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA28(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA27(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA29(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA28(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA30(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA29(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA31(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA30(MAC, A, ##__VA_ARGS__) +#define BLUEGRASS_META_FE_COMMA32(MAC, A, B, ...) MAC(A, B), BLUEGRASS_META_FE_COMMA31(MAC, A, ##__VA_ARGS__) + +#define BLUEGRASS_META_FOREACH_NO_COMMA(MAC, D, ...) \ + BLUEGRASS_META_GET_NTH_ARG("ignored", ##__VA_ARGS__, \ + BLUEGRASS_META_FE32,BLUEGRASS_META_FE31,BLUEGRASS_META_FE30,BLUEGRASS_META_FE29,BLUEGRASS_META_FE28,BLUEGRASS_META_FE27,BLUEGRASS_META_FE26,BLUEGRASS_META_FE25,BLUEGRASS_META_FE24,BLUEGRASS_META_FE23,BLUEGRASS_META_FE22,BLUEGRASS_META_FE21,BLUEGRASS_META_FE20,BLUEGRASS_META_FE19,BLUEGRASS_META_FE18,BLUEGRASS_META_FE17,BLUEGRASS_META_FE16,BLUEGRASS_META_FE15,BLUEGRASS_META_FE14,BLUEGRASS_META_FE13,BLUEGRASS_META_FE12,BLUEGRASS_META_FE11,BLUEGRASS_META_FE10,BLUEGRASS_META_FE9,BLUEGRASS_META_FE8,BLUEGRASS_META_FE7,BLUEGRASS_META_FE6,BLUEGRASS_META_FE5,BLUEGRASS_META_FE4,BLUEGRASS_META_FE3,BLUEGRASS_META_FE2,BLUEGRASS_META_FE1,BLUEGRASS_META_FE0)(MAC, D, ##__VA_ARGS__) + +#define BLUEGRASS_META_FOREACH(MAC, D, ...) \ + BLUEGRASS_META_GET_NTH_ARG("ignored", ##__VA_ARGS__, \ + BLUEGRASS_META_FE_COMMA32,BLUEGRASS_META_FE_COMMA31,BLUEGRASS_META_FE_COMMA30,BLUEGRASS_META_FE_COMMA29,BLUEGRASS_META_FE_COMMA28,BLUEGRASS_META_FE_COMMA27,BLUEGRASS_META_FE_COMMA26,BLUEGRASS_META_FE_COMMA25,BLUEGRASS_META_FE_COMMA24,BLUEGRASS_META_FE_COMMA23,BLUEGRASS_META_FE_COMMA22,BLUEGRASS_META_FE_COMMA21,BLUEGRASS_META_FE_COMMA20,BLUEGRASS_META_FE_COMMA19,BLUEGRASS_META_FE_COMMA18,BLUEGRASS_META_FE_COMMA17,BLUEGRASS_META_FE_COMMA16,BLUEGRASS_META_FE_COMMA15,BLUEGRASS_META_FE_COMMA14,BLUEGRASS_META_FE_COMMA13,BLUEGRASS_META_FE_COMMA12,BLUEGRASS_META_FE_COMMA11,BLUEGRASS_META_FE_COMMA10,BLUEGRASS_META_FE_COMMA9,BLUEGRASS_META_FE_COMMA8,BLUEGRASS_META_FE_COMMA7,BLUEGRASS_META_FE_COMMA6,BLUEGRASS_META_FE_COMMA5,BLUEGRASS_META_FE_COMMA4,BLUEGRASS_META_FE_COMMA3,BLUEGRASS_META_FE_COMMA2,BLUEGRASS_META_FE1,BLUEGRASS_META_FE0)(MAC, D, ##__VA_ARGS__) diff --git a/libraries/meta_refl/include/bluegrass/meta/refl.hpp b/libraries/meta_refl/include/bluegrass/meta/refl.hpp new file mode 100644 index 0000000000..94a50ef041 --- /dev/null +++ b/libraries/meta_refl/include/bluegrass/meta/refl.hpp @@ -0,0 +1,196 @@ +#pragma once + +#include "function_traits.hpp" +#include "utility.hpp" +#include "preprocessor.hpp" + +#include +#include +#include + +#include + +namespace bluegrass { namespace meta { + template + constexpr inline std::string_view type_name() { + constexpr std::string_view full_name = __PRETTY_FUNCTION__; + constexpr auto start = full_name.find("T = "); +#ifdef __clang__ + constexpr auto end = full_name.find("]"); +#elif __GNUC__ + constexpr auto end = full_name.find(";"); +#else +#error "Currently only supporting Clang and GCC compilers" +#endif + + return full_name.substr(start+4, end - start - 4); + } + + // tag used to define an invalid fields for field_types + struct invalid_fields {}; + + namespace detail { + template + constexpr inline auto which_field_types() { + if constexpr ( BLUEGRASS_HAS_MEMBER_TY(C, _bluegrass_meta_refl_valid) ) + return flatten_parameters_t<&C::_bluegrass_meta_refl_fields>{}; + else + return invalid_fields{}; + } + + template + constexpr inline std::size_t fields_size() { + if constexpr (std::is_same_v) + return 0; + else + return std::tuple_size_v; + } + + template + constexpr inline auto va_args_count_helper(Args&&...) { return sizeof...(Args); } + + template + struct fwd_t { using type = T; }; + + template + constexpr inline auto produce_tuple(std::index_sequence) + -> std::tuple< typename fwd_t::type ...>; + + template + constexpr inline auto homogeneous_field_types() + -> decltype(produce_tuple(std::make_index_sequence{})); + + template + constexpr inline std::size_t homogeneous_field_offset() { + static_assert(N <= Max); + return sizeof(T) * N; + } + } // ns bluegrass::meta::detail + + template + struct meta_object_base { + constexpr static inline std::string_view name = type_name(); + constexpr static inline auto get_name() { return name; } + + using field_types = invalid_fields; + template + using field_type = invalid_fields; + constexpr static inline std::size_t field_count = 0; + constexpr static auto field_names = std::array{}; + + constexpr static inline auto get_field_count() { return Derived::field_count; } + constexpr static inline auto get_field_name(std::size_t n) { return Derived::field_names[n]; } + constexpr static inline auto get_field_names() { return Derived::field_names; } + + template + constexpr static inline auto& get_field(T&& t) { + return Derived::template get_field(std::forward(t)); + } + + template + constexpr static inline auto& get_field(const T& t) { + return Derived::template get_field(t); + } + + template + constexpr inline static auto for_each_field_impl( T&& t, F&& f ) { + if constexpr (N+1 == get_field_count()) + return f(get_field(std::forward(t))); + else { + f(get_field(std::forward(t))); + return for_each_field_impl(std::forward(t), std::forward(f)); + } + } + template + constexpr inline static void for_each_field( T&& t, F&& f ) { + if constexpr (get_field_count() == 0) + return; + else + return for_each_field_impl<0>(t, f); + } + }; + + template + struct meta_object : meta_object_base> { + using base_t = meta_object_base>; + using base_t::name; + using base_t::get_name; + using base_t::for_each_field; + using base_t::get_field_count; + using base_t::get_field_name; + using base_t::get_field_names; + + using field_types = decltype(detail::which_field_types()); + template + using field_type = std::tuple_element_t; + constexpr static inline std::size_t field_count = detail::fields_size(); + constexpr static auto field_names = C::_bluegrass_meta_refl_field_names(); + + template + constexpr static inline auto& get_field(T&& t) { + static_assert(std::is_same_v, C>, "get_field(T), T should be the same type as C"); + using type = std::tuple_element_t; + return *reinterpret_cast(t.template _bluegrass_meta_refl_field_ptr()); + } + + template + constexpr static inline auto& get_field(const T& t) { + static_assert(std::is_same_v, C>, "get_field(T), T should be the same type as C"); + using type = std::tuple_element_t; + return *reinterpret_cast(t.template _bluegrass_meta_refl_field_ptr()); + } + }; + +}} // ns bluegrass::meta + +#define BLUEGRASS_META_ADDRESS( ignore, FIELD ) (void*)&FIELD +#define BLUEGRASS_META_DECLTYPE( ignore, FIELD ) decltype(FIELD) +#define BLUEGRASS_META_PASS_STR( ignore, X ) #X + +#define BLUEGRASS_META_VA_ARGS_SIZE(...) \ + bluegrass::meta::detail::va_args_count_helper( \ + BLUEGRASS_META_FOREACH( \ + BLUEGRASS_META_PASS_STR, "ignored", ##__VA_ARGS__)) + +#define BLUEGRASS_META_REFL(...) \ + constexpr void _bluegrass_meta_refl_valid(); \ + void _bluegrass_meta_refl_fields \ + ( BLUEGRASS_META_FOREACH(BLUEGRASS_META_DECLTYPE, "ignored", ##__VA_ARGS__) ){} \ + inline auto _bluegrass_meta_refl_field_ptrs() const { \ + return std::array{ \ + BLUEGRASS_META_FOREACH(BLUEGRASS_META_ADDRESS, "ignored", ##__VA_ARGS__)}; \ + } \ + template \ + inline void* _bluegrass_meta_refl_field_ptr() const { \ + return _bluegrass_meta_refl_field_ptrs()[N]; \ + } \ + constexpr inline static auto _bluegrass_meta_refl_field_names() { \ + return std::array { \ + BLUEGRASS_META_FOREACH(BLUEGRASS_META_PASS_STR, "ignored", ##__VA_ARGS__) \ + }; \ + } + +// EXPERIMENTAL macro to produce meta_object specializations for homogeneous structures +#define BLUEGRASS_HOM_META(_C, _FT, ...) \ + namespace bluegrass { namespace meta { \ + template <__VA_ARGS__> \ + struct meta_object<_C> : meta_object_base<_C, meta_object<_C>> { \ + using base_t = meta_object_base<_C, meta_object<_C>>; \ + using base_t::name; \ + using base_t::field_names; \ + using base_t::get_name; \ + using base_t::for_each_field; \ + using base_t::get_field_count; \ + using base_t::get_field_name; \ + using base_t::get_field_names; \ + constexpr static inline std::size_t field_count = sizeof(_C) / sizeof(_FT); \ + using field_types = decltype(detail::homogeneous_field_types()); \ + template \ + using field_type = std::tuple_element_t<_N, field_types>; \ + template \ + constexpr static inline auto& get_field(_C& t) { \ + /* very gross and bad code is about to follow */ \ + return *(reinterpret_cast<_FT*>(&t)+_N); \ + } \ + }; \ + }} diff --git a/libraries/meta_refl/include/bluegrass/meta/utility.hpp b/libraries/meta_refl/include/bluegrass/meta/utility.hpp new file mode 100644 index 0000000000..fc908dfa16 --- /dev/null +++ b/libraries/meta_refl/include/bluegrass/meta/utility.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include + +namespace bluegrass { namespace meta { + // helpers for std::visit + template + struct overloaded : Ts... { + using Ts::operator()...; + }; + template + overloaded(Ts...)->overloaded; + + template + struct ct_string { + constexpr static const char value[] = {Str..., '\0'}; + constexpr static std::size_t size = sizeof...(Str)+1; + }; + + namespace detail { + template + struct ct_string_appender; + template class CTS, char... Str> + struct ct_string_appender> { + using type = ct_string; + }; + template + struct ct_string_reverser; + template class O, char C> + struct ct_string_reverser> { + using type = typename ct_string_appender::type; + }; + template class O, char C, char... Rest> + struct ct_string_reverser> { + using type = typename ct_string_reverser::type, ct_string>::type; + }; + template + struct trim_front; + template