From 37f7e6aa2cf15070f25c7b5de7e240dd21d2eca4 Mon Sep 17 00:00:00 2001 From: thaipanda <45444502+Thaipanda@users.noreply.github.com> Date: Thu, 13 Dec 2018 20:50:13 +0800 Subject: [PATCH 1/5] merge v1.0.2 (#12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * finish BOS basic functions * add README files * update info * Release/1.0.x (#11) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * readme for kafka & add time for action (#5) * 重启 节点,黑名单 失效,fixes #7 (#8) * restart sync list db * recovery system account bos to eosio * recovery system account bos to eosio * recovery system account bos to eosio * Fix/#3 notify plugin (#10) * Add debug info * comment log * rm log for notify_plugin * prepare for v1.0.2 --- .gitlab-ci.yml | 2 +- CMakeLists.txt | 6 +- CMakeModules/EosioTester.cmake.in | 2 +- CMakeModules/FindCppkafka.cmake | 29 ++ Docker/Dockerfile | 14 +- Docker/README.md | 38 +- Docker/builder/Dockerfile | 19 +- Docker/config.ini | 5 + Docker/dev/Dockerfile | 4 +- README.md | 108 ++---- README_CN.md | 36 ++ contracts/eosio.system/delegate_bandwidth.cpp | 2 +- contracts/eosio.system/eosio.system.hpp | 1 - contracts/eosio.system/voting.cpp | 11 +- contracts/eosiolib/transaction.h | 22 ++ eosio_build.sh | 35 +- eosio_install.sh | 22 +- libraries/chain/apply_context.cpp | 4 + libraries/chain/block_header.cpp | 10 + libraries/chain/block_header_state.cpp | 4 +- libraries/chain/chain_config.cpp | 6 + libraries/chain/controller.cpp | 157 +++++++- libraries/chain/fork_database.cpp | 2 - .../include/eosio/chain/apply_context.hpp | 1 + libraries/chain/include/eosio/chain/block.hpp | 3 + .../include/eosio/chain/block_header.hpp | 9 +- .../include/eosio/chain/chain_config.hpp | 21 + .../chain/include/eosio/chain/config.hpp | 1 + .../chain/include/eosio/chain/config_xos.hpp | 23 ++ .../chain/include/eosio/chain/controller.hpp | 28 +- .../eosio/chain/global_property_object.hpp | 24 ++ .../include/eosio/chain/resource_limits.hpp | 22 +- .../eosio/chain/resource_limits_private.hpp | 25 +- libraries/chain/include/eosio/chain/types.hpp | 2 + libraries/chain/resource_limits.cpp | 48 ++- libraries/chain/wasm_interface.cpp | 125 +++++- .../testing/include/eosio/testing/tester.hpp | 2 +- plugins/CMakeLists.txt | 2 + .../history_api_plugin/history_api_plugin.cpp | 4 +- plugins/history_plugin/history_plugin.cpp | 93 ++++- .../eosio/history_plugin/history_plugin.hpp | 20 +- plugins/kafka_plugin/CMakeLists.txt | 10 + plugins/kafka_plugin/fifo.h | 85 +++++ plugins/kafka_plugin/kafka.cpp | 186 +++++++++ plugins/kafka_plugin/kafka.hpp | 46 +++ plugins/kafka_plugin/kafka_plugin.cpp | 166 ++++++++ plugins/kafka_plugin/kafka_plugin.hpp | 41 ++ plugins/kafka_plugin/readme.md | 31 ++ plugins/kafka_plugin/try_handle.cpp | 17 + plugins/kafka_plugin/try_handle.hpp | 9 + plugins/kafka_plugin/types.hpp | 94 +++++ .../include/eosio/net_plugin/protocol.hpp | 15 +- plugins/net_plugin/net_plugin.cpp | 135 ++++++- plugins/notify_plugin/CMakeLists.txt | 7 + plugins/notify_plugin/README.md | 73 ++++ .../eosio/notify_plugin/http_async_client.hpp | 104 +++++ .../eosio/notify_plugin/notify_plugin.hpp | 33 ++ plugins/notify_plugin/notify_plugin.cpp | 359 ++++++++++++++++++ plugins/producer_plugin/producer_plugin.cpp | 7 +- programs/cleos/httpc.hpp | 1 + programs/cleos/main.cpp | 20 +- programs/nodeos/CMakeLists.txt | 4 + scripts/eosio_build_amazon.sh | 120 ++++++ scripts/eosio_build_centos.sh | 120 ++++++ scripts/eosio_build_darwin.sh | 120 ++++++ scripts/eosio_build_fedora.sh | 120 ++++++ scripts/eosio_build_ubuntu.sh | 120 ++++++ unittests/actiondemo/actiondemo.abi | 99 +++++ unittests/actiondemo/actiondemo.cpp | 106 ++++++ unittests/actiondemo/actiondemo.hpp | 50 +++ unittests/actiondemo/test.py | 223 +++++++++++ unittests/database_gmr_blklst_tests.cpp | 309 +++++++++++++++ unittests/database_tests.cpp | 3 +- unittests/gmr_test.cpp | 234 ++++++++++++ 74 files changed, 3870 insertions(+), 189 deletions(-) create mode 100644 CMakeModules/FindCppkafka.cmake create mode 100644 README_CN.md create mode 100644 libraries/chain/include/eosio/chain/config_xos.hpp create mode 100644 plugins/kafka_plugin/CMakeLists.txt create mode 100644 plugins/kafka_plugin/fifo.h create mode 100644 plugins/kafka_plugin/kafka.cpp create mode 100644 plugins/kafka_plugin/kafka.hpp create mode 100644 plugins/kafka_plugin/kafka_plugin.cpp create mode 100644 plugins/kafka_plugin/kafka_plugin.hpp create mode 100644 plugins/kafka_plugin/readme.md create mode 100644 plugins/kafka_plugin/try_handle.cpp create mode 100644 plugins/kafka_plugin/try_handle.hpp create mode 100644 plugins/kafka_plugin/types.hpp create mode 100644 plugins/notify_plugin/CMakeLists.txt create mode 100644 plugins/notify_plugin/README.md create mode 100644 plugins/notify_plugin/include/eosio/notify_plugin/http_async_client.hpp create mode 100644 plugins/notify_plugin/include/eosio/notify_plugin/notify_plugin.hpp create mode 100644 plugins/notify_plugin/notify_plugin.cpp create mode 100644 unittests/actiondemo/actiondemo.abi create mode 100644 unittests/actiondemo/actiondemo.cpp create mode 100644 unittests/actiondemo/actiondemo.hpp create mode 100644 unittests/actiondemo/test.py create mode 100644 unittests/database_gmr_blklst_tests.cpp create mode 100644 unittests/gmr_test.cpp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a51b6e9564e..622a46f2642 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,4 +4,4 @@ build: script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -f Docker/Dockerfile . - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA + - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 360d6c973ab..1451955870c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,14 +28,14 @@ include( SetupTargetMacros ) include( InstallDirectoryPermissions ) include( MASSigning ) -set( BLOCKCHAIN_NAME "EOSIO" ) +set( BLOCKCHAIN_NAME "BOS" ) set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_EXTENSIONS ON ) set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) -set(VERSION_MINOR 4) -set(VERSION_PATCH 4) +set(VERSION_MINOR 0) +set(VERSION_PATCH 2) set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( NODE_EXECUTABLE_NAME nodeos ) diff --git a/CMakeModules/EosioTester.cmake.in b/CMakeModules/EosioTester.cmake.in index 741ee5f0e84..ac2bc0221fa 100644 --- a/CMakeModules/EosioTester.cmake.in +++ b/CMakeModules/EosioTester.cmake.in @@ -97,8 +97,8 @@ macro(add_eosio_test test_name) ${liblogging} ${libchainbase} ${libbuiltins} - ${GMP_LIBRARIES} ${libsecp256k1} + ${GMP_LIBRARIES} LLVMX86Disassembler LLVMX86AsmParser diff --git a/CMakeModules/FindCppkafka.cmake b/CMakeModules/FindCppkafka.cmake new file mode 100644 index 00000000000..aa8bc82ba85 --- /dev/null +++ b/CMakeModules/FindCppkafka.cmake @@ -0,0 +1,29 @@ +# Override default CMAKE_FIND_LIBRARY_SUFFIXES +if (CPPKAFKA_SHARED_LIB) + set(CPPKAFKA_SUFFIX so) +else() + set(CPPKAFKA_SUFFIX a) +endif() +message(STATUS "Cppkafka finding .${CPPKAFKA_SUFFIX} library") + +FIND_PATH( + CPPKAFKA_INCLUDE_DIR cppkafka.h + PATH "/usr/local" + PATH_SUFFIXES "" "cppkafka") +MARK_AS_ADVANCED(CPPKAFKA_INCLUDE_DIR) + +SET(CPPKAFKA_INCLUDE_DIR ${CPPKAFKA_INCLUDE_DIR}) + +FIND_LIBRARY( + CPPKAFKA_LIBRARY + NAMES cppkafka.${CPPKAFKA_SUFFIX} libcppkafka.${CPPKAFKA_SUFFIX} + HINTS ${CPPKAFKA_INCLUDE_DIR}/.. + PATH_SUFFIXES lib${LIB_SUFFIX}) +MARK_AS_ADVANCED(CPPKAFKA_LIBRARY) + +SET(CPPKAFKA_LIBRARY ${CPPKAFKA_LIBRARY}) +message(STATUS "Cppkafka found ${CPPKAFKA_LIBRARY}") + +include(FindPackageHandleStandardArgs) +SET(_CPPKAFKA_REQUIRED_VARS CPPKAFKA_INCLUDE_DIR CPPKAFKA_LIBRARY) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cppkafka DEFAULT_MSG ${_CPPKAFKA_REQUIRED_VARS}) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 24dd447ed75..67f7714c894 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -1,11 +1,15 @@ -FROM eosio/builder as builder +FROM boscore/builder as builder ARG branch=master ARG symbol=SYS -RUN git clone -b $branch https://github.com/EOSIO/eos.git --recursive \ - && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ +ENV OPENSSL_ROOT_DIR /usr/include/openssl + + +RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ + && cd bos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ + -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" \ && cmake --build /tmp/build --target install && rm /tmp/build/bin/eosiocpp @@ -15,9 +19,9 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl COPY --from=builder /usr/local/lib/* /usr/local/lib/ COPY --from=builder /tmp/build/bin /opt/eosio/bin COPY --from=builder /tmp/build/contracts /contracts -COPY --from=builder /eos/Docker/config.ini / +COPY --from=builder /bos/Docker/config.ini / COPY --from=builder /etc/eosio-version /etc -COPY --from=builder /eos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh +COPY --from=builder /bos/Docker/nodeosd.sh /opt/eosio/bin/nodeosd.sh ENV EOSIO_ROOT=/opt/eosio RUN chmod +x /opt/eosio/bin/nodeosd.sh ENV LD_LIBRARY_PATH /usr/local/lib diff --git a/Docker/README.md b/Docker/README.md index db0340e3116..9ff75404b7d 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -1,6 +1,6 @@ # Run in docker -Simple and fast setup of EOS.IO on Docker is also available. +Simple and fast setup of BOSCore on Docker is also available. ## Install Dependencies @@ -12,30 +12,30 @@ Simple and fast setup of EOS.IO on Docker is also available. - At least 7GB RAM (Docker -> Preferences -> Advanced -> Memory -> 7GB or above) - If the build below fails, make sure you've adjusted Docker Memory settings and try again. -## Build eos image +## Build BOSCore image ```bash -git clone https://github.com/EOSIO/eos.git --recursive --depth 1 -cd eos/Docker -docker build . -t eosio/eos +git clone https://github.com/boscore/bos.git --recursive --depth 1 +cd bos/Docker +docker build . -t boscore/bos ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.4.4 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.2 tag, you could do the following: ```bash -docker build -t eosio/eos:v1.4.4 --build-arg branch=v1.4.4 . +docker build -t boscore/bos:v1.0.2 --build-arg branch=v1.0.2 . ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. ```bash -docker build -t eosio/eos --build-arg symbol= . +docker build -t boscore/bos --build-arg symbol= . ``` ## Start nodeos docker container only ```bash -docker run --name nodeos -p 8888:8888 -p 9876:9876 -t eosio/eos nodeosd.sh -e --http-alias=nodeos:8888 --http-alias=127.0.0.1:8888 --http-alias=localhost:8888 arg1 arg2 +docker run --name nodeos -p 8888:8888 -p 9876:9876 -t boscore/bos nodeosd.sh -e --http-alias=nodeos:8888 --http-alias=127.0.0.1:8888 --http-alias=localhost:8888 arg1 arg2 ``` By default, all data is persisted in a docker volume. It can be deleted if the data is outdated or corrupted: @@ -49,7 +49,7 @@ $ docker volume rm fdc265730a4f697346fa8b078c176e315b959e79365fc9cbd11f090ea0cb5 Alternately, you can directly mount host directory into the container ```bash -docker run --name nodeos -v /path-to-data-dir:/opt/eosio/bin/data-dir -p 8888:8888 -p 9876:9876 -t eosio/eos nodeosd.sh -e --http-alias=nodeos:8888 --http-alias=127.0.0.1:8888 --http-alias=localhost:8888 arg1 arg2 +docker run --name nodeos -v /path-to-data-dir:/opt/eosio/bin/data-dir -p 8888:8888 -p 9876:9876 -t boscore/bos nodeosd.sh -e --http-alias=nodeos:8888 --http-alias=127.0.0.1:8888 --http-alias=localhost:8888 arg1 arg2 ``` ## Get chain info @@ -92,13 +92,13 @@ docker-compose stop keosd ### Develop/Build custom contracts -Due to the fact that the eosio/eos image does not contain the required dependencies for contract development (this is by design, to keep the image size small), you will need to utilize the eosio/eos-dev image. This image contains both the required binaries and dependencies to build contracts using eosiocpp. +Due to the fact that the boscore/bos image does not contain the required dependencies for contract development (this is by design, to keep the image size small), you will need to utilize the boscore/bos-dev image. This image contains both the required binaries and dependencies to build contracts using eosiocpp. -You can either use the image available on [Docker Hub](https://hub.docker.com/r/eosio/eos-dev/) or navigate into the dev folder and build the image manually. +You can either use the image available on [Docker Hub](https://hub.docker.com/r/boscore/bos-dev/) or navigate into the dev folder and build the image manually. ```bash cd dev -docker build -t eosio/eos-dev . +docker build -t boscore/bos-dev . ``` ### Change default configuration @@ -133,7 +133,7 @@ docker volume rm keosd-data-volume ### Docker Hub -Docker Hub image available from [docker hub](https://hub.docker.com/r/eosio/eos/). +Docker Hub image available from [docker hub](https://hub.docker.com/r/boscore/bos/). Create a new `docker-compose.yaml` file with the content below ```bash @@ -141,7 +141,7 @@ version: "3" services: nodeosd: - image: eosio/eos:latest + image: boscore/bos:latest command: /opt/eosio/bin/nodeosd.sh --data-dir /opt/eosio/bin/data-dir -e --http-alias=nodeosd:8888 --http-alias=127.0.0.1:8888 --http-alias=localhost:8888 hostname: nodeosd ports: @@ -153,7 +153,7 @@ services: - nodeos-data-volume:/opt/eosio/bin/data-dir keosd: - image: eosio/eos:latest + image: boscore/bos:latest command: /opt/eosio/bin/keosd --wallet-dir /opt/eosio/bin/data-dir --http-server-address=127.0.0.1:8900 --http-alias=localhost:8900 --http-alias=keosd:8900 hostname: keosd links: @@ -169,13 +169,13 @@ volumes: *NOTE:* the default version is the latest, you can change it to what you want -run `docker pull eosio/eos:latest` +run `docker pull boscore/bos:latest` run `docker-compose up` -### EOSIO Testnet +### BOSCore Testnet -We can easily set up a EOSIO local testnet using docker images. Just run the following commands: +We can easily set up a BOSCore local testnet using docker images. Just run the following commands: Note: if you want to use the mongo db plugin, you have to enable it in your `data-dir/config.ini` first. diff --git a/Docker/builder/Dockerfile b/Docker/builder/Dockerfile index cac09937cd0..74677b701c4 100644 --- a/Docker/builder/Dockerfile +++ b/Docker/builder/Dockerfile @@ -1,7 +1,7 @@ FROM ubuntu:18.04 -LABEL author="xiaobo " maintainer="Xiaobo Huang-Ming Huang " version="0.1.1" \ - description="This is a base image for building eosio/eos" +LABEL author="xiaobo " maintainer="Xiaobo Huang-Ming Huang Winlin " version="0.1.2" \ + description="This is a base image for building boscore/bos" RUN echo 'APT::Install-Recommends 0;' >> /etc/apt/apt.conf.d/01norecommends \ && echo 'APT::Install-Suggests 0;' >> /etc/apt/apt.conf.d/01norecommends \ @@ -56,3 +56,18 @@ RUN git clone --depth 1 -b releases/v3.3 https://github.com/mongodb/mongo-cxx-dr && make -j$(nproc) \ && make install \ && cd ../../ && rm -rf mongo-cxx-driver + +RUN git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git \ + && cd librdkafka/ \ + && cmake -H. -B_cmake_build \ + && cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build \ + && cd _cmake_build \ + && make install \ + && cd ../../ && rm -rf librdkafka + +RUN git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git \ + && cd cppkafka/ \ + && mkdir build && cd build \ + && cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. \ + && make install \ + && cd ../../ && rm -rf cppkafka diff --git a/Docker/config.ini b/Docker/config.ini index d9871858f19..71ae5c6c0ed 100644 --- a/Docker/config.ini +++ b/Docker/config.ini @@ -77,6 +77,9 @@ access-control-allow-credentials = false # The actual host:port used to listen for incoming p2p connections. (eosio::net_plugin) p2p-listen-endpoint = 0.0.0.0:9876 +#The p2p-discoverable is used to enable or disable p2p network self-discovery (eosio::net_plugin) +#p2p-discoverable= + # An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint. (eosio::net_plugin) # p2p-server-address = @@ -158,3 +161,5 @@ txn-reference-block-lag = 0 # plugin = plugin = eosio::chain_api_plugin plugin = eosio::history_api_plugin +# enable this option to produce blocks +#plugin = eosio::producer_plugin diff --git a/Docker/dev/Dockerfile b/Docker/dev/Dockerfile index f2dea74ac6c..cd79c5e0e2d 100644 --- a/Docker/dev/Dockerfile +++ b/Docker/dev/Dockerfile @@ -1,8 +1,8 @@ -FROM eosio/builder +FROM boscore/builder ARG branch=master ARG symbol=SYS -RUN git clone -b $branch https://github.com/EOSIO/eos.git --recursive \ +RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cd eos && echo "$branch:$(git rev-parse HEAD)" > /etc/eosio-version \ && cmake -H. -B"/opt/eosio" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/opt/eosio -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ diff --git a/README.md b/README.md index 2a048d5b973..43fcdfa2d61 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,37 @@ +# BOSCore - Born for DApp, be more useable. -# EOSIO - The Most Powerful Infrastructure for Decentralized Applications +## BOSCore Version: v1.0.2 +### Basic EOSIO Version: v1.4.4 -[![Build status](https://badge.buildkite.com/370fe5c79410f7d695e4e34c500b4e86e3ac021c6b1f739e20.svg?branch=master)](https://buildkite.com/EOSIO/eosio) +# Background +The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. +During the gradual development of the EOS main network, we found some deviations from expectations. As the most competitive third-generation public chain, we look forward to seeing more and more applications running on EOS. Developers will use EOS as their preferred platform for application development. But due to the limitations of the current EOS resource model, higher cost of use including creating more accounts for users and deploying operating DApp. The key technology IBC needed for the millions of TPS to be realized in the white paper has not been promoted. The main network has repeatedly experienced insufficient CPU computing resources, which has intensified the urgency of the demand for cross-chain communication. In addition, due to the Pipeline-DPOS consensus algorithm adopted by EOSIO, a transaction takes nearly three minutes to ensure that it cannot be changed. Although it is much better than Bitcoin and Ethereum, it also brings restrictions to a lot of EOS application scenarios. Fast payment can only focus on small transfers, large transfers must wait long enough to ensure that they cannot be changed, which limits the payment experience of users on the chain and under the chain. +In addition to the above mentioned, there are many other improvements that have been actively discussed in our community. From this, we feel that we should try more on EOS and let more developers or teams participate in the construction of EOSIO ecosystem. we will together make efforts for the blockchain to land in different scenarios in different industries. As a fully community-maintained EOS side chain, BOS will make more attempts based on its inherited good functions and will feed back to the EOSIO ecosystem its proven new features and functions. -Welcome to the EOSIO source code repository! This software enables businesses to rapidly build and deploy high-performance and high-security blockchain-based applications. +# Overview +BOS is committed to providing users with easy-to-access and easy-to-use blockchain services, providing a more user-friendly infrastructure for DApp operations, working to support richer application scenarios, and actively experimenting with DApp booms. In addition to technical improvements, BOS will also try other aspects. For example, in order to increase the participation of users in voting, estimator technology can be used to motivate accounts that meet clear rules. The rewards of BP on BOS will be adjusted according to the number of DApp on the chain, TPS, market value, liquidity and other indicators. Each BP is an encouragement for providing more resources for the ecology. A resolution reached by a community referendum will be coded as much as possible, to reduce human factors in the process, keep the process on chain, and maintain fairness and transparency. +The codes of the BOS chain are fully contributed and maintained by the community. Each ecological participant can submit codes or suggestions. The related process will refer to existing open source software, such as PEP (Python Enhancement Proposals). +In order to encourage the development of DApp in BOS, the BOS Foundation will provide Token replacement of low-cost resource mortgage services for DApp in BOS, reduce the operating costs of DApp in the early stage; in addition, it will also regularly provide BOS incentives to developers who contribute on a regular basis in order to establish a mutually reinforcing community development trend. -Some of the groundbreaking features of EOSIO include: +# Developer Rewards -1. Free Rate Limited Transactions -1. Low Latency Block confirmation (0.5 seconds) -1. Low-overhead Byzantine Fault Tolerant Finality -1. Designed for optional high-overhead, low-latency BFT finality -1. Smart contract platform powered by Web Assembly -1. Designed for Sparse Header Light Client Validation -1. Scheduled Recurring Transactions -1. Time Delay Security -1. Hierarchical Role Based Permissions -1. Support for Biometric Hardware Secured Keys (e.g. Apple Secure Enclave) -1. Designed for Parallel Execution of Context Free Validation Logic -1. Designed for Inter Blockchain Communication +An additional 0.8% issuance will be given to the BOS eco-contribution code developer every year. Fifty candidates will be nominated by the community. Top 50 BPs vote 40 winners to get the awards: the top 10 share 40%, people ranked 11 to 20 share 30%, the last 20 share the remaining 30% evenly. The reward happens once every 3 months and each reward will be carried out with a one-week publicity. It will be re-evaluated if there is a reasonable objection. And each reward list will be recorded on chain. +As BOS continues to develop, developer rewards will be appropriately adjusted to allow the community to provide more momentum for the evolution of BOS. -EOSIO is released under the open source MIT license and is offered “AS IS” without warranty of any kind, express or implied. Any security provided by the EOSIO software depends in part on how it is used, configured, and deployed. EOSIO is built upon many third-party libraries such as Binaryen (Apache License) and WAVM (BSD 3-clause) which are also provided “AS IS” without warranty of any kind. Without limiting the generality of the foregoing, Block.one makes no representation or guarantee that EOSIO or any third-party libraries will perform as intended or will be free of errors, bugs or faulty code. Both may fail in large or small ways that could completely or partially limit functionality or compromise computer systems. If you use or implement EOSIO, you do so at your own risk. In no event will Block.one be liable to any party for any damages whatsoever, even if it had been advised of the possibility of damage. +## Links +1. [Website](https://boscore.io) +2. [Developer Telegram Group](https://t.me/BOSCoreDev) +3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) -Block.one is neither launching nor operating any initial public blockchains based upon the EOSIO software. This release refers only to version 1.0 of our open source software. We caution those who wish to use blockchains built on EOSIO to carefully vet the companies and organizations launching blockchains based on EOSIO before disclosing any private keys to their derivative software. +## Start +1. Build from code : `bash ./eosio_build.sh -s BOS` +2. Docker Style,check [Docker](./Docker/README.md) -There is no public testnet running currently. +BOSCore bases on EOSIO, so you can also referer: -**If you have previously installed EOSIO, please run the `eosio_uninstall` script (it is in the directory where you cloned EOSIO) before downloading and using the binary releases.** +[Getting Started](https://developers.eos.io/eosio-nodeos/docs/overview-1) -#### Mac OS X Brew Install -```sh -$ brew tap eosio/eosio -$ brew install eosio -``` -#### Mac OS X Brew Uninstall -```sh -$ brew remove eosio -``` -#### Ubuntu 18.04 Debian Package Install -```sh -$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio_1.4.4-1-ubuntu-18.04_amd64.deb -$ sudo apt install ./eosio_1.4.4-1-ubuntu-18.04_amd64.deb -``` -#### Ubuntu 16.04 Debian Package Install -```sh -$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio_1.4.4-1-ubuntu-16.04_amd64.deb -$ sudo apt install ./eosio_1.4.4-1-ubuntu-16.04_amd64.deb -``` -#### Debian Package Uninstall -```sh -$ sudo apt remove eosio -``` -#### Centos RPM Package Install -```sh -$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio-1.4.4-1.el7.x86_64.rpm -$ sudo yum install ./eosio-1.4.4-1.el7.x86_64.rpm -``` -#### Centos RPM Package Uninstall -```sh -$ sudo yum remove eosio.cdt -``` -#### Fedora RPM Package Install -```sh -$ wget https://github.com/eosio/eos/releases/download/v1.4.4/eosio-1.4.4-1.fc27.x86_64.rpm -$ sudo yum install ./eosio-1.4.4-1.fc27.x86_64.rpm -``` -#### Fedora RPM Package Uninstall -```sh -$ sudo yum remove eosio.cdt -``` +[EOSIO Developer Portal](https://developers.eos.io). -## Supported Operating Systems -EOSIO currently supports the following operating systems: -1. Amazon 2017.09 and higher -2. Centos 7 -3. Fedora 25 and higher (Fedora 27 recommended) -4. Mint 18 -5. Ubuntu 16.04 (Ubuntu 16.10 recommended) -6. Ubuntu 18.04 -7. MacOS Darwin 10.12 and higher (MacOS 10.13.x recommended) -## Resources -1. [Website](https://eos.io) -1. [Blog](https://medium.com/eosio) -1. [Developer Portal](https://developers.eos.io) -1. [StackExchange for Q&A](https://eosio.stackexchange.com/) -1. [Community Telegram Group](https://t.me/EOSProject) -1. [Developer Telegram Group](https://t.me/joinchat/EaEnSUPktgfoI-XPfMYtcQ) -1. [White Paper](https://github.com/EOSIO/Documentation/blob/master/TechnicalWhitePaper.md) -1. [Roadmap](https://github.com/EOSIO/Documentation/blob/master/Roadmap.md) - - -## Getting Started -Instructions detailing the process of getting the software, building it, running a simple test network that produces blocks, account creation and uploading a sample contract to the blockchain can be found in [Getting Started](https://developers.eos.io/eosio-nodeos/docs/overview-1) on the [EOSIO Developer Portal](https://developers.eos.io). diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 00000000000..d4701484fb9 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,36 @@ +# BOSCore - 更可用的链,为DApp而生。 + +## BOSCore Version: v1.0.2 +### Basic EOSIO Version: v1.4.4 + +# 背景 +EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 +在EOS主网逐渐发展的过程中,我们发现了一些偏离期望的地方。作为最有竞争力的第三代公链,大家希望看到的是能够有更多、更丰富的应用能够在EOS上面运行,开发者会将EOS作为自己应用开发的首选平台,但是由于目前EOS的资源模型的限制,导致了很高的使用成本,包括为用户创建更多的账户,以及部署运营DApp需要的较高成本。针对白皮书中要实现的上百万TPS需要的关键技术IBC,一直没有进行推进,主网多次出现CPU计算资源不足的情况,更是加剧了对跨链通讯需求的迫切性。此外,由于EOSIO采用的Pipeline-DPOS共识机制,一个交易需要近三分钟才能保证不可更改,虽然相较比特币、以太坊是有很大的进步,但是这也给EOS的应用场景带来很大限制,快速支付只能聚焦于小额转账,大额转账必须要等待足够长的时间才能保证不可更改,这就限制了链上、链下用户支付体验。 +除了上面提到的情况,还有很多其他改进想法一直在我们社区进行活跃的讨论,由此,我们觉得应该基于EOS进行更多的尝试,让更多的开发者或者团队来参与到EOSIO生态的建设中来,一起为区块链在不同行业不同场景中的落地做出一份努力。BOS作为一条完全由社区维护的EOS侧链,在继承其良好功能的基础上,会进行更多的尝试,并且会将经过验证的新特性、新功能反哺给EOSIO生态。 + +# 概述 +BOS致力于为用户提供方便进入并易于使用的区块链服务,为DApp运营提供更友好的基础设施,为支持更丰富的应用场景努力,为DApp大繁荣进行积极尝试。除了技术改进以外,BOS也会进行其他方面的尝试。比如,为了提高用户投票参与度,可以通过预言机技术来针对符合明确规则的账户进行激励;BOS上面的BP的奖励会根据链上DApp的数量、TPS、市值、流通量等指标进行调整,鼓励每个BP为生态提供更多资源;一项社区公投达成的决议将会尽量被代码化,减少人为的因素在里面,流程上链,保持公正透明。 +BOS链的代码完全由社区贡献并维护,每个生态参与者都可以提交代码或者建议,相关的流程会参考已有开源软件来进行,比如PEP(Python Enhancement Proposals)。 +为鼓励DApp在BOS的发展,BOS基金会将会为其上的DApp提供Token置换的低成本的资源抵押服务,降低DApp前期的运营成本;此外还会定期对做出贡献的开发者提供BOS激励,以便建立起一个相互促进的社区发展趋势。 + +# 开发者激励 +每年增发 0.8% 面向BOS生态贡献代码的开发者,由社区提出50名奖励名单,由前50名BP投票选出40名的获奖者获取对应奖励:前10名获取40%,11到20名获取30%,最后20名均分30%,奖励周期3个月一次,每次奖励名额都会进行为期一周的公示,如果有合理异议,将会重新评审,每次奖励名单都会上链记录。 +随着BOS的不断发展,开发者奖励会适当调整,让社区为BOS的进化提供更多动力。 + + +## 资源 +1. [官网](https://boscore.io) +2. [开发者社群](https://t.me/BOSCoreDev) +3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) + +## 开始 +1. 源码直接编译: `bash ./eosio_build.sh -s BOS` +2. Docker方式部署,参看 [Docker](./Docker/README.md) + +BOSCore是基于EOSIO技术的扩展,所以EOSIO的相关资料也可以参考: + +[EOSIO 开始](https://developers.eos.io/eosio-nodeos/docs/overview-1) + +[EOSIO 开发者门户](https://developers.eos.io). + diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 1e190e9fe3c..95a40781530 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -205,7 +205,7 @@ namespace eosiosystem { const int64_t max_claimable = 100'000'000'0000ll; const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); - eosio_assert( max_claimable - claimable <= stake, "b1 can only claim their tokens over 10 years" ); + eosio_assert( max_claimable - claimable <= stake, "bosbosbosbos can only claim their tokens over 10 years" ); } void system_contract::changebw( account_name from, account_name receiver, diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp index a33238a1eaa..66964e39659 100644 --- a/contracts/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/eosio.system.hpp @@ -172,7 +172,6 @@ namespace eosiosystem { void undelegatebw( account_name from, account_name receiver, asset unstake_net_quantity, asset unstake_cpu_quantity ); - /** * Increases receiver's ram quota based upon current price and quantity of * tokens provided. An inline transfer from receiver to system contract of diff --git a/contracts/eosio.system/voting.cpp b/contracts/eosio.system/voting.cpp index 166f1707cd7..feeb53fc3d8 100644 --- a/contracts/eosio.system/voting.cpp +++ b/contracts/eosio.system/voting.cpp @@ -86,8 +86,15 @@ namespace eosiosystem { return; } - /// sort by producer name - std::sort( top_producers.begin(), top_producers.end() ); + /// sort by producer location + struct { + bool operator()(std::pair a, std::pair b) const + { + return a.second ==b.second?a.first producers; diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index dd7c05ded17..db115ca27e1 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -94,6 +94,28 @@ extern "C" { */ size_t transaction_size(); + /** + * Get transaction id + * + * @param id : return id + */ + void get_transaction_id( transaction_id_type* id ); + + /** + * Get the action globally unique sequence + * + * @param seq : return sequence + */ + void get_action_sequence(uint64_t* seq); + + /** + * Get the producer's signature for the action + * @param sig : Memory buffer + * @param siglen :Memory buffer size + * @return : Return valid data size + */ + int bpsig_action_time_seed( const char* sig, size_t siglen ); + /** * Gets the block number used for TAPOS on the currently executing transaction. * diff --git a/eosio_build.sh b/eosio_build.sh index b1988d74f0c..fafdbbaeb8e 100755 --- a/eosio_build.sh +++ b/eosio_build.sh @@ -120,8 +120,8 @@ if [ ! -d "${SOURCE_DIR}/.git" ]; then printf "\\n\\tThis build script only works with sources cloned from git\\n" - printf "\\tPlease clone a new eos directory with 'git clone https://github.com/EOSIO/eos --recursive'\\n" - printf "\\tSee the wiki for instructions: https://github.com/EOSIO/eos/wiki\\n" + printf "\\tPlease clone a new bos directory with 'git clone https://github.com/boscore/bos --recursive'\\n" + printf "\\tSee the wiki for instructions: https://github.com/boscore/bos/wiki\\n" exit 1 fi @@ -238,7 +238,7 @@ . "$FILE" - printf "\\n\\n>>>>>>>> ALL dependencies sucessfully found or installed . Installing EOSIO\\n\\n" + printf "\\n\\n>>>>>>>> ALL dependencies sucessfully found or installed . Installing BOSCore\\n\\n" printf ">>>>>>>> CMAKE_BUILD_TYPE=%s\\n" "${CMAKE_BUILD_TYPE}" printf ">>>>>>>> ENABLE_COVERAGE_TESTING=%s\\n" "${ENABLE_COVERAGE_TESTING}" printf ">>>>>>>> DOXYGEN=%s\\n\\n" "${DOXYGEN}" @@ -267,41 +267,42 @@ -DENABLE_COVERAGE_TESTING="${ENABLE_COVERAGE_TESTING}" -DBUILD_DOXYGEN="${DOXYGEN}" \ -DCMAKE_INSTALL_PREFIX="/usr/local/eosio" ${LOCAL_CMAKE_FLAGS} "${SOURCE_DIR}" then - printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building EOSIO has exited with the above error.\\n\\n" + printf "\\n\\t>>>>>>>>>>>>>>>>>>>> CMAKE building BOSCore has exited with the above error.\\n\\n" exit -1 fi if [ "${START_MAKE}" == "false" ]; then - printf "\\n\\t>>>>>>>>>>>>>>>>>>>> EOSIO has been successfully configured but not yet built.\\n\\n" + printf "\\n\\t>>>>>>>>>>>>>>>>>>>> BOSCore has been successfully configured but not yet built.\\n\\n" exit 0 fi if [ -z ${JOBS} ]; then JOBS=$CPU_CORE; fi # Future proofing: Ensure $JOBS is set (usually set in scripts/eosio_build_*.sh scripts) if ! make -j"${JOBS}" then - printf "\\n\\t>>>>>>>>>>>>>>>>>>>> MAKE building EOSIO has exited with the above error.\\n\\n" + printf "\\n\\t>>>>>>>>>>>>>>>>>>>> MAKE building BOSCore has exited with the above error.\\n\\n" exit -1 fi TIME_END=$(( $(date -u +%s) - ${TIME_BEGIN} )) - printf "\n\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${txtrst}" + printf "\n\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\n${txtrst}" - printf "\\n\\tEOSIO has been successfully built. %02d:%02d:%02d\\n\\n" $(($TIME_END/3600)) $(($TIME_END%3600/60)) $(($TIME_END%60)) + printf "\\n\\tBOSCore has been successfully built. %02d:%02d:%02d\\n\\n" $(($TIME_END/3600)) $(($TIME_END%3600/60)) $(($TIME_END%60)) printf "\\tTo verify your installation run the following commands:\\n" print_instructions printf "\\tFor more information:\\n" - printf "\\tEOSIO website: https://eos.io\\n" - printf "\\tEOSIO Telegram channel @ https://t.me/EOSProject\\n" + printf "\\tBOSCore website: https://boscore.io\\n" + printf "\\tBOSCore Telegram channel @ https://t.me/BOSCoreProject\\n" + printf "\\tBOSCore wiki: https://github.com/boscore/bos/wiki\\n" printf "\\tEOSIO resources: https://eos.io/resources/\\n" printf "\\tEOSIO Stack Exchange: https://eosio.stackexchange.com\\n" printf "\\tEOSIO wiki: https://github.com/EOSIO/eos/wiki\\n\\n\\n" diff --git a/eosio_install.sh b/eosio_install.sh index 9ed195df7d0..fcb6e3c81d7 100755 --- a/eosio_install.sh +++ b/eosio_install.sh @@ -103,18 +103,20 @@ fi install_symlinks create_cmake_symlink "eosio-config.cmake" - printf "\n\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${txtrst}" + printf "\n\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\n${txtrst}" printf "\\tFor more information:\\n" - printf "\\tEOSIO website: https://eos.io\\n" - printf "\\tEOSIO Telegram channel @ https://t.me/EOSProject\\n" + printf "\\tBOSCore website: https://boscore.io\\n" + printf "\\tBOSCore Telegram channel @ https://t.me/BOSCoreProject\\n" + printf "\\tBOSCore wiki: https://github.com/boscore/bos/wiki\\n" printf "\\tEOSIO resources: https://eos.io/resources/\\n" printf "\\tEOSIO Stack Exchange: https://eosio.stackexchange.com\\n" printf "\\tEOSIO wiki: https://github.com/EOSIO/eos/wiki\\n\\n\\n" + diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index de1450013d8..07ab384eeff 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -44,6 +44,9 @@ void apply_context::exec_one( action_trace& trace ) trace.act = act; trace.context_free = context_free; + const auto& p = control.get_dynamic_global_properties(); + global_action_sequence = p.global_action_sequence + 1; + const auto& cfg = control.get_global_properties().configuration; try { try { @@ -79,6 +82,7 @@ void apply_context::exec_one( action_trace& trace ) r.global_sequence = next_global_sequence(); r.recv_sequence = next_recv_sequence( receiver ); + global_action_sequence = 0; const auto& account_sequence = db.get(act.account); r.code_sequence = account_sequence.code_sequence; // could be modified by action execution above diff --git a/libraries/chain/block_header.cpp b/libraries/chain/block_header.cpp index 8ba95b705e2..b73338b3ca2 100644 --- a/libraries/chain/block_header.cpp +++ b/libraries/chain/block_header.cpp @@ -28,5 +28,15 @@ namespace eosio { namespace chain { return result; } + void block_header::set_block_extensions_mroot(digest_type& mroot) + { + if (header_extensions.size() < 1) + header_extensions.emplace_back(); + + header_extensions[0].first = static_cast(block_header_extensions_type::block_extensions_mroot); + header_extensions[0].second.resize(mroot.data_size()); + std::copy(mroot.data(), mroot.data() + mroot.data_size(), header_extensions[0].second.data()); + } + } } diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 6e7b339c42c..2ae15af7341 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -145,7 +145,7 @@ namespace eosio { namespace chain { */ block_header_state block_header_state::next( const signed_block_header& h, bool trust )const { EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) ); - EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); + //EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); EOS_ASSERT( h.timestamp > header.timestamp, block_validate_exception, "block must be later in time" ); EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); @@ -175,8 +175,10 @@ namespace eosio { namespace chain { result.header.action_mroot = h.action_mroot; result.header.transaction_mroot = h.transaction_mroot; result.header.producer_signature = h.producer_signature; + result.header.header_extensions = h.header_extensions; result.id = result.header.id(); + // ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here if( !trust ) { EOS_ASSERT( result.block_signing_key == result.signee(), wrong_signing_key, "block not signed by expected key", diff --git a/libraries/chain/chain_config.cpp b/libraries/chain/chain_config.cpp index 974675749fb..efb66bba95f 100644 --- a/libraries/chain/chain_config.cpp +++ b/libraries/chain/chain_config.cpp @@ -43,4 +43,10 @@ namespace eosio { namespace chain { "max authority depth should be at least 1" ); } +void chain_config2::validate() const{ + EOS_ASSERT(std::numeric_limits::max() > actor_blacklist.size(), action_validate_exception, "Overflow in blacklist when adding actor blacklist!"); + EOS_ASSERT(std::numeric_limits::max() > contract_blacklist.size(), action_validate_exception, "Overflow in blacklist when adding contract blacklist!"); + EOS_ASSERT(std::numeric_limits::max() > resource_greylist.size(), action_validate_exception, "Overflow in greylistwhen adding resource greylist!"); +} + } } // namespace eosio::chain diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 41e9d551728..cb824cf45ba 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -33,6 +33,7 @@ using controller_index_set = index_set< account_index, account_sequence_index, global_property_multi_index, + global_property2_multi_index, dynamic_global_property_multi_index, block_summary_multi_index, transaction_multi_index, @@ -108,6 +109,8 @@ struct pending_state { optional _producer_block_id; + std::function _signer; + void push() { _db_session.push(); } @@ -391,6 +394,11 @@ struct controller_impl { ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } + //*bos begin* + sync_name_list(list_type::actor_blacklist_type,true); + sync_name_list(list_type::contract_blacklist_type,true); + sync_name_list(list_type::resource_greylist_type,true); + //*bos end* } ~controller_impl() { @@ -637,6 +645,17 @@ struct controller_impl { }); db.create([](auto&){}); + // *bos begin* + //guaranteed minimum resources which is abbreviated gmr + db.create([&](auto &gpo) { + gpo.gmr.cpu_us = config::default_gmr_cpu_limit; + gpo.gmr.net_byte = config::default_gmr_net_limit; + gpo.gmr.ram_byte = config::default_gmr_ram_limit; + }); + + + // *bos end* + authorization.initialize_database(); resource_limits.initialize_database(); @@ -662,7 +681,73 @@ struct controller_impl { conf.genesis.initial_timestamp ); } + // "bos begin" + void set_name_list(list_type list, list_action_type action, std::vector name_list) + { + int64_t lst = static_cast(list); + + EOS_ASSERT(list >= list_type::actor_blacklist_type && list < list_type::list_type_count, transaction_exception, "unknown list type : ${l}, action: ${n}", ("l", static_cast(list))("n", static_cast(action))); + vector *> lists = {&conf.actor_blacklist, &conf.contract_blacklist, &conf.resource_greylist}; + EOS_ASSERT(lists.size() == static_cast(list_type::list_type_count) - 1, transaction_exception, " list size wrong : ${l}, action: ${n}", ("l", static_cast(list))("n", static_cast(action))); + flat_set &lo = *lists[lst - 1]; + + if (action == list_action_type::insert_type) + { + lo.insert(name_list.begin(), name_list.end()); + } + else if (action == list_action_type::remove_type) + { + flat_set name_set(name_list.begin(), name_list.end()); + + flat_set results; + results.reserve(lo.size()); + set_difference(lo.begin(), lo.end(), + name_set.begin(), name_set.end(), + std::inserter(results,results.begin())); + + lo = results; + } + + sync_name_list(list); + } + + void sync_list_and_db(list_type list, global_property2_object &gprops2,bool isMerge=false) + { + int64_t lst = static_cast(list); + EOS_ASSERT( list >= list_type::actor_blacklist_type && list < list_type::list_type_count, transaction_exception, "unknown list type : ${l}, ismerge: ${n}", ("l", static_cast(list))("n", isMerge)); + vector *> lists = {&gprops2.cfg.actor_blacklist, &gprops2.cfg.contract_blacklist, &gprops2.cfg.resource_greylist}; + vector *> conflists = {&conf.actor_blacklist, &conf.contract_blacklist, &conf.resource_greylist}; + EOS_ASSERT(lists.size() == static_cast(list_type::list_type_count) - 1, transaction_exception, " list size wrong : ${l}, ismerge: ${n}", ("l", static_cast(list))("n", isMerge)); + shared_vector &lo = *lists[lst - 1]; + flat_set &clo = *conflists[lst - 1]; + + if (isMerge) + { + //initialize, merge elements and deduplication between list and db.result save to list + for (auto &a : lo) + { + clo.insert(a); + } + } + + //clear list from db and save merge result to db object + lo.clear(); + for (auto &a : clo) + { + lo.push_back(a); + } + } + + void sync_name_list(list_type list,bool isMerge=false) + { + const auto &gpo2 = db.get(); + db.modify(gpo2, [&](auto &gprops2) { + sync_list_and_db(list, gprops2,isMerge); + }); + } + + // "bos end" /** * @post regardless of the success of commit block there is no active pending block @@ -1074,7 +1159,7 @@ struct controller_impl { void start_block( block_timestamp_type when, uint16_t confirm_block_count, controller::block_status s, - const optional& producer_block_id ) + const optional& producer_block_id , std::function signer = nullptr) { EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" ); @@ -1093,6 +1178,7 @@ struct controller_impl { pending->_block_status = s; pending->_producer_block_id = producer_block_id; + pending->_signer = signer; pending->_pending_block_state = std::make_shared( *head, when ); // promotes pending schedule (if any) to active pending->_pending_block_state->in_current_chain = true; @@ -1160,10 +1246,13 @@ struct controller_impl { void apply_block( const signed_block_ptr& b, controller::block_status s ) { try { try { - EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" ); + //EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" ); auto producer_block_id = b->id(); start_block( b->timestamp, b->confirmed, s , producer_block_id); + pending->_pending_block_state->block->header_extensions = b->header_extensions; + pending->_pending_block_state->block->block_extensions = b->block_extensions; + transaction_trace_ptr trace; for( const auto& receipt : b->transactions ) { @@ -1228,7 +1317,6 @@ struct controller_impl { void push_block( const signed_block_ptr& b, controller::block_status s ) { EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); - auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() { trusted_producer_light_validation = old_value; }); @@ -1361,6 +1449,17 @@ struct controller_impl { pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) ); } + void set_ext_merkle() { + vector ext_digests; + const auto& exts = pending->_pending_block_state->block->block_extensions; + ext_digests.reserve( exts.size()); + for( const auto& a : exts ) + ext_digests.emplace_back( digest_type::hash(a) ); + + auto mroot = merkle( move(ext_digests)); + pending->_pending_block_state->header.set_block_extensions_mroot(mroot); + } + void finalize_block() { @@ -1385,16 +1484,24 @@ struct controller_impl { // Update resource limits: resource_limits.process_account_limit_updates(); const auto& chain_config = self.get_global_properties().configuration; + const auto& gmr = self.get_global_properties2().gmr;//guaranteed minimum resources which is abbreviated gmr + uint32_t max_virtual_mult = 1000; uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct); resource_limits.set_block_parameters( { CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}}, {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}} ); + + resource_limits.set_gmr_parameters( + { gmr.ram_byte, gmr.cpu_us,gmr.net_byte} + ); + resource_limits.process_block_usage(pending->_pending_block_state->block_num); set_action_merkle(); set_trx_merkle(); + set_ext_merkle(); auto p = pending->_pending_block_state; p->id = p->header.id(); @@ -1605,9 +1712,9 @@ chainbase::database& controller::mutable_db()const { return my->db; } const fork_database& controller::fork_db()const { return my->fork_db; } -void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count) { +void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count, std::function signer) { validate_db_available_size(); - my->start_block(when, confirm_block_count, block_status::incomplete, optional() ); + my->start_block(when, confirm_block_count, block_status::incomplete, optional() , signer); } void controller::finalize_block() { @@ -1677,12 +1784,21 @@ void controller::set_actor_whitelist( const flat_set& new_actor_wh } void controller::set_actor_blacklist( const flat_set& new_actor_blacklist ) { my->conf.actor_blacklist = new_actor_blacklist; + + // *bos begin* + my->sync_name_list(list_type::actor_blacklist_type); + // *bos end* } void controller::set_contract_whitelist( const flat_set& new_contract_whitelist ) { my->conf.contract_whitelist = new_contract_whitelist; } void controller::set_contract_blacklist( const flat_set& new_contract_blacklist ) { my->conf.contract_blacklist = new_contract_blacklist; + + // *bos begin* + my->sync_name_list(list_type::contract_blacklist_type); + // *bos end* + } void controller::set_action_blacklist( const flat_set< pair >& new_action_blacklist ) { for (auto& act: new_action_blacklist) { @@ -1744,6 +1860,11 @@ optional controller::pending_producer_block_id()const { return my->pending->_producer_block_id; } +std::function controller::pending_producer_signer()const { + EOS_ASSERT( my->pending, block_validate_exception, "no pending block" ); + return my->pending->_signer; +} + uint32_t controller::last_irreversible_block_num() const { return std::max(std::max(my->head->bft_irreversible_blocknum, my->head->dpos_irreversible_blocknum), my->snapshot_head_block); } @@ -2092,10 +2213,19 @@ void controller::set_subjective_cpu_leeway(fc::microseconds leeway) { void controller::add_resource_greylist(const account_name &name) { my->conf.resource_greylist.insert(name); + + // *bos begin* + my->sync_name_list(list_type::resource_greylist_type); + // *bos end* } void controller::remove_resource_greylist(const account_name &name) { + my->conf.resource_greylist.erase(name); + + // *bos begin* + my->sync_name_list(list_type::resource_greylist_type); + // *bos end* } bool controller::is_resource_greylisted(const account_name &name) const { @@ -2106,4 +2236,21 @@ const flat_set &controller::get_resource_greylist() const { return my->conf.resource_greylist; } +// *bos begin* +const global_property2_object& controller::get_global_properties2()const { + return my->db.get(); +} + +void controller::set_name_list(int64_t list, int64_t action, std::vector name_list) +{ + //redundant sync + my->sync_name_list(list_type::actor_blacklist_type, true); + my->sync_name_list(list_type::contract_blacklist_type, true); + my->sync_name_list(list_type::resource_greylist_type, true); + + my->set_name_list(static_cast(list), static_cast(action), name_list); +} +// *bos end* + + } } /// eosio::chain diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index c56ed0add05..317453f19b8 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -142,7 +142,6 @@ namespace eosio { namespace chain { block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) { EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); - const auto& by_id_idx = my->index.get(); auto existing = by_id_idx.find( b->id() ); EOS_ASSERT( existing == by_id_idx.end(), fork_database_exception, "we already know about this block" ); @@ -203,7 +202,6 @@ namespace eosio { namespace chain { /// remove all of the invalid forks built of this id including this id void fork_database::remove( const block_id_type& id ) { vector remove_queue{id}; - for( uint32_t i = 0; i < remove_queue.size(); ++i ) { auto itr = my->index.find( remove_queue[i] ); if( itr != my->index.end() ) diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index a253d950358..2b68d015442 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -594,6 +594,7 @@ class apply_context { bool privileged = false; bool context_free = false; bool used_context_free_api = false; + uint64_t global_action_sequence = 0; generic_index idx64; generic_index idx128; diff --git a/libraries/chain/include/eosio/chain/block.hpp b/libraries/chain/include/eosio/chain/block.hpp index 0e85b167df8..28c49f9772e 100644 --- a/libraries/chain/include/eosio/chain/block.hpp +++ b/libraries/chain/include/eosio/chain/block.hpp @@ -51,6 +51,9 @@ namespace eosio { namespace chain { } }; + enum class block_extension_type : uint16_t { + bpsig_action_time_seed + }; /** */ diff --git a/libraries/chain/include/eosio/chain/block_header.hpp b/libraries/chain/include/eosio/chain/block_header.hpp index bf9cf0bedb8..723824b5310 100644 --- a/libraries/chain/include/eosio/chain/block_header.hpp +++ b/libraries/chain/include/eosio/chain/block_header.hpp @@ -4,6 +4,12 @@ namespace eosio { namespace chain { + /* Extended spatial data category + */ + enum block_header_extensions_type : uint16_t { + block_extensions_mroot = 0 // mroot of block extensions + }; + struct block_header { block_timestamp_type timestamp; @@ -32,13 +38,14 @@ namespace eosio { namespace chain { */ uint32_t schedule_version = 0; optional new_producers; - extensions_type header_extensions; + extensions_type header_extensions; // [0] : mroot of block extensions digest_type digest()const; block_id_type id() const; uint32_t block_num() const { return num_from_id(previous) + 1; } static uint32_t num_from_id(const block_id_type& id); + void set_block_extensions_mroot(digest_type& mroot); }; diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index 7f62ff111f9..907846d1a55 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -65,6 +65,24 @@ struct chain_config { bool operator==(const chain_config& a, const chain_config& b); inline bool operator!=(const chain_config& a, const chain_config& b) { return !(a == b); } +// *bos* +struct chain_config2 { + chain_config2( chainbase::allocator alloc ) + :actor_blacklist(alloc),contract_blacklist(alloc),resource_greylist(alloc){} + + shared_vector actor_blacklist; + shared_vector contract_blacklist; + shared_vector resource_greylist; + + void validate()const; +}; + +// *bos* +struct guaranteed_minimum_resources { + uint64_t ram_byte; + uint64_t cpu_us; + uint64_t net_byte; +}; } } // namespace eosio::chain FC_REFLECT(eosio::chain::chain_config, @@ -79,3 +97,6 @@ FC_REFLECT(eosio::chain::chain_config, (max_inline_action_size)(max_inline_action_depth)(max_authority_depth) ) +// *bos* +FC_REFLECT( eosio::chain::chain_config2, (actor_blacklist)(contract_blacklist)(resource_greylist) ) +FC_REFLECT( eosio::chain::guaranteed_minimum_resources, (ram_byte)(cpu_us)(net_byte) ) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index c0e9806319e..6aea7c3e3bd 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -5,6 +5,7 @@ #pragma once #include #include +#include "config_xos.hpp" #pragma GCC diagnostic ignored "-Wunused-variable" diff --git a/libraries/chain/include/eosio/chain/config_xos.hpp b/libraries/chain/include/eosio/chain/config_xos.hpp new file mode 100644 index 00000000000..02adf0d54d0 --- /dev/null +++ b/libraries/chain/include/eosio/chain/config_xos.hpp @@ -0,0 +1,23 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-variable" + +namespace eosio { namespace chain { namespace config { + +//guaranteed minimum resources which is abbreviated gmr +const static uint32_t default_gmr_cpu_limit = 200'000; /// free cpu usage in microseconds +const static uint32_t default_gmr_net_limit = 10 * 1024; // 10 KB +const static uint32_t default_gmr_ram_limit = 0; // 0 KB +const static uint16_t default_gmr_resource_limit_per_day = 1000; + + + +} } } // namespace eosio::chain::config + + diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index ec7b53fafc0..17ca27b3235 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -27,6 +27,7 @@ namespace eosio { namespace chain { class dynamic_global_property_object; class global_property_object; + class global_property2_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -45,6 +46,21 @@ namespace eosio { namespace chain { FULL, LIGHT }; + // *bos begin* + enum class list_type:int64_t { + actor_blacklist_type=1, + contract_blacklist_type, + resource_greylist_type, + list_type_count + }; + enum class list_action_type:int64_t + { + insert_type = 1, + remove_type, + list_action_type_count + }; + + // *bos end* class controller { public: @@ -95,7 +111,7 @@ namespace eosio { namespace chain { * Starts a new pending block session upon which new transactions can * be pushed. */ - void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0 ); + void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0, std::function signer = nullptr ); void abort_block(); @@ -190,6 +206,7 @@ namespace eosio { namespace chain { optional pending_producer_block_id()const; const producer_schedule_type& active_producers()const; + std::function pending_producer_signer()const; const producer_schedule_type& pending_producers()const; optional proposed_producers()const; @@ -216,6 +233,15 @@ namespace eosio { namespace chain { void add_resource_greylist(const account_name &name); void remove_resource_greylist(const account_name &name); + + // *bos begin* + const global_property2_object& get_global_properties2()const; // *bos* + void set_name_list(int64_t list, int64_t action, std::vector name_list); + + // void list_add_name(const int list, const account_name &name); + // void list_remove_name(const int list, const account_name &name); + // *bos end* + bool is_resource_greylisted(const account_name &name) const; const flat_set &get_resource_greylist() const; diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index fe9ae85db10..6f4f35ffd80 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -34,6 +34,15 @@ namespace eosio { namespace chain { chain_config configuration; }; + // *bos* + class global_property2_object : public chainbase::object + { + OBJECT_CTOR(global_property2_object, (cfg)) + + id_type id; + chain_config2 cfg; + guaranteed_minimum_resources gmr;//guaranteed_minimum_resources + }; /** @@ -71,11 +80,22 @@ namespace eosio { namespace chain { > >; + // *bos* + using global_property2_multi_index = chainbase::shared_multi_index_container< + global_property2_object, + indexed_by< + ordered_unique, + BOOST_MULTI_INDEX_MEMBER(global_property2_object, global_property2_object::id_type, id) + > + > + >; }} CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::global_property_multi_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, eosio::chain::dynamic_global_property_multi_index) +// *bos* +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -84,3 +104,7 @@ FC_REFLECT(eosio::chain::dynamic_global_property_object, FC_REFLECT(eosio::chain::global_property_object, (proposed_schedule_block_num)(proposed_schedule)(configuration) ) +// *bos* +FC_REFLECT(eosio::chain::global_property2_object, + (cfg)(gmr) + ) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/resource_limits.hpp b/libraries/chain/include/eosio/chain/resource_limits.hpp index 4b0c58beeb0..616deb3f2a0 100644 --- a/libraries/chain/include/eosio/chain/resource_limits.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits.hpp @@ -35,6 +35,16 @@ namespace eosio { namespace chain { namespace resource_limits { int64_t max = 0; ///< max per window under current congestion }; + + struct gmr_parameters { + uint64_t ram_byte; + uint64_t cpu_us; + uint64_t net_byte; + + void validate()const; // throws if the parameters do not satisfy basic sanity checks + }; + + class resource_limits_manager { public: explicit resource_limits_manager(chainbase::database& db) @@ -50,6 +60,14 @@ namespace eosio { namespace chain { namespace resource_limits { void initialize_account( const account_name& account ); void set_block_parameters( const elastic_limit_parameters& cpu_limit_parameters, const elastic_limit_parameters& net_limit_parameters ); + + /** + * @brief Set the guaranteed minimum resources parameters object + * + * @param res_parameters guaranteed minimum resources parameters object include ram net cpu + */ + void set_gmr_parameters( const gmr_parameters& res_parameters ); // *bos* //guaranteed minimum resources which is abbreviated gmr + void update_account_usage( const flat_set& accounts, uint32_t ordinal ); void add_transaction_usage( const flat_set& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal ); @@ -58,7 +76,7 @@ namespace eosio { namespace chain { namespace resource_limits { /// set_account_limits returns true if new ram_bytes limit is more restrictive than the previously set one bool set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight); - void get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight) const; + void get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight, bool raw = false) const; // *bos* add raw void process_account_limit_updates(); void process_block_usage( uint32_t block_num ); @@ -86,3 +104,5 @@ namespace eosio { namespace chain { namespace resource_limits { FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max) ) FC_REFLECT( eosio::chain::resource_limits::ratio, (numerator)(denominator)) FC_REFLECT( eosio::chain::resource_limits::elastic_limit_parameters, (target)(max)(periods)(max_multiplier)(contract_rate)(expand_rate)) + +FC_REFLECT( eosio::chain::resource_limits::gmr_parameters, (ram_byte)(cpu_us)(net_byte)) diff --git a/libraries/chain/include/eosio/chain/resource_limits_private.hpp b/libraries/chain/include/eosio/chain/resource_limits_private.hpp index 687a56a4d90..877c77e5acb 100644 --- a/libraries/chain/include/eosio/chain/resource_limits_private.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits_private.hpp @@ -203,6 +203,24 @@ namespace eosio { namespace chain { namespace resource_limits { > >; + class gmr_config_object : public chainbase::object { + OBJECT_CTOR(gmr_config_object); + id_type id; + + + gmr_parameters res_parameters = { config::default_gmr_ram_limit,config::default_gmr_cpu_limit, config::default_gmr_net_limit}; + + }; + + using gmr_config_index = chainbase::shared_multi_index_container< + gmr_config_object, + indexed_by< + ordered_unique, member> + > + >; + + + class resource_limits_state_object : public chainbase::object { OBJECT_CTOR(resource_limits_state_object); id_type id; @@ -265,9 +283,14 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::resource_limits::resource_usage_object, CHAINBASE_SET_INDEX_TYPE(eosio::chain::resource_limits::resource_limits_config_object, eosio::chain::resource_limits::resource_limits_config_index) CHAINBASE_SET_INDEX_TYPE(eosio::chain::resource_limits::resource_limits_state_object, eosio::chain::resource_limits::resource_limits_state_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::resource_limits::gmr_config_object, eosio::chain::resource_limits::gmr_config_index) + FC_REFLECT(eosio::chain::resource_limits::usage_accumulator, (last_ordinal)(value_ex)(consumed)) FC_REFLECT(eosio::chain::resource_limits::resource_limits_object, (owner)(net_weight)(cpu_weight)(ram_bytes)) FC_REFLECT(eosio::chain::resource_limits::resource_usage_object, (owner)(net_usage)(cpu_usage)(ram_usage)) FC_REFLECT(eosio::chain::resource_limits::resource_limits_config_object, (cpu_limit_parameters)(net_limit_parameters)(account_cpu_usage_average_window)(account_net_usage_average_window)) -FC_REFLECT(eosio::chain::resource_limits::resource_limits_state_object, (average_block_net_usage)(average_block_cpu_usage)(pending_net_usage)(pending_cpu_usage)(total_net_weight)(total_cpu_weight)(total_ram_bytes)(virtual_net_limit)(virtual_cpu_limit)) \ No newline at end of file +FC_REFLECT(eosio::chain::resource_limits::resource_limits_state_object, (average_block_net_usage)(average_block_cpu_usage)(pending_net_usage)(pending_cpu_usage)(total_net_weight)(total_cpu_weight)(total_ram_bytes)(virtual_net_limit)(virtual_cpu_limit)) + + +FC_REFLECT(eosio::chain::resource_limits::gmr_config_object, (res_parameters)) diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 4610f24c891..028b050a595 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -148,6 +148,7 @@ namespace eosio { namespace chain { index_double_object_type, index_long_double_object_type, global_property_object_type, + global_property2_object_type, dynamic_global_property_object_type, block_summary_object_type, transaction_object_type, @@ -169,6 +170,7 @@ namespace eosio { namespace chain { resource_usage_object_type, resource_limits_state_object_type, resource_limits_config_object_type, + gmr_config_object_type, ///< Defined by bos account_history_object_type, ///< Defined by history_plugin action_history_object_type, ///< Defined by history_plugin reversible_block_object_type, diff --git a/libraries/chain/resource_limits.cpp b/libraries/chain/resource_limits.cpp index fa38f76a1e2..21865ac8676 100644 --- a/libraries/chain/resource_limits.cpp +++ b/libraries/chain/resource_limits.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,7 +14,8 @@ using resource_index_set = index_set< resource_limits_index, resource_usage_index, resource_limits_state_index, - resource_limits_config_index + resource_limits_config_index, + gmr_config_index >; static_assert( config::rate_limiting_precision > 0, "config::rate_limiting_precision must be positive" ); @@ -36,6 +38,13 @@ void elastic_limit_parameters::validate()const { EOS_ASSERT( expand_rate.denominator > 0, resource_limit_exception, "elastic limit parameter 'expand_rate' is not a well-defined ratio" ); } +void gmr_parameters::validate()const { + + EOS_ASSERT( cpu_us > 0, resource_limit_exception, "guaranteed minmum resources parameter 'cpu_us' cannot be zero" ); + EOS_ASSERT( net_byte > 0, resource_limit_exception, "guaranteed minmum resources parameter 'net_byte' cannot be zero" ); + EOS_ASSERT( ram_byte >= 0, resource_limit_exception, "guaranteed minmum resources parameter'ram_byte' cannot be less than zero" ); +} + void resource_limits_state_object::update_virtual_cpu_limit( const resource_limits_config_object& cfg ) { //idump((average_block_cpu_usage.average())); @@ -56,6 +65,10 @@ void resource_limits_manager::initialize_database() { // see default settings in the declaration }); + const auto& gmr_config = _db.create([](gmr_config_object& config){ + // see default settings in the declaration + }); + _db.create([&config](resource_limits_state_object& state){ // see default settings in the declaration @@ -108,6 +121,15 @@ void resource_limits_manager::set_block_parameters(const elastic_limit_parameter }); } +//guaranteed minimum resources which is abbreviated gmr +void resource_limits_manager::set_gmr_parameters(const gmr_parameters& res_parameters) { + res_parameters.validate(); + const auto& config = _db.get(); + _db.modify(config, [&](gmr_config_object& c){ + c.res_parameters = res_parameters; + }); +} + void resource_limits_manager::update_account_usage(const flat_set& accounts, uint32_t time_slot ) { const auto& config = _db.get(); for( const auto& a : accounts ) { @@ -123,6 +145,10 @@ void resource_limits_manager::add_transaction_usage(const flat_set const auto& state = _db.get(); const auto& config = _db.get(); + + //guaranteed minimum resources which is abbreviated gmr + const auto& gmr = _db.get().res_parameters; // *bos* + for( const auto& a : accounts ) { const auto& usage = _db.get( a ); @@ -144,7 +170,7 @@ void resource_limits_manager::add_transaction_usage(const flat_set uint128_t user_weight = (uint128_t)cpu_weight; uint128_t all_user_weight = state.total_cpu_weight; - auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight; + auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight+gmr.cpu_us; EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window, tx_cpu_usage_exceeded, @@ -163,7 +189,7 @@ void resource_limits_manager::add_transaction_usage(const flat_set uint128_t user_weight = (uint128_t)net_weight; uint128_t all_user_weight = state.total_net_weight; - auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight; + auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight+gmr.net_byte; EOS_ASSERT( net_used_in_window <= max_user_use_in_window, tx_net_usage_exceeded, @@ -269,8 +295,9 @@ bool resource_limits_manager::set_account_limits( const account_name& account, i return decreased_limit; } -void resource_limits_manager::get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight ) const { +void resource_limits_manager::get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight, bool raw ) const { const auto* pending_buo = _db.find( boost::make_tuple(true, account) ); + const auto& gmr = _db.get().res_parameters; // *bos* if (pending_buo) { ram_bytes = pending_buo->ram_bytes; net_weight = pending_buo->net_weight; @@ -281,6 +308,13 @@ void resource_limits_manager::get_account_limits( const account_name& account, i net_weight = buo.net_weight; cpu_weight = buo.cpu_weight; } + + // *bos* + const int64_t ONEKM = 1024; + if (!raw && ram_bytes >= ONEKM) + { + ram_bytes += gmr.ram_byte; + } } @@ -373,6 +407,7 @@ account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const const auto& state = _db.get(); const auto& usage = _db.get(name); const auto& config = _db.get(); + const auto& gmr = _db.get().res_parameters; // *bos* int64_t cpu_weight, x, y; get_account_limits( name, x, y, cpu_weight ); @@ -389,7 +424,7 @@ account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const uint128_t user_weight = (uint128_t)cpu_weight; uint128_t all_user_weight = (uint128_t)state.total_cpu_weight; - auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight; + auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight + gmr.cpu_us; auto cpu_used_in_window = impl::integer_divide_ceil((uint128_t)usage.cpu_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision); if( max_user_use_in_window <= cpu_used_in_window ) @@ -411,6 +446,7 @@ account_resource_limit resource_limits_manager::get_account_net_limit_ex( const const auto& config = _db.get(); const auto& state = _db.get(); const auto& usage = _db.get(name); + const auto& gmr = _db.get().res_parameters; // *bos* int64_t net_weight, x, y; get_account_limits( name, x, net_weight, y ); @@ -428,7 +464,7 @@ account_resource_limit resource_limits_manager::get_account_net_limit_ex( const uint128_t all_user_weight = (uint128_t)state.total_net_weight; - auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight; + auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight + gmr.net_byte; auto net_used_in_window = impl::integer_divide_ceil((uint128_t)usage.net_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision); if( max_user_use_in_window <= net_used_in_window ) diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index f03fb71f445..f63d836d377 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -148,7 +148,7 @@ class privileged_api : public context_aware_api { } void get_resource_limits( account_name account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight ) { - context.control.get_resource_limits_manager().get_account_limits( account, ram_bytes, net_weight, cpu_weight); + context.control.get_resource_limits_manager().get_account_limits( account, ram_bytes, net_weight, cpu_weight, true); // *bos* add raw=true } int64_t set_proposed_producers( array_ptr packed_producer_schedule, size_t datalen) { @@ -192,6 +192,42 @@ class privileged_api : public context_aware_api { }); } + // *bos begin* + void set_name_list_packed(int64_t list, int64_t action, array_ptr packed_name_list, size_t datalen) + { + int64_t lstbegin = static_cast(list_type::actor_blacklist_type ); + int64_t lstend = static_cast(list_type::list_type_count); + int64_t actbegin = static_cast(list_action_type::insert_type); + int64_t actend = static_cast(list_action_type::list_action_type_count); + EOS_ASSERT(list >= lstbegin && list < lstend, wasm_execution_error, "unkown name list!"); + EOS_ASSERT(action >= actbegin && action < actend, wasm_execution_error, "unkown action"); + + datastream ds(packed_name_list, datalen); + std::vector name_list; // TODO std::set dosen't work, bug. + fc::raw::unpack(ds, name_list); + + context.control.set_name_list(list, action, name_list); + + + } + + void set_guaranteed_minimum_resources(int64_t ram_byte, int64_t cpu_us, int64_t net_byte) + { + EOS_ASSERT(ram_byte >= 0 && ram_byte <= 100 * 1024, wasm_execution_error, "resouces minimum guarantee for ram limit expected [0, 102400]"); + EOS_ASSERT(cpu_us >= 0 && cpu_us <= 100 * 1000, wasm_execution_error, "resouces minimum guarantee for cpu limit expected [0, 100000]"); + EOS_ASSERT(net_byte >= 0 && net_byte <= 100 * 1024, wasm_execution_error, "resouces minimum guarantee for net limit expected [0, 102400]"); + + //guaranteed minimum resources which is abbreviated gmr + context.db.modify(context.control.get_global_properties2(), + [&](auto &gprops2) { + gprops2.gmr.ram_byte = ram_byte; + gprops2.gmr.cpu_us = cpu_us; + gprops2.gmr.net_byte = net_byte; + }); + } + + // *bos end* + bool is_privileged( account_name n )const { return context.db.get( n ).privileged; } @@ -1362,6 +1398,14 @@ class context_free_transaction_api : public context_aware_api { return context.get_packed_transaction().size(); } + void get_transaction_id( fc::sha256& id ) { + id = context.trx_context.id; + } + + void get_action_sequence(uint64_t& seq){ + seq = context.global_action_sequence; + } + int expiration() { return context.trx_context.trx.expiration.sec_since_epoch(); } @@ -1644,6 +1688,81 @@ class call_depth_api : public context_aware_api { } }; + +class action_seed_api : public context_aware_api { +public: + action_seed_api(apply_context& ctx) + : context_aware_api(ctx) {} + + int bpsig_action_time_seed(array_ptr sig, size_t siglen) { + auto data = action_timestamp(); + fc::sha256::encoder encoder; + encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); + auto digest = encoder.result(); + optional signature; + auto block_state = context.control.pending_block_state(); + for (auto& extension: block_state->block->block_extensions) { + if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; + EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); + uint64_t* act_parts = reinterpret_cast(extension.second.data()); + if ( act_parts[0] != context.global_action_sequence) continue; + + auto sig_data = extension.second.data() + 8; + auto sig_size = extension.second.size() - 8; + signature.emplace(); + datastream ds(sig_data, sig_size); + fc::raw::unpack(ds, *signature); + auto check = fc::crypto::public_key(*signature, digest, false); + EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); + break; + } + bool sign = false; + if (context.control.is_producing_block() && !signature) { + auto signer = context.control.pending_producer_signer(); + if (signer) { + // Producer is producing this block + signature = signer(digest); + sign = true; + } else { + // Non-producer is speculating this block, so skips the signing + // TODO: speculating result will be different from producing result + signature.emplace(); + } + } + EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); + auto& s = *signature; + auto sig_size = fc::raw::pack_size(s); + if (siglen == 0) return sig_size; + if (sig_size <= siglen) { + datastream ds(sig, sig_size); + fc::raw::pack(ds, s); + if (sign) { + block_state->block->block_extensions.emplace_back(); + char* act_parts = reinterpret_cast(&context.global_action_sequence); + auto &extension = block_state->block->block_extensions.back(); + extension.first = static_cast(block_extension_type::bpsig_action_time_seed); + extension.second.resize(8 + sig_size); + std::copy(act_parts, act_parts + 8, extension.second.data()); + std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); + } + return sig_size; + } + return 0; + } +private: + vector action_timestamp() { + auto current = context.control.pending_block_time().time_since_epoch().count(); + current -= current % (config::block_interval_us); + + uint32_t* current_halves = reinterpret_cast(¤t); + uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); + return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; + } +}; +REGISTER_INTRINSICS(action_seed_api, +(bpsig_action_time_seed, int(int, int) ) +); + REGISTER_INJECTED_INTRINSICS(call_depth_api, (call_depth_assert, void() ) ); @@ -1702,6 +1821,8 @@ REGISTER_INTRINSICS(privileged_api, (set_proposed_producers, int64_t(int,int) ) (get_blockchain_parameters_packed, int(int, int) ) (set_blockchain_parameters_packed, void(int,int) ) + (set_name_list_packed, void(int64_t,int64_t,int,int) ) + (set_guaranteed_minimum_resources, void(int64_t,int64_t,int64_t) ) (is_privileged, int(int64_t) ) (set_privileged, void(int64_t, int) ) ); @@ -1823,6 +1944,8 @@ REGISTER_INTRINSICS(console_api, REGISTER_INTRINSICS(context_free_transaction_api, (read_transaction, int(int, int) ) (transaction_size, int() ) + (get_transaction_id, void(int) ) + (get_action_sequence, void(int) ) (expiration, int() ) (tapos_block_prefix, int() ) (tapos_block_num, int() ) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 9a4f4094330..22e52407953 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -140,7 +140,7 @@ namespace eosio { namespace testing { return traces; } - void push_genesis_block(); + void push_genesis_block(); vector get_producer_keys( const vector& producer_names )const; transaction_trace_ptr set_producers(const vector& producer_names); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9b0b17b9d0a..9d4a6ab93b3 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -19,6 +19,8 @@ add_subdirectory(mongo_db_plugin) add_subdirectory(login_plugin) add_subdirectory(test_control_plugin) add_subdirectory(test_control_api_plugin) +add_subdirectory(kafka_plugin) +add_subdirectory(notify_plugin) # Forward variables to top level so packaging picks them up set(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_PACKAGE_DEPENDS} PARENT_SCOPE) diff --git a/plugins/history_api_plugin/history_api_plugin.cpp b/plugins/history_api_plugin/history_api_plugin.cpp index bd78dede086..286e97f6e54 100644 --- a/plugins/history_api_plugin/history_api_plugin.cpp +++ b/plugins/history_api_plugin/history_api_plugin.cpp @@ -32,17 +32,15 @@ void history_api_plugin::plugin_initialize(const variables_map&) {} }} #define CHAIN_RO_CALL(call_name) CALL(history, ro_api, history_apis::read_only, call_name) -//#define CHAIN_RW_CALL(call_name) CALL(history, rw_api, history_apis::read_write, call_name) void history_api_plugin::plugin_startup() { ilog( "starting history_api_plugin" ); auto ro_api = app().get_plugin().get_read_only_api(); - //auto rw_api = app().get_plugin().get_read_write_api(); app().get_plugin().add_api({ -// CHAIN_RO_CALL(get_transaction), CHAIN_RO_CALL(get_actions), CHAIN_RO_CALL(get_transaction), + CHAIN_RO_CALL(get_block_detail), CHAIN_RO_CALL(get_key_accounts), CHAIN_RO_CALL(get_controlled_accounts) }); diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index 8245215b061..f3838726726 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -372,8 +372,9 @@ namespace eosio { namespace history_apis { + read_only::get_actions_result read_only::get_actions( const read_only::get_actions_params& params )const { - edump((params)); + edump((params)); auto& chain = history->chain_plug->chain(); const auto& db = chain.db(); const auto abi_serializer_max_time = history->chain_plug->get_abi_serializer_max_time(); @@ -564,6 +565,94 @@ namespace eosio { return result; } + fc::variant read_only::get_block_detail(const read_only::get_block_detail_params& params) const { + static char const TRANSACTIONS[] = "transactions"; + static char const TRX[] = "trx"; + static char const ID[] = "id"; + static char const TRACES[] = "traces"; + + auto & plugin = history->chain_plug; + auto & chain = plugin->chain(); + + auto get_object_value = [](fc::variant const& src, char const * key) -> fc::variant const & { + static auto const null_variant = fc::variant(); + + if ( !src.is_object() ) + return null_variant; + + auto & obj = src.get_object(); + auto const & itr = obj.find(key); + if ( itr == obj.end() ) + return null_variant; + + return itr->value(); + }; + + auto get_tx_array = [&get_object_value](fc::variant const& block) -> fc::variants const & { + static auto const null_variants = fc::variants(); + + auto & value = get_object_value(block, TRANSACTIONS); + if ( !value.is_array() ) + return null_variants; + + return value.get_array(); + }; + + auto get_tx_id = [&get_object_value](fc::variant const& tx) -> optional { + auto & id = get_object_value(get_object_value(tx, TRX), ID); + if ( !id.is_string() ) + return fc::optional(); + + return fc::optional(id.get_string()); + }; + + auto const & src = plugin->get_read_only_api().get_block( + chain_apis::read_only::get_block_params { + /*block_num_or_id = */ params.block_num_or_id + } + ); + + auto & rhs = get_tx_array(src); + if ( rhs.empty() ) + return src; + + auto lhs = fc::variants(); + lhs.reserve(rhs.size()); + + auto & database = chain.db(); + auto & index = database.get_index(); + auto const abi_serializer_max_time = plugin->get_abi_serializer_max_time(); + for ( auto const & tx : rhs ) { + auto maybe_id = get_tx_id(tx); + if ( maybe_id ) { + auto id = *maybe_id; + auto itr = index.lower_bound(boost::make_tuple(id)); + auto traces = fc::variants(); + + while ( itr != index.end() && itr->trx_id == id ) { + + fc::datastream ds( itr->packed_action_trace.data(), itr->packed_action_trace.size() ); + action_trace t; + fc::raw::unpack( ds, t ); + traces.emplace_back( chain.to_variant_with_abi(t, abi_serializer_max_time) ); + + ++itr; + } + + if ( !traces.empty() ) { + auto new_trx = fc::mutable_variant_object(tx[TRX])(TRACES, traces); + auto new_tx = fc::mutable_variant_object(tx).set(TRX, move(new_trx)); + lhs.emplace_back(move(new_tx)); + continue; + } + } + + lhs.emplace_back(tx); + } + + return fc::mutable_variant_object(src).set(TRANSACTIONS, move(lhs)); + } + read_only::get_key_accounts_results read_only::get_key_accounts(const get_key_accounts_params& params) const { std::set accounts; const auto& db = history->chain_plug->chain().db(); @@ -586,6 +675,4 @@ namespace eosio { } /// history_apis - - } /// namespace eosio diff --git a/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp b/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp index b6801b30a29..838f9b24662 100644 --- a/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp +++ b/plugins/history_plugin/include/eosio/history_plugin/history_plugin.hpp @@ -50,7 +50,6 @@ class read_only { optional time_limit_exceeded_error; }; - get_actions_result get_actions( const get_actions_params& )const; @@ -71,8 +70,6 @@ class read_only { get_transaction_result get_transaction( const get_transaction_params& )const; - - /* struct ordered_transaction_results { uint32_t seq_num; @@ -83,6 +80,12 @@ class read_only { get_transactions_results get_transactions(const get_transactions_params& params) const; */ + struct get_block_detail_params { + string block_num_or_id; + }; + + fc::variant get_block_detail(const get_block_detail_params& params) const; + struct get_key_accounts_params { chain::public_key_type public_key; @@ -150,7 +153,10 @@ FC_REFLECT(eosio::history_apis::read_only::get_transactions_params, (account_nam FC_REFLECT(eosio::history_apis::read_only::ordered_transaction_results, (seq_num)(transaction_id)(transaction) ) FC_REFLECT(eosio::history_apis::read_only::get_transactions_results, (transactions)(time_limit_exceeded_error) ) */ -FC_REFLECT(eosio::history_apis::read_only::get_key_accounts_params, (public_key) ) -FC_REFLECT(eosio::history_apis::read_only::get_key_accounts_results, (account_names) ) -FC_REFLECT(eosio::history_apis::read_only::get_controlled_accounts_params, (controlling_account) ) -FC_REFLECT(eosio::history_apis::read_only::get_controlled_accounts_results, (controlled_accounts) ) + +FC_REFLECT( eosio::history_apis::read_only::get_block_detail_params, (block_num_or_id) ) + +FC_REFLECT( eosio::history_apis::read_only::get_key_accounts_params, (public_key) ) +FC_REFLECT( eosio::history_apis::read_only::get_key_accounts_results, (account_names) ) +FC_REFLECT( eosio::history_apis::read_only::get_controlled_accounts_params, (controlling_account) ) +FC_REFLECT( eosio::history_apis::read_only::get_controlled_accounts_results, (controlled_accounts) ) diff --git a/plugins/kafka_plugin/CMakeLists.txt b/plugins/kafka_plugin/CMakeLists.txt new file mode 100644 index 00000000000..62f6127148f --- /dev/null +++ b/plugins/kafka_plugin/CMakeLists.txt @@ -0,0 +1,10 @@ +file(GLOB HEADERS "*.hpp") +add_library(kafka_plugin + kafka_plugin.cpp kafka.cpp try_handle.cpp + ${HEADERS}) + +find_package(Cppkafka) +find_package(RdKafka) + +target_include_directories(kafka_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ${CPPKAFKA_INCLUDE_DIR}) +target_link_libraries(kafka_plugin chain_plugin appbase ${CPPKAFKA_LIBRARY} RdKafka::rdkafka) diff --git a/plugins/kafka_plugin/fifo.h b/plugins/kafka_plugin/fifo.h new file mode 100644 index 00000000000..c65dbe2bf81 --- /dev/null +++ b/plugins/kafka_plugin/fifo.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace kafka { + +constexpr std::size_t FIFO_MAX_PUSH_SIZE = 1024; +constexpr std::size_t FIFO_MAX_POP_SIZE = 1024; + +template +class fifo : public boost::noncopyable { +public: + fifo(std::size_t max_push_size = FIFO_MAX_PUSH_SIZE, std::size_t max_pop_size = FIFO_MAX_POP_SIZE); + void push(const T& element); + std::vector pop(); + bool empty(); + void awaken(); + +private: + std::mutex mux_; + std::condition_variable not_empty_cv_; + std::condition_variable not_full_cv_; + bool non_blocking_{}; + std::deque deque_; + std::size_t max_push_size_; + std::size_t max_pop_size_; +}; + +template +fifo::fifo(std::size_t max_push_size, std::size_t max_pop_size) { + max_push_size_ = max_push_size; + max_pop_size_ = max_pop_size; +} + +template +void fifo::push(const T& element) { + std::unique_lock lock(mux_); + + if (deque_.size() >= max_push_size_) { + not_full_cv_.wait(lock, [&] { + return non_blocking_ || deque_.size() < max_push_size_; + }); + } + + deque_.push_back(element); + not_empty_cv_.notify_one(); +} + +template +std::vector fifo::pop() { + std::unique_lock lock(mux_); + if (deque_.empty()) { + not_empty_cv_.wait(lock, [&] { + return non_blocking_ || !deque_.empty(); + }); + } + + std::vector result; + for (std::size_t i = 0; i < max_pop_size_ && !deque_.empty(); ++i) { + result.push_back(std::move(deque_.front())); + deque_.pop_front(); + } + not_full_cv_.notify_all(); + return result; +} + +template +bool fifo::empty() { + std::unique_lock lock(mux_); + return deque_.empty(); +} + +template +void fifo::awaken() { + non_blocking_ = true; + not_empty_cv_.notify_all(); + not_full_cv_.notify_all(); +} + +} diff --git a/plugins/kafka_plugin/kafka.cpp b/plugins/kafka_plugin/kafka.cpp new file mode 100644 index 00000000000..86abbb6d62c --- /dev/null +++ b/plugins/kafka_plugin/kafka.cpp @@ -0,0 +1,186 @@ +#include "kafka.hpp" + +#include + +#include "try_handle.hpp" + +namespace std { +template<> struct hash { + typedef kafka::bytes argument_type; + typedef size_t result_type; + result_type operator()(argument_type const& s) const noexcept { + return std::hash{}(string(s.begin(), s.end())); + } +}; +} + +namespace kafka { + +using chain::account_name; +using chain::action_name; +using chain::block_id_type; +using chain::permission_name; +using chain::transaction; +using chain::signed_transaction; +using chain::signed_block; +using chain::transaction_id_type; + +namespace { + +inline bytes checksum_bytes(const fc::sha256& s) { return bytes(s.data(), s.data() + sizeof(fc::sha256)); } + +TransactionStatus transactionStatus(fc::enum_type status) { + if (status == chain::transaction_receipt::executed) return TransactionStatus::executed; + else if (status == chain::transaction_receipt::soft_fail) return TransactionStatus::soft_fail; + else if (status == chain::transaction_receipt::hard_fail) return TransactionStatus::hard_fail; + else if (status == chain::transaction_receipt::delayed) return TransactionStatus::delayed; + else if (status == chain::transaction_receipt::expired) return TransactionStatus::expired; + else return TransactionStatus::unknown; +} + +} + +void kafka::set_config(Configuration config) { + config_ = config; +} + +void kafka::set_topics(const string& block_topic, const string& tx_topic, const string& tx_trace_topic, const string& action_topic) { + block_topic_ = block_topic; + tx_topic_ = tx_topic; + tx_trace_topic_ = tx_trace_topic; + action_topic_ = action_topic; +} + +void kafka::set_partition(int partition) { + partition_ = partition; +} + +void kafka::start() { + producer_ = std::make_unique(config_); + + auto conf = producer_->get_configuration().get_all(); + ilog("Kafka config: ${conf}", ("conf", conf)); +} + +void kafka::stop() { + producer_->flush(); + + producer_.reset(); +} + +void kafka::push_block(const chain::block_state_ptr& block_state, bool irreversible) { + const auto& header = block_state->header; + auto b = std::make_shared(); + + b->id = checksum_bytes(block_state->id); + b->num = block_state->block_num; + b->timestamp = header.timestamp; + + b->lib = irreversible; + + b->block = fc::raw::pack(*block_state->block); + b->tx_count = static_cast(block_state->block->transactions.size()); + + uint16_t seq{}; + for (const auto& tx_receipt: block_state->block->transactions) { + auto count = push_transaction(tx_receipt, b, seq++); + b->action_count += count.first; + b->context_free_action_count += count.second; + } + + consume_block(b); +} + +std::pair kafka::push_transaction(const chain::transaction_receipt& tx_receipt, const BlockPtr& block, uint16_t block_seq) { + auto t = std::make_shared(); + if(tx_receipt.trx.contains()) { + t->id = checksum_bytes(tx_receipt.trx.get()); + } else { + auto signed_tx = tx_receipt.trx.get().get_signed_transaction(); + t->id = checksum_bytes(signed_tx.id()); + t->action_count = static_cast(signed_tx.actions.size()); + t->context_free_action_count = static_cast(signed_tx.context_free_actions.size()); + } + t->block_id = block->id; + t->block_num = block->num; + t->block_time = block->timestamp; + t->block_seq = block_seq; + + consume_transaction(t); + + return {t->action_count, t->context_free_action_count}; +} + +void kafka::push_transaction_trace(const chain::transaction_trace_ptr& tx_trace) { + auto t = std::make_shared(); + + t->id = checksum_bytes(tx_trace->id); + t->block_num = tx_trace->block_num; + t->scheduled = tx_trace->scheduled; + if (tx_trace->receipt) { + t->status = transactionStatus(tx_trace->receipt->status); + t->cpu_usage_us = tx_trace->receipt->cpu_usage_us; + t->net_usage_words = tx_trace->receipt->net_usage_words; + } + if (tx_trace->except) { + t->exception = tx_trace->except->to_string(); + } + + consume_transaction_trace(t); + + for (auto& action_trace: tx_trace->action_traces) { + push_action(action_trace, 0, t); // 0 means no parent + } +} + +void kafka::push_action(const chain::action_trace& action_trace, uint64_t parent_seq, const TransactionTracePtr& tx) { + auto a = std::make_shared(); + + a->global_seq = action_trace.receipt.global_sequence; + a->recv_seq = action_trace.receipt.recv_sequence; + a->parent_seq = parent_seq; + a->account = action_trace.act.account; + a->name = action_trace.act.name; + if (not action_trace.act.authorization.empty()) a->auth = fc::raw::pack(action_trace.act.authorization); + a->data = action_trace.act.data; + a->receiver = action_trace.receipt.receiver; + if (not action_trace.receipt.auth_sequence.empty()) a->auth_seq = fc::raw::pack(action_trace.receipt.auth_sequence); + a->code_seq = action_trace.receipt.code_sequence; + a->abi_seq = action_trace.receipt.abi_sequence; + a->block_num = action_trace.block_num; + a->block_time = action_trace.block_time; + a->tx_id = checksum_bytes(action_trace.trx_id); + if (not action_trace.console.empty()) a->console = action_trace.console; + + consume_action(a); + + for (auto& inline_trace: action_trace.inline_traces) { + push_action(inline_trace, action_trace.receipt.global_sequence, tx); + } +} + +void kafka::consume_block(BlockPtr block) { + auto payload = fc::json::to_string(*block, fc::json::legacy_generator); + Buffer buffer (block->id.data(), block->id.size()); + producer_->produce(MessageBuilder(block_topic_).partition(partition_).key(buffer).payload(payload)); +} + +void kafka::consume_transaction(TransactionPtr tx) { + auto payload = fc::json::to_string(*tx, fc::json::legacy_generator); + Buffer buffer (tx->id.data(), tx->id.size()); + producer_->produce(MessageBuilder(tx_topic_).partition(partition_).key(buffer).payload(payload)); +} + +void kafka::consume_transaction_trace(TransactionTracePtr tx_trace) { + auto payload = fc::json::to_string(*tx_trace, fc::json::legacy_generator); + Buffer buffer (tx_trace->id.data(), tx_trace->id.size()); + producer_->produce(MessageBuilder(tx_trace_topic_).partition(partition_).key(buffer).payload(payload)); +} + +void kafka::consume_action(ActionPtr action) { + auto payload = fc::json::to_string(*action, fc::json::legacy_generator); + Buffer buffer((char*)&action->global_seq, sizeof(action->global_seq)); + producer_->produce(MessageBuilder(action_topic_).partition(partition_).key(buffer).payload(payload)); +} + +} diff --git a/plugins/kafka_plugin/kafka.hpp b/plugins/kafka_plugin/kafka.hpp new file mode 100644 index 00000000000..5242ee872e7 --- /dev/null +++ b/plugins/kafka_plugin/kafka.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include + +#include "types.hpp" + +namespace kafka { + +using namespace std; +using namespace cppkafka; +using namespace eosio; + +class kafka { +public: + void set_config(Configuration config); + void set_topics(const string& block_topic, const string& tx_topic, const string& tx_trace_topic, const string& action_topic); + void set_partition(int partition); + void start(); + void stop(); + + void push_block(const chain::block_state_ptr& block_state, bool irreversible); + std::pair push_transaction(const chain::transaction_receipt& transaction_receipt, const BlockPtr& block, uint16_t block_seq); + void push_transaction_trace(const chain::transaction_trace_ptr& transaction_trace); + void push_action(const chain::action_trace& action_trace, uint64_t parent_seq, const TransactionTracePtr& tx); + +private: + void consume_block(BlockPtr block); + void consume_transaction(TransactionPtr tx); + void consume_transaction_trace(TransactionTracePtr tx_trace); + void consume_action(ActionPtr action); + + Configuration config_; + string block_topic_; + string tx_topic_; + string tx_trace_topic_; + string action_topic_; + + int partition_{-1}; + + std::unique_ptr producer_; +}; + +} diff --git a/plugins/kafka_plugin/kafka_plugin.cpp b/plugins/kafka_plugin/kafka_plugin.cpp new file mode 100644 index 00000000000..901fd57a29e --- /dev/null +++ b/plugins/kafka_plugin/kafka_plugin.cpp @@ -0,0 +1,166 @@ +#include "kafka_plugin.hpp" + +#include + +#include "kafka.hpp" +#include "try_handle.hpp" + +namespace eosio { + +using namespace std; + +namespace bpo = boost::program_options; +using bpo::options_description; +using bpo::variables_map; + +using kafka::handle; + +enum class compression_codec { + none, + gzip, + snappy, + lz4 +}; + +std::istream& operator>>(std::istream& in, compression_codec& codec) { + std::string s; + in >> s; + if (s == "none") codec = compression_codec::none; + else if (s == "gzip") codec = compression_codec::gzip; + else if (s == "snappy") codec = compression_codec::snappy; + else if (s == "lz4") codec = compression_codec::lz4; + else in.setstate(std::ios_base::failbit); + return in; +} + +static appbase::abstract_plugin& _kafka_relay_plugin = app().register_plugin(); + +kafka_plugin::kafka_plugin() : kafka_(std::make_unique()) {} +kafka_plugin::~kafka_plugin() {} + +void kafka_plugin::set_program_options(options_description&, options_description& cfg) { + cfg.add_options() + ("kafka-enable", bpo::value(), "Kafka enable") + ("kafka-broker-list", bpo::value()->default_value("127.0.0.1:9092"), "Kafka initial broker list, formatted as comma separated pairs of host or host:port, e.g., host1:port1,host2:port2") + ("kafka-block-topic", bpo::value()->default_value("eos.blocks"), "Kafka topic for message `block`") + ("kafka-transaction-topic", bpo::value()->default_value("eos.txs"), "Kafka topic for message `transaction`") + ("kafka-transaction-trace-topic", bpo::value()->default_value("eos.txtraces"), "Kafka topic for message `transaction_trace`") + ("kafka-action-topic", bpo::value()->default_value("eos.actions"), "Kafka topic for message `action`") + ("kafka-batch-num-messages", bpo::value()->default_value(1024), "Kafka minimum number of messages to wait for to accumulate in the local queue before sending off a message set") + ("kafka-queue-buffering-max-ms", bpo::value()->default_value(500), "Kafka how long to wait for kafka-batch-num-messages to fill up in the local queue") + ("kafka-compression-codec", bpo::value()->value_name("none/gzip/snappy/lz4"), "Kafka compression codec to use for compressing message sets, default is snappy") + ("kafka-request-required-acks", bpo::value()->default_value(1), "Kafka indicates how many acknowledgements the leader broker must receive from ISR brokers before responding to the request: 0=Broker does not send any response/ack to client, 1=Only the leader broker will need to ack the message, -1=broker will block until message is committed by all in sync replicas (ISRs) or broker's min.insync.replicas setting before sending response") + ("kafka-message-send-max-retries", bpo::value()->default_value(2), "Kafka how many times to retry sending a failing MessageSet") + ("kafka-start-block-num", bpo::value()->default_value(1), "Kafka starts syncing from which block number") + ("kafka-statistics-interval-ms", bpo::value()->default_value(0), "Kafka statistics emit interval, maximum is 86400000, 0 disables statistics") + ("kafka-fixed-partition", bpo::value()->default_value(-1), "Kafka specify fixed partition for all topics, -1 disables specify") + ; + // TODO: security options +} + +void kafka_plugin::plugin_initialize(const variables_map& options) { + if (not options.count("kafka-enable") || not options.at("kafka-enable").as()) { + wlog("kafka_plugin disabled, since no --kafka-enable=true specified"); + return; + } + + ilog("Initialize kafka plugin"); + configured_ = true; + + string compressionCodec = "snappy"; + if (options.count("kafka-compression-codec")) { + switch (options.at("kafka-compression-codec").as()) { + case compression_codec::none: + compressionCodec = "none"; + break; + case compression_codec::gzip: + compressionCodec = "gzip"; + break; + case compression_codec::snappy: + compressionCodec = "snappy"; + break; + case compression_codec::lz4: + compressionCodec = "lz4"; + break; + } + } + + kafka::Configuration config = { + {"metadata.broker.list", options.at("kafka-broker-list").as()}, + {"batch.num.messages", options.at("kafka-batch-num-messages").as()}, + {"queue.buffering.max.ms", options.at("kafka-queue-buffering-max-ms").as()}, + {"compression.codec", compressionCodec}, + {"request.required.acks", options.at("kafka-request-required-acks").as()}, + {"message.send.max.retries", options.at("kafka-message-send-max-retries").as()}, + {"socket.keepalive.enable", true} + }; + auto stats_interval = options.at("kafka-statistics-interval-ms").as(); + if (stats_interval > 0) { + config.set("statistics.interval.ms", stats_interval); + config.set_stats_callback([](kafka::KafkaHandleBase& handle, const std::string& json) { + ilog("kafka stats: ${json}", ("json", json)); + }); + } + kafka_->set_config(config); + kafka_->set_topics( + options.at("kafka-block-topic").as(), + options.at("kafka-transaction-topic").as(), + options.at("kafka-transaction-trace-topic").as(), + options.at("kafka-action-topic").as() + ); + + if (options.at("kafka-fixed-partition").as() >= 0) { + kafka_->set_partition(options.at("kafka-fixed-partition").as()); + } + + unsigned start_block_num = options.at("kafka-start-block-num").as(); + + // add callback to chain_controller config + chain_plugin_ = app().find_plugin(); + auto& chain = chain_plugin_->chain(); + + block_conn_ = chain.accepted_block.connect([=](const chain::block_state_ptr& b) { + if (not start_sync_) { + if (b->block_num >= start_block_num) start_sync_ = true; + else return; + } + handle([=] { kafka_->push_block(b, false); }, "push block"); + }); + irreversible_block_conn_ = chain.irreversible_block.connect([=](const chain::block_state_ptr& b) { + if (not start_sync_) { + if (b->block_num >= start_block_num) start_sync_ = true; + else return; + } + handle([=] { kafka_->push_block(b, true); }, "push irreversible block"); + }); + transaction_conn_ = chain.applied_transaction.connect([=](const chain::transaction_trace_ptr& t) { + if (not start_sync_) return; + handle([=] { kafka_->push_transaction_trace(t); }, "push transaction"); + }); +} + +void kafka_plugin::plugin_startup() { + if (not configured_) return; + ilog("Starting kafka_plugin"); + kafka_->start(); + ilog("Started kafka_plugin"); +} + +void kafka_plugin::plugin_shutdown() { + if (not configured_) return; + ilog("Stopping kafka_plugin"); + + try { + block_conn_.disconnect(); + irreversible_block_conn_.disconnect(); + transaction_conn_.disconnect(); + + kafka_->stop(); + } catch (const std::exception& e) { + elog("Exception on kafka_plugin shutdown: ${e}", ("e", e.what())); + } + + ilog("Stopped kafka_plugin"); +} + +} diff --git a/plugins/kafka_plugin/kafka_plugin.hpp b/plugins/kafka_plugin/kafka_plugin.hpp new file mode 100644 index 00000000000..0bc66108ad2 --- /dev/null +++ b/plugins/kafka_plugin/kafka_plugin.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +namespace kafka { +class kafka; // forward declaration +} + +namespace eosio { + +using namespace appbase; + +class kafka_plugin : public appbase::plugin { +public: + APPBASE_PLUGIN_REQUIRES((kafka_plugin)) + + kafka_plugin(); + virtual ~kafka_plugin(); + + void set_program_options(options_description&, options_description& cfg) override; + + void plugin_initialize(const variables_map& options); + void plugin_startup(); + void plugin_shutdown(); + +private: + bool configured_{}; + + chain_plugin* chain_plugin_{}; + + boost::signals2::connection block_conn_; + boost::signals2::connection irreversible_block_conn_; + boost::signals2::connection transaction_conn_; + + std::atomic start_sync_{false}; + + std::unique_ptr kafka_; +}; + +} diff --git a/plugins/kafka_plugin/readme.md b/plugins/kafka_plugin/readme.md new file mode 100644 index 00000000000..ecde9474053 --- /dev/null +++ b/plugins/kafka_plugin/readme.md @@ -0,0 +1,31 @@ +# Kafka Plugin 说明 + +### 一、Topic + +默认开启以下4个topic + + 1. blocks // 其中block字段是由完整区块数据持久化的json结构,是一份全量数据。 + 2. transaction + 3. transaction_trace + 4. action + + transaction、transaction_trace、action为nodeos中数据解析所得,提取了主要的可能使用的字段(相当于推荐配置),业务使用者可根据需要适当增减字段。 另,也可以删除这三个topic,仅依赖blocks中的全量数据。 + + 详见:`plugins/kafka_plugin/types.hpp ` + + +### 二、常见问题 + +#### bos在Mac上编译常见报错 +``` +Could not find a package configuration file provided by "RdKafka" with any of the following names: + RdKafkaConfig.cmake + rdkafka-config.cmake +``` + +原因:系统安装的kafka版本太低 + +解决方法: + + 删除`/usr/local/include/cppkafka` , `/usr/local/include/librdkafka`两个目录 + 重新开始bos编译(会自动下载安装适配的kafka版本) \ No newline at end of file diff --git a/plugins/kafka_plugin/try_handle.cpp b/plugins/kafka_plugin/try_handle.cpp new file mode 100644 index 00000000000..e9be213b652 --- /dev/null +++ b/plugins/kafka_plugin/try_handle.cpp @@ -0,0 +1,17 @@ +#include "try_handle.hpp" + +namespace kafka { + +void handle(std::function handler, const std::string& desc) { + try { + handler(); + } catch (fc::exception& e) { + elog("FC Exception while ${desc}: ${e}", ("e", e.to_string())("desc", desc)); + } catch (std::exception& e) { + elog("STD Exception while ${desc}: ${e}", ("e", e.what())("desc", desc)); + } catch (...) { + elog("Unknown exception while ${desc}", ("desc", desc)); + } +} + +} diff --git a/plugins/kafka_plugin/try_handle.hpp b/plugins/kafka_plugin/try_handle.hpp new file mode 100644 index 00000000000..7d059e34dcc --- /dev/null +++ b/plugins/kafka_plugin/try_handle.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace kafka { + +void handle(std::function handler, const std::string& desc); + +} diff --git a/plugins/kafka_plugin/types.hpp b/plugins/kafka_plugin/types.hpp new file mode 100644 index 00000000000..65f4091fb1f --- /dev/null +++ b/plugins/kafka_plugin/types.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include + +namespace kafka { + +using name_t = uint64_t; +using std::string; +using bytes = std::vector; +using eosio::chain::block_timestamp_type; + +struct Block { + bytes id; + unsigned num; + + block_timestamp_type timestamp; + + bool lib; // whether irreversible + + bytes block; + + uint32_t tx_count{}; + uint32_t action_count{}; + uint32_t context_free_action_count{}; +}; + +struct Transaction { + bytes id; + + bytes block_id; + uint32_t block_num; + block_timestamp_type block_time; + + uint16_t block_seq; // the sequence number of this transaction in its block + + uint32_t action_count{}; + uint32_t context_free_action_count{}; +}; + +enum TransactionStatus { + executed, soft_fail, hard_fail, delayed, expired, unknown +}; + +struct TransactionTrace { // new ones will override old ones, typically when status is changed + bytes id; + + uint32_t block_num; + + bool scheduled; + + TransactionStatus status; + unsigned net_usage_words; + uint32_t cpu_usage_us; + + string exception; +}; + +struct Action { + uint64_t global_seq; // the global sequence number of this action + uint64_t recv_seq; // the sequence number of this action for this receiver + + uint64_t parent_seq; // parent action trace global sequence number, only for inline traces + + name_t account; // account name + name_t name; // action name + bytes auth; // binary serialization of authorization array of permission_level + bytes data; // payload + + name_t receiver; // where this action is executed on; may not be equal with `account_`, such as from notification + + bytes auth_seq; + unsigned code_seq; + unsigned abi_seq; + + uint32_t block_num; + block_timestamp_type block_time; + bytes tx_id; // the transaction that generated this action + + string console; +}; + +using BlockPtr = std::shared_ptr; +using TransactionPtr = std::shared_ptr; +using TransactionTracePtr = std::shared_ptr; +using ActionPtr = std::shared_ptr; + +} + +FC_REFLECT_ENUM(kafka::TransactionStatus, (executed)(soft_fail)(hard_fail)(delayed)(expired)(unknown)) + +FC_REFLECT(kafka::Block, (id)(num)(timestamp)(lib)(block)(tx_count)(action_count)(context_free_action_count)) +FC_REFLECT(kafka::Transaction, (id)(block_id)(block_num)(block_time)(block_seq)(action_count)(context_free_action_count)) +FC_REFLECT(kafka::TransactionTrace, (id)(block_num)(scheduled)(status)(net_usage_words)(cpu_usage_us)(exception)) +FC_REFLECT(kafka::Action, (global_seq)(recv_seq)(parent_seq)(account)(name)(auth)(data)(receiver)(auth_seq)(code_seq)(abi_seq)(block_num)(block_time)(tx_id)(console)) diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index a736a9ff464..bbdd357eec7 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -132,6 +132,14 @@ namespace eosio { uint32_t end_block; }; +struct request_p2p_message{ + bool discoverable; + }; + + struct response_p2p_message{ + bool discoverable; + string p2p_peer_list; + }; using net_message = static_variant; + packed_transaction, + response_p2p_message, + request_p2p_message>; } // namespace eosio @@ -159,7 +169,8 @@ FC_REFLECT( eosio::time_message, (org)(rec)(xmt)(dst) ) FC_REFLECT( eosio::notice_message, (known_trx)(known_blocks) ) FC_REFLECT( eosio::request_message, (req_trx)(req_blocks) ) FC_REFLECT( eosio::sync_request_message, (start_block)(end_block) ) - +FC_REFLECT( eosio::request_p2p_message, (discoverable) ) +FC_REFLECT( eosio::response_p2p_message, (discoverable)(p2p_peer_list) ) /** * Goals of Network Code diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 9ee380b666f..8283c5c9320 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -118,6 +118,13 @@ namespace eosio { > node_transaction_index; + struct p2p_peer_record{ + string peer_address; + time_point_sec expiry; + bool is_config; + bool discoverable; + bool connected; + }; class net_plugin_impl { public: unique_ptr acceptor; @@ -128,6 +135,9 @@ namespace eosio { uint32_t num_clients = 0; vector supplied_peers; + map p2p_peer_records; + bool p2p_discoverable; + bool request_p2p_flag=true; vector allowed_peers; ///< peer keys allowed to connect std::map private_keys; ///< overlapping with producer keys, also authenticating non-producing nodes @@ -197,6 +207,8 @@ namespace eosio { bool is_valid( const handshake_message &msg); + void send_p2p_request(connection_ptr c); + void handle_message( connection_ptr c, const handshake_message &msg); void handle_message( connection_ptr c, const chain_size_message &msg); void handle_message( connection_ptr c, const go_away_message &msg ); @@ -220,6 +232,8 @@ namespace eosio { void handle_message( connection_ptr c, const sync_request_message &msg); void handle_message( connection_ptr c, const signed_block &msg); void handle_message( connection_ptr c, const packed_transaction &msg); + void handle_message( connection_ptr c, const request_p2p_message &msg); + void handle_message( connection_ptr c, const response_p2p_message &msg); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_txn_timer( ); @@ -575,6 +589,8 @@ namespace eosio { std::function callback); void do_queue_write(); + void send_p2p_request(bool discoverable); + void send_p2p_response(bool discoverable,string p2p_peer_list); /** \brief Process the next message from the pending message buffer * * Process the next message from the pending_message_buffer. @@ -942,6 +958,29 @@ namespace eosio { } + void connection::send_p2p_request(bool discoverable) + { + try + { + enqueue(net_message(request_p2p_message{discoverable})); + } + catch (...) + { + elog("send request_p2p_message message error"); + } + } + void connection::send_p2p_response(bool discoverable, string p2p_list) + { + try + { + enqueue(net_message(response_p2p_message{discoverable, p2p_list})); + } + catch (...) + { + elog("send response_p2p_message message error"); + } + } + void connection::stop_send() { syncing = false; } @@ -1952,7 +1991,8 @@ namespace eosio { if( !err && c->socket->is_open() ) { if (start_session( c )) { c->send_handshake (); - } + send_p2p_request(c); + } } else { if( endpoint_itr != tcp::resolver::iterator() ) { close(c); @@ -1968,6 +2008,37 @@ namespace eosio { } ); } + void net_plugin_impl::send_p2p_request(connection_ptr c) + { + if (p2p_discoverable && request_p2p_flag) + { + auto peer_record = p2p_peer_records.find(c->peer_addr); + if (peer_record != p2p_peer_records.end()) + { + if (peer_record->second.is_config && !peer_record->second.connected) + { + c->send_p2p_request(p2p_discoverable); + peer_record->second.connected = true; + } + else + { + bool stop_flag = true; + for (auto record : p2p_peer_records) + { + if (record.second.is_config && !( record.second.connected||record.second.expiry < time_point::now())) + { + stop_flag = false; + break; + } + } + if (stop_flag) + { + request_p2p_flag = false; + } + } + } + } + } bool net_plugin_impl::start_session( connection_ptr con ) { boost::asio::ip::tcp::no_delay nodelay( true ); boost::system::error_code ec; @@ -2217,6 +2288,56 @@ namespace eosio { } + void net_plugin_impl::handle_message( connection_ptr c, const request_p2p_message &msg){ + peer_ilog(c, "received request_p2p_message"); + string rspm; + for(auto sd :p2p_peer_records){ + if(sd.second.discoverable){ + rspm.append(sd.second.peer_address+"#"); + } + } + if(p2p_discoverable||rspm.size()>0){ + c->send_p2p_response(p2p_discoverable,rspm); + } + } + + void net_plugin_impl::handle_message( connection_ptr c, const response_p2p_message &msg){ + peer_ilog(c, "received response_p2p_message"); + auto peer_record=p2p_peer_records.find(c->peer_addr); + if(peer_record!=p2p_peer_records.end()){ + peer_record->second.discoverable=msg.discoverable; + if (peer_record->second.is_config&&msg.p2p_peer_list.length()>0){ + + vector p2p_peer_list; + int start = 0; + string delim="#"; + int idx = msg.p2p_peer_list.find(delim, start); + string peer_list; + while( idx != std::string::npos ) + { + if(max_nodes_per_host<=connections.size()||max_nodes_per_host<=p2p_peer_records.size()){ + return; + } + peer_list=msg.p2p_peer_list.substr(start, idx-start); + if(peer_list.size()<3){ + break; + } + start = idx+delim.size(); + idx = msg.p2p_peer_list.find(delim, start); + if( find_connection( peer_list )) + continue; + p2p_peer_record p2prcd; + p2prcd.peer_address=peer_list; + p2prcd.discoverable=false; + p2prcd.is_config=true; + p2prcd.connected=false; + p2p_peer_records.insert(pair(peer_list,p2prcd)); + connection_ptr c = std::make_shared(peer_list); + fc_dlog(logger,"adding new connection to the list"); + connections.insert( c ); + }}} + } + void net_plugin_impl::handle_message( connection_ptr c, const handshake_message &msg) { peer_ilog(c, "received handshake_message"); if (!is_valid(msg)) { @@ -2879,6 +3000,8 @@ namespace eosio { ( "sync-fetch-span", bpo::value()->default_value(def_sync_fetch_span), "number of blocks to retrieve in a chunk from any individual peer during synchronization") ( "max-implicit-request", bpo::value()->default_value(def_max_just_send), "maximum sizes of transaction or block messages that are sent without first sending a notice") ( "use-socket-read-watermark", bpo::value()->default_value(false), "Enable expirimental socket read watermark optimization") + ( "p2p-discoverable", bpo::value()->default_value(false), + "True to p2p discoverable.") ( "peer-log-format", bpo::value()->default_value( "[\"${_name}\" ${_ip}:${_port}]" ), "The string used to format peers when logging messages about them. Variables are escaped with ${}.\n" "Available Variables:\n" @@ -2919,6 +3042,8 @@ namespace eosio { my->use_socket_read_watermark = options.at( "use-socket-read-watermark" ).as(); + my->p2p_discoverable=options.at( "p2p-discoverable" ).as(); + my->resolver = std::make_shared( std::ref( app().get_io_service())); if( options.count( "p2p-listen-endpoint" )) { my->p2p_address = options.at( "p2p-listen-endpoint" ).as(); @@ -3037,6 +3162,14 @@ namespace eosio { my->start_monitors(); for( auto seed_node : my->supplied_peers ) { + p2p_peer_record p2prcd; + p2prcd.peer_address=seed_node; + p2prcd.discoverable=false; + p2prcd.is_config=true; + p2prcd.connected=false; + p2prcd.expiry=time_point_sec((time_point::now()).sec_since_epoch()+10); + my->p2p_peer_records.insert(pair(seed_node,p2prcd)); + connect( seed_node ); } diff --git a/plugins/notify_plugin/CMakeLists.txt b/plugins/notify_plugin/CMakeLists.txt new file mode 100644 index 00000000000..ea3d85eea9a --- /dev/null +++ b/plugins/notify_plugin/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB HEADERS "include/eosio/notify_plugin/*.hpp") +add_library( notify_plugin + notify_plugin.cpp + ${HEADERS} include/eosio/notify_plugin/notify_plugin.hpp) + +target_link_libraries( notify_plugin chain_plugin eosio_chain appbase fc ) +target_include_directories( notify_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) \ No newline at end of file diff --git a/plugins/notify_plugin/README.md b/plugins/notify_plugin/README.md new file mode 100644 index 00000000000..b962c6e0ead --- /dev/null +++ b/plugins/notify_plugin/README.md @@ -0,0 +1,73 @@ +# notify_plugin + +Send real time actions on chain to a `receive_url`, which you can use to do some notifications. + +### Usage + +Add some configs to your `config.ini` just as follows: + +``` +## Notify Plugin +plugin = eosio::notify_plugin +# notify-filter-on = account:action +notify-filter-on = b1: +notify-filter-on = b1:transfer +notify-filter-on = eosio:delegatebw +# http endpoint for each action seen on the chain. +notify-receive-url = http://127.0.0.1:8080/notify +# Age limit in seconds for blocks to send notifications. No age limit if set to negative. +# Used to prevent old actions from trigger HTTP request while on replay (seconds) +notify-age-limit = -1 +# Retry times of sending http notification if failed. +notify-retry-times = 3 +``` + +And you can receive the actions on chain by watching your server endpoint: `http://127.0.0.1:8080/notify`, the data sent to the API endpoint looks like: + +```json +{ + "irreversible": true, + "actions": [{ + "tx_id": "b31885bada6c2d5e71b1302e87d4006c59ff2a40a12108559d76142548d8cf79", + "account": "eosio.token", + "name": "transfer", + "seq_num": 1, + "receiver": "b1", + "block_time": "2018-09-29T11:51:06.000", + "block_num": 127225, + "authorization": [{ + "actor": "b1", + "permission": "active" + } + ], + "action_data": { + "from": "b1", + "to": "b11", + "quantity": "0.0001 EOS", + "memo": "Transfer from b1 to b11" + } + },{ + "tx_id": "b31885bada6c2d5e71b1302e87d4006c59ff2a40a12108559d76142548d8cf79", + "account": "eosio.token", + "name": "transfer", + "seq_num": 2, + "receiver": "b11", + "block_time": "2018-09-29T11:51:06.000", + "block_num": 127225, + "authorization": [{ + "actor": "b1", + "permission": "active" + } + ], + "action_data": { + "from": "b1", + "to": "b11", + "quantity": "0.0001 EOS", + "memo": "Transfer from b1 to b11" + } + } + ] +} +``` + +In your server side, you can use these actions to do many things, such as creating a telegram alert bot which you can subscribe on and receive your account's information on chain. \ No newline at end of file diff --git a/plugins/notify_plugin/include/eosio/notify_plugin/http_async_client.hpp b/plugins/notify_plugin/include/eosio/notify_plugin/http_async_client.hpp new file mode 100644 index 00000000000..cfc8f38a294 --- /dev/null +++ b/plugins/notify_plugin/include/eosio/notify_plugin/http_async_client.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace eosio +{ +using namespace fc; +namespace asio = boost::asio; + +template +struct final_action +{ + final_action(F f) : clean{f} {} + ~final_action() { clean(); } + +private: + F clean; +}; + +template +final_action finally(F f) +{ + return final_action(f); +} + +class http_async_client +{ +public: + http_async_client() : sync_client(std::make_unique()), + work_guard(asio::make_work_guard(ioc)) {} + + ~http_async_client() + { + work_guard.reset(); + } + + void start() + { + worker = std::make_unique([this]() { + ioc.run(); + }); + } + + void stop() + { + work_guard.reset(); + worker->join(); + } + + void set_default_retry_times(int64_t t) { + default_retry_times = t; + } + + template + void post(const url &dest, const T &payload, const time_point &deadline = time_point::maximum()) + { + asio::post(ioc.get_executor(), [this, dest, payload, deadline]() { + post_sync(dest, payload, deadline); + }); + } + +private: + template + void post_sync(const url &dest, const T &payload, + const time_point &deadline = time_point::maximum()) + { + auto exit = finally([this]() { + retry_times = default_retry_times; + }); + + try + { + sync_client->post_sync(dest, payload, deadline); + } + catch (const fc::eof_exception &exc) + { + } + catch (const fc::assert_exception &exc) + { + wlog("Exception while trying to send: ${exc}", ("exc", exc.to_detail_string())); + if (retry_times > 0) + { + wlog("Trying ${t} times: ", ("t", retry_times)); + retry_times--; + post_sync(dest, payload, deadline); + } + } + FC_CAPTURE_AND_LOG((dest)(payload)(deadline)) + }; + + std::unique_ptr sync_client; + std::unique_ptr worker; + asio::io_context ioc; + asio::executor_work_guard work_guard; + int64_t default_retry_times = 3; + int64_t retry_times = default_retry_times; +}; +} // namespace eosio \ No newline at end of file diff --git a/plugins/notify_plugin/include/eosio/notify_plugin/notify_plugin.hpp b/plugins/notify_plugin/include/eosio/notify_plugin/notify_plugin.hpp new file mode 100644 index 00000000000..e2a23a3a74a --- /dev/null +++ b/plugins/notify_plugin/include/eosio/notify_plugin/notify_plugin.hpp @@ -0,0 +1,33 @@ +/** + * @file + * @copyright eospace in eos/LICENSE.txt + */ +#pragma once +#include +#include + +namespace eosio { + +using namespace appbase; +using notify_plugin_ptr = std::unique_ptr; + +/** + * notify_plugin: make notifications to apps on chain. + */ +class notify_plugin : public appbase::plugin { +public: + notify_plugin(); + virtual ~notify_plugin(); + + APPBASE_PLUGIN_REQUIRES((chain_plugin)) + virtual void set_program_options(options_description&, options_description& cfg) override; + + void plugin_initialize(const variables_map& options); + void plugin_startup(); + void plugin_shutdown(); + +private: + notify_plugin_ptr my; +}; + +} diff --git a/plugins/notify_plugin/notify_plugin.cpp b/plugins/notify_plugin/notify_plugin.cpp new file mode 100644 index 00000000000..377daf8e5ef --- /dev/null +++ b/plugins/notify_plugin/notify_plugin.cpp @@ -0,0 +1,359 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace eosio +{ +static appbase::abstract_plugin &_notify_plugin = app().register_plugin(); +using namespace chain; +typedef uint32_t action_seq_type; + +class notify_plugin_impl +{ +public: + static const int64_t default_age_limit = 60; + static const int64_t default_retry_times = 3; + static const fc::microseconds http_timeout; + static const fc::microseconds max_deserialization_time; + + fc::url receive_url; + int64_t age_limit = default_age_limit; + int64_t retry_times = default_retry_times; + http_async_client httpc; + + struct sequenced_action : public action + { + sequenced_action(const action &act, action_seq_type seq, account_name receiver) + : action(act), seq_num(seq), receiver(receiver) {} + + action_seq_type seq_num; + account_name receiver; + }; + + struct action_notify + { + action_notify(const sequenced_action &act, transaction_id_type tx_id, + const variant &action_data, fc::time_point block_time, + uint32_t block_num) + : tx_id(tx_id), account(act.account), name(act.name), receiver(act.receiver), + seq_num(act.seq_num), block_time(block_time), block_num(block_num), + authorization(act.authorization), action_data(action_data) {} + + transaction_id_type tx_id; + account_name account; + account_name name; + account_name receiver; + action_seq_type seq_num; + fc::time_point block_time; + uint32_t block_num; + + vector authorization; + fc::variant action_data; + }; + + struct message + { + message() : irreversible(false), actions() {} + bool irreversible; + std::vector actions; + }; + + struct filter_entry + { + name receiver; + name action; + + std::tuple key() const + { + return std::make_tuple(receiver, action); + } + + friend bool operator<(const filter_entry &a, const filter_entry &b) + { + return a.key() < b.key(); + } + }; + + typedef std::unordered_multimap action_queue_type; + + chain_plugin *chain_plug = nullptr; + std::set filter_on; + fc::optional accepted_block_conn; + fc::optional irreversible_block_conn; + fc::optional applied_tx_conn; + action_queue_type action_queue; + action_queue_type irreversible_action_queue; + + bool filter(const action_trace &act); + fc::variant deserialize_action_data(action act); + void build_message(message &msg, const block_state_ptr &block, const transaction_id_type &tx_id, bool irreversible); + void send_message(const message &msg); + action_seq_type on_action_trace(const action_trace &act, const transaction_id_type &tx_id, action_seq_type act_s); + void on_applied_tx(const transaction_trace_ptr &trace); + void on_accepted_block(const block_state_ptr &block_state); + void on_irreversible_block(const block_state_ptr &block_state); +}; + +bool notify_plugin_impl::filter(const action_trace &act) +{ + if (filter_on.find({act.receipt.receiver, act.act.name}) != filter_on.end()) + { + return true; + } + else if (filter_on.find({act.receipt.receiver, 0}) != filter_on.end()) + { + return true; + } + return false; +} + +fc::variant notify_plugin_impl::deserialize_action_data(action act) +{ + auto &chain = chain_plug->chain(); + auto serializer = chain.get_abi_serializer(act.account, max_deserialization_time); + FC_ASSERT(serializer.valid() && serializer->get_action_type(act.name) != action_name(), + "Unable to get abi for account: ${acc}, action: ${a} Not sending notification.", + ("acc", act.account)("a", act.name)); + return serializer->binary_to_variant(act.name.to_string(), act.data, max_deserialization_time); +} + +void notify_plugin_impl::build_message(message &msg, const block_state_ptr &block, const transaction_id_type &tx_id, const bool irreversible) +{ + // dlog("irreversible: ${a}", ("a", fc::json::to_pretty_string(irreversible))); + auto range = irreversible ? irreversible_action_queue.equal_range(tx_id) : action_queue.equal_range(tx_id); + + msg.irreversible = irreversible; + for (auto &it = range.first; it != range.second; it++) + { + auto act_data = deserialize_action_data(it->second); + action_notify notify(it->second, tx_id, std::forward(act_data), + block->block->timestamp, block->block->block_num()); + msg.actions.push_back(notify); + } +} + +void notify_plugin_impl::send_message(const message &msg) +{ + try + { + httpc.post(receive_url, msg, fc::time_point::now() + http_timeout); + } + FC_CAPTURE_AND_LOG(("Error while sending notification")(msg)); +} + +action_seq_type notify_plugin_impl::on_action_trace(const action_trace &act, const transaction_id_type &tx_id, + action_seq_type act_s) +{ + if (filter(act)) + { + const auto pair = std::make_pair(tx_id, sequenced_action(act.act, act_s, act.receipt.receiver)); + action_queue.insert(pair); + irreversible_action_queue.insert(pair); + // dlog("on_action_trace: ${a}", ("a", fc::json::to_pretty_string(act.act))); + } + act_s++; + + for (const auto &iline : act.inline_traces) + { + act_s = on_action_trace(iline, tx_id, act_s); + } + return act_s; +} + +void notify_plugin_impl::on_applied_tx(const transaction_trace_ptr &trace) +{ + auto id = trace->id; + + if (!action_queue.count(id) || !irreversible_action_queue.count(id)) + { + action_seq_type seq = 0; + for (auto &at : trace->action_traces) + { + seq = on_action_trace(at, id, seq); + } + } +} + +void notify_plugin_impl::on_accepted_block(const block_state_ptr &block_state) +{ + fc::time_point block_time = block_state->block->timestamp; + + if (age_limit == -1 || (fc::time_point::now() - block_time < fc::seconds(age_limit))) + { + message msg; + transaction_id_type tx_id; + // dlog("block_state->block->transactions: ${a}", ("a", fc::json::to_pretty_string(block_state->block->transactions))); + for (const auto &trx : block_state->block->transactions) + { + if (trx.trx.contains()) + { + tx_id = trx.trx.get(); + } + else + { + tx_id = trx.trx.get().id(); + } + + // dlog("tx_id: ${a}", ("a", fc::json::to_pretty_string(tx_id))); + // dlog("action_queue.size(): ${a}", ("a", fc::json::to_pretty_string(action_queue.size()))); + if (action_queue.count(tx_id)) + { + build_message(msg, block_state, tx_id, false); + } + } + // dlog("msg: ${a}", ("a", msg)); + if (msg.actions.size() > 0) + { + send_message(msg); + } + } + action_queue.clear(); +} + +void notify_plugin_impl::on_irreversible_block(const block_state_ptr &block_state) +{ + fc::time_point block_time = block_state->block->timestamp; + if (age_limit == -1 || (fc::time_point::now() - block_time < fc::seconds(age_limit))) + { + message msg; + transaction_id_type tx_id; + // dlog("block_state->block->transactions: ${a}", ("a", fc::json::to_pretty_string(block_state->block->transactions))); + for (const auto &trx : block_state->block->transactions) + { + if (trx.trx.contains()) + { + tx_id = trx.trx.get(); + } + else + { + tx_id = trx.trx.get().id(); + } + // dlog("tx_id: ${a}", ("a", fc::json::to_pretty_string(tx_id))); + // dlog("irreversible_action_queue.size(): ${a}", ("a", fc::json::to_pretty_string(irreversible_action_queue.size()))); + if (irreversible_action_queue.count(tx_id)) + { + build_message(msg, block_state, tx_id, true); + } + } + // dlog("msg: ${a}", ("a", msg)); + if (msg.actions.size() > 0) + { + send_message(msg); + irreversible_action_queue.clear(); + } + } +} + +const fc::microseconds notify_plugin_impl::http_timeout = fc::seconds(10); +const fc::microseconds notify_plugin_impl::max_deserialization_time = fc::seconds(5); +const int64_t notify_plugin_impl::default_age_limit; +const int64_t notify_plugin_impl::default_retry_times; + +notify_plugin::notify_plugin() : my(new notify_plugin_impl()) {} +notify_plugin::~notify_plugin() {} + +void notify_plugin::set_program_options(options_description &, options_description &cfg) +{ + cfg.add_options()("notify-filter-on", bpo::value>()->composing(), + "Track actions and make notifications then it match receiver:action. In case action is not specified, " + "all actions to specified account are tracked.") + ("notify-receive-url", bpo::value(), "Notify URL which can receive the notifications") + ("notify-age-limit", bpo::value()->default_value(notify_plugin_impl::default_age_limit), + "Age limit in seconds for blocks to send notifications about." + " No age limit if this is set to negative.") + ("notify-retry-times", bpo::value()->default_value(notify_plugin_impl::default_retry_times), + "Retry times of sending http notification if failed.") + ; +} + +void notify_plugin::plugin_initialize(const variables_map &options) +{ + try + { + EOS_ASSERT(options.count("notify-receive-url") == 1, fc::invalid_arg_exception, + "notify_plugin requires one notify-receiver-url to be specified!"); + + EOS_ASSERT(options.count("notify-age-limit") == 1, fc::invalid_arg_exception, + "notify_plugin requires one notify-age-limit to be specified!"); + + EOS_ASSERT(options.count("notify-retry-times") == 1, fc::invalid_arg_exception, + "notify_plugin requires one notify-retry-times to be specified!"); + + string url_str = options.at("notify-receive-url").as(); + my->receive_url = fc::url(url_str); + + if (options.count("notify-filter-on")) + { + auto fo = options.at("notify-filter-on").as>(); + for (auto &s : fo) + { + std::vector v; + boost::split(v, s, boost::is_any_of(":")); + EOS_ASSERT(v.size() == 2, fc::invalid_arg_exception, + "Invalid value ${s} for --notify-filter-on", + ("s", s)); + notify_plugin_impl::filter_entry fe{v[0], v[1]}; + EOS_ASSERT(fe.receiver.value, fc::invalid_arg_exception, "Invalid value ${s} for --notify-filter-on", ("s", s)); + my->filter_on.insert(fe); + } + } + + if (options.count("notify-age-limit")) + my->age_limit = options.at("notify-age-limit").as(); + + if (options.count("notify-retry-times")) + my->retry_times = options.at("notify-retry-times").as(); + + my->httpc.set_default_retry_times(my->retry_times); + my->chain_plug = app().find_plugin(); + auto &chain = my->chain_plug->chain(); + my->accepted_block_conn.emplace(chain.accepted_block.connect( + [&](const block_state_ptr &b_state) { + my->on_accepted_block(b_state); + })); + + my->irreversible_block_conn.emplace(chain.irreversible_block.connect( + [&](const block_state_ptr &bs) { + my->on_irreversible_block(bs); + })); + + my->applied_tx_conn.emplace(chain.applied_transaction.connect( + [&](const transaction_trace_ptr &tx) { + my->on_applied_tx(tx); + })); + } + FC_LOG_AND_RETHROW() +} + +void notify_plugin::plugin_startup() +{ + ilog("Notify plugin started"); + my->httpc.start(); +} + +void notify_plugin::plugin_shutdown() +{ + my->applied_tx_conn.reset(); + my->accepted_block_conn.reset(); + my->irreversible_block_conn.reset(); + my->httpc.stop(); +} +} // namespace eosio + +FC_REFLECT(eosio::notify_plugin_impl::action_notify, (tx_id)(account)(name)(seq_num)(receiver)(block_time)(block_num)(authorization)(action_data)) +FC_REFLECT(eosio::notify_plugin_impl::message, (irreversible)(actions)) \ No newline at end of file diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index c46452b5fb4..2d60e92a006 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1071,8 +1071,13 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } } + signature_provider_type signature_provider; + if (signature_provider_itr != _signature_providers.end()) { + signature_provider = signature_provider_itr->second; + } + chain.abort_block(); - chain.start_block(block_time, blocks_to_confirm); + chain.start_block(block_time, blocks_to_confirm, signature_provider); } FC_LOG_AND_DROP(); const auto& pbs = chain.pending_block_state(); diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index 54e60866fbc..850b7bab787 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -105,6 +105,7 @@ namespace eosio { namespace client { namespace http { const string history_func_base = "/v1/history"; const string get_actions_func = history_func_base + "/get_actions"; const string get_transaction_func = history_func_base + "/get_transaction"; + const string get_block_detail_func = history_func_base + "/get_block_detail"; const string get_key_accounts_func = history_func_base + "/get_key_accounts"; const string get_controlled_accounts_func = history_func_base + "/get_controlled_accounts"; diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index b2a2c326353..7124357f158 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -552,12 +552,15 @@ chain::action create_delegate(const name& from, const name& receiver, const asse config::system_account_name, N(delegatebw), act_payload); } -fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, uint16_t location) { +fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, const string& location) { +auto _location=atoi(location.c_str()); + FC_ASSERT(_location>-12&&_location<=12,"time zone setting is not legal"); + _location=_location>=0?_location:24+_location; return fc::mutable_variant_object() ("producer", producer) ("producer_key", key) ("url", url) - ("location", location) + ("location", _location) ; } @@ -861,14 +864,14 @@ struct register_producer_subcommand { string producer_str; string producer_key_str; string url; - uint16_t loc = 0; + string loc; register_producer_subcommand(CLI::App* actionRoot) { auto register_producer = actionRoot->add_subcommand("regproducer", localized("Register a new producer")); register_producer->add_option("account", producer_str, localized("The account to register as a producer"))->required(); register_producer->add_option("producer_key", producer_key_str, localized("The producer's public key"))->required(); register_producer->add_option("url", url, localized("url where info about producer can be found"), true); - register_producer->add_option("location", loc, localized("relative location for purpose of nearest neighbor scheduling"), true); + register_producer->add_option("location", loc, localized("time zone from -11 to 12 "))->required(); add_standard_transaction_options(register_producer); @@ -2146,6 +2149,15 @@ int main( int argc, char** argv ) { std::cout << fc::json::to_pretty_string(call(get_transaction_func, arg)) << std::endl; }); + // get block detail + string block_detail_arg; + auto getBlockDetail = get->add_subcommand("block_detail", localized("Retrieve a full block from the blockchain"), false); + getBlockDetail->add_option("block", block_detail_arg, localized("The number or ID of the block to retrieve"))->required(); + getBlockDetail->set_callback([&block_detail_arg] { + auto arg = fc::mutable_variant_object("block_num_or_id", block_detail_arg); + std::cout << fc::json::to_pretty_string(call(get_block_detail_func, arg)) << std::endl; + }); + // get actions string account_name; string skip_seq_str; diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 9e1481c23c3..946c8c83200 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -69,6 +69,10 @@ target_link_libraries( ${NODE_EXECUTABLE_NAME} if(BUILD_MONGO_DB_PLUGIN) target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE -Wl,${whole_archive_flag} mongo_db_plugin -Wl,${no_whole_archive_flag} ) endif() +# kafka_plugin +target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE -Wl,${whole_archive_flag} kafka_plugin -Wl,${no_whole_archive_flag} ) +# notify_plugin +target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE -Wl,${whole_archive_flag} notify_plugin -Wl,${no_whole_archive_flag} ) include(additionalPlugins) diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh index 6183b0020d5..b32d2a51315 100644 --- a/scripts/eosio_build_amazon.sh +++ b/scripts/eosio_build_amazon.sh @@ -622,6 +622,126 @@ fi printf "\\tWASM found at %s/opt/wasm.\\n" "${HOME}" fi + printf "\\n\\tChecking for librdkafka with support.\\n" + RDKAFKA_DIR=/usr/local/include/librdkafka + if [ ! -d "${RDKAFKA_DIR}" ]; then + # Build librdkafka support: + printf "\\tInstalling librdkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/librdkafka" ]; then + if ! rm -rf "${TEMP_DIR}/librdkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/librdkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git + then + printf "\\tUnable to clone librdkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/" + then + printf "\\tUnable to enter directory %s/librdkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -H. -B_cmake_build + then + printf "\\tError cmake_build librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build + then + printf "\\tError compiling cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build , librdkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/_cmake_build" + then + printf "\\tUnable to enter directory %s/librdkafka/_cmake_build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tlibrdkafka successffully installed @ %s.\\n\\n" "${RDKAFKA_DIR}" + else + printf "\\t librdkafka found at %s.\\n" "${RDKAFKA_DIR}" + fi + + printf "\\n\\tChecking for cppkafka with support.\\n" + CPPKAFKA_DIR=/usr/local/include/cppkafka + if [ ! -d "${CPPKAFKA_DIR}" ]; then + # Build cppkafka support: + printf "\\tInstalling cppkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/cppkafka" ]; then + if ! rm -rf "${TEMP_DIR}/cppkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/cppkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git + then + printf "\\tUnable to clone cppkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/" + then + printf "\\tUnable to enter directory %s/cppkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! mkdir build + then + printf "\\tUnable to remove directory build.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/build" + then + printf "\\tUnable to enter directory %s/cppkafka/build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. + then + printf "\\tError compiling cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. , cppkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install cppkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tcppkafka successffully installed @ %s.\\n\\n" "${CPPKAFKA_DIR}" + else + printf "\\t cppkafka found at %s.\\n" "${CPPKAFKA_DIR}" + fi + function print_instructions() { printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index 652da373244..bedf64f6058 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -686,6 +686,126 @@ mongodconf printf "\\t - WASM found at %s/opt/wasm\\n" "${HOME}" fi + printf "\\n\\tChecking for librdkafka with support.\\n" + RDKAFKA_DIR=/usr/local/include/librdkafka + if [ ! -d "${RDKAFKA_DIR}" ]; then + # Build librdkafka support: + printf "\\tInstalling librdkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/librdkafka" ]; then + if ! rm -rf "${TEMP_DIR}/librdkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/librdkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git + then + printf "\\tUnable to clone librdkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/" + then + printf "\\tUnable to enter directory %s/librdkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -H. -B_cmake_build + then + printf "\\tError cmake_build librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build + then + printf "\\tError compiling cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build , librdkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/_cmake_build" + then + printf "\\tUnable to enter directory %s/librdkafka/_cmake_build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tlibrdkafka successffully installed @ %s.\\n\\n" "${RDKAFKA_DIR}" + else + printf "\\t librdkafka found at %s.\\n" "${RDKAFKA_DIR}" + fi + + printf "\\n\\tChecking for cppkafka with support.\\n" + CPPKAFKA_DIR=/usr/local/include/cppkafka + if [ ! -d "${CPPKAFKA_DIR}" ]; then + # Build cppkafka support: + printf "\\tInstalling cppkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/cppkafka" ]; then + if ! rm -rf "${TEMP_DIR}/cppkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/cppkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.2 https://github.com/boscore/cppkafka.git + then + printf "\\tUnable to clone cppkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/" + then + printf "\\tUnable to enter directory %s/cppkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! mkdir build + then + printf "\\tUnable to remove directory build.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/build" + then + printf "\\tUnable to enter directory %s/cppkafka/build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. + then + printf "\\tError compiling cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. , cppkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install cppkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tcppkafka successffully installed @ %s.\\n\\n" "${CPPKAFKA_DIR}" + else + printf "\\t cppkafka found at %s.\\n" "${CPPKAFKA_DIR}" + fi + printf "\\n" function print_instructions() diff --git a/scripts/eosio_build_darwin.sh b/scripts/eosio_build_darwin.sh index a91e1611d44..f3ee81cf467 100644 --- a/scripts/eosio_build_darwin.sh +++ b/scripts/eosio_build_darwin.sh @@ -479,6 +479,126 @@ printf "\\tWASM found at /usr/local/wasm/bin/.\\n" fi + printf "\\n\\tChecking for librdkafka with support.\\n" + RDKAFKA_DIR=/usr/local/include/librdkafka + if [ ! -d "${RDKAFKA_DIR}" ]; then + # Build librdkafka support: + printf "\\tInstalling librdkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/librdkafka" ]; then + if ! rm -rf "${TEMP_DIR}/librdkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/librdkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git + then + printf "\\tUnable to clone librdkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/" + then + printf "\\tUnable to enter directory %s/librdkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -H. -B_cmake_build + then + printf "\\tError cmake_build librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build + then + printf "\\tError compiling cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build , librdkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/_cmake_build" + then + printf "\\tUnable to enter directory %s/librdkafka/_cmake_build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tlibrdkafka successffully installed @ %s.\\n\\n" "${RDKAFKA_DIR}" + else + printf "\\t librdkafka found at %s.\\n" "${RDKAFKA_DIR}" + fi + + printf "\\n\\tChecking for cppkafka with support.\\n" + CPPKAFKA_DIR=/usr/local/include/cppkafka + if [ ! -d "${CPPKAFKA_DIR}" ]; then + # Build cppkafka support: + printf "\\tInstalling cppkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/cppkafka" ]; then + if ! rm -rf "${TEMP_DIR}/cppkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/cppkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git + then + printf "\\tUnable to clone cppkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/" + then + printf "\\tUnable to enter directory %s/cppkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! mkdir build + then + printf "\\tUnable to remove directory build.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/build" + then + printf "\\tUnable to enter directory %s/cppkafka/build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. + then + printf "\\tError compiling cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. , cppkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install cppkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tcppkafka successffully installed @ %s.\\n\\n" "${CPPKAFKA_DIR}" + else + printf "\\t cppkafka found at %s.\\n" "${CPPKAFKA_DIR}" + fi + function print_instructions() { printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index 35cad3d7d8e..238781f2f8f 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -492,6 +492,126 @@ printf "\\n\\tWASM found @ %s/opt/wasm\\n\\n" "${HOME}" fi + printf "\\n\\tChecking for librdkafka with support.\\n" + RDKAFKA_DIR=/usr/local/include/librdkafka + if [ ! -d "${RDKAFKA_DIR}" ]; then + # Build librdkafka support: + printf "\\tInstalling librdkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/librdkafka" ]; then + if ! rm -rf "${TEMP_DIR}/librdkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/librdkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git + then + printf "\\tUnable to clone librdkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/" + then + printf "\\tUnable to enter directory %s/librdkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -H. -B_cmake_build + then + printf "\\tError cmake_build librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build + then + printf "\\tError compiling cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build , librdkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/_cmake_build" + then + printf "\\tUnable to enter directory %s/librdkafka/_cmake_build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tlibrdkafka successffully installed @ %s.\\n\\n" "${RDKAFKA_DIR}" + else + printf "\\t librdkafka found at %s.\\n" "${RDKAFKA_DIR}" + fi + + printf "\\n\\tChecking for cppkafka with support.\\n" + CPPKAFKA_DIR=/usr/local/include/cppkafka + if [ ! -d "${CPPKAFKA_DIR}" ]; then + # Build cppkafka support: + printf "\\tInstalling cppkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/cppkafka" ]; then + if ! rm -rf "${TEMP_DIR}/cppkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/cppkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git + then + printf "\\tUnable to clone cppkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/" + then + printf "\\tUnable to enter directory %s/cppkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! mkdir build + then + printf "\\tUnable to remove directory build.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/build" + then + printf "\\tUnable to enter directory %s/cppkafka/build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. + then + printf "\\tError compiling cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. , cppkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install cppkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tcppkafka successffully installed @ %s.\\n\\n" "${CPPKAFKA_DIR}" + else + printf "\\t cppkafka found at %s.\\n" "${CPPKAFKA_DIR}" + fi + function print_instructions() { printf "\\n\\t%s -f %s &\\n" "$( command -v mongod )" "${MONGOD_CONF}" diff --git a/scripts/eosio_build_ubuntu.sh b/scripts/eosio_build_ubuntu.sh index 4c9873a60a1..ab3e8823d8e 100644 --- a/scripts/eosio_build_ubuntu.sh +++ b/scripts/eosio_build_ubuntu.sh @@ -503,6 +503,126 @@ mongodconf printf "\\tWASM found at %s/opt/wasm/bin.\\n" "${HOME}" fi + printf "\\n\\tChecking for librdkafka with support.\\n" + RDKAFKA_DIR=/usr/local/include/librdkafka + if [ ! -d "${RDKAFKA_DIR}" ]; then + # Build librdkafka support: + printf "\\tInstalling librdkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/librdkafka" ]; then + if ! rm -rf "${TEMP_DIR}/librdkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/librdkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b v0.11.6 https://github.com/boscore/librdkafka.git + then + printf "\\tUnable to clone librdkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/" + then + printf "\\tUnable to enter directory %s/librdkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -H. -B_cmake_build + then + printf "\\tError cmake_build librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build + then + printf "\\tError compiling cmake -DRDKAFKA_BUILD_STATIC=1 --build _cmake_build , librdkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/librdkafka/_cmake_build" + then + printf "\\tUnable to enter directory %s/librdkafka/_cmake_build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install librdkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tlibrdkafka successffully installed @ %s.\\n\\n" "${RDKAFKA_DIR}" + else + printf "\\t librdkafka found at %s.\\n" "${RDKAFKA_DIR}" + fi + + printf "\\n\\tChecking for cppkafka with support.\\n" + CPPKAFKA_DIR=/usr/local/include/cppkafka + if [ ! -d "${CPPKAFKA_DIR}" ]; then + # Build cppkafka support: + printf "\\tInstalling cppkafka\\n" + if ! cd "${TEMP_DIR}" + then + printf "\\n\\tUnable to cd into directory %s.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if [ -d "${TEMP_DIR}/cppkafka" ]; then + if ! rm -rf "${TEMP_DIR}/cppkafka" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "${TEMP_DIR}/cppkafka/" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + if ! git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git + then + printf "\\tUnable to clone cppkafka repo.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/" + then + printf "\\tUnable to enter directory %s/cppkafka/.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! mkdir build + then + printf "\\tUnable to remove directory build.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cd "${TEMP_DIR}/cppkafka/build" + then + printf "\\tUnable to enter directory %s/cppkafka/build.\\n" "${TEMP_DIR}" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. + then + printf "\\tError compiling cmake -DCPPKAFKA_RDKAFKA_STATIC_LIB=1 -DCPPKAFKA_BUILD_SHARED=0 .. , cppkafka.1\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + if ! sudo make install + then + printf "\\tUnable to make install cppkafka.\\n" + printf "\\n\\tExiting now.\\n" + exit 1; + fi + printf "\\n\\tcppkafka successffully installed @ %s.\\n\\n" "${CPPKAFKA_DIR}" + else + printf "\\t cppkafka found at %s.\\n" "${CPPKAFKA_DIR}" + fi + function print_instructions() { printf '\n\texport PATH=${HOME}/opt/mongodb/bin:$PATH\n' diff --git a/unittests/actiondemo/actiondemo.abi b/unittests/actiondemo/actiondemo.abi new file mode 100644 index 00000000000..172d180bfef --- /dev/null +++ b/unittests/actiondemo/actiondemo.abi @@ -0,0 +1,99 @@ +{ + "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-11-17T13:26:02", + "version": "eosio::abi/1.0", + "types": [], + "structs": [{ + "name": "seedobj", + "base": "", + "fields": [{ + "name": "id", + "type": "uint64" + },{ + "name": "create", + "type": "time_point" + },{ + "name": "seedstr", + "type": "string" + },{ + "name": "txid", + "type": "string" + },{ + "name": "action", + "type": "uint64" + } + ] + },{ + "name": "args", + "base": "", + "fields": [{ + "name": "loop", + "type": "uint64" + },{ + "name": "num", + "type": "uint64" + } + ] + },{ + "name": "generate", + "base": "", + "fields": [{ + "name": "t", + "type": "args" + } + ] + },{ + "name": "clear", + "base": "", + "fields": [] + },{ + "name": "args_inline", + "base": "", + "fields": [{ + "name": "payer", + "type": "name" + },{ + "name": "in", + "type": "name" + } + ] + },{ + "name": "inlineact", + "base": "", + "fields": [{ + "name": "t", + "type": "args_inline" + } + ] + } + ], + "actions": [{ + "name": "generate", + "type": "generate", + "ricardian_contract": "" + },{ + "name": "clear", + "type": "clear", + "ricardian_contract": "" + },{ + "name": "inlineact", + "type": "inlineact", + "ricardian_contract": "" + } + ], + "tables": [{ + "name": "seedobjs", + "index_type": "i64", + "key_names": [ + "id" + ], + "key_types": [ + "uint64" + ], + "type": "seedobj" + } + ], + "ricardian_clauses": [], + "error_messages": [], + "abi_extensions": [], + "variants": [] +} \ No newline at end of file diff --git a/unittests/actiondemo/actiondemo.cpp b/unittests/actiondemo/actiondemo.cpp new file mode 100644 index 00000000000..3f8a3fcb6e0 --- /dev/null +++ b/unittests/actiondemo/actiondemo.cpp @@ -0,0 +1,106 @@ +#include "actiondemo.hpp" +#include "../../contracts/eosiolib/print.hpp" +#include "../../contracts/eosiolib/types.hpp" +#include "../../contracts/eosiolib/transaction.hpp" + +namespace spaceaction { + + void actiondemo::apply( account_name code, account_name act ) { + + if( code != _self ) + return; + + switch( act ) { + case N(generate): + generate(unpack_action_data()); + return; + case N(inlineact): + inlineact(unpack_action_data()); + case N(clear): + clear(); + return; + } + } + + void actiondemo::clear(){ + //require_auth(_self); + seedobjs table(_self, _self); + auto iter = table.begin(); + while (iter != table.end()) + { + table.erase(iter); + iter = table.begin(); + } + } + + std::string to_hex( const char* d, uint32_t s ) + { + std::string r; + const char* to_hex="0123456789abcdef"; + uint8_t* c = (uint8_t*)d; + for( uint32_t i = 0; i < s; ++i ) + (r += to_hex[(c[i]>>4)]) += to_hex[(c[i] &0x0f)]; + return r; + } + + void actiondemo::generate(const args& t){ + for (int i = 0; i < t.loop; ++i) { + transaction_id_type txid; + get_transaction_id(&txid); + std::string tx = to_hex((char*)&txid.hash, 32); + + uint64_t seq = 0; + get_action_sequence(&seq); + + + size_t szBuff = sizeof(signature); + char buf[szBuff]; + memset(buf,0,szBuff); + size_t size = bpsig_action_time_seed(buf, sizeof(buf)); + eosio_assert(size > 0 && size <= sizeof(buf), "buffer is too small"); + std::string seedstr = to_hex(buf,size); + + + seedobjs table(_self, _self); + uint64_t count = 0; + for (auto itr = table.begin(); itr != table.end(); ++itr) { + ++count; + } + + auto r = table.emplace(_self, [&](auto &a) { + a.id = count + 1; + a.create = eosio::time_point_sec(now()); + a.seedstr = seedstr; + a.txid = tx; + a.action = seq; + }); + print_f("self:%, loop:%, count:%, seedstr:%", name{_self}.to_string(), t.loop, count, r->seedstr); + } + } + + void actiondemo::inlineact(const args_inline& t){ + auto& payer = t.payer; + args gen; + gen.loop = 1; + gen.num = 1; + + generate(gen); + + if(t.in != 0) + { + INLINE_ACTION_SENDER(spaceaction::actiondemo, generate)( t.in, {payer,N(active)}, + { gen}); + INLINE_ACTION_SENDER(spaceaction::actiondemo, generate)( t.in, {payer,N(active)}, + { gen}); + } + + } +} + +extern "C" { +[[noreturn]] void apply(uint64_t receiver, uint64_t code, uint64_t action) { + spaceaction::actiondemo obj(receiver); + obj.apply(code, action); + eosio_exit(0); +} +} \ No newline at end of file diff --git a/unittests/actiondemo/actiondemo.hpp b/unittests/actiondemo/actiondemo.hpp new file mode 100644 index 00000000000..e1d5031bfa5 --- /dev/null +++ b/unittests/actiondemo/actiondemo.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include + +namespace spaceaction { + + using namespace eosio; + class actiondemo : public contract { + typedef std::chrono::milliseconds duration; + public: + actiondemo( account_name self ):contract(self){} + + void apply( account_name contract, account_name act ); + + struct args{ + uint64_t loop; + uint64_t num; + }; + //@abi action + void generate(const args& t); + + //@abi action + void clear(); + + + struct args_inline{ + account_name payer; + account_name in; + }; + //@abi action + void inlineact(const args_inline& t); + + public: + // @abi table seedobjs i64 + struct seedobj { + uint64_t id; + time_point create; + std::string seedstr; + std::string txid; + uint64_t action; + + uint64_t primary_key()const { return id; } + EOSLIB_SERIALIZE(seedobj,(id)(create)(seedstr)(txid)(action)) + }; + typedef eosio::multi_index< N(seedobjs), seedobj> seedobjs; + + + }; + +} /// namespace eosio diff --git a/unittests/actiondemo/test.py b/unittests/actiondemo/test.py new file mode 100644 index 00000000000..5ced2b4276c --- /dev/null +++ b/unittests/actiondemo/test.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 + +import argparse +import json + +import os + +import subprocess + +import time + +args = None +logFile = None + +unlockTimeout = 999999 + +systemAccounts = [ + 'eosio.bpay', + 'eosio.msig', + 'eosio.names', + 'eosio.ram', + 'eosio.ramfee', + 'eosio.saving', + 'eosio.stake', + 'eosio.token', + 'eosio.vpay', +] + + +def jsonArg(a): + return " '" + json.dumps(a) + "' " + +def run(args): + print('testtool.py:', args) + logFile.write(args + '\n') + if subprocess.call(args, shell=True): + print('testtool.py: exiting because of error') + #sys.exit(1) + +def retry(args): + while True: + print('testtool.py:', args) + logFile.write(args + '\n') + if subprocess.call(args, shell=True): + print('*** Retry') + else: + break + +def background(args): + print('testtool.py:', args) + logFile.write(args + '\n') + return subprocess.Popen(args, shell=True) + +def getOutput(args): + print('testtool.py:', args) + logFile.write(args + '\n') + proc = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) + return proc.communicate()[0].decode('utf-8') + +def getJsonOutput(args): + print('testtool.py:', args) + logFile.write(args + '\n') + proc = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) + return json.loads(proc.communicate()[0].decode('utf-8')) + +def sleep(t): + print('sleep', t, '...') + time.sleep(t) + print('resume') + +def startWallet(): + run('rm -rf ' + os.path.abspath(args.wallet_dir)) + run('mkdir -p ' + os.path.abspath(args.wallet_dir)) + background(args.keosd + ' --unlock-timeout %d --http-server-address 127.0.0.1:6666 --wallet-dir %s' % (unlockTimeout, os.path.abspath(args.wallet_dir))) + sleep(4) + run(args.cleos + 'wallet create --file ./unlock.key ' ) + +def importKeys(): + run(args.cleos + 'wallet import --private-key ' + args.private_key) + +# def createStakedAccounts(b, e): +# for i in range(b, e): +# a = accounts[i] +# stake = 100 +# run(args.cleos + 'system newaccount eosio --transfer ' + a['name'] + ' ' + a['pub'] + ' --stake-net "' + stake + '" --stake-cpu "' + stake + '"') + + +def stepStartWallet(): + startWallet() + importKeys() + # run('rm -rf ~/.local/share/eosio/nodeos/data ') + run("rm -rf ./data/*") + background(args.nodeos + ' -e -p eosio --blocks-dir ./data/block/ --genesis-json %s --config-dir ./ --data-dir ./data/ --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --plugin eosio::history_api_plugin> eos.log 2>&1 &' % args.genesis) + run("rm -rf ./data2/*") + background(args.nodeos + ' --blocks-dir ./data2/block/ --genesis-json %s --data-dir ./data2/ --config-dir ./ --p2p-peer-address 127.0.0.1:9876 --http-server-address 0.0.0.0:8001 --p2p-listen-endpoint 0.0.0.0:9001 --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --plugin eosio::history_api_plugin > eos2.log 2>&1 &' % args.genesis) + sleep(30) + + +def createAccounts(): + for a in systemAccounts: + run(args.cleos + 'create account eosio ' + a + ' ' + args.public_key) + run(args.cleos + 'set contract eosio.token ' + args.contracts_dir + 'eosio.token/') + run(args.cleos + 'set contract eosio.msig ' + args.contracts_dir + 'eosio.msig/') + run(args.cleos + 'push action eosio.token create \'["eosio", "10000000000.0000 %s"]\' -p eosio.token' % (args.symbol)) + run(args.cleos + 'push action eosio.token issue \'["eosio", "%s %s", "memo"]\' -p eosio' % ("1000000.0000", args.symbol)) + retry(args.cleos + 'set contract eosio ' + args.contracts_dir + 'eosio.system/ -p eosio') + sleep(1) + run(args.cleos + 'push action eosio setpriv' + jsonArg(['eosio.msig', 1]) + '-p eosio@active') + + for a in accounts: + run(args.cleos + 'system newaccount --stake-net "10.0000 %s" --stake-cpu "10.0000 %s" --buy-ram-kbytes 80 eosio ' %(args.symbol,args.symbol) + a + ' ' + args.public_key) + + run(args.cleos + 'system newaccount --stake-net "10.0000 %s" --stake-cpu "10.0000 %s" --buy-ram-kbytes 80 eosio '%(args.symbol,args.symbol) + 'cochaintoken' + ' ' + args.public_key) + + run(args.cleos + 'system buyram eosio %s -k 80000 -p eosio ' % args.contract ) + run(args.cleos + 'system delegatebw eosio %s "1000.0000 SYS" "1000.0000 SYS"'% args.contract ) + + run(args.cleos + 'system buyram eosio %s -k 80000 -p eosio ' % args.contract2 ) + run(args.cleos + 'system delegatebw eosio %s "1000.0000 SYS" "1000.0000 SYS"'% args.contract2 ) + +# stepIssueToken() +# +# +# def stepIssueToken(): +# run(args.cleos + 'push action eosio.token issue \'["eosio", "%s %s", "memo"]\' -p eosio' % ("1000000.0000", args.symbol)) +# for i in accounts: +# run(args.cleos + 'push action eosio.token issue \'["%s", "%s %s", "memo"]\' -p eosio' % (i, "1000000.0000", args.symbol)) +# +# sleep(1) + + +def stepKillAll(): + run('killall keosd nodeos || true') + sleep(1.5) +# Command Line Arguments + +def stepInitCaee(): + print ("=========================== set contract caee ===========================" ) + run(args.cleos + 'set contract %s ../actiondemo' %args.contract ) + run(args.cleos + 'set contract %s ../actiondemo' %args.contract2 ) + run(args.cleos + 'set account permission %s active \'{"threshold": 1,"keys": [{"key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","weight": 1}],"accounts": [{"permission":{"actor":"%s","permission":"eosio.code"},"weight":1}]}\' ' % (args.contract,args.contract)) + print ("sleep 5") + + +def stepClear(): + print ("=========================== set contract clear ===========================" ) + run(args.cleos + 'push action %s clear "[]" -p %s ' %(args.contract, args.contract)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract, args.contract) ) + run(args.cleos + 'push action %s clear "[]" -p %s ' %(args.contract2, args.contract2)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract2, args.contract2) ) + print ("sleep 5") + + +def stepGenerate(): + print ("=========================== set contract stepGenerate ===========================" ) + # run(args.cleos + 'push action %s generate \'[{"loop":1, "num":1}]\' -p %s ' %(args.contract, args.contract)) + run(args.cleos + 'push action %s inlineact \'[{"payer":"%s", "in":"%s"}]\' -p %s ' %(args.contract,args.contract,args.contract2, args.contract)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract, args.contract) ) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract2, args.contract2) ) + print ("sleep 5") + + +parser = argparse.ArgumentParser() + +commands = [ + ('k', 'kill', stepKillAll, True, ""), + ('w', 'wallet', stepStartWallet, True, "Start keosd, create wallet"), + ('s', 'sys', createAccounts, True, "Create all accounts"), + ('i', 'init', stepInitCaee, True, "stepInitCaee"), + ('c', 'clear', stepClear, True, "stepInitCaee"), + ('g', 'generate', stepGenerate, True, "stepInitCaee"), +] + +parser.add_argument('--public-key', metavar='', help="EOSIO Public Key", default='EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV', dest="public_key") +parser.add_argument('--private-Key', metavar='', help="EOSIO Private Key", default='5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3', dest="private_key") +parser.add_argument('--cleos', metavar='', help="Cleos command", default='../../build/programs/cleos/cleos --wallet-url http://127.0.0.1:6666 ') +parser.add_argument('--nodeos', metavar='', help="Path to nodeos binary", default='../../build/programs/nodeos/nodeos ') +parser.add_argument('--keosd', metavar='', help="Path to keosd binary", default='../../build/programs/keosd/keosd ') +parser.add_argument('--contracts-dir', metavar='', help="Path to contracts directory", default='../../build/contracts/') +parser.add_argument('--nodes-dir', metavar='', help="Path to nodes diretodctory", default='./') +parser.add_argument('--genesis', metavar='', help="Path to genesis.json", default="./genesis.json") +parser.add_argument('--wallet-dir', metavar='', help="Path to wallet directory", default='./wallet/') +parser.add_argument('--log-path', metavar='', help="Path to log file", default='./output.log') +# parser.add_argument('--symbol', metavar='', help="The eosio.system symbol", default='SYS') +parser.add_argument('-a', '--all', action='store_true', help="Do everything marked with (*)") +#parser.add_argument('-H', '--http-port', type=int, default=8888, metavar='', help='HTTP port for cleos') + +for (flag, command, function, inAll, help) in commands: + prefix = '' + if inAll: prefix += '*' + if prefix: help = '(' + prefix + ') ' + help + if flag: + parser.add_argument('-' + flag, '--' + command, action='store_true', help=help, dest=command) + else: + parser.add_argument('--' + command, action='store_true', help=help, dest=command) + +args = parser.parse_args() + +args.cleos += '--url http://127.0.0.1:8888 ' +args.symbol = 'SYS' +args.contract = 'caee' +args.contract2 = 'caee2' + + +accnum = 26 +accounts = [] +# for i in range(97,97+accnum): +# accounts.append("user%c"% chr(i)) +# accounts.append("payman") +accounts.append(args.contract) +accounts.append(args.contract2) + +logFile = open(args.log_path, 'a') +logFile.write('\n\n' + '*' * 80 + '\n\n\n') + +haveCommand = False +for (flag, command, function, inAll, help) in commands: + if getattr(args, command) or inAll and args.all: + if function: + haveCommand = True + function() +if not haveCommand: + print('testtool.py: Tell me what to do. -a does almost everything. -h shows options.') \ No newline at end of file diff --git a/unittests/database_gmr_blklst_tests.cpp b/unittests/database_gmr_blklst_tests.cpp new file mode 100644 index 00000000000..f448ba5a172 --- /dev/null +++ b/unittests/database_gmr_blklst_tests.cpp @@ -0,0 +1,309 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NON_VALIDATING_TEST +#define TESTER tester +#else +#define TESTER validating_tester +#endif + +using namespace eosio::chain; +using namespace eosio::testing; +namespace bfs = boost::filesystem; + +BOOST_AUTO_TEST_SUITE(database_gmr_blklst_tests) + +vector parse_list_string(string items) +{ + vector item_list; + vector itemlist; + boost::split(itemlist, items, boost::is_any_of(",")); + for (string item : itemlist) + { + item_list.push_back(string_to_name(item.c_str())); + } + + return item_list; +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(list_config_parse_test) +{ + try + { + TESTER test; + + string str = "alice,bob,tom"; + vector list = parse_list_string(str); + BOOST_TEST(list.size() > 0); + account_name n = N(a); + if (list.size() > 0) + { + n = *(list.begin()); + } + + BOOST_TEST(n != N(a)); + BOOST_TEST(n == N(alice)); + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(set_name_list_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + string str = "alice,bob,tom"; + vector list = parse_list_string(str); + + flat_set nameset(list.begin(), list.end()); + + test.control->set_actor_blacklist(nameset); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.actor_blacklist = {N(a)}; + a.cfg.contract_blacklist = {N(a)}; + a.cfg.resource_greylist = {N(a)}; + }); + + int64_t lt = static_cast(list_type::actor_blacklist_type); + int64_t lat = static_cast(list_action_type::insert_type); + test.control->set_name_list(lt, lat, list); + + + + + const flat_set& ab = test.control->get_actor_blacklist(); + const flat_set& cb = test.control->get_contract_blacklist(); + const flat_set& rg = test.control->get_resource_greylist(); + + + + + auto convert_names = [&](const shared_vector& namevec, flat_set& nameset) -> void { + for(const auto& a :namevec) + { + nameset.insert(uint64_t(a)); + } + }; + + flat_set aab; + flat_set acb; + flat_set arg; + + const global_property2_object &ptr1 = db.get(); + chain_config2 c = ptr1.cfg; + + BOOST_TEST(c.actor_blacklist.size() == 4); + BOOST_TEST(ab.size() == 4); + + convert_names(c.actor_blacklist, aab); + convert_names(c.contract_blacklist, acb); + convert_names(c.resource_greylist, arg); + + + if (c.actor_blacklist.size() == 4) + { + + bool b = (aab.find(N(a)) != aab.end()); + BOOST_TEST(b); + } + + bool d = ab.find(N(a)) != ab.end(); + BOOST_TEST(d); + bool m = aab.find(N(alice)) != aab.end(); + BOOST_TEST(m); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(actor_blacklist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.actor_blacklist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v; + if (a.actor_blacklist.size() > 0) + { + v = *(a.actor_blacklist.begin()); + } + + std::size_t s = a.actor_blacklist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(contract_blacklist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.contract_blacklist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v ; + if (a.contract_blacklist.size() > 0) + { + v = *(a.contract_blacklist.begin()); + } + + std::size_t s = a.contract_blacklist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(resource_greylist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.resource_greylist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v ; + if (a.resource_greylist.size() > 0) + { + v = *(a.resource_greylist.begin()); + } + + std::size_t s = a.resource_greylist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(gmrource_limit_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.gmr.cpu_us = 100; + a.gmr.net_byte = 1024; + a.gmr.ram_byte = 1; + }); + + BOOST_TEST(ptr.gmr.cpu_us == 100); + BOOST_TEST(ptr.gmr.net_byte == 1024); + BOOST_TEST(ptr.gmr.ram_byte == 1); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/database_tests.cpp b/unittests/database_tests.cpp index ac97f6c21a6..8f9d3553928 100644 --- a/unittests/database_tests.cpp +++ b/unittests/database_tests.cpp @@ -28,7 +28,8 @@ BOOST_AUTO_TEST_SUITE(database_tests) TESTER test; // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. - eosio::chain::database& db = const_cast( test.control->db() ); + // eosio::chain::database& db = const_cast( test.control->db() ); + chainbase::database &db = const_cast(test.control->db()); auto ses = db.start_undo_session(true); diff --git a/unittests/gmr_test.cpp b/unittests/gmr_test.cpp new file mode 100644 index 00000000000..3874552d0e5 --- /dev/null +++ b/unittests/gmr_test.cpp @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include +#include + +#include +#ifdef NON_VALIDATING_TEST +#define TESTER tester +#else +#define TESTER validating_tester +#endif + +using namespace eosio::chain::resource_limits; +using namespace eosio::testing; +using namespace eosio::chain; + +class gmr_fixture : private chainbase_fixture<512 * 1024>, public resource_limits_manager +{ + public: + gmr_fixture() + : chainbase_fixture(), resource_limits_manager(*chainbase_fixture::_db) + { + add_indices(); + initialize_database(); + } + + ~gmr_fixture() {} + + chainbase::database::session start_session() + { + return chainbase_fixture::_db->start_undo_session(true); + } +}; + +BOOST_AUTO_TEST_SUITE(gmr_test) + +BOOST_FIXTURE_TEST_CASE(check_block_limits_cpu, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 10000; + initialize_account(account); + set_account_limits(account, 1000, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 0, 10000); + set_account_limits(N(everyone), 0, 0, 10000000000000ll); + + + process_account_limit_updates(); + + // uint16_t gmrource_limit_per_day = 100; + + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + + // test.control->startup(); + + // // Make sure we can no longer find + + const uint64_t expected_iterations = config::default_gmr_cpu_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, increment, 0, 0); + process_block_usage(idx); + } + + auto arl = get_account_cpu_limit_ex(account, true); + + BOOST_TEST(arl.available >= 9997); + BOOST_REQUIRE_THROW(add_transaction_usage({account}, increment, 0, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_cpu_lowerthan, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 10000; + initialize_account(account); + set_account_limits(account, increment, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 0, 10000); + set_account_limits(N(everyone), 0, 0, 10000000000000ll); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_cpu_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, increment, 0, 0); + process_block_usage(idx); + } + + auto arl = get_account_cpu_limit_ex(account, true); + BOOST_TEST(arl.available >= 9997); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, increment, 0, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_net_lowerthan, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available >= 1238); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_ram, gmr_fixture) +try +{ + set_gmr_parameters( + { 1024, 200000,10240} + ); + + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment, 10, 10); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + //for ( + int idx = 0;// idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available >= 0); + + int64_t ram_bytes; + int64_t net_weight; + int64_t cpu_weight; + bool raw = false; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024*2 == ram_bytes); + BOOST_TEST(10 == net_weight); + BOOST_TEST(10 == cpu_weight); + + + raw = true; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(10 == net_weight); + BOOST_TEST(10 == cpu_weight); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + + + +BOOST_FIXTURE_TEST_CASE(get_account_limits_res, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment+24, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available > 0); + + int64_t ram_bytes; + int64_t net_weight; + int64_t cpu_weight; + bool raw = false; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(0 == net_weight); + BOOST_TEST(0 == cpu_weight); + + + raw = true; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(0 == net_weight); + BOOST_TEST(0 == cpu_weight); + + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + + +BOOST_AUTO_TEST_SUITE_END() From 8f36168c755fa760a51efc5f7e9ca760dd32bceb Mon Sep 17 00:00:00 2001 From: thaipanda <45444502+Thaipanda@users.noreply.github.com> Date: Mon, 17 Dec 2018 11:29:41 +0800 Subject: [PATCH 2/5] release v1.0.3 to master (#15) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * finish BOS basic functions * add README files * update info * Release/1.0.x (#11) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * readme for kafka & add time for action (#5) * 重启 节点,黑名单 失效,fixes #7 (#8) * restart sync list db * recovery system account bos to eosio * recovery system account bos to eosio * recovery system account bos to eosio * Fix/#3 notify plugin (#10) * Add debug info * comment log * rm log for notify_plugin * prepare for v1.0.2 * merge v1.0.2 (#13) * boscore basic improvement (#2) * kafka_plugin code * Automatic installation librdkafka/cppkafka * Feature/ci * Feature/48 kafka plugin * add CMakeModules/FindCppkafka.cmake * Production of block in time zone sequence * P2p self discovery * P2p self discovery * add notify_plugin * add api "get_block_detail" * add free res limit and blklst code * update free res limit and blklst code * update res code * update unittest code * revert submodule version * code typo * update blklist code * update sync name list db object error code * update code * update index code * Feature/5 ramdom * Revert "Merge branch 'feature/5-ramdom' into 'develop'" This reverts merge request !8 * adjust for setup BOSCore * change description * adjust the kafka plugin dependency be more special * use boscore repository to improve security * change version tag * finish for docker/builder * pass to build docker and update readme * add actionseed, global action sequence (#5) * delete renamed old file * BOSCore v1.0.1-1.4.3 * restructure the version schema * fix __gmpn_set_str error when build bos.contract * prepare for the v1.0.1 * add README files * update info * prepare for v1.0.2 * patch the EOSIO 1.5.1 security bug fixes * prepare for v1.0.3 * adjust the slogon --- CMakeLists.txt | 2 +- Docker/README.md | 4 +- README.md | 4 +- README_CN.md | 2 +- libraries/chain/apply_context.cpp | 108 ++++++++++++++---- libraries/chain/authorization_manager.cpp | 11 +- .../eosio/chain/authorization_manager.hpp | 3 +- 7 files changed, 100 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1451955870c..0309bb0b5e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( NODE_EXECUTABLE_NAME nodeos ) diff --git a/Docker/README.md b/Docker/README.md index 9ff75404b7d..ffdfe07e2c5 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -20,10 +20,10 @@ cd bos/Docker docker build . -t boscore/bos ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.2 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.3 tag, you could do the following: ```bash -docker build -t boscore/bos:v1.0.2 --build-arg branch=v1.0.2 . +docker build -t boscore/bos:v1.0.3 --build-arg branch=v1.0.3 . ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. diff --git a/README.md b/README.md index 43fcdfa2d61..eecfaf7ec1c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# BOSCore - Born for DApp, be more useable. +# BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v1.0.2 +## BOSCore Version: v1.0.3 ### Basic EOSIO Version: v1.4.4 # Background diff --git a/README_CN.md b/README_CN.md index d4701484fb9..a1f55247bcf 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,6 +1,6 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v1.0.2 +## BOSCore Version: v1.0.3 ### Basic EOSIO Version: v1.4.4 # 背景 diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 07ab384eeff..4e9807ed85c 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -209,6 +209,15 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( code != nullptr, action_validate_exception, "inline action's code account ${account} does not exist", ("account", a.account) ); + bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated + bool send_to_self = (a.account == receiver); + bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); + + flat_set inherited_authorizations; + if( inherit_parent_authorizations ) { + inherited_authorizations.reserve( a.authorization.size() ); + } + for( const auto& auth : a.authorization ) { auto* actor = control.db().find(auth.actor); EOS_ASSERT( actor != nullptr, action_validate_exception, @@ -216,22 +225,45 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( control.get_authorization_manager().find_permission(auth) != nullptr, action_validate_exception, "inline action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); + + if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { + inherited_authorizations.insert( auth ); + } } - // No need to check authorization if: replaying irreversible blocks; contract is privileged; or, contract is calling itself. - if( !control.skip_auth_check() && !privileged && a.account != receiver ) { - control.get_authorization_manager() - .check_authorization( {a}, - {}, - {{receiver, config::eosio_code_name}}, - control.pending_block_time() - trx_context.published, - std::bind(&transaction_context::checktime, &this->trx_context), - false - ); - - //QUESTION: Is it smart to allow a deferred transaction that has been delayed for some time to get away - // with sending an inline action that requires a delay even though the decision to send that inline - // action was made at the moment the deferred transaction was executed with potentially no forewarning? + // No need to check authorization if replaying irreversible blocks or contract is privileged + if( !control.skip_auth_check() && !privileged ) { + try { + control.get_authorization_manager() + .check_authorization( {a}, + {}, + {{receiver, config::eosio_code_name}}, + control.pending_block_time() - trx_context.published, + std::bind(&transaction_context::checktime, &this->trx_context), + false, + inherited_authorizations + ); + + //QUESTION: Is it smart to allow a deferred transaction that has been delayed for some time to get away + // with sending an inline action that requires a delay even though the decision to send that inline + // action was made at the moment the deferred transaction was executed with potentially no forewarning? + } catch( const fc::exception& e ) { + if( disallow_send_to_self_bypass || !send_to_self ) { + throw; + } else if( control.is_producing_block() ) { + subjective_block_production_exception new_exception(FC_LOG_MESSAGE( error, "Authorization failure with inline action sent to self")); + for (const auto& log: e.get_log()) { + new_exception.append_log(log); + } + throw new_exception; + } + } catch( ... ) { + if( disallow_send_to_self_bypass || !send_to_self ) { + throw; + } else if( control.is_producing_block() ) { + EOS_THROW(subjective_block_production_exception, "Unexpected exception occurred validating inline action sent to self"); + } + } } _inline_actions.emplace_back( move(a) ); @@ -268,16 +300,30 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a require_authorization(payer); /// uses payer's storage } - // if a contract is deferring only actions to itself then there is no need - // to check permissions, it could have done everything anyway. - bool check_auth = false; - for( const auto& act : trx.actions ) { - if( act.account != receiver ) { - check_auth = true; - break; + // Originally this code bypassed authorization checks if a contract was deferring only actions to itself. + // The idea was that the code could already do whatever the deferred transaction could do, so there was no point in checking authorizations. + // But this is not true. The original implementation didn't validate the authorizations on the actions which allowed for privilege escalation. + // It would make it possible to bill RAM to some unrelated account. + // Furthermore, even if the authorizations were forced to be a subset of the current action's authorizations, it would still violate the expectations + // of the signers of the original transaction, because the deferred transaction would allow billing more CPU and network bandwidth than the maximum limit + // specified on the original transaction. + // So, the deferred transaction must always go through the authorization checking if it is not sent by a privileged contract. + // However, the old logic must still be considered because it cannot objectively change until a consensus protocol upgrade. + + bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated + + auto is_sending_only_to_self = [&trx]( const account_name& self ) { + bool send_to_self = true; + for( const auto& act : trx.actions ) { + if( act.account != self ) { + send_to_self = false; + break; + } } - } - if( check_auth ) { + return send_to_self; + }; + + try { control.get_authorization_manager() .check_authorization( trx.actions, {}, @@ -286,6 +332,22 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a std::bind(&transaction_context::checktime, &this->trx_context), false ); + } catch( const fc::exception& e ) { + if( disallow_send_to_self_bypass || !is_sending_only_to_self(receiver) ) { + throw; + } else if( control.is_producing_block() ) { + subjective_block_production_exception new_exception(FC_LOG_MESSAGE( error, "Authorization failure with sent deferred transaction consisting only of actions to self")); + for (const auto& log: e.get_log()) { + new_exception.append_log(log); + } + throw new_exception; + } + } catch( ... ) { + if( disallow_send_to_self_bypass || !is_sending_only_to_self(receiver) ) { + throw; + } else if( control.is_producing_block() ) { + EOS_THROW(subjective_block_production_exception, "Unexpected exception occurred validating sent deferred transaction consisting only of actions to self"); + } } } diff --git a/libraries/chain/authorization_manager.cpp b/libraries/chain/authorization_manager.cpp index 832f69c71cd..6725468cf97 100644 --- a/libraries/chain/authorization_manager.cpp +++ b/libraries/chain/authorization_manager.cpp @@ -431,7 +431,8 @@ namespace eosio { namespace chain { const flat_set& provided_permissions, fc::microseconds provided_delay, const std::function& _checktime, - bool allow_unused_keys + bool allow_unused_keys, + const flat_set& satisfied_authorizations )const { const auto& checktime = ( static_cast(_checktime) ? _checktime : _noop_checktime ); @@ -488,9 +489,11 @@ namespace eosio { namespace chain { } } - auto res = permissions_to_satisfy.emplace( declared_auth, delay ); - if( !res.second && res.first->second > delay) { // if the declared_auth was already in the map and with a higher delay - res.first->second = delay; + if( satisfied_authorizations.find( declared_auth ) == satisfied_authorizations.end() ) { + auto res = permissions_to_satisfy.emplace( declared_auth, delay ); + if( !res.second && res.first->second > delay) { // if the declared_auth was already in the map and with a higher delay + res.first->second = delay; + } } } } diff --git a/libraries/chain/include/eosio/chain/authorization_manager.hpp b/libraries/chain/include/eosio/chain/authorization_manager.hpp index 9a75b5f80b1..a6df7ad2568 100644 --- a/libraries/chain/include/eosio/chain/authorization_manager.hpp +++ b/libraries/chain/include/eosio/chain/authorization_manager.hpp @@ -84,7 +84,8 @@ namespace eosio { namespace chain { const flat_set& provided_permissions = flat_set(), fc::microseconds provided_delay = fc::microseconds(0), const std::function& checktime = std::function(), - bool allow_unused_keys = false + bool allow_unused_keys = false, + const flat_set& satisfied_authorizations = flat_set() )const; From 62d701e36a767c9500045c677f33fc964d9ee2a3 Mon Sep 17 00:00:00 2001 From: thaipanda <45444502+Thaipanda@users.noreply.github.com> Date: Tue, 15 Jan 2019 15:16:34 +0800 Subject: [PATCH 3/5] merge v2.0.1 version (#36) --- .buildkite/pipeline.yml | 6 +- .github/PULL_REQUEST_TEMPLATE.md | 8 +- CMakeLists.txt | 10 +- CMakeModules/EosioTester.cmake.in | 4 +- CMakeModules/EosioTesterBuild.cmake.in | 6 +- CMakeModules/doxygen.cmake | 2 +- Docker/Dockerfile | 3 +- Docker/README.md | 7 +- README.md | 12 +- README_CN.md | 11 +- contracts/CMakeLists.txt | 4 - contracts/bancor/CMakeLists.txt | 8 - contracts/bancor/bancor.cpp | 18 - contracts/bancor/bancor.hpp | 22 - contracts/bancor/converter.hpp | 166 - contracts/bancor/eosio.system.abi | 37 - contracts/eosio.system/delegate_bandwidth.cpp | 2 +- contracts/eosiolib/currency.hpp | 254 - contracts/eosiolib/transaction.h | 14 + contracts/infinite/CMakeLists.txt | 5 - contracts/infinite/infinite.cpp | 16 - contracts/simple.token/CMakeLists.txt | 9 - contracts/simple.token/simple.token.abi | 2 - contracts/simple.token/simple.token.cpp | 49 - contracts/social/CMakeLists.txt | 5 - contracts/social/social.cpp | 107 - contracts/tic_tac_toe/tic_tac_toe.cpp | 2 +- eosio.version.in | 2 +- libraries/CMakeLists.txt | 2 - libraries/abi_generator/CMakeLists.txt | 64 - libraries/abi_generator/abi_generator.cpp | 688 - .../eosio/abi_generator/abi_generator.hpp | 442 - libraries/appbase | 2 +- libraries/chain/CMakeLists.txt | 2 +- libraries/chain/apply_context.cpp | 18 +- libraries/chain/block_header_state.cpp | 14 +- libraries/chain/block_state.cpp | 6 +- libraries/chain/controller.cpp | 364 +- libraries/chain/eosio_contract.cpp | 4 +- libraries/chain/fork_database.cpp | 17 +- .../include/eosio/chain/apply_context.hpp | 6 - .../include/eosio/chain/authority_checker.hpp | 7 +- .../eosio/chain/block_header_state.hpp | 2 + .../chain/include/eosio/chain/block_state.hpp | 4 +- .../include/eosio/chain/chain_config.hpp | 46 +- .../chain/include/eosio/chain/config.hpp | 1 + .../eosio/chain/contract_table_objects.hpp | 70 +- .../chain/include/eosio/chain/controller.hpp | 16 +- .../include/eosio/chain/database_utils.hpp | 1 - .../chain/include/eosio/chain/exceptions.hpp | 4 +- .../include/eosio/chain/fork_database.hpp | 6 +- .../include/eosio/chain/genesis_state.hpp | 8 + .../include/eosio/chain}/parallel_markers.hpp | 4 +- .../eosio/chain/transaction_context.hpp | 4 +- .../eosio/chain/transaction_metadata.hpp | 17 +- libraries/chain/transaction.cpp | 2 +- libraries/chain/transaction_context.cpp | 42 +- libraries/chain/wasm_interface.cpp | 80 +- libraries/fc | 2 +- libraries/softfloat | 2 +- libraries/testing/CMakeLists.txt | 2 +- .../testing/include/eosio/testing/tester.hpp | 27 +- libraries/testing/tester.cpp | 55 +- libraries/utilities/CMakeLists.txt | 32 - libraries/utilities/git_revision.cpp.in | 14 - .../include/eosio/utilities/common.hpp | 22 - .../include/eosio/utilities/git_revision.hpp | 14 - .../eosio/utilities/key_conversion.hpp | 17 - .../eosio/utilities/padding_ostream.hpp | 39 - .../include/eosio/utilities/rand.hpp | 44 - .../include/eosio/utilities/string_escape.hpp | 13 - .../include/eosio/utilities/tempdir.hpp | 15 - .../include/eosio/utilities/words.hpp | 13 - libraries/utilities/key_conversion.cpp | 53 - libraries/utilities/string_escape.cpp | 55 - libraries/utilities/tempdir.cpp | 20 - libraries/utilities/words.cpp | 49764 ---------------- libraries/wabt | 2 +- plugins/CMakeLists.txt | 1 + plugins/bnet_plugin/bnet_plugin.cpp | 51 +- plugins/chain_plugin/chain_plugin.cpp | 176 +- .../eosio/chain_plugin/chain_plugin.hpp | 182 +- .../faucet_testnet_plugin.cpp | 1 - plugins/net_plugin/net_plugin.cpp | 11 +- plugins/producer_plugin/CMakeLists.txt | 2 +- .../eosio/producer_plugin/producer_plugin.hpp | 1 + plugins/producer_plugin/producer_plugin.cpp | 79 +- plugins/state_history_plugin/.clang-format | 8 + plugins/state_history_plugin/CMakeLists.txt | 8 + .../state_history_log.hpp | 279 + .../state_history_plugin.hpp | 101 + .../state_history_serialization.hpp | 557 + .../state_history_plugin.cpp | 571 + .../state_history_plugin_abi.cpp | 475 + plugins/test_control_plugin/CMakeLists.txt | 2 +- .../txn_test_gen_plugin.cpp | 1 - plugins/wallet_plugin/se_wallet.cpp | 8 + programs/CMakeLists.txt | 1 - programs/cleos/eosc.pot | 8 +- programs/cleos/main.cpp | 600 +- programs/eosio-abigen/CMakeLists.txt | 28 - programs/eosio-abigen/main.cpp | 106 - programs/nodeos/CMakeLists.txt | 1 + programs/nodeos/main.cpp | 3 - scripts/abi_to_rc/README.md | 14 - scripts/abi_to_rc/abi_to_rc.py | 135 - scripts/abi_to_rc/rc-action-template.md | 14 - scripts/abi_to_rc/rc-overview-template.md | 14 - scripts/abigen.sh | 22 - scripts/eosio_build_amazon.sh | 2 +- scripts/eosio_build_centos.sh | 4 +- scripts/eosio_build_fedora.sh | 2 +- scripts/generate_deb.sh | 11 +- scripts/generate_package.sh.in | 7 +- scripts/generate_rpm.sh | 15 +- scripts/ricardeos/README.md | 20 - scripts/ricardeos/ricardeos.py | 164 - tests/CMakeLists.txt | 5 +- tests/Cluster.py | 3 + tests/Node.py | 87 +- tests/chain_plugin_tests.cpp | 9 - tests/chain_tests/proof_tests.cpp | 340 - tests/distributed-transactions-remote-test.py | 2 +- tests/get_table_tests.cpp | 345 +- tests/launcher_test.py | 3 +- tests/nodeos_forked_chain_test.py | 5 + tests/nodeos_run_remote_test.py | 2 +- tests/nodeos_run_test.py | 2 +- tests/p2p_tests/fuzz_test_generic.sh | 11 - tests/p2p_tests/pump/run_test.pl | 285 - tests/validate-dirty-db.py | 17 +- tests/wallet_tests.cpp | 3 - tools/CMakeLists.txt | 14 - tools/eosiocpp.in | 204 - tools/print_floats.cpp | 102 - tutorials/bios-boot-tutorial/.gitignore | 1 + .../bios-boot-tutorial/bios-boot-tutorial.py | 10 +- unittests/CMakeLists.txt | 4 +- unittests/abi_tests.cpp | 1293 - unittests/actiondemo/actiondemo.abi | 22 +- unittests/actiondemo/actiondemo.cpp | 19 +- unittests/actiondemo/actiondemo.hpp | 6 + unittests/actiondemo/test.py | 14 +- unittests/api_tests.cpp | 115 +- unittests/block_tests.cpp | 3 +- unittests/bootseq_tests.cpp | 2 - .../contracts/deferred_test/deferred_test.abi | 24 +- .../contracts/deferred_test/deferred_test.cpp | 8 + unittests/database_gmr_blklst_tests.cpp | 31 +- unittests/delay_tests.cpp | 2 - unittests/eosio.sudo_tests.cpp | 367 - unittests/eosio.system_tests.cpp | 2585 - unittests/eosio.token_tests.cpp | 268 - unittests/forked_tests.cpp | 95 +- unittests/misc_tests.cpp | 37 - unittests/multisig_tests.cpp | 626 - unittests/ram_tests.cpp | 3 - unittests/snapshot_tests.cpp | 4 + unittests/special_accounts_tests.cpp | 2 - unittests/tic_tac_toe_tests.cpp | 5 - unittests/wasm_tests.cpp | 73 - unittests/whitelist_blacklist_tests.cpp | 299 + 162 files changed, 4353 insertions(+), 59628 deletions(-) delete mode 100644 contracts/bancor/CMakeLists.txt delete mode 100644 contracts/bancor/bancor.cpp delete mode 100644 contracts/bancor/bancor.hpp delete mode 100644 contracts/bancor/converter.hpp delete mode 100644 contracts/bancor/eosio.system.abi delete mode 100644 contracts/eosiolib/currency.hpp delete mode 100644 contracts/infinite/CMakeLists.txt delete mode 100644 contracts/infinite/infinite.cpp delete mode 100644 contracts/simple.token/CMakeLists.txt delete mode 100644 contracts/simple.token/simple.token.abi delete mode 100644 contracts/simple.token/simple.token.cpp delete mode 100644 contracts/social/CMakeLists.txt delete mode 100644 contracts/social/social.cpp delete mode 100644 libraries/abi_generator/CMakeLists.txt delete mode 100644 libraries/abi_generator/abi_generator.cpp delete mode 100644 libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp rename libraries/{utilities/include/eosio/utilities => chain/include/eosio/chain}/parallel_markers.hpp (95%) delete mode 100644 libraries/utilities/CMakeLists.txt delete mode 100644 libraries/utilities/git_revision.cpp.in delete mode 100644 libraries/utilities/include/eosio/utilities/common.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/git_revision.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/key_conversion.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/padding_ostream.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/rand.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/string_escape.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/tempdir.hpp delete mode 100644 libraries/utilities/include/eosio/utilities/words.hpp delete mode 100644 libraries/utilities/key_conversion.cpp delete mode 100644 libraries/utilities/string_escape.cpp delete mode 100644 libraries/utilities/tempdir.cpp delete mode 100644 libraries/utilities/words.cpp create mode 100644 plugins/state_history_plugin/.clang-format create mode 100644 plugins/state_history_plugin/CMakeLists.txt create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp create mode 100644 plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp create mode 100644 plugins/state_history_plugin/state_history_plugin.cpp create mode 100644 plugins/state_history_plugin/state_history_plugin_abi.cpp delete mode 100644 programs/eosio-abigen/CMakeLists.txt delete mode 100644 programs/eosio-abigen/main.cpp delete mode 100644 scripts/abi_to_rc/README.md delete mode 100644 scripts/abi_to_rc/abi_to_rc.py delete mode 100644 scripts/abi_to_rc/rc-action-template.md delete mode 100644 scripts/abi_to_rc/rc-overview-template.md delete mode 100755 scripts/abigen.sh delete mode 100644 scripts/ricardeos/README.md delete mode 100755 scripts/ricardeos/ricardeos.py delete mode 100644 tests/chain_tests/proof_tests.cpp delete mode 100644 tests/p2p_tests/fuzz_test_generic.sh delete mode 100755 tests/p2p_tests/pump/run_test.pl delete mode 100755 tools/eosiocpp.in delete mode 100644 tools/print_floats.cpp delete mode 100644 unittests/eosio.sudo_tests.cpp delete mode 100644 unittests/eosio.system_tests.cpp delete mode 100644 unittests/eosio.token_tests.cpp delete mode 100644 unittests/multisig_tests.cpp diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 1cd49460163..3c7f63def07 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -442,7 +442,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh deb label: ":ubuntu: 18.04 Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/*.deb" plugins: @@ -469,7 +469,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh rpm label: ":fedora: Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/x86_64/*.rpm" plugins: @@ -496,7 +496,7 @@ steps: cd /data/job/build/packages && bash generate_package.sh rpm label: ":centos: Package builder" agents: - - "role=linux-builder" + queue: "automation-large-builder-fleet" artifact_paths: - "build/packages/x86_64/*.rpm" plugins: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9ffbb5ffb6b..7e186303e51 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,20 +1,20 @@ -**Change Description** +## Change Description -**Consensus Changes** +## Consensus Changes -**API Changes** +## API Changes -**Documentation Additions** +## Documentation Additions diff --git a/CMakeLists.txt b/CMakeLists.txt index 0309bb0b5e4..2303eee93b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,9 +33,15 @@ set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_EXTENSIONS ON ) set( CXX_STANDARD_REQUIRED ON) -set(VERSION_MAJOR 1) +set(VERSION_MAJOR 2) set(VERSION_MINOR 0) -set(VERSION_PATCH 3) +set(VERSION_PATCH 1) + +if(VERSION_SUFFIX) + set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") +else() + set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") +endif() set( CLI_CLIENT_EXECUTABLE_NAME cleos ) set( NODE_EXECUTABLE_NAME nodeos ) diff --git a/CMakeModules/EosioTester.cmake.in b/CMakeModules/EosioTester.cmake.in index ac2bc0221fa..d767251cf54 100644 --- a/CMakeModules/EosioTester.cmake.in +++ b/CMakeModules/EosioTester.cmake.in @@ -1,10 +1,10 @@ cmake_minimum_required( VERSION 3.5 ) -message(STATUS "Setting up Eosio Tester @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ at @EOS_ROOT_DIR@") +message(STATUS "Setting up Eosio Tester @VERSION_FULL@ at @EOS_ROOT_DIR@") set(CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@) set(CMAKE_C_COMPILER @CMAKE_C_COMPILER@) -set(EOSIO_VERSION "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@") +set(EOSIO_VERSION "@VERSION_FULL@") enable_testing() diff --git a/CMakeModules/EosioTesterBuild.cmake.in b/CMakeModules/EosioTesterBuild.cmake.in index 04ac7da6fe5..290cefa576c 100644 --- a/CMakeModules/EosioTesterBuild.cmake.in +++ b/CMakeModules/EosioTesterBuild.cmake.in @@ -1,10 +1,10 @@ cmake_minimum_required( VERSION 3.5 ) -message(STATUS "Setting up Eosio Tester @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ at @EOS_ROOT_DIR@") +message(STATUS "Setting up Eosio Tester @VERSION_FULL@ at @EOS_ROOT_DIR@") set(CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@) set(CMAKE_C_COMPILER @CMAKE_C_COMPILER@) -set(EOSIO_VERSION "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@") +set(EOSIO_VERSION "@VERSION_FULL@") enable_testing() @@ -98,8 +98,8 @@ macro(add_eosio_test test_name) ${liblogging} ${libchainbase} ${libbuiltins} - ${GMP_LIBRARIES} ${libsecp256k1} + ${GMP_LIBRARIES} LLVMX86Disassembler LLVMX86AsmParser diff --git a/CMakeModules/doxygen.cmake b/CMakeModules/doxygen.cmake index 2857f668364..d3014b4efce 100644 --- a/CMakeModules/doxygen.cmake +++ b/CMakeModules/doxygen.cmake @@ -5,7 +5,7 @@ include(FindDoxygen) if(NOT DOXYGEN_FOUND) message(STATUS "Doxygen not found. Contract documentation will not be generated.") else() - set(DOXY_EOS_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" CACHE INTERNAL "Version string used in PROJECT_NUMBER.") + set(DOXY_EOS_VERSION "${VERSION_FULL}" CACHE INTERNAL "Version string used in PROJECT_NUMBER.") # CMake strips trailing path separators off of variables it knows are paths, # so the trailing '/' Doxygen expects is embedded in the doxyfile. set(DOXY_DOC_DEST_DIR "${CMAKE_BINARY_DIR}/docs" CACHE PATH "Path to the doxygen output") diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 67f7714c894..81b09c4171a 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -10,7 +10,8 @@ RUN git clone -b $branch https://github.com/boscore/bos.git --recursive \ && cmake -H. -B"/tmp/build" -GNinja -DCMAKE_BUILD_TYPE=Release -DWASM_ROOT=/opt/wasm -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_COMPILER=clang -DCMAKE_INSTALL_PREFIX=/tmp/build -DBUILD_MONGO_DB_PLUGIN=true -DCORE_SYMBOL_NAME=$symbol \ -DOPENSSL_ROOT_DIR="${OPENSSL_ROOT_DIR}" \ - && cmake --build /tmp/build --target install && rm /tmp/build/bin/eosiocpp + && cmake --build /tmp/build --target install + FROM ubuntu:18.04 diff --git a/Docker/README.md b/Docker/README.md index ffdfe07e2c5..582b8936e0d 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -17,13 +17,14 @@ Simple and fast setup of BOSCore on Docker is also available. ```bash git clone https://github.com/boscore/bos.git --recursive --depth 1 cd bos/Docker -docker build . -t boscore/bos +docker build . -t boscore/bos -s BOS ``` -The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v1.0.3 tag, you could do the following: +The above will build off the most recent commit to the master branch by default. If you would like to target a specific branch/tag, you may use a build argument. For example, if you wished to generate a docker image based off of the v2.0.1 tag, you could do the following: ```bash -docker build -t boscore/bos:v1.0.3 --build-arg branch=v1.0.3 . +docker build -t boscore/bos:v2.0.1 --build-arg branch=v2.0.1 . + ``` By default, the symbol in eosio.system is set to SYS. You can override this using the symbol argument while building the docker image. diff --git a/README.md b/README.md index eecfaf7ec1c..a237aa1cf77 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # BOSCore - Born for DApps. Born for Usability. -## BOSCore Version: v1.0.3 -### Basic EOSIO Version: v1.4.4 +## BOSCore Version: v2.0.1 +### Basic EOSIO Version: v1.5.3-patched # Background The emergence of EOS has brought new imagination to the blockchain. In just a few months since the main network was launched, the version has undergone dozens of upgrades, not only the stability has been greatly improved, but also the new functions have been gradually realized. The node team is also actively involved in building the EOSIO ecosystem. What is even more exciting is that EOS has attracted more and more development teams. There are already hundreds of DApp running on the EOS main network. The transaction volume and circulation market value far exceed Ethereum, and the space for development is growing broader. @@ -20,14 +20,16 @@ As BOS continues to develop, developer rewards will be appropriately adjusted to ## Links 1. [Website](https://boscore.io) -2. [Developer Telegram Group](https://t.me/BOSCoreDev) -3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +2. [Developer Telegram Group](https://t.me/BOSDevelopers) +3. [Community Telegram Group](https://t.me/boscorecommunity) +4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) ## Start 1. Build from code : `bash ./eosio_build.sh -s BOS` 2. Docker Style,check [Docker](./Docker/README.md) + BOSCore bases on EOSIO, so you can also referer: [Getting Started](https://developers.eos.io/eosio-nodeos/docs/overview-1) diff --git a/README_CN.md b/README_CN.md index a1f55247bcf..e8e8d3a9d41 100644 --- a/README_CN.md +++ b/README_CN.md @@ -1,7 +1,7 @@ # BOSCore - 更可用的链,为DApp而生。 -## BOSCore Version: v1.0.3 -### Basic EOSIO Version: v1.4.4 +## BOSCore Version: v2.0.1 +### Basic EOSIO Version: v1.5.3-patched # 背景 EOS的出现给区块链带来了新的想象力,主网启动短短几个月以来,版本经历了几十次升级,不仅稳定性得到了很大提高,并且新功能也逐步实现,各个节点团队也积极参与建设EOSIO生态。让人更加兴奋的是,EOS已经吸引了越来越多的开发团队,当前已经有数百个DApp在EOS主网上面运行,其交易量和流通市值远超以太坊,可发展的空间愈来愈广阔。 @@ -20,9 +20,10 @@ BOS链的代码完全由社区贡献并维护,每个生态参与者都可以 ## 资源 1. [官网](https://boscore.io) -2. [开发者社群](https://t.me/BOSCoreDev) -3. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) -4. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) +2. [Developer Telegram Group](https://t.me/BOSDevelopers) +3. [Community Telegram Group](https://t.me/boscorecommunity) +4. [WhitePaper](https://github.com/boscore/Documentation/blob/master/BOSCoreTechnicalWhitePaper.md) +5. [白皮书](https://github.com/boscore/Documentation/blob/master/zh-CN/BOSCoreTechnicalWhitePaper.md) ## 开始 1. 源码直接编译: `bash ./eosio_build.sh -s BOS` diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index bd84d155e85..443330c886a 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -7,7 +7,6 @@ set(STANDARD_INCLUDE_FOLDERS ${CMAKE_SOURCE_DIR}/contracts ${CMAKE_BINARY_DIR}/c add_subdirectory(eosiolib) add_subdirectory(musl) add_subdirectory(libc++) -add_subdirectory(simple.token) add_subdirectory(eosio.token) add_subdirectory(eosio.msig) add_subdirectory(eosio.sudo) @@ -18,17 +17,14 @@ add_subdirectory(identity) add_subdirectory(stltest) add_subdirectory(test.inline) -#add_subdirectory(bancor) add_subdirectory(hello) add_subdirectory(asserter) -add_subdirectory(infinite) add_subdirectory(proxy) add_subdirectory(test_api) add_subdirectory(test_api_mem) add_subdirectory(test_api_db) add_subdirectory(test_api_multi_index) add_subdirectory(test_ram_limit) -#add_subdirectory(social) add_subdirectory(eosio.bios) add_subdirectory(noop) add_subdirectory(tic_tac_toe) diff --git a/contracts/bancor/CMakeLists.txt b/contracts/bancor/CMakeLists.txt deleted file mode 100644 index b845361e8f0..00000000000 --- a/contracts/bancor/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET bancor - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc libc++ eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/bancor/bancor.cpp b/contracts/bancor/bancor.cpp deleted file mode 100644 index 15bc9e802c8..00000000000 --- a/contracts/bancor/bancor.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include - -namespace bancor { - -extern "C" { - - /// The apply method implements the dispatch of events to this contract - void apply( uint64_t r, uint64_t c, uint64_t a ) { - bancor::example_converter::apply( c, a ); - } -} - -} diff --git a/contracts/bancor/bancor.hpp b/contracts/bancor/bancor.hpp deleted file mode 100644 index b6030908b81..00000000000 --- a/contracts/bancor/bancor.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include -#include - -#include -#include - -namespace bancor { - typedef eosio::generic_currency< eosio::token > other_currency; - typedef eosio::generic_currency< eosio::token > relay_currency; - typedef eosio::generic_currency< eosio::token > cur_currency; - - typedef converter example_converter; -} /// bancor - diff --git a/contracts/bancor/converter.hpp b/contracts/bancor/converter.hpp deleted file mode 100644 index 774fc910e32..00000000000 --- a/contracts/bancor/converter.hpp +++ /dev/null @@ -1,166 +0,0 @@ -#pragma once -namespace bancor { - template - class converter_contract { - public: - typedef ConverterCurrency converter_currency; - typedef FirstCurrency first_currency; - typedef SecondCurrency second_currency; - - - static const account_name converter_account = converter_currency::code; - - struct converter_state { - typename converter_currency::token_type supply; /// total supply held by all users - typename converter_currency::token_type balance; /// supply held by converter in its own balance - }; - - struct converter_args { - eosio::account_name to_currency_account; - eosio::symbol_name to_currency_symbol; - uint64_t min_return_currency; - }; - - - template - struct connector { - typedef CurrencyType currency_type; - typedef typename converter_currency::token_type converter_token_type; - typedef typename currency_type::token_type in_token_type; - - converter_token_type convert_to_converter( in_token_type in, converter_state& state ) { - in_token_type balance = currency_type::get_balance( converter_account ); - - /// balance already changed when transfer executed, get pre-transfer balance - in_token_type previous_balance = balance - in; - - auto init_price = (previous_balance * Base) / (Weight * state.supply); - auto init_out = init_price * in; - - auto out_price = (balance*Base) / (Weight * (state.supply+init_out) ); - auto final_out = out_price * in; - - state.balance += final_out; - state.supply += final_out; - - return final_out; - } - - - in_token_type convert_from_converter( converter_token_type converter_in, converter_state& state ) { - in_token_type to_balance = CurrencyType::get_balance( converter_account ); - - auto init_price = (to_balance * Base) / (Weight * state.supply); - in_token_type init_out = init_price * converter_in; - - state.supply -= converter_in; - state.balance -= converter_in; - - auto out_price = ((to_balance-init_out) * Base) / ( Weight * (state.supply) ); - - return out_price * converter_in; - } - - }; - - - - /** - * This is called when we receive RELAY tokens from user and wish to - * convert to one of the connector currencies. - */ - static void on_convert( const typename converter_currency::transfer& trans, - const converter_args& args, - converter_state& state ) { - - if( args.to_currency_type == first_currency ) { - auto output = first_connector::convert_from_converter( trans.quantity, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - else if( args.to_currency_type == second_currency ) { - auto output = second_connector::convert_from_converter( trans.quantity, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - else { - eosio_assert( false, "invalid to currency" ); - } - } - - - /** - * This is called when the converter receives one of the connector currencies and it - * will send either converter tokens or a different connector currency in response. - */ - template - static void on_convert( const typename ConnectorType::currency_type::transfer& trans, - const converter_args& args, - converter_state& state ) - { - /// convert to converter - auto converter_out = ConnectorType::convert_to_converter( trans.quantity, state ); - - if( args.to_currency_type == converter_currency ) - { - save_and_send( trans.from, state, converter_out, args.min_return ); - } - else - { - auto output = ConnectorType::convert_from_converter( converter_out, state ); - save_and_send( trans.from, state, output, args.min_return ); - } - } - - - /** - * This method factors out the boiler plate for parsing args and loading the - * initial state before dispatching to the proper on_convert case - */ - template - static void start_convert( const typename CurrencyType::transfer_memo& trans ) { - auto args = unpack( trans.memo ); - eosio_assert( args.to_currency_type != trans.quantity.token_type(), "cannot convert to self" ); - - auto state = read_converter_state(); - on_convert( trans, args, state ); - } - - - /** - * converter_account first needs to call the currency handler to perform - * user-to-user transfers of the converter token, then if a transfer is sending - * the token back to the converter contract, it should convert like everything else. - * - * This method should be called from apply( code, action ) for each of the - * transfer types that we support (for each currency) - */ - static void on( const typename converter_currency::transfer_memo& trans ) { - converter_currency::on( trans ); - if( trans.to == converter_account ) { - start_convert( trans ); - } - } - - /** - * All other currencies simply call start_convert if to == converter_account - */ - template - static void on( const typename Currency::transfer_memo& trans ) { - if( trans.to == converter_account ) { - start_convert( trans ); - } else { - eosio_assert( trans.from == converter_account, - "received unexpected notification of transfer" ); - } - } - - static void apply( account_name code, action_name action ) { - if( !dispatch( converter_contract, - converter_currency::transfer, - converter_currency::issue, - first_currency::transfer, - second_currency::transfer ) { - eosio_assert( false, "received unexpected action" ); - } - } - }; /// converter_contract -} /// namespace bancor diff --git a/contracts/bancor/eosio.system.abi b/contracts/bancor/eosio.system.abi deleted file mode 100644 index c8d8e4b16e9..00000000000 --- a/contracts/bancor/eosio.system.abi +++ /dev/null @@ -1,37 +0,0 @@ -{ - "types": [{ - "new_type_name": "account_name", - "type": "name" - } - ], - "structs": [{ - "name": "transfer", - "base": "", - "fields": [ - {"name":"from", "type":"account_name"}, - {"name":"to", "type":"account_name"}, - {"name":"quantity", "type":"uint64"} - ] - },{ - "name": "account", - "base": "", - "fields": [ - {"name":"key", "type":"name"}, - {"name":"balance", "type":"uint64"} - ] - } - ], - "actions": [{ - "name": "transfer", - "type": "transfer" - } - ], - "tables": [{ - "name": "account", - "type": "account", - "index_type": "i64", - "key_names" : ["key"], - "key_types" : ["name"] - } - ] -} \ No newline at end of file diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 95a40781530..fd4e83fcce7 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -205,7 +205,7 @@ namespace eosiosystem { const int64_t max_claimable = 100'000'000'0000ll; const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); - eosio_assert( max_claimable - claimable <= stake, "bosbosbosbos can only claim their tokens over 10 years" ); + eosio_assert( max_claimable - claimable <= stake, "bos can only claim their tokens over 10 years" ); } void system_contract::changebw( account_name from, account_name receiver, diff --git a/contracts/eosiolib/currency.hpp b/contracts/eosiolib/currency.hpp deleted file mode 100644 index 1328c493876..00000000000 --- a/contracts/eosiolib/currency.hpp +++ /dev/null @@ -1,254 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { - using std::string; - using std::array; - - /** - * This contract enables the creation, issuance, and transfering of many different tokens. - * @deprecated This class is deprecated in favor of eosio.token in Dawn 3.0 - */ - class currency { - public: - currency( account_name contract ) - :_contract(contract) - { } - - struct create { - account_name issuer; - asset maximum_supply; - // array issuer_agreement_hash; - uint8_t issuer_can_freeze = true; - uint8_t issuer_can_recall = true; - uint8_t issuer_can_whitelist = true; - - /*(issuer_agreement_hash)*/ - EOSLIB_SERIALIZE( create, (issuer)(maximum_supply)(issuer_can_freeze)(issuer_can_recall)(issuer_can_whitelist) ) - }; - - struct transfer - { - account_name from; - account_name to; - asset quantity; - string memo; - - EOSLIB_SERIALIZE( transfer, (from)(to)(quantity)(memo) ) - }; - - struct issue { - account_name to; - asset quantity; - string memo; - - EOSLIB_SERIALIZE( issue, (to)(quantity)(memo) ) - }; - - struct fee_schedule { - uint64_t primary_key()const { return 0; } - - array fee_per_length; - EOSLIB_SERIALIZE( fee_schedule, (fee_per_length) ) - }; - - struct account { - asset balance; - bool frozen = false; - bool whitelist = true; - - uint64_t primary_key()const { return balance.symbol.name(); } - - EOSLIB_SERIALIZE( account, (balance)(frozen)(whitelist) ) - }; - - struct currency_stats { - asset supply; - asset max_supply; - account_name issuer; - bool can_freeze = true; - bool can_recall = true; - bool can_whitelist = true; - bool is_frozen = false; - bool enforce_whitelist = false; - - uint64_t primary_key()const { return supply.symbol.name(); } - - EOSLIB_SERIALIZE( currency_stats, (supply)(max_supply)(issuer)(can_freeze)(can_recall)(can_whitelist)(is_frozen)(enforce_whitelist) ) - }; - - typedef eosio::multi_index accounts; - typedef eosio::multi_index stats; - - - asset get_balance( account_name owner, symbol_name symbol )const { - accounts t( _contract, owner ); - return t.get(symbol).balance; - } - - asset get_supply( symbol_name symbol )const { - accounts t( _contract, symbol ); - return t.get(symbol).balance; - } - - static void inline_transfer( account_name from, account_name to, extended_asset amount, string memo = string(), permission_name perm = N(active) ) { - action act( permission_level( from, perm ), amount.contract, N(transfer), transfer{from,to,amount,memo} ); - act.send(); - } - - void inline_transfer( account_name from, account_name to, asset amount, string memo = string(), permission_name perm = N(active) ) { - action act( permission_level( from, perm ), _contract, N(transfer), transfer{from,to,amount,memo} ); - act.send(); - } - - - bool apply( account_name contract, action_name act ) { - if( contract != _contract ) - return false; - - switch( act ) { - case N(issue): - print( "issue\n"); - on( unpack_action_data() ); - return true; - case N(transfer): - print( "transfer\n"); - on( unpack_action_data() ); - return true; - case N(create): - print( "create\n"); - on( unpack_action_data() ); - return true; - } - return false; - } - - /** - * This is factored out so it can be used as a building block - */ - void create_currency( const create& c ) { - auto sym = c.maximum_supply.symbol; - eosio_assert( sym.is_valid(), "invalid symbol name" ); - - stats statstable( _contract, sym.name() ); - auto existing = statstable.find( sym.name() ); - eosio_assert( existing == statstable.end(), "token with symbol already exists" ); - - statstable.emplace( c.issuer, [&]( auto& s ) { - s.supply.symbol = c.maximum_supply.symbol; - s.max_supply = c.maximum_supply; - s.issuer = c.issuer; - s.can_freeze = c.issuer_can_freeze; - s.can_recall = c.issuer_can_recall; - s.can_whitelist = c.issuer_can_whitelist; - }); - } - - void issue_currency( const issue& i ) { - auto sym = i.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - statstable.modify( st, 0, [&]( auto& s ) { - s.supply.amount += i.quantity.amount; - eosio_assert( s.supply.amount >= 0, "underflow" ); - }); - - add_balance( st.issuer, i.quantity, st, st.issuer ); - } - - - void on( const create& c ) { - require_auth( c.issuer ); - create_currency( c ); - - /* - auto fee = get_fee_schedule()[c.maximum_supply.name_length()]; - if( fee.amount > 0 ) { - inline_transfer( c.issuer, _contract, fee, "symbol registration fee" ); - } - */ - } - - void on( const issue& i ) { - auto sym = i.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - require_auth( st.issuer ); - eosio_assert( i.quantity.is_valid(), "invalid quantity" ); - eosio_assert( i.quantity.amount > 0, "must issue positive quantity" ); - - statstable.modify( st, 0, [&]( auto& s ) { - s.supply.amount += i.quantity.amount; - }); - - add_balance( st.issuer, i.quantity, st, st.issuer ); - - if( i.to != st.issuer ) - { - inline_transfer( st.issuer, i.to, i.quantity, i.memo ); - } - } - - void on( const transfer& t ) { - require_auth(t.from); - auto sym = t.quantity.symbol.name(); - stats statstable( _contract, sym ); - const auto& st = statstable.get( sym ); - - require_recipient( t.to ); - - eosio_assert( t.quantity.is_valid(), "invalid quantity" ); - eosio_assert( t.quantity.amount > 0, "must transfer positive quantity" ); - sub_balance( t.from, t.quantity, st ); - add_balance( t.to, t.quantity, st, t.from ); - } - - - private: - void sub_balance( account_name owner, asset value, const currency_stats& st ) { - accounts from_acnts( _contract, owner ); - - const auto& from = from_acnts.get( value.symbol.name() ); - eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" ); - - if( has_auth( owner ) ) { - eosio_assert( !st.can_freeze || !from.frozen, "account is frozen by issuer" ); - eosio_assert( !st.can_freeze || !st.is_frozen, "all transfers are frozen by issuer" ); - eosio_assert( !st.enforce_whitelist || from.whitelist, "account is not white listed" ); - } else if( has_auth( st.issuer ) ) { - eosio_assert( st.can_recall, "issuer may not recall token" ); - } else { - eosio_assert( false, "insufficient authority" ); - } - - from_acnts.modify( from, owner, [&]( auto& a ) { - a.balance.amount -= value.amount; - }); - } - - void add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer ) - { - accounts to_acnts( _contract, owner ); - auto to = to_acnts.find( value.symbol.name() ); - if( to == to_acnts.end() ) { - eosio_assert( !st.enforce_whitelist, "can only transfer to white listed accounts" ); - to_acnts.emplace( ram_payer, [&]( auto& a ){ - a.balance = value; - }); - } else { - eosio_assert( !st.enforce_whitelist || to->whitelist, "receiver requires whitelist by issuer" ); - to_acnts.modify( to, 0, [&]( auto& a ) { - a.balance.amount += value.amount; - }); - } - } - - private: - account_name _contract; - }; - -} diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index db115ca27e1..95a41322acc 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -108,6 +108,20 @@ extern "C" { */ void get_action_sequence(uint64_t* seq); + /** + * Tests if the account has an installed contract + * @param name : account name + * @return : Return has contract + */ + bool has_contract( account_name name); + + /** + * Get the code of the deployment contract + * @param name : account name + * @param code : return contract code + */ + void get_contract_code( account_name name, checksum256* code); + /** * Get the producer's signature for the action * @param sig : Memory buffer diff --git a/contracts/infinite/CMakeLists.txt b/contracts/infinite/CMakeLists.txt deleted file mode 100644 index af3ec44f496..00000000000 --- a/contracts/infinite/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET infinite - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/infinite/infinite.cpp b/contracts/infinite/infinite.cpp deleted file mode 100644 index 21a542c1a28..00000000000 --- a/contracts/infinite/infinite.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include /// defines transfer struct (abi) - -extern "C" { - - /// The apply method just prints forever - void apply( uint64_t, uint64_t, uint64_t ) { - int idx = 0; - while(true) { - eosio::print(idx++); - } - } -} diff --git a/contracts/simple.token/CMakeLists.txt b/contracts/simple.token/CMakeLists.txt deleted file mode 100644 index 1e755eabe2f..00000000000 --- a/contracts/simple.token/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -file(GLOB ABI_FILES "*.abi") -configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - -add_wast_executable(TARGET simple.token - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES libc++ libc eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/simple.token/simple.token.abi b/contracts/simple.token/simple.token.abi deleted file mode 100644 index 2c63c085104..00000000000 --- a/contracts/simple.token/simple.token.abi +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/contracts/simple.token/simple.token.cpp b/contracts/simple.token/simple.token.cpp deleted file mode 100644 index 1f2ab97feca..00000000000 --- a/contracts/simple.token/simple.token.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -class simpletoken : public eosio::contract { - public: - simpletoken( account_name self ) - :contract(self),_accounts( _self, _self){} - - void transfer( account_name from, account_name to, uint64_t quantity ) { - require_auth( from ); - - const auto& fromacnt = _accounts.get( from ); - eosio_assert( fromacnt.balance >= quantity, "overdrawn balance" ); - _accounts.modify( fromacnt, from, [&]( auto& a ){ a.balance -= quantity; } ); - - add_balance( from, to, quantity ); - } - - void issue( account_name to, uint64_t quantity ) { - require_auth( _self ); - add_balance( _self, to, quantity ); - } - - private: - struct account { - account_name owner; - uint64_t balance; - - uint64_t primary_key()const { return owner; } - }; - - eosio::multi_index _accounts; - - void add_balance( account_name payer, account_name to, uint64_t q ) { - auto toitr = _accounts.find( to ); - if( toitr == _accounts.end() ) { - _accounts.emplace( payer, [&]( auto& a ) { - a.owner = to; - a.balance = q; - }); - } else { - _accounts.modify( toitr, 0, [&]( auto& a ) { - a.balance += q; - eosio_assert( a.balance >= q, "overflow detected" ); - }); - } - } -}; - -EOSIO_ABI( simpletoken, (transfer)(issue) ) diff --git a/contracts/social/CMakeLists.txt b/contracts/social/CMakeLists.txt deleted file mode 100644 index 72d5d9e059e..00000000000 --- a/contracts/social/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_wast_executable(TARGET social - INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}" - LIBRARIES eosiolib - DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} -) diff --git a/contracts/social/social.cpp b/contracts/social/social.cpp deleted file mode 100644 index 7cee3dd1ddf..00000000000 --- a/contracts/social/social.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include - -/** - * The purpose of this contract is to implement something like Steem on EOS, this - * means this contract defines its own currency, allows people to create posts, vote - * on posts, and stake their voting power. - * - * Unlike Steem, the goal is to enable maximum parallelism and enable the currency to - * be easily integrated with an exchange contract. - */ - -struct post_action { - account_name author; - post_name postid; - account_name reply_to_author; - int32_t reply_to_id; - uint8_t author; /// index in notify list - char[] data; /// ignored, title is embedded within - - account_name get_author()const { return get_notify(author); } -}; - -struct vote_action { - account_name voter; - account_name author; - post_name postid; - int32_t vote_power; -}; - -struct post_record { - uint64_t total_votes = 0; - uint64_t claimed_votes = 0; - uint32_t created; - - post_record( uint32_t c = now() ):created(c){} - static Name table_id() { return Name("post"); } -}; - -struct account { - uint64_t social = 0; - uint64_t social_power = 0; - int32_t vote_power = 0; - uint32_t last_vote = 0; - - static Name table_id() { return Name("account"); } -}; - - -/** - * When a user posts we create a record that tracks the total votes and the time it - * was created. A user can submit this action multiple times, but subsequent calls do - * nothing. - * - * This method only does something when called in the context of the author, if - * any other contexts are notified - */ -void apply_social_post() { - const auto& post = current_action(); - require_auth( post.author ); - - eosio_assert( current_context() == post.author, "cannot call from any other context" ); - - static post_record& existing; - if( !Db::get( post.postid, existing ) ) - Db::store( post.postid, post_record( now() ) ); -} - -/** - * This action is called when a user casts a vote, it requires that this code is executed - * in the context of both the voter and the author. When executed in the author's context it - * updates the vote total. When executed - */ -void apply_social_vote() { - const auto& vote = current_action(); - require_recipient( vote.voter, vote.author ); - disable_context_code( vote.author() ); /// prevent the author's code from rejecting the potentially negative vote - - auto context = current_context(); - auto voter = vote.getVoter(); - - if( context == vote.author ) { - static post_record post; - eosio_assert( Db::get( vote.postid, post ) > 0, "unable to find post" ); - eosio_assert( now() - post.created < days(7), "cannot vote after 7 days" ); - post.votes += vote.vote_power; - Db::store( vote.postid, post ); - } - else if( context == vote.voter ) { - static account vote_account; - Db::get( "account", vote_account ); - auto abs_vote = abs(vote.vote_power); - vote_account.vote_power = min( vote_account.social_power, - vote_account.vote_power + (vote_account.social_power * (now()-last_vote)) / days(7)); - eosio_assert( abs_vote <= vote_account.vote_power, "insufficient vote power" ); - post.votes += vote.vote_power; - vote_account.vote_power -= abs_vote; - vote_account.last_vote = now(); - Db::store( "account", vote_account ); - } else { - eosio_assert( false, "invalid context for execution of this vote" ); - } -} - diff --git a/contracts/tic_tac_toe/tic_tac_toe.cpp b/contracts/tic_tac_toe/tic_tac_toe.cpp index cdbdc3d098d..ebc5cc46203 100644 --- a/contracts/tic_tac_toe/tic_tac_toe.cpp +++ b/contracts/tic_tac_toe/tic_tac_toe.cpp @@ -51,7 +51,7 @@ account_name get_winner(const tic_tac_toe::game& current_game) { uint32_t consecutive_diagonal_backslash = 3; uint32_t consecutive_diagonal_slash = 3; for (uint32_t i = 0; i < board.size(); i++) { - is_board_full &= is_empty_cell(board[i]); + is_board_full &= !is_empty_cell(board[i]); uint16_t row = uint16_t(i / tic_tac_toe::game::board_width); uint16_t column = uint16_t(i % tic_tac_toe::game::board_width); diff --git a/eosio.version.in b/eosio.version.in index 239b7599404..8d29e7ced19 100644 --- a/eosio.version.in +++ b/eosio.version.in @@ -1,6 +1,6 @@ #pragma once -/// VERSION @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@ +/// VERSION @VERSION_FULL@ namespace eosio { enum version { MAJOR @VERSION_MAJOR@, diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 78593706c7d..18013317c57 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -3,11 +3,9 @@ add_subdirectory( builtins ) add_subdirectory( softfloat ) add_subdirectory( chainbase ) add_subdirectory( wasm-jit ) -add_subdirectory( utilities ) add_subdirectory( appbase ) add_subdirectory( chain ) add_subdirectory( testing ) -add_subdirectory( abi_generator ) #turn these off for now set(BUILD_TESTS OFF CACHE BOOL "Build GTest-based tests") diff --git a/libraries/abi_generator/CMakeLists.txt b/libraries/abi_generator/CMakeLists.txt deleted file mode 100644 index 88e32a84048..00000000000 --- a/libraries/abi_generator/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -# Find an installed build of LLVM -find_package(LLVM 4.0 REQUIRED CONFIG) -set( CMAKE_CXX_STANDARD 14 ) - -file(GLOB HEADERS "include/eosio/abi_generator/*.hpp") - -set(SOURCES ${HEADERS}) - -add_library( abi_generator - abi_generator.cpp - ${HEADERS} ) - -target_include_directories(abi_generator - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${LLVM_INCLUDE_DIRS}") - -target_link_libraries(abi_generator eosio_chain - clangRewrite - clangTooling - clangToolingCore - clangFrontend - clangDriver - clangSerialization - clangParse - clangSema - clangAnalysis - clangAST - clangBasic - clangEdit - clangLex -) - -target_link_libraries(abi_generator - LLVMX86AsmParser # MC, MCParser, Support, X86CodeGen, X86Desc, X86Info - LLVMX86CodeGen # Analysis, AsmPrinter, CodeGen, Core, MC, Support, Target, - # X86AsmPrinter, X86Desc, X86Info, X86Utils - LLVMX86Desc # MC, MCDisassembler, Object, Support, X86AsmPrinter, X86Info - LLVMX86AsmPrinter # MC, Support, X86Utils - LLVMX86Info # Support - LLVMX86Utils # Core, Support - LLVMCodeGen # Analysis, Core, MC, Scalar, Support, Target, TransformUtils - LLVMipo - LLVMScalarOpts - LLVMInstCombine - LLVMTransformUtils - LLVMTarget # Analysis, MC, Core, Support - LLVMAnalysis # Core, Support - LLVMOption # Support - LLVMMCDisassembler # MC, Support - LLVMMCParser # MC, Support - LLVMMC # Object, Support - LLVMProfileData # Core, Support, Object - LLVMObject # BitReader, Core, Support - LLVMBitReader # Core, Support - LLVMCore # BinaryFormat, Support - #LLVMBinaryFormat # Support - LLVMSupport # Demangle - LLVMDemangle -) - -if (USE_PCH) - set_target_properties(abi_generator PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) - cotire(eos_utilities) -endif(USE_PCH) diff --git a/libraries/abi_generator/abi_generator.cpp b/libraries/abi_generator/abi_generator.cpp deleted file mode 100644 index fc021c0a3fd..00000000000 --- a/libraries/abi_generator/abi_generator.cpp +++ /dev/null @@ -1,688 +0,0 @@ -#include -#include - -namespace eosio { - -void abi_generator::set_target_contract(const string& contract, const vector& actions) { - target_contract = contract; - target_actions = actions; -} - -void abi_generator::enable_optimizaton(abi_generator::optimization o) { - optimizations |= o; -} - -bool abi_generator::is_opt_enabled(abi_generator::optimization o) { - return (optimizations & o) != 0; -} - -void abi_generator::set_output(abi_def& output) { - this->output = &output; -} - -void abi_generator::set_verbose(bool verbose) { - this->verbose = verbose; -} - -void abi_generator::set_ricardian_contracts(const ricardian_contracts& contracts) { - this->rc = contracts; -} - -void abi_generator::set_abi_context(const string& abi_context) { - this->abi_context = abi_context; -} - -void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) { - this->compiler_instance = &compiler_instance; -} - -void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) { - ast_context = &tag_decl->getASTContext(); - auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager()); - try { - handle_decl(tag_decl); -} FC_CAPTURE_AND_RETHROW((decl_location)) } - -string abi_generator::remove_namespace(const string& full_name) { - int i = full_name.size(); - int on_spec = 0; - int colons = 0; - while( --i >= 0 ) { - if( full_name[i] == '>' ) { - ++on_spec; colons=0; - } else if( full_name[i] == '<' ) { - --on_spec; colons=0; - } else if( full_name[i] == ':' && !on_spec) { - if (++colons == 2) - return full_name.substr(i+2); - } else { - colons = 0; - } - } - return full_name; -} - -bool abi_generator::is_builtin_type(const string& type_name) { - abi_serializer serializer; - auto rtype = resolve_type(type_name); - return serializer.is_builtin_type(translate_type(rtype)); -} - -string abi_generator::translate_type(const string& type_name) { - string built_in_type = type_name; - - if (type_name == "unsigned __int128" || type_name == "uint128_t") built_in_type = "uint128"; - else if (type_name == "__int128" || type_name == "int128_t") built_in_type = "int128"; - - else if (type_name == "unsigned long long" || type_name == "uint64_t") built_in_type = "uint64"; - else if (type_name == "unsigned long" || type_name == "uint32_t") built_in_type = "uint32"; - else if (type_name == "unsigned short" || type_name == "uint16_t") built_in_type = "uint16"; - else if (type_name == "unsigned char" || type_name == "uint8_t") built_in_type = "uint8"; - - else if (type_name == "long long" || type_name == "int64_t") built_in_type = "int64"; - else if (type_name == "long" || type_name == "int32_t") built_in_type = "int32"; - else if (type_name == "short" || type_name == "int16_t") built_in_type = "int16"; - else if (type_name == "char" || type_name == "int8_t") built_in_type = "int8"; - else if (type_name == "double") built_in_type = "float64"; - else { - static auto types = eosio::chain::common_type_defs(); - auto itr = std::find_if( types.begin(), types.end(), - [&type_name]( const eosio::chain::type_def& t ) { return t.new_type_name == type_name; } ); - if( itr != types.end()) { - built_in_type = itr->type; - } - } - - return built_in_type; -} - -bool abi_generator::inspect_type_methods_for_actions(const Decl* decl) { try { - - const auto* rec_decl = dyn_cast(decl); - if(rec_decl == nullptr) return false; - - const auto* type = rec_decl->getTypeForDecl(); - ABI_ASSERT(type != nullptr); - - bool at_least_one_action = false; - - auto export_method = [&](const CXXMethodDecl* method) { - - auto method_name = method->getNameAsString(); - - // Try to get "action" annotation from method comment - bool raw_comment_is_action = false; - string action_name_from_comment; - const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(method); - if(raw_comment != nullptr) { - SourceManager& source_manager = ast_context->getSourceManager(); - string raw_text = raw_comment->getRawText(source_manager); - regex r(R"(@abi (action) ?((?:[a-z0-9]+)*))"); - smatch smatch; - regex_search(raw_text, smatch, r); - raw_comment_is_action = smatch.size() == 3; - - if (raw_comment_is_action) { - action_name_from_comment = smatch[2]; - } - } - - // Check if current method is listed the EOSIO_ABI macro - bool is_action_from_macro = rec_decl->getName().str() == target_contract && std::find(target_actions.begin(), target_actions.end(), method_name) != target_actions.end(); - - if(!raw_comment_is_action && !is_action_from_macro) { - return; - } - - ABI_ASSERT(find_struct(method_name) == nullptr, "action already exists ${method_name}", ("method_name",method_name)); - - struct_def abi_struct; - for(const auto* p : method->parameters() ) { - clang::QualType qt = p->getOriginalType().getNonReferenceType(); - qt.setLocalFastQualifiers(0); - - string field_name = p->getNameAsString(); - string field_type_name = add_type(qt, 0); - - field_def struct_field{field_name, field_type_name}; - ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) - || find_struct(get_vector_element_type(struct_field.type)) - || find_type(get_vector_element_type(struct_field.type)) - , "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output)); - - type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt); - abi_struct.fields.push_back(struct_field); - } - - abi_struct.name = method_name; - abi_struct.base = ""; - - output->structs.push_back(abi_struct); - - full_types[method_name] = method_name; - - string action_name = action_name_from_comment.empty() ? method_name : action_name_from_comment; - output->actions.push_back({action_name, method_name, rc[method_name]}); - at_least_one_action = true; - }; - - const auto export_methods = [&export_method](const CXXRecordDecl* rec_decl) { - - - auto export_methods_impl = [&export_method](const CXXRecordDecl* rec_decl, auto& ref) -> void { - - - auto tmp = rec_decl->bases(); - auto rec_name = rec_decl->getName().str(); - - rec_decl->forallBases([&ref](const CXXRecordDecl* base) -> bool { - ref(base, ref); - return true; - }); - - for(const auto* method : rec_decl->methods()) { - export_method(method); - } - - }; - - export_methods_impl(rec_decl, export_methods_impl); - }; - - export_methods(rec_decl); - - return at_least_one_action; - -} FC_CAPTURE_AND_RETHROW() } - -void abi_generator::handle_decl(const Decl* decl) { try { - - ABI_ASSERT(decl != nullptr); - ABI_ASSERT(output != nullptr); - ABI_ASSERT(ast_context != nullptr); - - // Only process declarations that has the `abi_context` folder as parent. - SourceManager& source_manager = ast_context->getSourceManager(); - auto file_name = source_manager.getFilename(decl->getLocStart()); - if ( !abi_context.empty() && !file_name.startswith(abi_context) ) { - return; - } - - // Check if the current declaration has actions (EOSIO_ABI, or explicit) - bool type_has_actions = inspect_type_methods_for_actions(decl); - if( type_has_actions ) return; - - // The current Decl doesn't have actions - const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl); - if(raw_comment == nullptr) { - return; - } - - string raw_text = raw_comment->getRawText(source_manager); - regex r; - - // If EOSIO_ABI macro was found, we will only check if the current Decl - // is intented to be an ABI table record, otherwise we check for both (action or table) - if( target_contract.size() ) - r = regex(R"(@abi (table)((?: [a-z0-9]+)*))"); - else - r = regex(R"(@abi (action|table)((?: [a-z0-9]+)*))"); - - smatch smatch; - while(regex_search(raw_text, smatch, r)) - { - if(smatch.size() == 3) { - - auto type = smatch[1].str(); - - vector params; - auto string_params = smatch[2].str(); - boost::trim(string_params); - if(!string_params.empty()) - boost::split(params, string_params, boost::is_any_of(" ")); - - if(type == "action") { - - const auto* action_decl = dyn_cast(decl); - ABI_ASSERT(action_decl != nullptr); - - auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal(); - - auto type_name = add_struct(qt, "", 0); - ABI_ASSERT(!is_builtin_type(type_name), - "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); - - if(params.size()==0) { - params.push_back( boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_")) ); - } - - for(const auto& action : params) { - const auto* ac = find_action(action); - if( ac ) { - ABI_ASSERT(ac->type == type_name, "Same action name with different type ${action}",("action",action)); - continue; - } - output->actions.push_back({action, type_name, rc[action]}); - } - - } else if (type == "table") { - - const auto* table_decl = dyn_cast(decl); - ABI_ASSERT(table_decl != nullptr); - - auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal(); - auto type_name = add_struct(qt, "", 0); - - ABI_ASSERT(!is_builtin_type(type_name), - "A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name)); - - const auto* s = find_struct(type_name); - ABI_ASSERT(s, "Unable to find type ${type}", ("type",type_name)); - - table_def table; - table.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_")); - table.type = type_name; - - if(params.size() >= 1) { - table.name = params[0]; - } - - if(params.size() >= 2) { - table.index_type = params[1]; - ABI_ASSERT(table.index_type == "i64", "Only i64 index is supported. ${index_type}",("index_type",table.index_type)); - } else { try { - guess_index_type(table, *s); - } FC_CAPTURE_AND_RETHROW( (type_name) ) } - - try { - guess_key_names(table, *s); - } FC_CAPTURE_AND_RETHROW( (type_name) ) - - //TODO: assert that we are adding the same table - const auto* ta = find_table(table.name); - if(!ta) { - output->tables.push_back(table); - } - } - } - - raw_text = smatch.suffix(); - } - -} FC_CAPTURE_AND_RETHROW() } - -bool abi_generator::is_64bit(const string& type) { - return type_size[type] == 64; -} - -bool abi_generator::is_128bit(const string& type) { - return type_size[type] == 128; -} - -bool abi_generator::is_string(const string& type) { - return type == "String" || type == "string"; -} - -void abi_generator::get_all_fields(const struct_def& s, vector& fields) { - abi_serializer abis(*output, fc::seconds(1)); // No risk to client side serialization taking a long time - - for(const auto& field : s.fields) { - fields.push_back(field); - } - - if(s.base.size()) { - const auto* base = find_struct(s.base); - ABI_ASSERT(base, "Unable to find base type ${type}",("type",s.base)); - get_all_fields(*base, fields); - } -} - -bool abi_generator::is_i64_index(const vector& fields) { - return fields.size() >= 1 && is_64bit(fields[0].type); -} - -void abi_generator::guess_index_type(table_def& table, const struct_def s) { - vector fields; - get_all_fields(s, fields); - if( is_i64_index(fields) ) { - table.index_type = "i64"; - } else { - ABI_ASSERT(false, "Unable to guess index type"); - } -} - -void abi_generator::guess_key_names(table_def& table, const struct_def s) { - - vector fields; - get_all_fields(s, fields); - - if( table.index_type == "i64") { - - table.key_names.clear(); - table.key_types.clear(); - - unsigned int key_size = 0; - bool valid_key = false; - for(auto& f : fields) { - table.key_names.emplace_back(f.name); - table.key_types.emplace_back(f.type); - key_size += type_size[f.type]/8; - - if(table.index_type == "i64" && key_size >= sizeof(uint64_t)) { - valid_key = true; - break; - } - } - - ABI_ASSERT(valid_key, "Unable to guess key names"); - } else { - ABI_ASSERT(false, "Unable to guess key names"); - } -} - -const table_def* abi_generator::find_table(const table_name& name) { - for( const auto& ta : output->tables ) { - if(ta.name == name) { - return &ta; - } - } - return nullptr; -} - -const type_def* abi_generator::find_type(const type_name& new_type_name) { - for( const auto& td : output->types ) { - if(td.new_type_name == new_type_name) { - return &td; - } - } - return nullptr; -} - -const action_def* abi_generator::find_action(const action_name& name) { - for( const auto& ac : output->actions ) { - if(ac.name == name) { - return ∾ - } - } - return nullptr; -} - -const struct_def* abi_generator::find_struct(const type_name& name) { - auto rname = resolve_type(name); - for( const auto& st : output->structs ) { - if(st.name == rname) { - return &st; - } - } - return nullptr; -} - -type_name abi_generator::resolve_type(const type_name& type){ - const auto* td = find_type(type); - if( td ) { - for( auto i = output->types.size(); i > 0; --i ) { // avoid infinite recursion - const type_name& t = td->type; - td = find_type(t); - if( td == nullptr ) return t; - } - } - return type; -} - -bool abi_generator::is_one_filed_no_base(const string& type_name) { - const auto* s = find_struct(type_name); - return s && s->base.size() == 0 && s->fields.size() == 1; -} - -string abi_generator::decl_to_string(clang::Decl* d) { - //ASTContext& ctx = d->getASTContext(); - const auto& sm = ast_context->getSourceManager(); - clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd()); - clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts())); - return string(sm.getCharacterData(b), - sm.getCharacterData(e)-sm.getCharacterData(b)); -} - -bool abi_generator::is_typedef(const clang::QualType& qt) { - return isa(qt.getTypePtr()); -} - -bool abi_generator::is_elaborated(const clang::QualType& qt) { - return isa(qt.getTypePtr()); -} - -bool abi_generator::is_vector(const clang::QualType& vqt) { - - QualType qt(vqt); - - if ( is_elaborated(qt) ) - qt = qt->getAs()->getNamedType(); - - return isa(qt.getTypePtr()) \ - && boost::starts_with( get_type_name(qt, false), "vector"); -} - -bool abi_generator::is_vector(const string& type_name) { - return boost::ends_with(type_name, "[]"); -} - -bool abi_generator::is_struct_specialization(const clang::QualType& qt) { - return is_struct(qt) && isa(qt.getTypePtr()); -} - -bool abi_generator::is_struct(const clang::QualType& sqt) { - clang::QualType qt(sqt); - const auto* type = qt.getTypePtr(); - return !is_vector(qt) && (type->isStructureType() || type->isClassType()); -} - -clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) { - const auto* tst = clang::dyn_cast(qt.getTypePtr()); - ABI_ASSERT(tst != nullptr); - const clang::TemplateArgument& arg0 = tst->getArg(0); - return arg0.getAsType(); -} - -string abi_generator::get_vector_element_type(const string& type_name) { - if( is_vector(type_name) ) - return type_name.substr(0, type_name.size()-2); - return type_name; -} - -string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespace=false) { - auto name = clang::TypeName::getFullyQualifiedName(qt, *ast_context); - if(!with_namespace) - name = remove_namespace(name); - return name; -} - -clang::QualType abi_generator::add_typedef(const clang::QualType& tqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(tqt)); - - const auto* td_decl = qt->getAs()->getDecl(); - auto underlying_type = td_decl->getUnderlyingType().getUnqualifiedType(); - - auto new_type_name = td_decl->getName().str(); - auto underlying_type_name = get_type_name(underlying_type); - - if ( is_vector(underlying_type) ) { - underlying_type_name = add_vector(underlying_type, recursion_depth); - } - - type_def abi_typedef; - abi_typedef.new_type_name = new_type_name; - abi_typedef.type = translate_type(underlying_type_name); - const auto* td = find_type(abi_typedef.new_type_name); - - if(!td && !is_struct_specialization(underlying_type) ) { - output->types.push_back(abi_typedef); - } else { - if(td) ABI_ASSERT(abi_typedef.type == td->type); - } - - if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) ) - return add_typedef(underlying_type, recursion_depth); - - return underlying_type; -} - -clang::CXXRecordDecl::base_class_range abi_generator::get_struct_bases(const clang::QualType& sqt) { - - clang::QualType qt(sqt); - if(is_typedef(qt)) { - const auto* td_decl = qt->getAs()->getDecl(); - qt = td_decl->getUnderlyingType().getUnqualifiedType(); - } - - const auto* record_type = qt->getAs(); - ABI_ASSERT(record_type != nullptr); - auto cxxrecord_decl = clang::dyn_cast(record_type->getDecl()); - ABI_ASSERT(cxxrecord_decl != nullptr); - //record_type->getCanonicalTypeInternal().dump(); - ABI_ASSERT(cxxrecord_decl->hasDefinition(), "No definition for ${t}", ("t", qt.getAsString())); - - auto bases = cxxrecord_decl->bases(); - - return bases; -} - -const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clang::QualType& sqt) { - clang::QualType qt(sqt); - - if(is_typedef(qt)) { - const auto* td_decl = qt->getAs()->getDecl(); - qt = td_decl->getUnderlyingType().getUnqualifiedType(); - } - - const auto* record_type = qt->getAs(); - ABI_ASSERT(record_type != nullptr); - return record_type->getDecl()->fields(); -} - -string abi_generator::add_vector(const clang::QualType& vqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(vqt)); - - auto vector_element_type = get_vector_element_type(qt); - ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported"); - - add_type(vector_element_type, recursion_depth); - - auto vector_element_type_str = translate_type(get_type_name(vector_element_type)); - vector_element_type_str += "[]"; - - return vector_element_type_str; -} - -string abi_generator::add_type(const clang::QualType& tqt, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(tqt)); - - string full_type_name = translate_type(get_type_name(qt, true)); - string type_name = translate_type(get_type_name(qt)); - bool is_type_def = false; - - if( is_builtin_type(type_name) ) { - return type_name; - } - - if( is_typedef(qt) ) { - qt = add_typedef(qt, recursion_depth); - if( is_builtin_type(translate_type(get_type_name(qt))) ) { - return type_name; - } - is_type_def = true; - } - - if( is_vector(qt) ) { - auto vector_type_name = add_vector(qt, recursion_depth); - return is_type_def ? type_name : vector_type_name; - } - - if( is_struct(qt) ) { - return add_struct(qt, full_type_name, recursion_depth); - } - - ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt))); - return type_name; -} - -clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualType& qt) { - if( is_elaborated(qt) ) { - return qt->getAs()->getNamedType(); - } - return qt; -} - -string abi_generator::add_struct(const clang::QualType& sqt, string full_name, size_t recursion_depth) { - - ABI_ASSERT( ++recursion_depth < max_recursion_depth, "recursive definition, max_recursion_depth" ); - - clang::QualType qt(get_named_type_if_elaborated(sqt)); - - if( full_name.empty() ) { - full_name = get_type_name(qt, true); - } - - auto name = remove_namespace(full_name); - - ABI_ASSERT(is_struct(qt), "Only struct and class are supported. ${full_name}",("full_name",full_name)); - - if( find_struct(name) ) { - auto itr = full_types.find(resolve_type(name)); - if(itr != full_types.end()) { - ABI_ASSERT(itr->second == full_name, "Unable to add type '${full_name}' because '${conflict}' is already in.\n${t}", ("full_name",full_name)("conflict",itr->second)("t",output->types)); - } - return name; - } - - auto bases = get_struct_bases(qt); - auto bitr = bases.begin(); - int total_bases = 0; - - string base_name; - while( bitr != bases.end() ) { - auto base_qt = bitr->getType(); - const auto* record_type = base_qt->getAs(); - if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) { - ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name)); - base_name = add_type(base_qt, recursion_depth); - ++total_bases; - } - ++bitr; - } - - struct_def abi_struct; - for (const clang::FieldDecl* field : get_struct_fields(qt) ) { - clang::QualType qt = field->getType(); - - string field_name = field->getNameAsString(); - string field_type_name = add_type(qt, recursion_depth); - - field_def struct_field{field_name, field_type_name}; - ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type)) - || find_struct(get_vector_element_type(struct_field.type)) - || find_type(get_vector_element_type(struct_field.type)) - , "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output)); - - type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt); - abi_struct.fields.push_back(struct_field); - } - - abi_struct.name = resolve_type(name); - abi_struct.base = base_name; - - output->structs.push_back(abi_struct); - - full_types[name] = full_name; - return name; -} - -} diff --git a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp b/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp deleted file mode 100644 index 9248846cd88..00000000000 --- a/libraries/abi_generator/include/eosio/abi_generator/abi_generator.hpp +++ /dev/null @@ -1,442 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -//clashes with something deep in the AST includes in clang 6 and possibly other versions of clang -#pragma push_macro("N") -#undef N - -#include "clang/Driver/Options.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/ASTConsumer.h" - -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Sema/Sema.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/MacroArgs.h" -#include "clang/Tooling/Tooling.h" -#include "clang/Tooling/CommonOptionsParser.h" -#include "clang/Tooling/Core/QualTypeNames.h" -#include "llvm/Support/raw_ostream.h" -#include -#include - -using namespace clang; -using namespace std; -using namespace clang::tooling; -namespace cl = llvm::cl; - -namespace eosio { - using namespace eosio::chain; - - FC_DECLARE_EXCEPTION( abi_generation_exception, 999999, "Unable to generate abi" ); - - #define ABI_ASSERT( TEST, ... ) \ - FC_EXPAND_MACRO( \ - FC_MULTILINE_MACRO_BEGIN \ - if( UNLIKELY(!(TEST)) ) \ - { \ - if( fc::enable_record_assert_trip ) \ - fc::record_assert_trip( __FILE__, __LINE__, #TEST ); \ - FC_THROW_EXCEPTION( eosio::abi_generation_exception, #TEST ": " __VA_ARGS__ ); \ - } \ - FC_MULTILINE_MACRO_END \ - ) - - class ricardian_contracts { - public: - ricardian_contracts() = default; - ricardian_contracts( const string& context, const string& contract, const vector& actions ) { - ifstream clauses_file( context+"/"+contract+"_rc.md"); - if ( !clauses_file.good() ) - wlog("Warning, no ricardian clauses found for ${con}\n", ("con", contract)); - else - parse_clauses( clauses_file ); - - for ( auto act : actions ) { - ifstream contract_file( context+"/"+contract+"."+act+"_rc.md" ); - if ( !contract_file.good() ) - wlog("Warning, no ricardian contract found for ${act}\n", ("act", act)); - else { - parse_contract( contract_file ); - } - } - } - - vector get_clauses() { - return _clauses; - } - string operator[]( string key ) { - return _contracts[key]; - } - private: - inline string is_clause_decl( string line ) { - smatch match; - if ( regex_match( line, match, regex("(###[ ]+CLAUSE[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) { - EOS_ASSERT( match.size() == 3, invalid_ricardian_clause_exception, "Error, malformed clause declaration" ); - return match[2].str(); - } - return {}; - } - - inline string is_action_decl( string line ) { - smatch match; - if ( regex_match( line, match, regex("(##[ ]+ACTION[ ]+NAME[ ]*:[ ]*)(.*)", regex_constants::ECMAScript) ) ) { - EOS_ASSERT( match.size() == 3, invalid_ricardian_action_exception, "Error, malformed action declaration" ); - return match[2].str(); - } - return {}; - } - - void parse_contract( ifstream& contract_file ) { - string line; - string name; - string _name; - stringstream body; - bool first_time = true; - while ( contract_file.peek() != EOF ) { - getline( contract_file, line ); - body << line; - if ( !(_name = is_action_decl( line )).empty() ) { - name = _name; - first_time = false; - } - else - if ( !first_time ) - body << line << '\n'; - } - - _contracts.emplace(name, body.str()); - } - - void parse_clauses( ifstream& clause_file ) { - string line; - string name; - string _name; - stringstream body; - bool first_time = true; - while ( clause_file.peek() != EOF ) { - getline( clause_file, line ); - - if ( !(_name = is_clause_decl( line )).empty() ) { - if ( !first_time ) { - if (body.str().empty() ) { - EOS_ASSERT( false, invalid_ricardian_clause_exception, "Error, invalid input in ricardian clauses, no body found" ); - } - _clauses.emplace_back( name, body.str() ); - body.str(""); - } - name = _name; - first_time = false; - } - else - if ( !first_time ) - body << line << '\n'; - } - - } - vector _clauses; - map _contracts; - }; - - /** - * @brief Generates eosio::abi_def struct handling events from ASTConsumer - */ - class abi_generator { - private: - static constexpr size_t max_recursion_depth = 25; // arbitrary depth to prevent infinite recursion - bool verbose; - int optimizations; - abi_def* output; - CompilerInstance* compiler_instance; - map type_size; - map full_types; - string abi_context; - clang::ASTContext* ast_context; - string target_contract; - vector target_actions; - ricardian_contracts rc; - - public: - - enum optimization { - OPT_SINGLE_FIELD_STRUCT - }; - - abi_generator() - : verbose(false) - , optimizations(0) - , output(nullptr) - , compiler_instance(nullptr) - , ast_context(nullptr) - {} - - ~abi_generator() {} - - /** - * @brief Enable optimization when generating ABI - * @param o optimization to enable - */ - void enable_optimizaton(optimization o); - - /** - * @brief Check if an optimization is enabled - * @param o optimization to check - */ - bool is_opt_enabled(optimization o); - - /** - * @brief Set the destination ABI struct to write - * @param output ABI destination - */ - void set_output(abi_def& output); - - /** - * @brief Enable/Disable verbose status messages - * @param verbose enable/disable flag - */ - void set_verbose(bool verbose); - - /** - * @brief Set the root folder that limits where types will be imported. Types declared in header files located in child sub-folders will also be exported - * @param abi_context folder - */ - void set_abi_context(const string& abi_context); - - /** - * @brief Set the ricardian_contracts object with parsed contracts and clauses - * @param ricardian_contracts contracts - */ - void set_ricardian_contracts(const ricardian_contracts& contracts); - - - /** - * @brief Set the single instance of the Clang compiler - * @param compiler_instance compiler instance - */ - void set_compiler_instance(CompilerInstance& compiler_instance); - - /** - * @brief Handle declaration of struct/union/enum - * @param tag_decl declaration to handle - */ - void handle_tagdecl_definition(TagDecl* tag_decl); - - void set_target_contract(const string& contract, const vector& actions); - - private: - bool inspect_type_methods_for_actions(const Decl* decl); - - string remove_namespace(const string& full_name); - - bool is_builtin_type(const string& type_name); - - string translate_type(const string& type_name); - - void handle_decl(const Decl* decl); - - bool is_64bit(const string& type); - - bool is_128bit(const string& type); - - bool is_string(const string& type); - - void get_all_fields(const struct_def& s, vector& fields); - - bool is_i64i64i64_index(const vector& fields); - - bool is_i64_index(const vector& fields); - - bool is_i128i128_index(const vector& fields); - - bool is_str_index(const vector& fields); - - void guess_index_type(table_def& table, const struct_def s); - - void guess_key_names(table_def& table, const struct_def s); - - const table_def* find_table(const table_name& name); - - const type_def* find_type(const type_name& new_type_name); - - const action_def* find_action(const action_name& name); - - const struct_def* find_struct(const type_name& name); - - type_name resolve_type(const type_name& type); - - bool is_one_filed_no_base(const string& type_name); - - string decl_to_string(clang::Decl* d); - - bool is_typedef(const clang::QualType& qt); - QualType add_typedef(const clang::QualType& qt, size_t recursion_depth); - - bool is_vector(const clang::QualType& qt); - bool is_vector(const string& type_name); - string add_vector(const clang::QualType& qt, size_t recursion_depth); - - bool is_struct(const clang::QualType& qt); - string add_struct(const clang::QualType& qt, string full_type_name, size_t recursion_depth); - - string get_type_name(const clang::QualType& qt, bool no_namespace); - string add_type(const clang::QualType& tqt, size_t recursion_depth); - - bool is_elaborated(const clang::QualType& qt); - bool is_struct_specialization(const clang::QualType& qt); - - QualType get_vector_element_type(const clang::QualType& qt); - string get_vector_element_type(const string& type_name); - - clang::QualType get_named_type_if_elaborated(const clang::QualType& qt); - - const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt); - clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt); - }; - - struct abi_generator_astconsumer : public ASTConsumer { - abi_generator& abi_gen; - - abi_generator_astconsumer(CompilerInstance& compiler_instance, abi_generator& abi_gen) - :abi_gen(abi_gen) - { - abi_gen.set_compiler_instance(compiler_instance); - } - - void HandleTagDeclDefinition(TagDecl* tag_decl) override { - abi_gen.handle_tagdecl_definition(tag_decl); - } - }; - - struct find_eosio_abi_macro_action : public PreprocessOnlyAction { - - string& contract; - vector& actions; - const string& abi_context; - - find_eosio_abi_macro_action(string& contract, vector& actions, const string& abi_context - ): contract(contract), - actions(actions), abi_context(abi_context) { - } - - struct callback_handler : public PPCallbacks { - - CompilerInstance& compiler_instance; - find_eosio_abi_macro_action& act; - - callback_handler(CompilerInstance& compiler_instance, find_eosio_abi_macro_action& act) - : compiler_instance(compiler_instance), act(act) {} - - string remove_namespace(const string& full_name) { - int i = full_name.size(); - int on_spec = 0; - int colons = 0; - while( --i >= 0 ) { - if( full_name[i] == '>' ) { - ++on_spec; colons=0; - } else if( full_name[i] == '<' ) { - --on_spec; colons=0; - } else if( full_name[i] == ':' && !on_spec) { - if (++colons == 2) - return full_name.substr(i+2); - } else { - colons = 0; - } - } - return full_name; - } - - void MacroExpands (const Token &token, const MacroDefinition &md, SourceRange range, const MacroArgs *args) override { - - auto* id = token.getIdentifierInfo(); - if( id == nullptr ) return; - if( id->getName() != "EOSIO_ABI" ) return; - - const auto& sm = compiler_instance.getSourceManager(); - auto file_name = sm.getFilename(range.getBegin()); - if ( !act.abi_context.empty() && !file_name.startswith(act.abi_context) ) { - return; - } - - ABI_ASSERT( md.getMacroInfo()->getNumArgs() == 2 ); - - clang::SourceLocation b(range.getBegin()), _e(range.getEnd()); - clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance.getLangOpts())); - auto macrostr = string(sm.getCharacterData(b), sm.getCharacterData(e)-sm.getCharacterData(b)); - - regex r(R"(EOSIO_ABI\s*\(\s*(.+?)\s*,((?:.+?)*)\s*\))"); - smatch smatch; - auto res = regex_search(macrostr, smatch, r); - ABI_ASSERT( res ); - - act.contract = remove_namespace(smatch[1].str()); - - auto actions_str = smatch[2].str(); - boost::trim(actions_str); - actions_str = actions_str.substr(1); - actions_str.pop_back(); - boost::remove_erase_if(actions_str, boost::is_any_of(" (")); - - boost::split(act.actions, actions_str, boost::is_any_of(")")); - } - }; - - void ExecuteAction() override { - getCompilerInstance().getPreprocessor().addPPCallbacks( - llvm::make_unique(getCompilerInstance(), *this) - ); - PreprocessOnlyAction::ExecuteAction(); - }; - - }; - - - class generate_abi_action : public ASTFrontendAction { - - private: - set parsed_templates; - abi_generator abi_gen; - - public: - - generate_abi_action(bool verbose, bool opt_sfs, string abi_context, - abi_def& output, const string& contract, const vector& actions) { - - ricardian_contracts rc( abi_context, contract, actions ); - abi_gen.set_output(output); - abi_gen.set_verbose(verbose); - abi_gen.set_abi_context(abi_context); - abi_gen.set_target_contract(contract, actions); - abi_gen.set_ricardian_contracts( rc ); - output.ricardian_clauses = rc.get_clauses(); - - if(opt_sfs) - abi_gen.enable_optimizaton(abi_generator::OPT_SINGLE_FIELD_STRUCT); - } - - protected: - std::unique_ptr CreateASTConsumer(CompilerInstance& compiler_instance, - llvm::StringRef) override { - return llvm::make_unique(compiler_instance, abi_gen); - } - }; - -} //ns eosio - -#pragma pop_macro("N") diff --git a/libraries/appbase b/libraries/appbase index f3a63c1c04d..1d6e6e4a0b3 160000 --- a/libraries/appbase +++ b/libraries/appbase @@ -1 +1 @@ -Subproject commit f3a63c1c04df957c0675b51d298851c71d6ccbe7 +Subproject commit 1d6e6e4a0b334553658fe05cfa1e86081b6d0b4a diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index a8eeadaa94a..ee8fe1ebab2 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -50,7 +50,7 @@ add_library( eosio_chain ${HEADERS} ) -target_link_libraries( eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime +target_link_libraries( eosio_chain fc chainbase Logging IR WAST WASM Runtime softfloat builtins wabt ) target_include_directories( eosio_chain diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 4e9807ed85c..3a0de3b1466 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -54,7 +54,7 @@ void apply_context::exec_one( action_trace& trace ) privileged = a.privileged; auto native = control.find_apply_handler( receiver, act.account, act.name ); if( native ) { - if( trx_context.can_subjectively_fail && control.is_producing_block() ) { + if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); control.check_action_list( act.account, act.name ); } @@ -64,7 +64,7 @@ void apply_context::exec_one( action_trace& trace ) if( a.code.size() > 0 && !(act.account == config::system_account_name && act.name == N( setcode ) && receiver == config::system_account_name) ) { - if( trx_context.can_subjectively_fail && control.is_producing_block() ) { + if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); control.check_action_list( act.account, act.name ); } @@ -209,6 +209,9 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( code != nullptr, action_validate_exception, "inline action's code account ${account} does not exist", ("account", a.account) ); + bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block(); + flat_set actors; + bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated bool send_to_self = (a.account == receiver); bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); @@ -225,12 +228,18 @@ void apply_context::execute_inline( action&& a ) { EOS_ASSERT( control.get_authorization_manager().find_permission(auth) != nullptr, action_validate_exception, "inline action's authorizations include a non-existent permission: ${permission}", ("permission", auth) ); + if( enforce_actor_whitelist_blacklist ) + actors.insert( auth.actor ); if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { inherited_authorizations.insert( auth ); } } + if( enforce_actor_whitelist_blacklist ) { + control.check_actor_list( actors ); + } + // No need to check authorization if replaying irreversible blocks or contract is privileged if( !control.skip_auth_check() && !privileged ) { try { @@ -285,7 +294,10 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a EOS_ASSERT( trx.context_free_actions.size() == 0, cfa_inside_generated_tx, "context free actions are not currently allowed in generated transactions" ); trx.expiration = control.pending_block_time() + fc::microseconds(999'999); // Rounds up to nearest second (makes expiration check unnecessary) trx.set_reference_block(control.head_block_id()); // No TaPoS check necessary - control.validate_referenced_accounts( trx ); + + bool enforce_actor_whitelist_blacklist = trx_context.enforce_whiteblacklist && control.is_producing_block() + && !control.sender_avoids_whitelist_blacklist_enforcement( receiver ); + trx_context.validate_referenced_accounts( trx, enforce_actor_whitelist_blacklist ); // Charge ahead of time for the additional net usage needed to retire the deferred transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 2ae15af7341..70bcfa3a236 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -58,8 +58,6 @@ namespace eosio { namespace chain { result.blockroot_merkle = blockroot_merkle; result.blockroot_merkle.append( id ); - auto block_mroot = result.blockroot_merkle.get_root(); - result.active_schedule = active_schedule; result.pending_schedule = pending_schedule; result.dpos_proposed_irreversible_blocknum = dpos_proposed_irreversible_blocknum; @@ -143,7 +141,7 @@ namespace eosio { namespace chain { * * If the header specifies new_producers then apply them accordingly. */ - block_header_state block_header_state::next( const signed_block_header& h, bool trust )const { + block_header_state block_header_state::next( const signed_block_header& h, bool skip_validate_signee )const { EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) ); //EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); @@ -180,9 +178,8 @@ namespace eosio { namespace chain { // ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here - if( !trust ) { - EOS_ASSERT( result.block_signing_key == result.signee(), wrong_signing_key, "block not signed by expected key", - ("result.block_signing_key", result.block_signing_key)("signee", result.signee() ) ); + if( !skip_validate_signee ) { + result.verify_signee( result.signee() ); } return result; @@ -238,6 +235,11 @@ namespace eosio { namespace chain { return fc::crypto::public_key( header.producer_signature, sig_digest(), true ); } + void block_header_state::verify_signee( const public_key_type& signee )const { + EOS_ASSERT( block_signing_key == signee, wrong_signing_key, "block not signed by expected key", + ("block_signing_key", block_signing_key)( "signee", signee ) ); + } + void block_header_state::add_confirmation( const header_confirmation& conf ) { for( const auto& c : confirmations ) EOS_ASSERT( c.producer != conf.producer, producer_double_confirm, "block already confirmed by this producer" ); diff --git a/libraries/chain/block_state.cpp b/libraries/chain/block_state.cpp index f62da8655df..b4834775951 100644 --- a/libraries/chain/block_state.cpp +++ b/libraries/chain/block_state.cpp @@ -10,9 +10,9 @@ namespace eosio { namespace chain { static_cast(*block) = header; } - block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool trust ) - :block_header_state( prev.next( *b, trust )), block( move(b) ) - { } + block_state::block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee ) + :block_header_state( prev.next( *b, skip_validate_signee )), block( move(b) ) + { } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cb824cf45ba..85507dea83a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -20,10 +21,11 @@ #include #include #include - #include -#include +#include +#include + namespace eosio { namespace chain { @@ -136,6 +138,7 @@ struct controller_impl { optional subjective_cpu_leeway; bool trusted_producer_light_validation = false; uint32_t snapshot_head_block = 0; + optional thread_pool; typedef pair handler_key; map< account_name, map > apply_handlers; @@ -147,6 +150,14 @@ struct controller_impl { */ map unapplied_transactions; + // async on thread_pool and return future + template + auto async_thread_pool( F&& f ) { + auto task = std::make_shared>( std::forward( f ) ); + boost::asio::post( *thread_pool, [task]() { (*task)(); } ); + return task->get_future(); + } + void pop_block() { auto prev = fork_db.get_block( head->header.previous ); EOS_ASSERT( prev, block_validate_exception, "attempt to pop beyond last irreversible block" ); @@ -299,22 +310,25 @@ struct controller_impl { } } - void replay() { + void replay(std::function shutdown) { auto blog_head = blog.read_head(); auto blog_head_time = blog_head->timestamp.to_time_point(); replaying = true; replay_head_time = blog_head_time; - ilog( "existing block log, attempting to replay ${n} blocks", ("n",blog_head->block_num()) ); + auto start_block_num = head->block_num + 1; + ilog( "existing block log, attempting to replay from ${s} to ${n} blocks", + ("s", start_block_num)("n", blog_head->block_num()) ); auto start = fc::time_point::now(); while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) { - self.push_block( next, controller::block_status::irreversible ); + replay_push_block( next, controller::block_status::irreversible ); if( next->block_num() % 100 == 0 ) { std::cerr << std::setw(10) << next->block_num() << " of " << blog_head->block_num() <<"\r"; + if( shutdown() ) break; } } std::cerr<< "\n"; - ilog( "${n} blocks replayed", ("n", head->block_num) ); + ilog( "${n} blocks replayed", ("n", head->block_num - start_block_num) ); // if the irreverible log is played without undo sessions enabled, we need to sync the // revision ordinal to the appropriate expected value here. @@ -324,46 +338,54 @@ struct controller_impl { int rev = 0; while( auto obj = reversible_blocks.find(head->block_num+1) ) { ++rev; - self.push_block( obj->get_block(), controller::block_status::validated ); + replay_push_block( obj->get_block(), controller::block_status::validated ); } ilog( "${n} reversible blocks replayed", ("n",rev) ); auto end = fc::time_point::now(); ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block", - ("n", head->block_num)("duration", (end-start).count()/1000000) - ("mspb", ((end-start).count()/1000.0)/head->block_num) ); + ("n", head->block_num - start_block_num)("duration", (end-start).count()/1000000) + ("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) ); replaying = false; replay_head_time.reset(); } - void init(const snapshot_reader_ptr& snapshot) { + void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { + thread_pool.emplace( conf.thread_pool_size ); + + bool report_integrity_hash = !!snapshot; if (snapshot) { - EOS_ASSERT(!head, fork_database_exception, ""); + EOS_ASSERT( !head, fork_database_exception, "" ); snapshot->validate(); - read_from_snapshot(snapshot); + read_from_snapshot( snapshot ); auto end = blog.read_head(); if( !end ) { - blog.reset(conf.genesis, signed_block_ptr(), head->block_num + 1); - } else if ( end->block_num() > head->block_num) { - replay(); + blog.reset( conf.genesis, signed_block_ptr(), head->block_num + 1 ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); } else { - EOS_ASSERT(end->block_num() == head->block_num, fork_database_exception, - "Block log is provided with snapshot but does not contain the head block from the snapshot"); + EOS_ASSERT( end->block_num() == head->block_num, fork_database_exception, + "Block log is provided with snapshot but does not contain the head block from the snapshot" ); + } + } else { + if( !head ) { + initialize_fork_db(); // set head to genesis state } - } else if( !head ) { - initialize_fork_db(); // set head to genesis state auto end = blog.read_head(); - if( end && end->block_num() > 1 ) { - replay(); - } else if( !end ) { + if( !end ) { blog.reset( conf.genesis, head->block ); + } else if( end->block_num() > head->block_num ) { + replay( shutdown ); + report_integrity_hash = true; } } + if( shutdown() ) return; + const auto& ubi = reversible_blocks.get_index(); auto objitr = ubi.rbegin(); if( objitr != ubi.rend() ) { @@ -389,7 +411,7 @@ struct controller_impl { db.undo(); } - if( snapshot ) { + if( report_integrity_hash ) { const auto hash = calculate_integrity_hash(); ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } @@ -404,6 +426,11 @@ struct controller_impl { ~controller_impl() { pending.reset(); + if( thread_pool ) { + thread_pool->join(); + thread_pool->stop(); + } + db.flush(); reversible_blocks.flush(); } @@ -741,10 +768,17 @@ struct controller_impl { void sync_name_list(list_type list,bool isMerge=false) { - const auto &gpo2 = db.get(); - db.modify(gpo2, [&](auto &gprops2) { - sync_list_and_db(list, gprops2,isMerge); - }); + try + { + const auto &gpo2 = db.get(); + db.modify(gpo2, [&](auto &gprops2) { + sync_list_and_db(list, gprops2, isMerge); + }); + } + catch (...) + { + wlog("plugin initialize sync list ignore before initialize database"); + } } // "bos end" @@ -760,7 +794,7 @@ struct controller_impl { try { if (add_to_fork_db) { pending->_pending_block_state->validated = true; - auto new_bsp = fork_db.add(pending->_pending_block_state); + auto new_bsp = fork_db.add(pending->_pending_block_state, true); emit(self.accepted_block_header, pending->_pending_block_state); head = fork_db.head(); EOS_ASSERT(new_bsp == head, fork_database_exception, "committed block did not become the new head in fork database"); @@ -809,7 +843,10 @@ struct controller_impl { fc::time_point start, uint32_t& cpu_time_to_bill_us, // only set on failure uint32_t billed_cpu_time_us, - bool explicit_billed_cpu_time = false ) { + bool explicit_billed_cpu_time = false, + bool enforce_whiteblacklist = true + ) + { signed_transaction etrx; // Deliver onerror action containing the failed deferred transaction directly back to the sender. etrx.actions.emplace_back( vector{{gtrx.sender, config::active_name}}, @@ -821,6 +858,7 @@ struct controller_impl { trx_context.deadline = deadline; trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time; trx_context.billed_cpu_time_us = billed_cpu_time_us; + trx_context.enforce_whiteblacklist = enforce_whiteblacklist; transaction_trace_ptr trace = trx_context.trace; try { trx_context.init_for_implicit_trx(); @@ -939,9 +977,15 @@ struct controller_impl { trx_context.deadline = deadline; trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time; trx_context.billed_cpu_time_us = billed_cpu_time_us; + trx_context.enforce_whiteblacklist = gtrx.sender.empty() ? true : !sender_avoids_whitelist_blacklist_enforcement( gtrx.sender ); trace = trx_context.trace; try { trx_context.init_for_deferred_trx( gtrx.published ); + + if( trx_context.enforce_whiteblacklist && pending->_block_status == controller::block_status::incomplete ) { + check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction + } + trx_context.exec(); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful @@ -975,8 +1019,10 @@ struct controller_impl { if( gtrx.sender != account_name() && !failure_is_subjective(*trace->except)) { // Attempt error handling for the generated transaction. - dlog("${detail}", ("detail", trace->except->to_detail_string())); - auto error_trace = apply_onerror( gtrx, deadline, trx_context.pseudo_start, cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time ); + + auto error_trace = apply_onerror( gtrx, deadline, trx_context.pseudo_start, + cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time, + trx_context.enforce_whiteblacklist ); error_trace->failed_dtrx_trace = trace; trace = error_trace; if( !trace->except_ptr ) { @@ -1071,7 +1117,7 @@ struct controller_impl { try { if( trx->implicit ) { trx_context.init_for_implicit_trx(); - trx_context.can_subjectively_fail = false; + trx_context.enforce_whiteblacklist = false; } else { bool skip_recording = replay_head_time && (time_point(trx->trx.expiration) <= *replay_head_time); trx_context.init_for_input_trx( trx->packed_trx.get_unprunable_size(), @@ -1080,11 +1126,6 @@ struct controller_impl { skip_recording); } - if( trx_context.can_subjectively_fail && pending->_block_status == controller::block_status::incomplete ) { - check_actor_list( trx_context.bill_to_accounts ); // Assumes bill_to_accounts is the set of actors authorizing the transaction - } - - trx_context.delay = fc::seconds(trx->trx.delay_sec); if( !self.skip_auth_check() && !trx->implicit ) { @@ -1250,17 +1291,35 @@ struct controller_impl { auto producer_block_id = b->id(); start_block( b->timestamp, b->confirmed, s , producer_block_id); + std::vector packed_transactions; + packed_transactions.reserve( b->transactions.size() ); + for( const auto& receipt : b->transactions ) { + if( receipt.trx.contains()) { + auto& pt = receipt.trx.get(); + auto mtrx = std::make_shared( pt ); + if( !self.skip_auth_check() ) { + std::weak_ptr mtrx_wp = mtrx; + mtrx->signing_keys_future = async_thread_pool( [chain_id = this->chain_id, mtrx_wp]() { + auto mtrx = mtrx_wp.lock(); + return mtrx ? + std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id ) ) : + std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id ) ){} ); + } ); + } + packed_transactions.emplace_back( std::move( mtrx ) ); + } + } + pending->_pending_block_state->block->header_extensions = b->header_extensions; pending->_pending_block_state->block->block_extensions = b->block_extensions; transaction_trace_ptr trace; + size_t packed_idx = 0; for( const auto& receipt : b->transactions ) { auto num_pending_receipts = pending->_pending_block_state->block->transactions.size(); if( receipt.trx.contains() ) { - auto& pt = receipt.trx.get(); - auto mtrx = std::make_shared(pt); - trace = push_transaction( mtrx, fc::time_point::maximum(), receipt.cpu_usage_us, true ); + trace = push_transaction( packed_transactions.at(packed_idx++), fc::time_point::maximum(), receipt.cpu_usage_us, true ); } else if( receipt.trx.contains() ) { trace = push_scheduled_transaction( receipt.trx.get(), fc::time_point::maximum(), receipt.cpu_usage_us, true ); } else { @@ -1314,18 +1373,37 @@ struct controller_impl { } } FC_CAPTURE_AND_RETHROW() } /// apply_block + std::future create_block_state_future( const signed_block_ptr& b ) { + EOS_ASSERT( b, block_validate_exception, "null block" ); + + auto id = b->id(); + + // no reason for a block_state if fork_db already knows about block + auto existing = fork_db.get_block( id ); + EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) ); - void push_block( const signed_block_ptr& b, controller::block_status s ) { + auto prev = fork_db.get_block( b->previous ); + EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); + + return async_thread_pool( [b, prev]() { + const bool skip_validate_signee = false; + return std::make_shared( *prev, move( b ), skip_validate_signee ); + } ); + } + + void push_block( std::future& block_state_future ) { + controller::block_status s = controller::block_status::complete; EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() { trusted_producer_light_validation = old_value; }); try { - EOS_ASSERT( b, block_validate_exception, "trying to push empty block" ); - EOS_ASSERT( s != controller::block_status::incomplete, block_validate_exception, "invalid block status for a completed block" ); + block_state_ptr new_header_state = block_state_future.get(); + auto& b = new_header_state->block; emit( self.pre_accepted_block, b ); - bool trust = !conf.force_all_checks && (s == controller::block_status::irreversible || s == controller::block_status::validated); - auto new_header_state = fork_db.add( b, trust ); + + fork_db.add( new_header_state, false ); + if (conf.trusted_producers.count(b->producer)) { trusted_producer_light_validation = true; }; @@ -1335,6 +1413,29 @@ struct controller_impl { maybe_switch_forks( s ); } + } FC_LOG_AND_RETHROW( ) + } + + void replay_push_block( const signed_block_ptr& b, controller::block_status s ) { + self.validate_db_available_size(); + self.validate_reversible_available_size(); + + EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); + + try { + EOS_ASSERT( b, block_validate_exception, "trying to push empty block" ); + EOS_ASSERT( (s == controller::block_status::irreversible || s == controller::block_status::validated), + block_validate_exception, "invalid block status for replay" ); + emit( self.pre_accepted_block, b ); + const bool skip_validate_signee = !conf.force_all_checks; + auto new_header_state = fork_db.add( b, skip_validate_signee ); + + emit( self.accepted_block_header, new_header_state ); + + if ( read_mode != db_read_mode::IRREVERSIBLE ) { + maybe_switch_forks( s ); + } + // on replay irreversible is not emitted by fork database, so emit it explicitly here if( s == controller::block_status::irreversible ) emit( self.irreversible_block, new_header_state ); @@ -1342,16 +1443,7 @@ struct controller_impl { } FC_LOG_AND_RETHROW( ) } - void push_confirmation( const header_confirmation& c ) { - EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a confirmation when there is a pending block"); - fork_db.add( c ); - emit( self.accepted_confirmation, c ); - if ( read_mode != db_read_mode::IRREVERSIBLE ) { - maybe_switch_forks(); - } - } - - void maybe_switch_forks( controller::block_status s = controller::block_status::complete ) { + void maybe_switch_forks( controller::block_status s ) { auto new_head = fork_db.head(); if( new_head->header.previous == head->id ) { @@ -1370,13 +1462,13 @@ struct controller_impl { auto branches = fork_db.fetch_branch_from( new_head->id, head->id ); for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr , false ); + fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, - "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail + "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail - for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) { + for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) { optional except; try { apply_block( (*ritr)->block, (*ritr)->validated ? controller::block_status::validated : controller::block_status::complete ); @@ -1386,7 +1478,7 @@ struct controller_impl { } catch (const fc::exception& e) { except = e; } if (except) { - elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string())); + elog("exception thrown while switching forks ${e}", ("e", except->to_detail_string())); // ritr currently points to the block that threw // if we mark it invalid it will automatically remove all forks built off it. @@ -1396,11 +1488,11 @@ struct controller_impl { // ritr base is a forward itr to the last block successfully applied auto applied_itr = ritr.base(); for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) { - fork_db.mark_in_current_chain( *itr , false ); + fork_db.mark_in_current_chain( *itr, false ); pop_block(); } EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception, - "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail + "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail // re-apply good blocks for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) { @@ -1411,7 +1503,7 @@ struct controller_impl { throw *except; } // end if exception } /// end for each block in branch - ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id)); + ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id) ); } } /// push_block @@ -1565,28 +1657,97 @@ struct controller_impl { } } + bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const { + if( conf.sender_bypass_whiteblacklist.size() > 0 && + ( conf.sender_bypass_whiteblacklist.find( sender ) != conf.sender_bypass_whiteblacklist.end() ) ) + { + return true; + } + + return false; + } void check_actor_list( const flat_set& actors )const { + if( actors.size() == 0 ) return; + if( conf.actor_whitelist.size() > 0 ) { - vector excluded; - excluded.reserve( actors.size() ); - set_difference( actors.begin(), actors.end(), - conf.actor_whitelist.begin(), conf.actor_whitelist.end(), - std::back_inserter(excluded) ); - EOS_ASSERT( excluded.size() == 0, actor_whitelist_exception, + // throw if actors is not a subset of whitelist + const auto& whitelist = conf.actor_whitelist; + bool is_subset = true; + + // quick extents check, then brute force the check actors + if (*actors.cbegin() >= *whitelist.cbegin() && *actors.crbegin() <= *whitelist.crbegin() ) { + auto lower_bound = whitelist.cbegin(); + for (const auto& actor: actors) { + lower_bound = std::lower_bound(lower_bound, whitelist.cend(), actor); + + // if the actor is not found, this is not a subset + if (lower_bound == whitelist.cend() || *lower_bound != actor ) { + is_subset = false; + break; + } + + // if the actor was found, we are guaranteed that other actors are either not present in the whitelist + // or will be present in the range defined as [next actor,end) + lower_bound = std::next(lower_bound); + } + } else { + is_subset = false; + } + + // helper lambda to lazily calculate the actors for error messaging + static auto generate_missing_actors = [](const flat_set& actors, const flat_set& whitelist) -> vector { + vector excluded; + excluded.reserve( actors.size() ); + set_difference( actors.begin(), actors.end(), + whitelist.begin(), whitelist.end(), + std::back_inserter(excluded) ); + return excluded; + }; + + EOS_ASSERT( is_subset, actor_whitelist_exception, "authorizing actor(s) in transaction are not on the actor whitelist: ${actors}", - ("actors", excluded) + ("actors", generate_missing_actors(actors, whitelist)) ); } else if( conf.actor_blacklist.size() > 0 ) { - vector blacklisted; - blacklisted.reserve( actors.size() ); - set_intersection( actors.begin(), actors.end(), - conf.actor_blacklist.begin(), conf.actor_blacklist.end(), - std::back_inserter(blacklisted) - ); - EOS_ASSERT( blacklisted.size() == 0, actor_blacklist_exception, + // throw if actors intersects blacklist + const auto& blacklist = conf.actor_blacklist; + bool intersects = false; + + // quick extents check then brute force check actors + if( *actors.cbegin() <= *blacklist.crbegin() && *actors.crbegin() >= *blacklist.cbegin() ) { + auto lower_bound = blacklist.cbegin(); + for (const auto& actor: actors) { + lower_bound = std::lower_bound(lower_bound, blacklist.cend(), actor); + + // if the lower bound in the blacklist is at the end, all other actors are guaranteed to + // not exist in the blacklist + if (lower_bound == blacklist.cend()) { + break; + } + + // if the lower bound of an actor IS the actor, then we have an intersection + if (*lower_bound == actor) { + intersects = true; + break; + } + } + } + + // helper lambda to lazily calculate the actors for error messaging + static auto generate_blacklisted_actors = [](const flat_set& actors, const flat_set& blacklist) -> vector { + vector blacklisted; + blacklisted.reserve( actors.size() ); + set_intersection( actors.begin(), actors.end(), + blacklist.begin(), blacklist.end(), + std::back_inserter(blacklisted) + ); + return blacklisted; + }; + + EOS_ASSERT( !intersects, actor_blacklist_exception, "authorizing actor(s) in transaction are on the actor blacklist: ${actors}", - ("actors", blacklisted) + ("actors", generate_blacklisted_actors(actors, blacklist)) ); } } @@ -1697,12 +1858,12 @@ void controller::add_indices() { my->add_indices(); } -void controller::startup( const snapshot_reader_ptr& snapshot ) { +void controller::startup( std::function shutdown, const snapshot_reader_ptr& snapshot ) { my->head = my->fork_db.head(); if( !my->head ) { elog( "No head block in fork db, perhaps we need to replay" ); } - my->init(snapshot); + my->init(shutdown, snapshot); } const chainbase::database& controller::db()const { return my->db; } @@ -1736,15 +1897,14 @@ void controller::abort_block() { my->abort_block(); } -void controller::push_block( const signed_block_ptr& b, block_status s ) { - validate_db_available_size(); - validate_reversible_available_size(); - my->push_block( b, s ); +std::future controller::create_block_state_future( const signed_block_ptr& b ) { + return my->create_block_state_future( b ); } -void controller::push_confirmation( const header_confirmation& c ) { +void controller::push_block( std::future& block_state_future ) { validate_db_available_size(); - my->push_confirmation( c ); + validate_reversible_available_size(); + my->push_block( block_state_future ); } transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline, uint32_t billed_cpu_time_us ) { @@ -2118,6 +2278,14 @@ vector controller::get_scheduled_transactions() const { return result; } +bool controller::sender_avoids_whitelist_blacklist_enforcement( account_name sender )const { + return my->sender_avoids_whitelist_blacklist_enforcement( sender ); +} + +void controller::check_actor_list( const flat_set& actors )const { + my->check_actor_list( actors ); +} + void controller::check_contract_list( account_name code )const { my->check_contract_list( code ); } @@ -2140,32 +2308,6 @@ bool controller::is_ram_billing_in_notify_allowed()const { return !is_producing_block() || my->conf.allow_ram_billing_in_notify; } -void controller::validate_referenced_accounts( const transaction& trx )const { - for( const auto& a : trx.context_free_actions ) { - auto* code = my->db.find(a.account); - EOS_ASSERT( code != nullptr, transaction_exception, - "action's code account '${account}' does not exist", ("account", a.account) ); - EOS_ASSERT( a.authorization.size() == 0, transaction_exception, - "context-free actions cannot have authorizations" ); - } - bool one_auth = false; - for( const auto& a : trx.actions ) { - auto* code = my->db.find(a.account); - EOS_ASSERT( code != nullptr, transaction_exception, - "action's code account '${account}' does not exist", ("account", a.account) ); - for( const auto& auth : a.authorization ) { - one_auth = true; - auto* actor = my->db.find(auth.actor); - EOS_ASSERT( actor != nullptr, transaction_exception, - "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); - EOS_ASSERT( my->authorization.find_permission(auth) != nullptr, transaction_exception, - "action's authorizations include a non-existent permission: {permission}", - ("permission", auth) ); - } - } - EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" ); -} - void controller::validate_expiration( const transaction& trx )const { try { const auto& chain_configuration = get_global_properties().configuration; diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 33a123981a1..e41fe815834 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -57,7 +57,7 @@ void validate_authority_precondition( const apply_context& context, const author } } - if( context.control.is_producing_block() ) { + if( context.trx_context.enforce_whiteblacklist && context.control.is_producing_block() ) { for( const auto& p : auth.keys ) { context.control.check_key_list( p.key ); } @@ -282,7 +282,7 @@ void apply_eosio_deleteauth(apply_context& context) { const auto& index = db.get_index(); auto range = index.equal_range(boost::make_tuple(remove.account, remove.permission)); EOS_ASSERT(range.first == range.second, action_validate_exception, - "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", + "Cannot delete a linked authority. Unlink the authority first. This authority is linked to ${code}::${type}.", ("code", string(range.first->code))("type", string(range.first->message_type))); } diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 317453f19b8..441677bb8a8 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -123,7 +123,16 @@ namespace eosio { namespace chain { } } - block_state_ptr fork_database::add( block_state_ptr n ) { + block_state_ptr fork_database::add( const block_state_ptr& n, bool skip_validate_previous ) { + EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); + EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); + + if( !skip_validate_previous ) { + auto prior = my->index.find( n->block->previous ); + EOS_ASSERT( prior != my->index.end(), unlinkable_block_exception, + "unlinkable block", ("id", n->block->id())("previous", n->block->previous) ); + } + auto inserted = my->index.insert(n); EOS_ASSERT( inserted.second, fork_database_exception, "duplicate block added?" ); @@ -139,7 +148,7 @@ namespace eosio { namespace chain { return n; } - block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) { + block_state_ptr fork_database::add( signed_block_ptr b, bool skip_validate_signee ) { EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); const auto& by_id_idx = my->index.get(); @@ -149,9 +158,9 @@ namespace eosio { namespace chain { auto prior = by_id_idx.find( b->previous ); EOS_ASSERT( prior != by_id_idx.end(), unlinkable_block_exception, "unlinkable block", ("id", string(b->id()))("previous", string(b->previous)) ); - auto result = std::make_shared( **prior, move(b), trust ); + auto result = std::make_shared( **prior, move(b), skip_validate_signee ); EOS_ASSERT( result, fork_database_exception , "fail to add new block state" ); - return add(result); + return add(result, true); } const block_state_ptr& fork_database::head()const { return my->head; } diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 2b68d015442..3a81b3ffc9d 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -575,12 +575,6 @@ class apply_context { void add_ram_usage( account_name account, int64_t ram_delta ); void finalize_trace( action_trace& trace, const fc::time_point& start ); - private: - - void validate_referenced_accounts( const transaction& t )const; - void validate_expiration( const transaction& t )const; - - /// Fields: public: diff --git a/libraries/chain/include/eosio/chain/authority_checker.hpp b/libraries/chain/include/eosio/chain/authority_checker.hpp index 5f1fdfbfb76..068cc5a9137 100644 --- a/libraries/chain/include/eosio/chain/authority_checker.hpp +++ b/libraries/chain/include/eosio/chain/authority_checker.hpp @@ -7,8 +7,7 @@ #include #include #include - -#include +#include #include @@ -148,11 +147,11 @@ namespace detail { bool all_keys_used() const { return boost::algorithm::all_of_equal(_used_keys, true); } flat_set used_keys() const { - auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, true); + auto range = filter_data_by_marker(provided_keys, _used_keys, true); return {range.begin(), range.end()}; } flat_set unused_keys() const { - auto range = utilities::filter_data_by_marker(provided_keys, _used_keys, false); + auto range = filter_data_by_marker(provided_keys, _used_keys, false); return {range.begin(), range.end()}; } diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index ecd272353d4..c318843d5df 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace eosio { namespace chain { @@ -51,6 +52,7 @@ struct block_header_state { digest_type sig_digest()const; void sign( const std::function& signer ); public_key_type signee()const; + void verify_signee(const public_key_type& signee)const; }; diff --git a/libraries/chain/include/eosio/chain/block_state.hpp b/libraries/chain/include/eosio/chain/block_state.hpp index 73602023a42..6870d04f5b2 100644 --- a/libraries/chain/include/eosio/chain/block_state.hpp +++ b/libraries/chain/include/eosio/chain/block_state.hpp @@ -12,8 +12,8 @@ namespace eosio { namespace chain { struct block_state : public block_header_state { - block_state( const block_header_state& cur ):block_header_state(cur){} - block_state( const block_header_state& prev, signed_block_ptr b, bool trust = false ); + explicit block_state( const block_header_state& cur ):block_header_state(cur){} + block_state( const block_header_state& prev, signed_block_ptr b, bool skip_validate_signee ); block_state( const block_header_state& prev, block_timestamp_type when ); block_state() = default; diff --git a/libraries/chain/include/eosio/chain/chain_config.hpp b/libraries/chain/include/eosio/chain/chain_config.hpp index 907846d1a55..649d11a3cdd 100644 --- a/libraries/chain/include/eosio/chain/chain_config.hpp +++ b/libraries/chain/include/eosio/chain/chain_config.hpp @@ -60,10 +60,50 @@ struct chain_config { << "Max Inline Action Depth: " << c.max_inline_action_depth << ", " << "Max Authority Depth: " << c.max_authority_depth << "\n"; } -}; - bool operator==(const chain_config& a, const chain_config& b); -inline bool operator!=(const chain_config& a, const chain_config& b) { return !(a == b); } + friend inline bool operator ==( const chain_config& lhs, const chain_config& rhs ) { + return std::tie( lhs.max_block_net_usage, + lhs.target_block_net_usage_pct, + lhs.max_transaction_net_usage, + lhs.base_per_transaction_net_usage, + lhs.net_usage_leeway, + lhs.context_free_discount_net_usage_num, + lhs.context_free_discount_net_usage_den, + lhs.max_block_cpu_usage, + lhs.target_block_cpu_usage_pct, + lhs.max_transaction_cpu_usage, + lhs.max_transaction_cpu_usage, + lhs.max_transaction_lifetime, + lhs.deferred_trx_expiration_window, + lhs.max_transaction_delay, + lhs.max_inline_action_size, + lhs.max_inline_action_depth, + lhs.max_authority_depth + ) + == + std::tie( rhs.max_block_net_usage, + rhs.target_block_net_usage_pct, + rhs.max_transaction_net_usage, + rhs.base_per_transaction_net_usage, + rhs.net_usage_leeway, + rhs.context_free_discount_net_usage_num, + rhs.context_free_discount_net_usage_den, + rhs.max_block_cpu_usage, + rhs.target_block_cpu_usage_pct, + rhs.max_transaction_cpu_usage, + rhs.max_transaction_cpu_usage, + rhs.max_transaction_lifetime, + rhs.deferred_trx_expiration_window, + rhs.max_transaction_delay, + rhs.max_inline_action_size, + rhs.max_inline_action_depth, + rhs.max_authority_depth + ); + }; + + friend inline bool operator !=( const chain_config& lhs, const chain_config& rhs ) { return !(lhs == rhs); } + +}; // *bos* struct chain_config2 { diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 6aea7c3e3bd..4fb86f86ae8 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -80,6 +80,7 @@ const static uint32_t default_max_trx_delay = 45*24*3600; // const static uint32_t default_max_inline_action_size = 4 * 1024; // 4 KB const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; +const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024; // Should be large enough to allow recovery from badly set blockchain parameters without a hard fork diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index b3428340823..8be51a98daf 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -131,14 +131,14 @@ namespace eosio { namespace chain { typedef secondary_index::index_index index256_index; struct soft_double_less { - bool operator()( const float64_t& lhs, const float64_t& rhs )const { - return f64_lt(lhs, rhs); + bool operator()( const float64_t& lhs, const float64_t& rhs ) const { + return f64_lt( lhs, rhs ); } }; struct soft_long_double_less { - bool operator()( const float128_t lhs, const float128_t& rhs )const { - return f128_lt(lhs, rhs); + bool operator()( const float128_t& lhs, const float128_t& rhs ) const { + return f128_lt( lhs, rhs ); } }; @@ -147,6 +147,7 @@ namespace eosio { namespace chain { * * The software double implementation is using the Berkeley softfloat library (release 3). */ + typedef secondary_index::index_object index_double_object; typedef secondary_index::index_index index_double_index; @@ -158,6 +159,65 @@ namespace eosio { namespace chain { typedef secondary_index::index_object index_long_double_object; typedef secondary_index::index_index index_long_double_index; + template + struct secondary_key_traits { + using value_type = std::enable_if_t::value, T>; + + static_assert( std::numeric_limits::is_specialized, "value_type does not have specialized numeric_limits" ); + + static constexpr value_type true_lowest() { return std::numeric_limits::lowest(); } + static constexpr value_type true_highest() { return std::numeric_limits::max(); } + }; + + template + struct secondary_key_traits> { + private: + static constexpr uint128_t max_uint128 = (static_cast(std::numeric_limits::max()) << 64) | std::numeric_limits::max(); + static_assert( std::numeric_limits::max() == max_uint128, "numeric_limits for uint128_t is not properly defined" ); + + public: + using value_type = std::array; + + static value_type true_lowest() { + value_type arr; + return arr; + } + + static value_type true_highest() { + value_type arr; + for( auto& v : arr ) { + v = std::numeric_limits::max(); + } + return arr; + } + }; + + template<> + struct secondary_key_traits { + using value_type = float64_t; + + static value_type true_lowest() { + return f64_negative_infinity(); + } + + static value_type true_highest() { + return f64_positive_infinity(); + } + }; + + template<> + struct secondary_key_traits { + using value_type = float128_t; + + static value_type true_lowest() { + return f128_negative_infinity(); + } + + static value_type true_highest() { + return f128_positive_infinity(); + } + }; + /** * helper template to map from an index type to the best tag * to use when traversing by table_id @@ -185,7 +245,7 @@ namespace config { template<> struct billable_size { static const uint64_t overhead = overhead_per_row_per_index_ram_bytes * 2; ///< overhead for 2x indices internal-key and code,scope,table - static const uint64_t value = 44 + overhead; ///< 36 bytes for constant size fields + overhead + static const uint64_t value = 44 + overhead; ///< 44 bytes for constant size fields + overhead }; template<> diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 17ca27b3235..62251d08512 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -66,6 +66,7 @@ namespace eosio { namespace chain { public: struct config { + flat_set sender_bypass_whiteblacklist; flat_set actor_whitelist; flat_set actor_blacklist; flat_set contract_whitelist; @@ -78,6 +79,7 @@ namespace eosio { namespace chain { uint64_t state_guard_size = chain::config::default_state_guard_size; uint64_t reversible_cache_size = chain::config::default_reversible_cache_size; uint64_t reversible_guard_size = chain::config::default_reversible_guard_size; + uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size; bool read_only = false; bool force_all_checks = false; bool disable_replay_opts = false; @@ -105,7 +107,7 @@ namespace eosio { namespace chain { ~controller(); void add_indices(); - void startup( const snapshot_reader_ptr& snapshot = nullptr ); + void startup( std::function shutdown, const snapshot_reader_ptr& snapshot = nullptr ); /** * Starts a new pending block session upon which new transactions can @@ -155,13 +157,8 @@ namespace eosio { namespace chain { void commit_block(); void pop_block(); - void push_block( const signed_block_ptr& b, block_status s = block_status::complete ); - - /** - * Call this method when a producer confirmation is received, this might update - * the last bft irreversible block and/or cause a switch of forks - */ - void push_confirmation( const header_confirmation& c ); + std::future create_block_state_future( const signed_block_ptr& b ); + void push_block( std::future& block_state_future ); const chainbase::database& db()const; @@ -224,6 +221,8 @@ namespace eosio { namespace chain { sha256 calculate_integrity_hash()const; void write_snapshot( const snapshot_writer_ptr& snapshot )const; + bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const; + void check_actor_list( const flat_set& actors )const; void check_contract_list( account_name code )const; void check_action_list( account_name code, action_name action )const; void check_key_list( const public_key_type& key )const; @@ -245,7 +244,6 @@ namespace eosio { namespace chain { bool is_resource_greylisted(const account_name &name) const; const flat_set &get_resource_greylist() const; - void validate_referenced_accounts( const transaction& t )const; void validate_expiration( const transaction& t )const; void validate_tapos( const transaction& t )const; void validate_db_available_size() const; diff --git a/libraries/chain/include/eosio/chain/database_utils.hpp b/libraries/chain/include/eosio/chain/database_utils.hpp index e2b0c0d487f..eee26bce1c0 100644 --- a/libraries/chain/include/eosio/chain/database_utils.hpp +++ b/libraries/chain/include/eosio/chain/database_utils.hpp @@ -216,4 +216,3 @@ DataStream& operator >> ( DataStream& ds, float128_t& v ) { fc::raw::unpack(ds, *reinterpret_cast(&v)); return ds; } - diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 2dc5e114d03..01a42793e94 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -439,8 +439,8 @@ namespace eosio { namespace chain { 3160007, "Invalid contract vm version" ) FC_DECLARE_DERIVED_EXCEPTION( set_exact_code, contract_exception, 3160008, "Contract is already running this version of code" ) - FC_DECLARE_DERIVED_EXCEPTION( wast_file_not_found, contract_exception, - 3160009, "No wast file found" ) + FC_DECLARE_DERIVED_EXCEPTION( wasm_file_not_found, contract_exception, + 3160009, "No wasm file found" ) FC_DECLARE_DERIVED_EXCEPTION( abi_file_not_found, contract_exception, 3160010, "No abi file found" ) diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 529a43a0a05..998157ab41a 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -36,12 +36,12 @@ namespace eosio { namespace chain { */ void set( block_state_ptr s ); - /** this method will attempt to append the block to an exsting + /** this method will attempt to append the block to an existing * block_state and will return a pointer to the new block state or * throw on error. */ - block_state_ptr add( signed_block_ptr b, bool trust = false ); - block_state_ptr add( block_state_ptr next_block ); + block_state_ptr add( signed_block_ptr b, bool skip_validate_signee ); + block_state_ptr add( const block_state_ptr& next_block, bool skip_validate_previous ); void remove( const block_id_type& id ); void add( const header_confirmation& c ); diff --git a/libraries/chain/include/eosio/chain/genesis_state.hpp b/libraries/chain/include/eosio/chain/genesis_state.hpp index 9fd05a82dc6..7b1da43043f 100644 --- a/libraries/chain/include/eosio/chain/genesis_state.hpp +++ b/libraries/chain/include/eosio/chain/genesis_state.hpp @@ -51,6 +51,14 @@ struct genesis_state { * This is the SHA256 serialization of the genesis_state. */ chain_id_type compute_chain_id() const; + + friend inline bool operator==( const genesis_state& lhs, const genesis_state& rhs ) { + return std::tie( lhs.initial_configuration, lhs.initial_timestamp, lhs.initial_key ) + == std::tie( rhs.initial_configuration, rhs.initial_timestamp, rhs.initial_key ); + }; + + friend inline bool operator!=( const genesis_state& lhs, const genesis_state& rhs ) { return !(lhs == rhs); } + }; } } // namespace eosio::chain diff --git a/libraries/utilities/include/eosio/utilities/parallel_markers.hpp b/libraries/chain/include/eosio/chain/parallel_markers.hpp similarity index 95% rename from libraries/utilities/include/eosio/utilities/parallel_markers.hpp rename to libraries/chain/include/eosio/chain/parallel_markers.hpp index 0d6aa5a9821..c78ebdabdae 100644 --- a/libraries/utilities/include/eosio/utilities/parallel_markers.hpp +++ b/libraries/chain/include/eosio/chain/parallel_markers.hpp @@ -8,7 +8,7 @@ #include #include -namespace eosio { namespace utilities { +namespace eosio { namespace chain { /** * @brief Return values in DataRange corresponding to matching Markers @@ -39,5 +39,5 @@ DataRange filter_data_by_marker(DataRange data, MarkerRange markers, const Marke return {range.begin(), range.end()}; } -}} // namespace eosio::utilities +}} // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index b69a00143e9..2e215f00ec2 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -56,6 +56,8 @@ namespace eosio { namespace chain { std::tuple max_bandwidth_billed_accounts_can_pay( bool force_elastic_limits = false )const; + void validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const; + private: friend struct controller_impl; @@ -95,7 +97,7 @@ namespace eosio { namespace chain { fc::microseconds delay; bool is_input = false; bool apply_context_free = true; - bool can_subjectively_fail = true; + bool enforce_whiteblacklist = true; fc::time_point deadline = fc::time_point::maximum(); fc::microseconds leeway = fc::microseconds(3000); diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 44d5d008a79..c5eb0c790f4 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -4,8 +4,8 @@ */ #pragma once #include -#include -#include +#include +#include namespace eosio { namespace chain { @@ -20,6 +20,7 @@ class transaction_metadata { signed_transaction trx; packed_transaction packed_trx; optional>> signing_keys; + std::future>> signing_keys_future; bool accepted = false; bool implicit = false; bool scheduled = false; @@ -39,8 +40,16 @@ class transaction_metadata { } const flat_set& recover_keys( const chain_id_type& chain_id ) { - if( !signing_keys || signing_keys->first != chain_id ) // Unlikely for more than one chain_id to be used in one nodeos instance - signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id ) ); + // Unlikely for more than one chain_id to be used in one nodeos instance + if( !signing_keys || signing_keys->first != chain_id ) { + if( signing_keys_future.valid() ) { + signing_keys = signing_keys_future.get(); + if( signing_keys->first == chain_id ) { + return signing_keys->second; + } + } + signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id )); + } return signing_keys->second; } diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index c49f76ce771..6e6639bac52 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -87,7 +87,7 @@ flat_set transaction::get_signature_keys( const vector recovered_pub_keys; diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 476a78d982b..989905ef9a0 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -26,7 +26,7 @@ namespace bacc = boost::accumulators; struct deadline_timer_verify { deadline_timer_verify() { //keep longest first in list. You're effectively going to take test_intervals[0]*sizeof(test_intervals[0]) - //time to do the the "calibration" + //time to do the the "calibration" int test_intervals[] = {50000, 10000, 5000, 1000, 500, 100, 50, 10}; struct sigaction act; @@ -314,7 +314,7 @@ namespace bacc = boost::accumulators; if (!control.skip_trx_checks()) { control.validate_expiration(trx); control.validate_tapos(trx); - control.validate_referenced_accounts(trx); + validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() ); } init( initial_net_usage); if (!skip_recording) @@ -615,5 +615,43 @@ namespace bacc = boost::accumulators; } } /// record_transaction + void transaction_context::validate_referenced_accounts( const transaction& trx, bool enforce_actor_whitelist_blacklist )const { + const auto& db = control.db(); + const auto& auth_manager = control.get_authorization_manager(); + + for( const auto& a : trx.context_free_actions ) { + auto* code = db.find(a.account); + EOS_ASSERT( code != nullptr, transaction_exception, + "action's code account '${account}' does not exist", ("account", a.account) ); + EOS_ASSERT( a.authorization.size() == 0, transaction_exception, + "context-free actions cannot have authorizations" ); + } + + flat_set actors; + + bool one_auth = false; + for( const auto& a : trx.actions ) { + auto* code = db.find(a.account); + EOS_ASSERT( code != nullptr, transaction_exception, + "action's code account '${account}' does not exist", ("account", a.account) ); + for( const auto& auth : a.authorization ) { + one_auth = true; + auto* actor = db.find(auth.actor); + EOS_ASSERT( actor != nullptr, transaction_exception, + "action's authorizing actor '${account}' does not exist", ("account", auth.actor) ); + EOS_ASSERT( auth_manager.find_permission(auth) != nullptr, transaction_exception, + "action's authorizations include a non-existent permission: {permission}", + ("permission", auth) ); + if( enforce_actor_whitelist_blacklist ) + actors.insert( auth.actor ); + } + } + EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" ); + + if( enforce_actor_whitelist_blacklist ) { + control.check_actor_list( actors ); + } + } + } } /// eosio::chain diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index f63d836d377..9204f3d27bb 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -273,8 +273,8 @@ class softfloat_api : public context_aware_api { if (is_nan(b)) { return bf; } - if ( sign_bit(a) != sign_bit(b) ) { - return sign_bit(a) ? af : bf; + if ( f32_sign_bit(a) != f32_sign_bit(b) ) { + return f32_sign_bit(a) ? af : bf; } return f32_lt(a,b) ? af : bf; } @@ -287,8 +287,8 @@ class softfloat_api : public context_aware_api { if (is_nan(b)) { return bf; } - if ( sign_bit(a) != sign_bit(b) ) { - return sign_bit(a) ? bf : af; + if ( f32_sign_bit(a) != f32_sign_bit(b) ) { + return f32_sign_bit(a) ? bf : af; } return f32_lt( a, b ) ? bf : af; } @@ -440,8 +440,8 @@ class softfloat_api : public context_aware_api { return af; if (is_nan(b)) return bf; - if (sign_bit(a) != sign_bit(b)) - return sign_bit(a) ? af : bf; + if (f64_sign_bit(a) != f64_sign_bit(b)) + return f64_sign_bit(a) ? af : bf; return f64_lt( a, b ) ? af : bf; } double _eosio_f64_max( double af, double bf ) { @@ -451,8 +451,8 @@ class softfloat_api : public context_aware_api { return af; if (is_nan(b)) return bf; - if (sign_bit(a) != sign_bit(b)) - return sign_bit(a) ? bf : af; + if (f64_sign_bit(a) != f64_sign_bit(b)) + return f64_sign_bit(a) ? bf : af; return f64_lt( a, b ) ? bf : af; } double _eosio_f64_copysign( double af, double bf ) { @@ -686,32 +686,17 @@ class softfloat_api : public context_aware_api { } static bool is_nan( const float32_t f ) { - return ((f.v & 0x7FFFFFFF) > 0x7F800000); + return f32_is_nan( f ); } static bool is_nan( const float64_t f ) { - return ((f.v & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000); + return f64_is_nan( f ); } static bool is_nan( const float128_t& f ) { - return (((~(f.v[1]) & uint64_t( 0x7FFF000000000000 )) == 0) && (f.v[0] || ((f.v[1]) & uint64_t( 0x0000FFFFFFFFFFFF )))); - } - static float32_t to_softfloat32( float f ) { - return *reinterpret_cast(&f); - } - static float64_t to_softfloat64( double d ) { - return *reinterpret_cast(&d); - } - static float from_softfloat32( float32_t f ) { - return *reinterpret_cast(&f); - } - static double from_softfloat64( float64_t d ) { - return *reinterpret_cast(&d); + return f128_is_nan( f ); } + static constexpr uint32_t inv_float_eps = 0x4B000000; static constexpr uint64_t inv_double_eps = 0x4330000000000000; - - static bool sign_bit( float32_t f ) { return f.v >> 31; } - static bool sign_bit( float64_t f ) { return f.v >> 63; } - }; class producer_api : public context_aware_api { @@ -958,7 +943,6 @@ class context_free_system_api : public context_aware_api { :context_aware_api(ctx,true){} void abort() { - edump(("abort() called")); EOS_ASSERT( false, abort_called, "abort() called"); } @@ -966,7 +950,6 @@ class context_free_system_api : public context_aware_api { void eosio_assert( bool condition, null_terminated_ptr msg ) { if( BOOST_UNLIKELY( !condition ) ) { std::string message( msg ); - edump((message)); EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) ); } } @@ -974,14 +957,12 @@ class context_free_system_api : public context_aware_api { void eosio_assert_message( bool condition, array_ptr msg, size_t msg_len ) { if( BOOST_UNLIKELY( !condition ) ) { std::string message( msg, msg_len ); - edump((message)); EOS_THROW( eosio_assert_message_exception, "assertion failure with message: ${s}", ("s",message) ); } } void eosio_assert_code( bool condition, uint64_t error_code ) { if( BOOST_UNLIKELY( !condition ) ) { - edump((error_code)); EOS_THROW( eosio_assert_code_exception, "assertion failure with error code: ${error_code}", ("error_code", error_code) ); } @@ -1406,6 +1387,23 @@ class context_free_transaction_api : public context_aware_api { seq = context.global_action_sequence; } + bool has_contract(account_name name){ + const auto accnt = context.db.find( name ); + EOS_ASSERT( accnt != nullptr, action_validate_exception, "account '${account}' does not exist", ("account", name) ); + return accnt->code.size() > 0; + } + + void get_contract_code(account_name name, fc::sha256& code ) { + const auto accnt = context.db.find( name ); + EOS_ASSERT( accnt != nullptr, action_validate_exception, "account '${account}' does not exist", ("account", name) ); + + if( accnt->code.size() > 0) { + code = fc::sha256::hash( accnt->code.data(), accnt->code.size() ); + } else { + code = fc::sha256(); + } + } + int expiration() { return context.trx_context.trx.expiration.sec_since_epoch(); } @@ -1559,18 +1557,18 @@ class compiler_builtins : public context_aware_api { // conversion long double void __extendsftf2( float128_t& ret, float f ) { - ret = f32_to_f128( softfloat_api::to_softfloat32(f) ); + ret = f32_to_f128( to_softfloat32(f) ); } void __extenddftf2( float128_t& ret, double d ) { - ret = f64_to_f128( softfloat_api::to_softfloat64(d) ); + ret = f64_to_f128( to_softfloat64(d) ); } double __trunctfdf2( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; - return softfloat_api::from_softfloat64(f128_to_f64( f )); + return from_softfloat64(f128_to_f64( f )); } float __trunctfsf2( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; - return softfloat_api::from_softfloat32(f128_to_f32( f )); + return from_softfloat32(f128_to_f32( f )); } int32_t __fixtfsi( uint64_t l, uint64_t h ) { float128_t f = {{ l, h }}; @@ -1597,19 +1595,19 @@ class compiler_builtins : public context_aware_api { ret = ___fixunstfti( f ); } void __fixsfti( __int128& ret, float a ) { - ret = ___fixsfti( softfloat_api::to_softfloat32(a).v ); + ret = ___fixsfti( to_softfloat32(a).v ); } void __fixdfti( __int128& ret, double a ) { - ret = ___fixdfti( softfloat_api::to_softfloat64(a).v ); + ret = ___fixdfti( to_softfloat64(a).v ); } void __fixunssfti( unsigned __int128& ret, float a ) { - ret = ___fixunssfti( softfloat_api::to_softfloat32(a).v ); + ret = ___fixunssfti( to_softfloat32(a).v ); } void __fixunsdfti( unsigned __int128& ret, double a ) { - ret = ___fixunsdfti( softfloat_api::to_softfloat64(a).v ); + ret = ___fixunsdfti( to_softfloat64(a).v ); } double __floatsidf( int32_t i ) { - return softfloat_api::from_softfloat64(i32_to_f64(i)); + return from_softfloat64(i32_to_f64(i)); } void __floatsitf( float128_t& ret, int32_t i ) { ret = i32_to_f128(i); @@ -1946,6 +1944,8 @@ REGISTER_INTRINSICS(context_free_transaction_api, (transaction_size, int() ) (get_transaction_id, void(int) ) (get_action_sequence, void(int) ) + (has_contract, int(int64_t) ) + (get_contract_code, void(int64_t, int) ) (expiration, int() ) (tapos_block_prefix, int() ) (tapos_block_num, int() ) diff --git a/libraries/fc b/libraries/fc index 9adee183df3..e5ad1ad65b0 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 9adee183df3ce4170d1f362c96d960132bd77ed9 +Subproject commit e5ad1ad65b012103222a113239a28fc1e4bddbb4 diff --git a/libraries/softfloat b/libraries/softfloat index 9942875eb70..203b6df7ded 160000 --- a/libraries/softfloat +++ b/libraries/softfloat @@ -1 +1 @@ -Subproject commit 9942875eb704369db297eb289aa4e9912bddcfb8 +Subproject commit 203b6df7dedc5bae1b2a7b1b23562335a6344578 diff --git a/libraries/testing/CMakeLists.txt b/libraries/testing/CMakeLists.txt index 620c7fb4003..eaf9bf87502 100644 --- a/libraries/testing/CMakeLists.txt +++ b/libraries/testing/CMakeLists.txt @@ -7,7 +7,7 @@ add_library( eosio_testing ${HEADERS} ) -target_link_libraries( eosio_testing eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime ) +target_link_libraries( eosio_testing eosio_chain fc chainbase Logging IR WAST WASM Runtime ) target_include_directories( eosio_testing PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 22e52407953..906d2cb3c44 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -91,6 +91,7 @@ namespace eosio { namespace testing { virtual signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0; virtual signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0/*skip_missed_block_penalty*/ ) = 0; + virtual signed_block_ptr finish_block() = 0; void produce_blocks( uint32_t n = 1, bool empty = false ); void produce_blocks_until_end_of_round(); void produce_blocks_for_n_rounds(const uint32_t num_of_rounds = 1); @@ -271,6 +272,7 @@ namespace eosio { namespace testing { protected: signed_block_ptr _produce_block( fc::microseconds skip_time, bool skip_pending_trxs = false, uint32_t skip_flag = 0 ); void _start_block(fc::time_point block_time); + signed_block_ptr _finish_block(); // Fields: protected: @@ -304,6 +306,10 @@ namespace eosio { namespace testing { return _produce_block(skip_time, true, skip_flag); } + signed_block_ptr finish_block()override { + return _finish_block(); + } + bool validate() { return true; } }; @@ -351,7 +357,7 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(true); } @@ -366,14 +372,15 @@ namespace eosio { namespace testing { validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); init(config); } signed_block_ptr produce_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override { auto sb = _produce_block(skip_time, false, skip_flag | 2); - validating_node->push_block( sb ); + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); return sb; } @@ -383,19 +390,23 @@ namespace eosio { namespace testing { } void validate_push_block(const signed_block_ptr& sb) { - validating_node->push_block( sb ); + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); } signed_block_ptr produce_empty_block( fc::microseconds skip_time = fc::milliseconds(config::block_interval_ms), uint32_t skip_flag = 0 /*skip_missed_block_penalty*/ )override { control->abort_block(); auto sb = _produce_block(skip_time, true, skip_flag | 2); - validating_node->push_block( sb ); - - + auto bs = validating_node->create_block_state_future( sb ); + validating_node->push_block( bs ); return sb; } + signed_block_ptr finish_block()override { + return _finish_block(); + } + bool validate() { @@ -411,7 +422,7 @@ namespace eosio { namespace testing { validating_node.reset(); validating_node = std::make_unique(vcfg); validating_node->add_indices(); - validating_node->startup(); + validating_node->startup( []() { return false; } ); return ok; } diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index b116d1a4969..a2307904da3 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -124,7 +124,7 @@ namespace eosio { namespace testing { void base_tester::open( const snapshot_reader_ptr& snapshot) { control.reset( new controller(cfg) ); control->add_indices(); - control->startup(snapshot); + control->startup( []() { return false; }, snapshot); chain_transactions.clear(); control->accepted_block.connect([this]( const block_state_ptr& block_state ){ FC_ASSERT( block_state->block ); @@ -141,8 +141,9 @@ namespace eosio { namespace testing { } signed_block_ptr base_tester::push_block(signed_block_ptr b) { + auto bs = control->create_block_state_future(b); control->abort_block(); - control->push_block(b); + control->push_block(bs); auto itr = last_produced_block.find(b->producer); if (itr == last_produced_block.end() || block_header::num_from_id(b->id()) > block_header::num_from_id(itr->second)) { @@ -161,17 +162,6 @@ namespace eosio { namespace testing { _start_block( next_time ); } - auto producer = control->head_block_state()->get_scheduled_producer(next_time); - private_key_type priv_key; - // Check if signing private key exist in the list - auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key ); - if( private_key_itr == block_signing_private_keys.end() ) { - // If it's not found, default to active k1 key - priv_key = get_private_key( producer.producer_name, "active" ); - } else { - priv_key = private_key_itr->second; - } - if( !skip_pending_trxs ) { auto unapplied_trxs = control->get_unapplied_transactions(); for (const auto& trx : unapplied_trxs ) { @@ -192,18 +182,10 @@ namespace eosio { namespace testing { } } - - - control->finalize_block(); - control->sign_block( [&]( digest_type d ) { - return priv_key.sign(d); - }); - - control->commit_block(); - last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id; + auto head_block = _finish_block(); _start_block( next_time + fc::microseconds(config::block_interval_us)); - return control->head_block_state()->block; + return head_block; } void base_tester::_start_block(fc::time_point block_time) { @@ -220,6 +202,30 @@ namespace eosio { namespace testing { control->start_block( block_time, head_block_number - last_produced_block_num ); } + signed_block_ptr base_tester::_finish_block() { + FC_ASSERT( control->pending_block_state(), "must first start a block before it can be finished" ); + + auto producer = control->head_block_state()->get_scheduled_producer( control->pending_block_time() ); + private_key_type priv_key; + // Check if signing private key exist in the list + auto private_key_itr = block_signing_private_keys.find( producer.block_signing_key ); + if( private_key_itr == block_signing_private_keys.end() ) { + // If it's not found, default to active k1 key + priv_key = get_private_key( producer.producer_name, "active" ); + } else { + priv_key = private_key_itr->second; + } + + control->finalize_block(); + control->sign_block( [&]( digest_type d ) { + return priv_key.sign(d); + }); + + control->commit_block(); + last_produced_block[control->head_block_state()->header.producer] = control->head_block_state()->id; + + return control->head_block_state()->block; + } void base_tester::produce_blocks( uint32_t n, bool empty ) { if( empty ) { @@ -795,8 +801,9 @@ namespace eosio { namespace testing { for( int i = 1; i <= a.control->head_block_num(); ++i ) { auto block = a.control->fetch_block_by_number(i); if( block ) { //&& !b.control->is_known_block(block->id()) ) { + auto bs = b.control->create_block_state_future( block ); b.control->abort_block(); - b.control->push_block(block); //, eosio::chain::validation_steps::created_block); + b.control->push_block(bs); //, eosio::chain::validation_steps::created_block); } } }; diff --git a/libraries/utilities/CMakeLists.txt b/libraries/utilities/CMakeLists.txt deleted file mode 100644 index 4aed508d14f..00000000000 --- a/libraries/utilities/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -#list( APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/libraries/fc/GitVersionGen" ) -#include( GetGitRevisionDescription ) -#get_git_head_revision(GIT_REFSPEC EOS_GIT_REVISION_SHA) -#get_git_unix_timestamp(EOS_GIT_REVISION_UNIX_TIMESTAMP) -#git_describe(EOS_GIT_REVISION_DESCRIPTION --tags) -if(NOT EOS_GIT_REVISION_DESCRIPTION) - set(EOS_GIT_REVISION_DESCRIPTION "unknown") -endif(NOT EOS_GIT_REVISION_DESCRIPTION) - -file(GLOB HEADERS "include/eosio/utilities/*.hpp") - -set(sources - key_conversion.cpp - string_escape.cpp - tempdir.cpp - words.cpp - ${HEADERS}) - -#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/git_revision.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp" @ONLY) -#list(APPEND sources "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp") - -add_library( eos_utilities - ${sources} - ${HEADERS} ) -target_link_libraries( eos_utilities fc WAST WASM ) -target_include_directories( eos_utilities - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_SOURCE_DIR}/../wasm-jit/Include" ) -if (USE_PCH) - set_target_properties(eos_utilities PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) - cotire(eos_utilities) -endif(USE_PCH) diff --git a/libraries/utilities/git_revision.cpp.in b/libraries/utilities/git_revision.cpp.in deleted file mode 100644 index 9c52da41307..00000000000 --- a/libraries/utilities/git_revision.cpp.in +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -#define EOS_GIT_REVISION_SHA "@EOS_GIT_REVISION_SHA@" -#define EOS_GIT_REVISION_UNIX_TIMESTAMP @EOS_GIT_REVISION_UNIX_TIMESTAMP@ -#define EOS_GIT_REVISION_DESCRIPTION "@EOS_GIT_REVISION_DESCRIPTION@" - -namespace eosio { namespace utilities { - -const char* const git_revision_sha = EOS_GIT_REVISION_SHA; -const uint32_t git_revision_unix_timestamp = EOS_GIT_REVISION_UNIX_TIMESTAMP; -const char* const git_revision_description = EOS_GIT_REVISION_DESCRIPTION; - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/common.hpp b/libraries/utilities/include/eosio/utilities/common.hpp deleted file mode 100644 index 793a3d58e7a..00000000000 --- a/libraries/utilities/include/eosio/utilities/common.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - * - */ -#pragma once - -#ifndef COMMON_HPP -#define COMMON_HPP - -namespace eosio { namespace utilities { namespace common { - template - std::string itoh(I n, size_t hlen = sizeof(I)<<1) { - static const char* digits = "0123456789abcdef"; - std::string r(hlen, '0'); - for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4) - r[i] = digits[(n>>j) & 0x0f]; - return r; - } -}}} - -#endif // COMMON_HPP diff --git a/libraries/utilities/include/eosio/utilities/git_revision.hpp b/libraries/utilities/include/eosio/utilities/git_revision.hpp deleted file mode 100644 index 85697d645eb..00000000000 --- a/libraries/utilities/include/eosio/utilities/git_revision.hpp +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once -#include - -namespace eosio { namespace utilities { - -extern const char* const git_revision_sha; -extern const uint32_t git_revision_unix_timestamp; -extern const char* const git_revision_description; - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/key_conversion.hpp b/libraries/utilities/include/eosio/utilities/key_conversion.hpp deleted file mode 100644 index 0d6daaf903a..00000000000 --- a/libraries/utilities/include/eosio/utilities/key_conversion.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include -#include -#include - -namespace eosio { namespace utilities { - -std::string key_to_wif(const fc::sha256& private_secret ); -std::string key_to_wif(const fc::ecc::private_key& key); -fc::optional wif_to_key( const std::string& wif_key ); - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/padding_ostream.hpp b/libraries/utilities/include/eosio/utilities/padding_ostream.hpp deleted file mode 100644 index fbf7a34396a..00000000000 --- a/libraries/utilities/include/eosio/utilities/padding_ostream.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -namespace eosio { namespace utilities { - -template -class padding_ostream : public fc::buffered_ostream { -public: - padding_ostream( fc::ostream_ptr o, size_t bufsize = 4096 ) : buffered_ostream(o, bufsize) {} - virtual ~padding_ostream() {} - - virtual size_t writesome( const char* buffer, size_t len ) { - auto out = buffered_ostream::writesome(buffer, len); - bytes_out += out; - bytes_out %= BlockSize; - return out; - } - virtual size_t writesome( const std::shared_ptr& buf, size_t len, size_t offset ) { - auto out = buffered_ostream::writesome(buf, len, offset); - bytes_out += out; - bytes_out %= BlockSize; - return out; - } - virtual void flush() { - static const char pad = PaddingChar; - while( bytes_out % BlockSize ) - writesome(&pad, 1); - buffered_ostream::flush(); - } - -private: - size_t bytes_out = 0; -}; - -} } //eosio::utilities - diff --git a/libraries/utilities/include/eosio/utilities/rand.hpp b/libraries/utilities/include/eosio/utilities/rand.hpp deleted file mode 100644 index 556f706d1b3..00000000000 --- a/libraries/utilities/include/eosio/utilities/rand.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#ifndef RAND_HPP -#define RAND_HPP 1 - -#include - -namespace eosio { namespace utilities { namespace rand { - -/// High performance random generator -/// http://xorshift.di.unimi.it/ - -class random { -private: - - uint64_t seed; - -public: - - random(uint64_t seed) { - this->seed = seed; - } - - uint64_t next() { - uint64_t z = (seed += UINT64_C(0x9E3779B97F4A7C15)); - z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); - z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB); - return z ^ (z >> 31); - } - - template - void shuffle(Range&& range) { - int idx_count = range.size(); - for (auto idx = range.rbegin(); idx != range.rend() - 1; ++idx , --idx_count) { - std::swap(range.at(next() % idx_count), *idx); - } - } -}; - -} } } //eosio::utilities::rand - -#endif // RAND_HPP diff --git a/libraries/utilities/include/eosio/utilities/string_escape.hpp b/libraries/utilities/include/eosio/utilities/string_escape.hpp deleted file mode 100644 index 03870b73e2d..00000000000 --- a/libraries/utilities/include/eosio/utilities/string_escape.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include - -namespace eosio { namespace utilities { - - std::string escape_string_for_c_source_code(const std::string& input); - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/tempdir.hpp b/libraries/utilities/include/eosio/utilities/tempdir.hpp deleted file mode 100644 index 0151a7d88a7..00000000000 --- a/libraries/utilities/include/eosio/utilities/tempdir.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -#include - -#include - -namespace eosio { namespace utilities { - -fc::path temp_directory_path(); - -} } // eosio::utilities diff --git a/libraries/utilities/include/eosio/utilities/words.hpp b/libraries/utilities/include/eosio/utilities/words.hpp deleted file mode 100644 index cc1ead427a7..00000000000 --- a/libraries/utilities/include/eosio/utilities/words.hpp +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#pragma once - -namespace eosio { namespace words { - -typedef const char* const_char_ptr; -extern const const_char_ptr word_list[]; -extern const uint32_t word_list_size; - -} } diff --git a/libraries/utilities/key_conversion.cpp b/libraries/utilities/key_conversion.cpp deleted file mode 100644 index 693514f6c99..00000000000 --- a/libraries/utilities/key_conversion.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include -#include - -namespace eosio { namespace utilities { - -std::string key_to_wif(const fc::sha256& secret ) -{ - const size_t size_of_data_to_hash = sizeof(secret) + 1; - const size_t size_of_hash_bytes = 4; - char data[size_of_data_to_hash + size_of_hash_bytes]; - data[0] = (char)0x80; - memcpy(&data[1], (char*)&secret, sizeof(secret)); - fc::sha256 digest = fc::sha256::hash(data, size_of_data_to_hash); - digest = fc::sha256::hash(digest); - memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); - return fc::to_base58(data, sizeof(data)); -} -std::string key_to_wif(const fc::ecc::private_key& key) -{ - return key_to_wif( key.get_secret() ); -} - -fc::optional wif_to_key( const std::string& wif_key ) -{ - std::vector wif_bytes; - try - { - wif_bytes = fc::from_base58(wif_key); - } - catch (const fc::parse_error_exception&) - { - return fc::optional(); - } - if (wif_bytes.size() < 5) - return fc::optional(); - std::vector key_bytes(wif_bytes.begin() + 1, wif_bytes.end() - 4); - fc::ecc::private_key key = fc::variant(key_bytes).as(); - fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); - fc::sha256 check2 = fc::sha256::hash(check); - - if( memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || - memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ) - return key; - - return fc::optional(); -} - -} } // end namespace eosio::utilities diff --git a/libraries/utilities/string_escape.cpp b/libraries/utilities/string_escape.cpp deleted file mode 100644 index 05421b327c3..00000000000 --- a/libraries/utilities/string_escape.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include -#include - -namespace eosio { namespace utilities { - - std::string escape_string_for_c_source_code(const std::string& input) - { - std::ostringstream escaped_string; - escaped_string << "\""; - for (unsigned i = 0; i < input.size(); ++i) - { - switch (input[i]) - { - case '\a': - escaped_string << "\\a"; - break; - case '\b': - escaped_string << "\\b"; - break; - case '\t': - escaped_string << "\\t"; - break; - case '\n': - escaped_string << "\\n"; - break; - case '\v': - escaped_string << "\\v"; - break; - case '\f': - escaped_string << "\\f"; - break; - case '\r': - escaped_string << "\\r"; - break; - case '\\': - escaped_string << "\\\\"; - break; - case '\"': - escaped_string << "\\\""; - break; - default: - escaped_string << input[i]; - } - } - escaped_string << "\""; - return escaped_string.str(); - } - -} } // end namespace eosio::utilities - diff --git a/libraries/utilities/tempdir.cpp b/libraries/utilities/tempdir.cpp deleted file mode 100644 index 5aae9cbbede..00000000000 --- a/libraries/utilities/tempdir.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - -#include - -#include - -namespace eosio { namespace utilities { - -fc::path temp_directory_path() -{ - const char* eos_tempdir = getenv("EOS_TEMPDIR"); - if( eos_tempdir != nullptr ) - return fc::path( eos_tempdir ); - return fc::temp_directory_path() / "eos-tmp"; -} - -} } // eosio::utilities diff --git a/libraries/utilities/words.cpp b/libraries/utilities/words.cpp deleted file mode 100644 index 0da88e78af5..00000000000 --- a/libraries/utilities/words.cpp +++ /dev/null @@ -1,49764 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ -#include -#include - -namespace eosio { namespace words { - -const const_char_ptr word_list[] = { -"a", -"aa", -"aal", -"aalii", -"aam", -"aba", -"abac", -"abaca", -"abacate", -"abacay", -"abacist", -"aback", -"abactor", -"abacus", -"abaff", -"abaft", -"abaiser", -"abalone", -"abandon", -"abas", -"abase", -"abased", -"abaser", -"abash", -"abashed", -"abasia", -"abasic", -"abask", -"abate", -"abater", -"abatis", -"abaton", -"abator", -"abature", -"abave", -"abaxial", -"abaxile", -"abaze", -"abb", -"abbacy", -"abbas", -"abbasi", -"abbassi", -"abbess", -"abbey", -"abbot", -"abbotcy", -"abdal", -"abdat", -"abdest", -"abdomen", -"abduce", -"abduct", -"abeam", -"abear", -"abed", -"abeigh", -"abele", -"abelite", -"abet", -"abettal", -"abettor", -"abey", -"abeyant", -"abfarad", -"abhenry", -"abhor", -"abidal", -"abide", -"abider", -"abidi", -"abiding", -"abietic", -"abietin", -"abigail", -"abigeat", -"abigeus", -"abilao", -"ability", -"abilla", -"abilo", -"abiosis", -"abiotic", -"abir", -"abiston", -"abiuret", -"abject", -"abjoint", -"abjudge", -"abjure", -"abjurer", -"abkar", -"abkari", -"ablach", -"ablare", -"ablate", -"ablator", -"ablaut", -"ablaze", -"able", -"ableeze", -"abler", -"ablest", -"ablins", -"abloom", -"ablow", -"ablude", -"abluent", -"ablush", -"ably", -"abmho", -"abnet", -"aboard", -"abode", -"abody", -"abohm", -"aboil", -"abolish", -"abolla", -"aboma", -"abomine", -"aboon", -"aborad", -"aboral", -"abord", -"abort", -"aborted", -"abortin", -"abortus", -"abound", -"about", -"abouts", -"above", -"abox", -"abrade", -"abrader", -"abraid", -"abrasax", -"abrase", -"abrash", -"abraum", -"abraxas", -"abreact", -"abreast", -"abret", -"abrico", -"abridge", -"abrim", -"abrin", -"abroach", -"abroad", -"abrook", -"abrupt", -"abscess", -"abscind", -"abscise", -"absciss", -"abscond", -"absence", -"absent", -"absit", -"absmho", -"absohm", -"absolve", -"absorb", -"absorpt", -"abstain", -"absume", -"absurd", -"absvolt", -"abthain", -"abu", -"abucco", -"abulia", -"abulic", -"abuna", -"abura", -"aburban", -"aburst", -"aburton", -"abuse", -"abusee", -"abuser", -"abusion", -"abusive", -"abut", -"abuttal", -"abutter", -"abuzz", -"abvolt", -"abwab", -"aby", -"abysm", -"abysmal", -"abyss", -"abyssal", -"acaciin", -"acacin", -"academe", -"academy", -"acajou", -"acaleph", -"acana", -"acanth", -"acantha", -"acapnia", -"acapu", -"acara", -"acardia", -"acari", -"acarian", -"acarid", -"acarine", -"acaroid", -"acarol", -"acate", -"acatery", -"acaudal", -"acca", -"accede", -"acceder", -"accend", -"accent", -"accept", -"accerse", -"access", -"accidia", -"accidie", -"accinge", -"accite", -"acclaim", -"accloy", -"accoast", -"accoil", -"accolle", -"accompt", -"accord", -"accost", -"account", -"accoy", -"accrete", -"accrual", -"accrue", -"accruer", -"accurse", -"accusal", -"accuse", -"accused", -"accuser", -"ace", -"acedia", -"acedy", -"acephal", -"acerate", -"acerb", -"acerbic", -"acerdol", -"acerin", -"acerose", -"acerous", -"acerra", -"aceship", -"acetal", -"acetate", -"acetic", -"acetify", -"acetin", -"acetize", -"acetoin", -"acetol", -"acetone", -"acetose", -"acetous", -"acetum", -"acetyl", -"ach", -"achage", -"achar", -"achate", -"ache", -"achene", -"acher", -"achete", -"achieve", -"achigan", -"achill", -"achime", -"aching", -"achira", -"acholia", -"acholic", -"achor", -"achree", -"achroma", -"achtel", -"achy", -"achylia", -"achymia", -"acicula", -"acid", -"acider", -"acidic", -"acidify", -"acidite", -"acidity", -"acidize", -"acidly", -"acidoid", -"acidyl", -"acier", -"aciform", -"acinar", -"acinary", -"acinic", -"acinose", -"acinous", -"acinus", -"aciurgy", -"acker", -"ackey", -"ackman", -"acknow", -"acle", -"aclinal", -"aclinic", -"acloud", -"aclys", -"acmatic", -"acme", -"acmic", -"acmite", -"acne", -"acnemia", -"acnodal", -"acnode", -"acock", -"acocotl", -"acoin", -"acoine", -"acold", -"acology", -"acolous", -"acolyte", -"acoma", -"acomia", -"acomous", -"acone", -"aconic", -"aconin", -"aconine", -"aconite", -"acopic", -"acopon", -"acor", -"acorea", -"acoria", -"acorn", -"acorned", -"acosmic", -"acouasm", -"acouchi", -"acouchy", -"acoupa", -"acquest", -"acquire", -"acquist", -"acquit", -"acracy", -"acraein", -"acrasia", -"acratia", -"acrawl", -"acraze", -"acre", -"acreage", -"acreak", -"acream", -"acred", -"acreman", -"acrid", -"acridan", -"acridic", -"acridly", -"acridyl", -"acrinyl", -"acrisia", -"acritan", -"acrite", -"acritol", -"acroama", -"acrobat", -"acrogen", -"acron", -"acronyc", -"acronym", -"acronyx", -"acrook", -"acrose", -"across", -"acrotic", -"acryl", -"acrylic", -"acrylyl", -"act", -"acta", -"actable", -"actify", -"actin", -"actinal", -"actine", -"acting", -"actinic", -"actinon", -"action", -"active", -"activin", -"actless", -"acton", -"actor", -"actress", -"actu", -"actual", -"actuary", -"acture", -"acuate", -"acuity", -"aculea", -"aculeus", -"acumen", -"acushla", -"acutate", -"acute", -"acutely", -"acutish", -"acyclic", -"acyesis", -"acyetic", -"acyl", -"acylate", -"acyloin", -"acyloxy", -"acystia", -"ad", -"adactyl", -"adad", -"adage", -"adagial", -"adagio", -"adamant", -"adamas", -"adamine", -"adamite", -"adance", -"adangle", -"adapid", -"adapt", -"adapter", -"adaptor", -"adarme", -"adat", -"adati", -"adatom", -"adaunt", -"adaw", -"adawe", -"adawlut", -"adawn", -"adaxial", -"aday", -"adays", -"adazzle", -"adcraft", -"add", -"adda", -"addable", -"addax", -"added", -"addedly", -"addend", -"addenda", -"adder", -"addible", -"addict", -"addle", -"addlins", -"address", -"addrest", -"adduce", -"adducer", -"adduct", -"ade", -"adead", -"adeem", -"adeep", -"adeling", -"adelite", -"adenase", -"adenia", -"adenine", -"adenoid", -"adenoma", -"adenose", -"adenyl", -"adept", -"adermia", -"adermin", -"adet", -"adevism", -"adfix", -"adhaka", -"adharma", -"adhere", -"adherer", -"adhibit", -"adiate", -"adicity", -"adieu", -"adieux", -"adinole", -"adion", -"adipate", -"adipic", -"adipoid", -"adipoma", -"adipose", -"adipous", -"adipsia", -"adipsic", -"adipsy", -"adipyl", -"adit", -"adital", -"aditus", -"adjag", -"adject", -"adjiger", -"adjoin", -"adjoint", -"adjourn", -"adjudge", -"adjunct", -"adjure", -"adjurer", -"adjust", -"adlay", -"adless", -"adlet", -"adman", -"admi", -"admiral", -"admire", -"admired", -"admirer", -"admit", -"admix", -"adnate", -"adnex", -"adnexal", -"adnexed", -"adnoun", -"ado", -"adobe", -"adonin", -"adonite", -"adonize", -"adopt", -"adopted", -"adoptee", -"adopter", -"adoral", -"adorant", -"adore", -"adorer", -"adorn", -"adorner", -"adossed", -"adoulie", -"adown", -"adoxy", -"adoze", -"adpao", -"adpress", -"adread", -"adream", -"adreamt", -"adrenal", -"adrenin", -"adrift", -"adrip", -"adroit", -"adroop", -"adrop", -"adrowse", -"adrue", -"adry", -"adsbud", -"adsmith", -"adsorb", -"adtevac", -"adular", -"adulate", -"adult", -"adulter", -"adunc", -"adusk", -"adust", -"advance", -"advene", -"adverb", -"adverse", -"advert", -"advice", -"advisal", -"advise", -"advised", -"advisee", -"adviser", -"advisor", -"advowee", -"ady", -"adynamy", -"adyta", -"adyton", -"adytum", -"adz", -"adze", -"adzer", -"adzooks", -"ae", -"aecial", -"aecium", -"aedile", -"aedilic", -"aefald", -"aefaldy", -"aefauld", -"aegis", -"aenach", -"aenean", -"aeneous", -"aeolid", -"aeolina", -"aeoline", -"aeon", -"aeonial", -"aeonian", -"aeonist", -"aer", -"aerage", -"aerate", -"aerator", -"aerial", -"aeric", -"aerical", -"aerie", -"aeried", -"aerify", -"aero", -"aerobe", -"aerobic", -"aerobus", -"aerogel", -"aerogen", -"aerogun", -"aeronat", -"aeronef", -"aerose", -"aerosol", -"aerugo", -"aery", -"aes", -"aevia", -"aface", -"afaint", -"afar", -"afara", -"afear", -"afeard", -"afeared", -"afernan", -"afetal", -"affa", -"affable", -"affably", -"affair", -"affaite", -"affect", -"affeer", -"affeir", -"affiant", -"affinal", -"affine", -"affined", -"affirm", -"affix", -"affixal", -"affixer", -"afflict", -"afflux", -"afforce", -"afford", -"affray", -"affront", -"affuse", -"affy", -"afghani", -"afield", -"afire", -"aflame", -"aflare", -"aflat", -"aflaunt", -"aflight", -"afloat", -"aflow", -"aflower", -"aflush", -"afoam", -"afoot", -"afore", -"afoul", -"afraid", -"afreet", -"afresh", -"afret", -"afront", -"afrown", -"aft", -"aftaba", -"after", -"aftergo", -"aftmost", -"aftosa", -"aftward", -"aga", -"again", -"against", -"agal", -"agalaxy", -"agalite", -"agallop", -"agalma", -"agama", -"agamete", -"agami", -"agamian", -"agamic", -"agamid", -"agamoid", -"agamont", -"agamous", -"agamy", -"agape", -"agapeti", -"agar", -"agaric", -"agarita", -"agarwal", -"agasp", -"agate", -"agathin", -"agatine", -"agatize", -"agatoid", -"agaty", -"agavose", -"agaze", -"agazed", -"age", -"aged", -"agedly", -"agee", -"ageless", -"agelong", -"agen", -"agency", -"agenda", -"agendum", -"agent", -"agentry", -"ager", -"ageusia", -"ageusic", -"agger", -"aggrade", -"aggrate", -"aggress", -"aggroup", -"aggry", -"aggur", -"agha", -"aghanee", -"aghast", -"agile", -"agilely", -"agility", -"aging", -"agio", -"agist", -"agistor", -"agitant", -"agitate", -"agla", -"aglance", -"aglare", -"agleaf", -"agleam", -"aglet", -"agley", -"aglint", -"aglow", -"aglucon", -"agnail", -"agname", -"agnamed", -"agnate", -"agnatic", -"agnel", -"agnize", -"agnomen", -"agnosia", -"agnosis", -"agnosy", -"agnus", -"ago", -"agog", -"agoge", -"agogic", -"agogics", -"agoho", -"agoing", -"agon", -"agonal", -"agone", -"agonic", -"agonied", -"agonist", -"agonium", -"agonize", -"agony", -"agora", -"agouara", -"agouta", -"agouti", -"agpaite", -"agrah", -"agral", -"agre", -"agree", -"agreed", -"agreer", -"agrege", -"agria", -"agrin", -"agrise", -"agrito", -"agroan", -"agrom", -"agroof", -"agrope", -"aground", -"agrufe", -"agruif", -"agsam", -"agua", -"ague", -"aguey", -"aguish", -"agunah", -"agush", -"agust", -"agy", -"agynary", -"agynous", -"agyrate", -"agyria", -"ah", -"aha", -"ahaaina", -"ahaunch", -"ahead", -"aheap", -"ahem", -"ahey", -"ahimsa", -"ahind", -"ahint", -"ahmadi", -"aho", -"ahong", -"ahorse", -"ahoy", -"ahsan", -"ahu", -"ahuatle", -"ahull", -"ahum", -"ahungry", -"ahunt", -"ahura", -"ahush", -"ahwal", -"ahypnia", -"ai", -"aid", -"aidable", -"aidance", -"aidant", -"aide", -"aider", -"aidful", -"aidless", -"aiel", -"aiglet", -"ail", -"ailanto", -"aile", -"aileron", -"ailette", -"ailing", -"aillt", -"ailment", -"ailsyte", -"ailuro", -"ailweed", -"aim", -"aimara", -"aimer", -"aimful", -"aiming", -"aimless", -"ainaleh", -"ainhum", -"ainoi", -"ainsell", -"aint", -"aion", -"aionial", -"air", -"airable", -"airampo", -"airan", -"aircrew", -"airdock", -"airdrop", -"aire", -"airer", -"airfoil", -"airhead", -"airily", -"airing", -"airish", -"airless", -"airlift", -"airlike", -"airmail", -"airman", -"airmark", -"airpark", -"airport", -"airship", -"airsick", -"airt", -"airward", -"airway", -"airy", -"aisle", -"aisled", -"aisling", -"ait", -"aitch", -"aitesis", -"aition", -"aiwan", -"aizle", -"ajaja", -"ajangle", -"ajar", -"ajari", -"ajava", -"ajhar", -"ajivika", -"ajog", -"ajoint", -"ajowan", -"ak", -"aka", -"akala", -"akaroa", -"akasa", -"akazga", -"akcheh", -"ake", -"akeake", -"akebi", -"akee", -"akeki", -"akeley", -"akepiro", -"akerite", -"akey", -"akhoond", -"akhrot", -"akhyana", -"akia", -"akimbo", -"akin", -"akindle", -"akinete", -"akmudar", -"aknee", -"ako", -"akoasm", -"akoasma", -"akonge", -"akov", -"akpek", -"akra", -"aku", -"akule", -"akund", -"al", -"ala", -"alacha", -"alack", -"alada", -"alaihi", -"alaite", -"alala", -"alalite", -"alalus", -"alameda", -"alamo", -"alamoth", -"alan", -"aland", -"alangin", -"alani", -"alanine", -"alannah", -"alantic", -"alantin", -"alantol", -"alanyl", -"alar", -"alares", -"alarm", -"alarmed", -"alarum", -"alary", -"alas", -"alate", -"alated", -"alatern", -"alation", -"alb", -"alba", -"alban", -"albarco", -"albata", -"albe", -"albedo", -"albee", -"albeit", -"albetad", -"albify", -"albinal", -"albinic", -"albino", -"albite", -"albitic", -"albugo", -"album", -"albumen", -"albumin", -"alburn", -"albus", -"alcaide", -"alcalde", -"alcanna", -"alcazar", -"alchemy", -"alchera", -"alchimy", -"alchymy", -"alcine", -"alclad", -"alco", -"alcoate", -"alcogel", -"alcohol", -"alcosol", -"alcove", -"alcyon", -"aldane", -"aldazin", -"aldehol", -"alder", -"aldern", -"aldim", -"aldime", -"aldine", -"aldol", -"aldose", -"ale", -"aleak", -"alec", -"alecize", -"alecost", -"alecup", -"alee", -"alef", -"aleft", -"alegar", -"alehoof", -"alem", -"alemana", -"alembic", -"alemite", -"alemmal", -"alen", -"aleph", -"alephs", -"alepole", -"alepot", -"alerce", -"alerse", -"alert", -"alertly", -"alesan", -"aletap", -"alette", -"alevin", -"alewife", -"alexia", -"alexic", -"alexin", -"aleyard", -"alf", -"alfa", -"alfaje", -"alfalfa", -"alfaqui", -"alfet", -"alfiona", -"alfonso", -"alforja", -"alga", -"algae", -"algal", -"algalia", -"algate", -"algebra", -"algedo", -"algesia", -"algesic", -"algesis", -"algetic", -"algic", -"algid", -"algific", -"algin", -"algine", -"alginic", -"algist", -"algoid", -"algor", -"algosis", -"algous", -"algum", -"alhenna", -"alias", -"alibi", -"alible", -"alichel", -"alidade", -"alien", -"aliency", -"alienee", -"aliener", -"alienor", -"alif", -"aliform", -"alight", -"align", -"aligner", -"aliipoe", -"alike", -"alima", -"aliment", -"alimony", -"alin", -"aliofar", -"alipata", -"aliped", -"aliptes", -"aliptic", -"aliquot", -"alish", -"alisier", -"alismad", -"alismal", -"aliso", -"alison", -"alisp", -"alist", -"alit", -"alite", -"aliunde", -"alive", -"aliyah", -"alizari", -"aljoba", -"alk", -"alkali", -"alkalic", -"alkamin", -"alkane", -"alkanet", -"alkene", -"alkenna", -"alkenyl", -"alkide", -"alkine", -"alkool", -"alkoxy", -"alkoxyl", -"alky", -"alkyd", -"alkyl", -"alkylic", -"alkyne", -"all", -"allan", -"allay", -"allayer", -"allbone", -"allege", -"alleger", -"allegro", -"allele", -"allelic", -"allene", -"aller", -"allergy", -"alley", -"alleyed", -"allgood", -"allheal", -"allice", -"allied", -"allies", -"allness", -"allonym", -"alloquy", -"allose", -"allot", -"allotee", -"allover", -"allow", -"allower", -"alloxan", -"alloy", -"allseed", -"alltud", -"allude", -"allure", -"allurer", -"alluvia", -"allwork", -"ally", -"allyl", -"allylic", -"alma", -"almadia", -"almadie", -"almagra", -"almanac", -"alme", -"almemar", -"almique", -"almirah", -"almoign", -"almon", -"almond", -"almondy", -"almoner", -"almonry", -"almost", -"almous", -"alms", -"almsful", -"almsman", -"almuce", -"almud", -"almude", -"almug", -"almuten", -"aln", -"alnage", -"alnager", -"alnein", -"alnico", -"alnoite", -"alnuin", -"alo", -"alochia", -"alod", -"alodial", -"alodian", -"alodium", -"alody", -"aloe", -"aloed", -"aloesol", -"aloetic", -"aloft", -"alogia", -"alogism", -"alogy", -"aloid", -"aloin", -"aloma", -"alone", -"along", -"alongst", -"aloof", -"aloofly", -"aloose", -"alop", -"alopeke", -"alose", -"aloud", -"alow", -"alowe", -"alp", -"alpaca", -"alpeen", -"alpha", -"alphol", -"alphorn", -"alphos", -"alphyl", -"alpieu", -"alpine", -"alpist", -"alquier", -"alraun", -"already", -"alright", -"alroot", -"alruna", -"also", -"alsoon", -"alt", -"altaite", -"altar", -"altared", -"alter", -"alterer", -"altern", -"alterne", -"althea", -"althein", -"altho", -"althorn", -"altilik", -"altin", -"alto", -"altoun", -"altrose", -"altun", -"aludel", -"alula", -"alular", -"alulet", -"alum", -"alumic", -"alumina", -"alumine", -"alumish", -"alumite", -"alumium", -"alumna", -"alumnae", -"alumnal", -"alumni", -"alumnus", -"alunite", -"alupag", -"alure", -"aluta", -"alvar", -"alveary", -"alveloz", -"alveola", -"alveole", -"alveoli", -"alveus", -"alvine", -"alvite", -"alvus", -"alway", -"always", -"aly", -"alypin", -"alysson", -"am", -"ama", -"amaas", -"amadou", -"amaga", -"amah", -"amain", -"amakebe", -"amala", -"amalaka", -"amalgam", -"amaltas", -"amamau", -"amandin", -"amang", -"amani", -"amania", -"amanori", -"amanous", -"amapa", -"amar", -"amarin", -"amarine", -"amarity", -"amaroid", -"amass", -"amasser", -"amastia", -"amasty", -"amateur", -"amative", -"amatol", -"amatory", -"amaze", -"amazed", -"amazia", -"amazing", -"amba", -"ambage", -"ambalam", -"amban", -"ambar", -"ambaree", -"ambary", -"ambash", -"ambassy", -"ambatch", -"ambay", -"ambeer", -"amber", -"ambery", -"ambiens", -"ambient", -"ambier", -"ambit", -"ambital", -"ambitty", -"ambitus", -"amble", -"ambler", -"ambling", -"ambo", -"ambon", -"ambos", -"ambrain", -"ambrein", -"ambrite", -"ambroid", -"ambrose", -"ambry", -"ambsace", -"ambury", -"ambush", -"amchoor", -"ame", -"ameed", -"ameen", -"amelia", -"amellus", -"amelu", -"amelus", -"amen", -"amend", -"amende", -"amender", -"amends", -"amene", -"amenia", -"amenity", -"ament", -"amental", -"amentia", -"amentum", -"amerce", -"amercer", -"amerism", -"amesite", -"ametria", -"amgarn", -"amhar", -"amhran", -"ami", -"amiable", -"amiably", -"amianth", -"amic", -"amical", -"amice", -"amiced", -"amicron", -"amid", -"amidase", -"amidate", -"amide", -"amidic", -"amidid", -"amidide", -"amidin", -"amidine", -"amido", -"amidol", -"amidon", -"amidoxy", -"amidst", -"amil", -"amimia", -"amimide", -"amin", -"aminate", -"amine", -"amini", -"aminic", -"aminity", -"aminize", -"amino", -"aminoid", -"amir", -"amiray", -"amiss", -"amity", -"amixia", -"amla", -"amli", -"amlikar", -"amlong", -"amma", -"amman", -"ammelin", -"ammer", -"ammeter", -"ammine", -"ammo", -"ammonal", -"ammonia", -"ammonic", -"ammono", -"ammu", -"amnesia", -"amnesic", -"amnesty", -"amnia", -"amniac", -"amnic", -"amnion", -"amniote", -"amober", -"amobyr", -"amoeba", -"amoebae", -"amoeban", -"amoebic", -"amoebid", -"amok", -"amoke", -"amole", -"amomal", -"amomum", -"among", -"amongst", -"amor", -"amorado", -"amoraic", -"amoraim", -"amoral", -"amoret", -"amorism", -"amorist", -"amoroso", -"amorous", -"amorphy", -"amort", -"amotion", -"amotus", -"amount", -"amour", -"amove", -"ampalea", -"amper", -"ampere", -"ampery", -"amphid", -"amphide", -"amphora", -"amphore", -"ample", -"amplify", -"amply", -"ampoule", -"ampul", -"ampulla", -"amputee", -"ampyx", -"amra", -"amreeta", -"amrita", -"amsath", -"amsel", -"amt", -"amtman", -"amuck", -"amuguis", -"amula", -"amulet", -"amulla", -"amunam", -"amurca", -"amuse", -"amused", -"amusee", -"amuser", -"amusia", -"amusing", -"amusive", -"amutter", -"amuyon", -"amuyong", -"amuze", -"amvis", -"amy", -"amyelia", -"amyelic", -"amygdal", -"amyl", -"amylan", -"amylase", -"amylate", -"amylene", -"amylic", -"amylin", -"amylo", -"amyloid", -"amylom", -"amylon", -"amylose", -"amylum", -"amyous", -"amyrin", -"amyrol", -"amyroot", -"an", -"ana", -"anabata", -"anabo", -"anabong", -"anacara", -"anacard", -"anacid", -"anadem", -"anadrom", -"anaemia", -"anaemic", -"anagap", -"anagep", -"anagoge", -"anagogy", -"anagram", -"anagua", -"anahau", -"anal", -"analav", -"analgen", -"analgia", -"analgic", -"anally", -"analogy", -"analyse", -"analyst", -"analyze", -"anam", -"anama", -"anamite", -"anan", -"anana", -"ananas", -"ananda", -"ananym", -"anaphia", -"anapnea", -"anapsid", -"anaqua", -"anarch", -"anarchy", -"anareta", -"anarya", -"anatase", -"anatifa", -"anatine", -"anatomy", -"anatox", -"anatron", -"anaudia", -"anaxial", -"anaxon", -"anaxone", -"anay", -"anba", -"anbury", -"anchor", -"anchovy", -"ancient", -"ancile", -"ancilla", -"ancon", -"anconad", -"anconal", -"ancone", -"ancony", -"ancora", -"ancoral", -"and", -"anda", -"andante", -"andirin", -"andiron", -"andric", -"android", -"androl", -"andron", -"anear", -"aneath", -"anele", -"anemia", -"anemic", -"anemone", -"anemony", -"anend", -"anenst", -"anent", -"anepia", -"anergia", -"anergic", -"anergy", -"anerly", -"aneroid", -"anes", -"anesis", -"aneuria", -"aneuric", -"aneurin", -"anew", -"angaria", -"angary", -"angekok", -"angel", -"angelet", -"angelic", -"angelin", -"angelot", -"anger", -"angerly", -"angeyok", -"angico", -"angild", -"angili", -"angina", -"anginal", -"angioid", -"angioma", -"angle", -"angled", -"angler", -"angling", -"angloid", -"ango", -"angolar", -"angor", -"angrily", -"angrite", -"angry", -"angst", -"angster", -"anguid", -"anguine", -"anguis", -"anguish", -"angula", -"angular", -"anguria", -"anhang", -"anhima", -"anhinga", -"ani", -"anicut", -"anidian", -"aniente", -"anigh", -"anight", -"anights", -"anil", -"anilao", -"anilau", -"anile", -"anilic", -"anilid", -"anilide", -"aniline", -"anility", -"anilla", -"anima", -"animal", -"animate", -"anime", -"animi", -"animism", -"animist", -"animize", -"animous", -"animus", -"anion", -"anionic", -"anis", -"anisal", -"anisate", -"anise", -"aniseed", -"anisic", -"anisil", -"anisoin", -"anisole", -"anisoyl", -"anisum", -"anisyl", -"anither", -"anjan", -"ankee", -"anker", -"ankh", -"ankle", -"anklet", -"anklong", -"ankus", -"ankusha", -"anlace", -"anlaut", -"ann", -"anna", -"annal", -"annale", -"annals", -"annat", -"annates", -"annatto", -"anneal", -"annelid", -"annet", -"annex", -"annexa", -"annexal", -"annexer", -"annite", -"annona", -"annoy", -"annoyer", -"annual", -"annuary", -"annuent", -"annuity", -"annul", -"annular", -"annulet", -"annulus", -"anoa", -"anodal", -"anode", -"anodic", -"anodize", -"anodos", -"anodyne", -"anoesia", -"anoesis", -"anoetic", -"anoil", -"anoine", -"anoint", -"anole", -"anoli", -"anolian", -"anolyte", -"anomaly", -"anomite", -"anomy", -"anon", -"anonang", -"anonol", -"anonym", -"anonyma", -"anopia", -"anopsia", -"anorak", -"anorexy", -"anormal", -"anorth", -"anosmia", -"anosmic", -"another", -"anotia", -"anotta", -"anotto", -"anotus", -"anounou", -"anoxia", -"anoxic", -"ansa", -"ansar", -"ansate", -"ansu", -"answer", -"ant", -"anta", -"antacid", -"antal", -"antapex", -"antdom", -"ante", -"anteact", -"anteal", -"antefix", -"antenna", -"antes", -"antewar", -"anthela", -"anthem", -"anthema", -"anthemy", -"anther", -"anthill", -"anthine", -"anthoid", -"anthood", -"anthrax", -"anthrol", -"anthryl", -"anti", -"antiae", -"antiar", -"antic", -"antical", -"anticly", -"anticor", -"anticum", -"antifat", -"antigen", -"antigod", -"antihum", -"antiqua", -"antique", -"antired", -"antirun", -"antisun", -"antitax", -"antiwar", -"antiwit", -"antler", -"antlia", -"antling", -"antoeci", -"antonym", -"antra", -"antral", -"antre", -"antrin", -"antrum", -"antship", -"antu", -"antwise", -"anubing", -"anuloma", -"anuran", -"anuria", -"anuric", -"anurous", -"anury", -"anus", -"anusim", -"anvil", -"anxiety", -"anxious", -"any", -"anybody", -"anyhow", -"anyone", -"anyway", -"anyways", -"anywhen", -"anywhy", -"anywise", -"aogiri", -"aonach", -"aorist", -"aorta", -"aortal", -"aortic", -"aortism", -"aosmic", -"aoudad", -"apa", -"apace", -"apache", -"apadana", -"apagoge", -"apaid", -"apalit", -"apandry", -"apar", -"aparejo", -"apart", -"apasote", -"apatan", -"apathic", -"apathy", -"apatite", -"ape", -"apeak", -"apedom", -"apehood", -"apeiron", -"apelet", -"apelike", -"apeling", -"apepsia", -"apepsy", -"apeptic", -"aper", -"aperch", -"aperea", -"apert", -"apertly", -"apery", -"apetaly", -"apex", -"apexed", -"aphagia", -"aphakia", -"aphakic", -"aphasia", -"aphasic", -"aphemia", -"aphemic", -"aphesis", -"apheta", -"aphetic", -"aphid", -"aphides", -"aphidid", -"aphodal", -"aphodus", -"aphonia", -"aphonic", -"aphony", -"aphoria", -"aphotic", -"aphrite", -"aphtha", -"aphthic", -"aphylly", -"aphyric", -"apian", -"apiary", -"apiator", -"apicad", -"apical", -"apices", -"apicula", -"apiece", -"apieces", -"apii", -"apiin", -"apilary", -"apinch", -"aping", -"apinoid", -"apio", -"apioid", -"apiole", -"apiolin", -"apionol", -"apiose", -"apish", -"apishly", -"apism", -"apitong", -"apitpat", -"aplanat", -"aplasia", -"aplenty", -"aplite", -"aplitic", -"aplomb", -"aplome", -"apnea", -"apneal", -"apneic", -"apocarp", -"apocha", -"apocope", -"apod", -"apodal", -"apodan", -"apodema", -"apodeme", -"apodia", -"apodous", -"apogamy", -"apogeal", -"apogean", -"apogee", -"apogeic", -"apogeny", -"apohyal", -"apoise", -"apojove", -"apokrea", -"apolar", -"apology", -"aponia", -"aponic", -"apoop", -"apoplex", -"apopyle", -"aporia", -"aporose", -"aport", -"aposia", -"aposoro", -"apostil", -"apostle", -"apothem", -"apotome", -"apotype", -"apout", -"apozem", -"apozema", -"appall", -"apparel", -"appay", -"appeal", -"appear", -"appease", -"append", -"appet", -"appete", -"applaud", -"apple", -"applied", -"applier", -"applot", -"apply", -"appoint", -"apport", -"appose", -"apposer", -"apprend", -"apprise", -"apprize", -"approof", -"approve", -"appulse", -"apraxia", -"apraxic", -"apricot", -"apriori", -"apron", -"apropos", -"apse", -"apsidal", -"apsides", -"apsis", -"apt", -"apteral", -"apteran", -"aptly", -"aptness", -"aptote", -"aptotic", -"apulse", -"apyonin", -"apyrene", -"apyrexy", -"apyrous", -"aqua", -"aquabib", -"aquage", -"aquaria", -"aquatic", -"aquavit", -"aqueous", -"aquifer", -"aquiver", -"aquo", -"aquose", -"ar", -"ara", -"araba", -"araban", -"arabana", -"arabin", -"arabit", -"arable", -"araca", -"aracari", -"arachic", -"arachin", -"arad", -"arado", -"arain", -"arake", -"araliad", -"aralie", -"aralkyl", -"aramina", -"araneid", -"aranein", -"aranga", -"arango", -"arar", -"arara", -"ararao", -"arariba", -"araroba", -"arati", -"aration", -"aratory", -"arba", -"arbacin", -"arbalo", -"arbiter", -"arbor", -"arboral", -"arbored", -"arboret", -"arbute", -"arbutin", -"arbutus", -"arc", -"arca", -"arcade", -"arcana", -"arcanal", -"arcane", -"arcanum", -"arcate", -"arch", -"archae", -"archaic", -"arche", -"archeal", -"arched", -"archer", -"archery", -"arches", -"archeus", -"archfoe", -"archgod", -"archil", -"arching", -"archive", -"archly", -"archon", -"archont", -"archsee", -"archsin", -"archspy", -"archwag", -"archway", -"archy", -"arcing", -"arcked", -"arcking", -"arctian", -"arctic", -"arctiid", -"arctoid", -"arcual", -"arcuale", -"arcuate", -"arcula", -"ardeb", -"ardella", -"ardency", -"ardent", -"ardish", -"ardoise", -"ardor", -"ardri", -"ardu", -"arduous", -"are", -"area", -"areach", -"aread", -"areal", -"arear", -"areaway", -"arecain", -"ared", -"areek", -"areel", -"arefact", -"areito", -"arena", -"arenae", -"arend", -"areng", -"arenoid", -"arenose", -"arent", -"areola", -"areolar", -"areole", -"areolet", -"arete", -"argal", -"argala", -"argali", -"argans", -"argasid", -"argeers", -"argel", -"argenol", -"argent", -"arghan", -"arghel", -"arghool", -"argil", -"argo", -"argol", -"argolet", -"argon", -"argosy", -"argot", -"argotic", -"argue", -"arguer", -"argufy", -"argute", -"argyria", -"argyric", -"arhar", -"arhat", -"aria", -"aribine", -"aricine", -"arid", -"aridge", -"aridian", -"aridity", -"aridly", -"ariel", -"arienzo", -"arietta", -"aright", -"arigue", -"aril", -"ariled", -"arillus", -"ariose", -"arioso", -"ariot", -"aripple", -"arisard", -"arise", -"arisen", -"arist", -"arista", -"arite", -"arjun", -"ark", -"arkite", -"arkose", -"arkosic", -"arles", -"arm", -"armada", -"armbone", -"armed", -"armer", -"armet", -"armful", -"armhole", -"armhoop", -"armied", -"armiger", -"armil", -"armilla", -"arming", -"armless", -"armlet", -"armload", -"armoire", -"armor", -"armored", -"armorer", -"armory", -"armpit", -"armrack", -"armrest", -"arms", -"armscye", -"armure", -"army", -"arn", -"arna", -"arnee", -"arni", -"arnica", -"arnotta", -"arnotto", -"arnut", -"aroar", -"aroast", -"arock", -"aroeira", -"aroid", -"aroint", -"arolium", -"arolla", -"aroma", -"aroon", -"arose", -"around", -"arousal", -"arouse", -"arouser", -"arow", -"aroxyl", -"arpen", -"arpent", -"arrack", -"arrah", -"arraign", -"arrame", -"arrange", -"arrant", -"arras", -"arrased", -"arratel", -"arrau", -"array", -"arrayal", -"arrayer", -"arrear", -"arrect", -"arrent", -"arrest", -"arriage", -"arriba", -"arride", -"arridge", -"arrie", -"arriere", -"arrimby", -"arris", -"arrish", -"arrival", -"arrive", -"arriver", -"arroba", -"arrope", -"arrow", -"arrowed", -"arrowy", -"arroyo", -"arse", -"arsenal", -"arsenic", -"arseno", -"arsenyl", -"arses", -"arsheen", -"arshin", -"arshine", -"arsine", -"arsinic", -"arsino", -"arsis", -"arsle", -"arsoite", -"arson", -"arsonic", -"arsono", -"arsyl", -"art", -"artaba", -"artabe", -"artal", -"artar", -"artel", -"arterin", -"artery", -"artful", -"artha", -"arthel", -"arthral", -"artiad", -"article", -"artisan", -"artist", -"artiste", -"artless", -"artlet", -"artlike", -"artware", -"arty", -"aru", -"arui", -"aruke", -"arumin", -"arupa", -"arusa", -"arusha", -"arustle", -"arval", -"arvel", -"arx", -"ary", -"aryl", -"arylate", -"arzan", -"arzun", -"as", -"asaddle", -"asak", -"asale", -"asana", -"asaphia", -"asaphid", -"asaprol", -"asarite", -"asaron", -"asarone", -"asbest", -"asbolin", -"ascan", -"ascare", -"ascarid", -"ascaron", -"ascend", -"ascent", -"ascetic", -"ascham", -"asci", -"ascian", -"ascii", -"ascites", -"ascitic", -"asclent", -"ascoma", -"ascon", -"ascot", -"ascribe", -"ascript", -"ascry", -"ascula", -"ascus", -"asdic", -"ase", -"asearch", -"aseethe", -"aseity", -"asem", -"asemia", -"asepsis", -"aseptic", -"aseptol", -"asexual", -"ash", -"ashake", -"ashame", -"ashamed", -"ashamnu", -"ashcake", -"ashen", -"asherah", -"ashery", -"ashes", -"ashet", -"ashily", -"ashine", -"ashiver", -"ashkoko", -"ashlar", -"ashless", -"ashling", -"ashman", -"ashore", -"ashpan", -"ashpit", -"ashraf", -"ashrafi", -"ashur", -"ashweed", -"ashwort", -"ashy", -"asialia", -"aside", -"asideu", -"asiento", -"asilid", -"asimen", -"asimmer", -"asinego", -"asinine", -"asitia", -"ask", -"askable", -"askance", -"askant", -"askar", -"askari", -"asker", -"askew", -"askip", -"asklent", -"askos", -"aslant", -"aslaver", -"asleep", -"aslop", -"aslope", -"asmack", -"asmalte", -"asmear", -"asmile", -"asmoke", -"asnort", -"asoak", -"asocial", -"asok", -"asoka", -"asonant", -"asonia", -"asop", -"asor", -"asouth", -"asp", -"aspace", -"aspect", -"aspen", -"asper", -"asperge", -"asperse", -"asphalt", -"asphyxy", -"aspic", -"aspire", -"aspirer", -"aspirin", -"aspish", -"asport", -"aspout", -"asprawl", -"aspread", -"aspring", -"asprout", -"asquare", -"asquat", -"asqueal", -"asquint", -"asquirm", -"ass", -"assacu", -"assagai", -"assai", -"assail", -"assapan", -"assart", -"assary", -"assate", -"assault", -"assaut", -"assay", -"assayer", -"assbaa", -"asse", -"assegai", -"asself", -"assent", -"assert", -"assess", -"asset", -"assets", -"assever", -"asshead", -"assi", -"assify", -"assign", -"assilag", -"assis", -"assise", -"assish", -"assist", -"assize", -"assizer", -"assizes", -"asslike", -"assman", -"assoil", -"assort", -"assuade", -"assuage", -"assume", -"assumed", -"assumer", -"assure", -"assured", -"assurer", -"assurge", -"ast", -"asta", -"astalk", -"astare", -"astart", -"astasia", -"astatic", -"astay", -"asteam", -"asteep", -"asteer", -"asteism", -"astelic", -"astely", -"aster", -"asteria", -"asterin", -"astern", -"astheny", -"asthma", -"asthore", -"astilbe", -"astint", -"astir", -"astite", -"astomia", -"astony", -"astoop", -"astor", -"astound", -"astrain", -"astral", -"astrand", -"astray", -"astream", -"astrer", -"astrict", -"astride", -"astrier", -"astrild", -"astroid", -"astrut", -"astute", -"astylar", -"asudden", -"asunder", -"aswail", -"aswarm", -"asway", -"asweat", -"aswell", -"aswim", -"aswing", -"aswirl", -"aswoon", -"asyla", -"asylum", -"at", -"atabal", -"atabeg", -"atabek", -"atactic", -"atafter", -"ataman", -"atangle", -"atap", -"ataraxy", -"ataunt", -"atavi", -"atavic", -"atavism", -"atavist", -"atavus", -"ataxia", -"ataxic", -"ataxite", -"ataxy", -"atazir", -"atbash", -"ate", -"atebrin", -"atechny", -"ateeter", -"atef", -"atelets", -"atelier", -"atelo", -"ates", -"ateuchi", -"athanor", -"athar", -"atheism", -"atheist", -"atheize", -"athelia", -"athenee", -"athenor", -"atheous", -"athing", -"athirst", -"athlete", -"athodyd", -"athort", -"athrill", -"athrive", -"athrob", -"athrong", -"athwart", -"athymia", -"athymic", -"athymy", -"athyria", -"athyrid", -"atilt", -"atimon", -"atinga", -"atingle", -"atinkle", -"atip", -"atis", -"atlas", -"atlatl", -"atle", -"atlee", -"atloid", -"atma", -"atman", -"atmid", -"atmo", -"atmos", -"atocha", -"atocia", -"atokal", -"atoke", -"atokous", -"atoll", -"atom", -"atomerg", -"atomic", -"atomics", -"atomism", -"atomist", -"atomity", -"atomize", -"atomy", -"atonal", -"atone", -"atoner", -"atonia", -"atonic", -"atony", -"atop", -"atophan", -"atopic", -"atopite", -"atopy", -"atour", -"atoxic", -"atoxyl", -"atrail", -"atrepsy", -"atresia", -"atresic", -"atresy", -"atretic", -"atria", -"atrial", -"atrip", -"atrium", -"atrocha", -"atropal", -"atrophy", -"atropia", -"atropic", -"atrous", -"atry", -"atta", -"attacco", -"attach", -"attache", -"attack", -"attacus", -"attagen", -"attain", -"attaint", -"attaleh", -"attar", -"attask", -"attempt", -"attend", -"attent", -"atter", -"attern", -"attery", -"attest", -"attic", -"attid", -"attinge", -"attire", -"attired", -"attirer", -"attorn", -"attract", -"attrap", -"attrist", -"attrite", -"attune", -"atule", -"atumble", -"atune", -"atwain", -"atweel", -"atween", -"atwin", -"atwirl", -"atwist", -"atwitch", -"atwixt", -"atwo", -"atypic", -"atypy", -"auantic", -"aube", -"aubrite", -"auburn", -"auca", -"auchlet", -"auction", -"aucuba", -"audible", -"audibly", -"audient", -"audile", -"audio", -"audion", -"audit", -"auditor", -"auge", -"augen", -"augend", -"auger", -"augerer", -"augh", -"aught", -"augite", -"augitic", -"augment", -"augur", -"augural", -"augury", -"august", -"auh", -"auhuhu", -"auk", -"auklet", -"aula", -"aulae", -"auld", -"auletai", -"aulete", -"auletes", -"auletic", -"aulic", -"auloi", -"aulos", -"aulu", -"aum", -"aumaga", -"aumail", -"aumbry", -"aumery", -"aumil", -"aumous", -"aumrie", -"auncel", -"aune", -"aunt", -"auntie", -"auntish", -"auntly", -"aupaka", -"aura", -"aurae", -"aural", -"aurally", -"aurar", -"aurate", -"aurated", -"aureate", -"aureity", -"aurelia", -"aureola", -"aureole", -"aureous", -"auresca", -"aureus", -"auric", -"auricle", -"auride", -"aurific", -"aurify", -"aurigal", -"aurin", -"aurir", -"aurist", -"aurite", -"aurochs", -"auronal", -"aurora", -"aurorae", -"auroral", -"aurore", -"aurous", -"aurum", -"aurure", -"auryl", -"auscult", -"auslaut", -"auspex", -"auspice", -"auspicy", -"austere", -"austral", -"ausu", -"ausubo", -"autarch", -"autarky", -"aute", -"autecy", -"autem", -"author", -"autism", -"autist", -"auto", -"autobus", -"autocab", -"autocar", -"autoecy", -"autoist", -"automa", -"automat", -"autonym", -"autopsy", -"autumn", -"auxesis", -"auxetic", -"auxin", -"auxinic", -"auxotox", -"ava", -"avadana", -"avahi", -"avail", -"aval", -"avalent", -"avania", -"avarice", -"avast", -"avaunt", -"ave", -"avellan", -"aveloz", -"avenage", -"avener", -"avenge", -"avenger", -"avenin", -"avenous", -"avens", -"avenue", -"aver", -"avera", -"average", -"averah", -"averil", -"averin", -"averral", -"averse", -"avert", -"averted", -"averter", -"avian", -"aviary", -"aviate", -"aviatic", -"aviator", -"avichi", -"avicide", -"avick", -"avid", -"avidity", -"avidly", -"avidous", -"avidya", -"avigate", -"avijja", -"avine", -"aviso", -"avital", -"avitic", -"avives", -"avo", -"avocado", -"avocate", -"avocet", -"avodire", -"avoid", -"avoider", -"avolate", -"avouch", -"avow", -"avowal", -"avowant", -"avowed", -"avower", -"avowry", -"avoyer", -"avulse", -"aw", -"awa", -"awabi", -"awaft", -"awag", -"await", -"awaiter", -"awake", -"awaken", -"awald", -"awalim", -"awalt", -"awane", -"awapuhi", -"award", -"awarder", -"aware", -"awash", -"awaste", -"awat", -"awatch", -"awater", -"awave", -"away", -"awber", -"awd", -"awe", -"aweary", -"aweband", -"awee", -"aweek", -"aweel", -"aweigh", -"awesome", -"awest", -"aweto", -"awfu", -"awful", -"awfully", -"awheel", -"awheft", -"awhet", -"awhile", -"awhir", -"awhirl", -"awide", -"awiggle", -"awin", -"awing", -"awink", -"awiwi", -"awkward", -"awl", -"awless", -"awlwort", -"awmous", -"awn", -"awned", -"awner", -"awning", -"awnless", -"awnlike", -"awny", -"awoke", -"awork", -"awreck", -"awrist", -"awrong", -"awry", -"ax", -"axal", -"axe", -"axed", -"axenic", -"axes", -"axfetch", -"axhead", -"axial", -"axially", -"axiate", -"axiform", -"axil", -"axile", -"axilla", -"axillae", -"axillar", -"axine", -"axinite", -"axiom", -"axion", -"axis", -"axised", -"axite", -"axle", -"axled", -"axmaker", -"axman", -"axogamy", -"axoid", -"axolotl", -"axon", -"axonal", -"axonost", -"axseed", -"axstone", -"axtree", -"axunge", -"axweed", -"axwise", -"axwort", -"ay", -"ayah", -"aye", -"ayelp", -"ayin", -"ayless", -"aylet", -"ayllu", -"ayond", -"ayont", -"ayous", -"ayu", -"azafrin", -"azalea", -"azarole", -"azelaic", -"azelate", -"azide", -"azilut", -"azimene", -"azimide", -"azimine", -"azimino", -"azimuth", -"azine", -"aziola", -"azo", -"azoch", -"azofier", -"azofy", -"azoic", -"azole", -"azon", -"azonal", -"azonic", -"azonium", -"azophen", -"azorite", -"azotate", -"azote", -"azoted", -"azoth", -"azotic", -"azotine", -"azotite", -"azotize", -"azotous", -"azox", -"azoxime", -"azoxine", -"azoxy", -"azteca", -"azulene", -"azulite", -"azulmic", -"azumbre", -"azure", -"azurean", -"azured", -"azurine", -"azurite", -"azurous", -"azury", -"azygos", -"azygous", -"azyme", -"azymite", -"azymous", -"b", -"ba", -"baa", -"baal", -"baar", -"baba", -"babai", -"babasco", -"babassu", -"babbitt", -"babble", -"babbler", -"babbly", -"babby", -"babe", -"babelet", -"babery", -"babiche", -"babied", -"babish", -"bablah", -"babloh", -"baboen", -"baboo", -"baboon", -"baboot", -"babroot", -"babu", -"babudom", -"babuina", -"babuism", -"babul", -"baby", -"babydom", -"babyish", -"babyism", -"bac", -"bacaba", -"bacach", -"bacalao", -"bacao", -"bacca", -"baccae", -"baccara", -"baccate", -"bacchar", -"bacchic", -"bacchii", -"bach", -"bache", -"bachel", -"bacilli", -"back", -"backage", -"backcap", -"backed", -"backen", -"backer", -"backet", -"backie", -"backing", -"backjaw", -"backlet", -"backlog", -"backrun", -"backsaw", -"backset", -"backup", -"backway", -"baclin", -"bacon", -"baconer", -"bacony", -"bacula", -"bacule", -"baculi", -"baculum", -"baculus", -"bacury", -"bad", -"badan", -"baddish", -"baddock", -"bade", -"badge", -"badger", -"badiaga", -"badian", -"badious", -"badland", -"badly", -"badness", -"bae", -"baetuli", -"baetyl", -"bafaro", -"baff", -"baffeta", -"baffle", -"baffler", -"baffy", -"baft", -"bafta", -"bag", -"baga", -"bagani", -"bagasse", -"bagel", -"bagful", -"baggage", -"baggala", -"bagged", -"bagger", -"baggie", -"baggily", -"bagging", -"baggit", -"baggy", -"baglike", -"bagman", -"bagnio", -"bagnut", -"bago", -"bagonet", -"bagpipe", -"bagre", -"bagreef", -"bagroom", -"bagwig", -"bagworm", -"bagwyn", -"bah", -"bahan", -"bahar", -"bahay", -"bahera", -"bahisti", -"bahnung", -"baho", -"bahoe", -"bahoo", -"baht", -"bahur", -"bahut", -"baignet", -"baikie", -"bail", -"bailage", -"bailee", -"bailer", -"bailey", -"bailie", -"bailiff", -"bailor", -"bain", -"bainie", -"baioc", -"baiocco", -"bairagi", -"bairn", -"bairnie", -"bairnly", -"baister", -"bait", -"baiter", -"baith", -"baittle", -"baize", -"bajada", -"bajan", -"bajra", -"bajree", -"bajri", -"bajury", -"baka", -"bakal", -"bake", -"baked", -"baken", -"bakepan", -"baker", -"bakerly", -"bakery", -"bakie", -"baking", -"bakli", -"baktun", -"baku", -"bakula", -"bal", -"balafo", -"balagan", -"balai", -"balance", -"balanic", -"balanid", -"balao", -"balas", -"balata", -"balboa", -"balcony", -"bald", -"balden", -"balder", -"baldish", -"baldly", -"baldrib", -"baldric", -"baldy", -"bale", -"baleen", -"baleful", -"balei", -"baleise", -"baler", -"balete", -"bali", -"baline", -"balita", -"balk", -"balker", -"balky", -"ball", -"ballad", -"ballade", -"ballam", -"ballan", -"ballant", -"ballast", -"ballata", -"ballate", -"balldom", -"balled", -"baller", -"ballet", -"balli", -"ballist", -"ballium", -"balloon", -"ballot", -"ballow", -"ballup", -"bally", -"balm", -"balmily", -"balmony", -"balmy", -"balneal", -"balonea", -"baloney", -"baloo", -"balow", -"balsa", -"balsam", -"balsamo", -"balsamy", -"baltei", -"balter", -"balteus", -"balu", -"balut", -"balza", -"bam", -"bamban", -"bambini", -"bambino", -"bamboo", -"bamoth", -"ban", -"banaba", -"banago", -"banak", -"banal", -"banally", -"banana", -"banat", -"banc", -"banca", -"bancal", -"banchi", -"banco", -"bancus", -"band", -"banda", -"bandage", -"bandaka", -"bandala", -"bandar", -"bandbox", -"bande", -"bandeau", -"banded", -"bander", -"bandhu", -"bandi", -"bandie", -"banding", -"bandit", -"bandle", -"bandlet", -"bandman", -"bando", -"bandog", -"bandore", -"bandrol", -"bandy", -"bane", -"baneful", -"bang", -"banga", -"bange", -"banger", -"banghy", -"banging", -"bangkok", -"bangle", -"bangled", -"bani", -"banian", -"banig", -"banilad", -"banish", -"baniwa", -"baniya", -"banjo", -"banjore", -"banjuke", -"bank", -"banked", -"banker", -"bankera", -"banket", -"banking", -"bankman", -"banky", -"banner", -"bannet", -"banning", -"bannock", -"banns", -"bannut", -"banquet", -"banshee", -"bant", -"bantam", -"bantay", -"banteng", -"banter", -"bantery", -"banty", -"banuyo", -"banya", -"banyan", -"banzai", -"baobab", -"bap", -"baptism", -"baptize", -"bar", -"bara", -"barad", -"barauna", -"barb", -"barbal", -"barbary", -"barbas", -"barbate", -"barbe", -"barbed", -"barbel", -"barber", -"barbet", -"barbion", -"barblet", -"barbone", -"barbudo", -"barbule", -"bard", -"bardane", -"bardash", -"bardel", -"bardess", -"bardic", -"bardie", -"bardily", -"barding", -"bardish", -"bardism", -"bardlet", -"bardo", -"bardy", -"bare", -"bareca", -"barefit", -"barely", -"barer", -"baresma", -"baretta", -"barff", -"barfish", -"barfly", -"barful", -"bargain", -"barge", -"bargee", -"bargeer", -"barger", -"bargh", -"bargham", -"bari", -"baria", -"baric", -"barid", -"barie", -"barile", -"barilla", -"baring", -"baris", -"barish", -"barit", -"barite", -"barium", -"bark", -"barken", -"barker", -"barkery", -"barkey", -"barkhan", -"barking", -"barkle", -"barky", -"barless", -"barley", -"barling", -"barlock", -"barlow", -"barm", -"barmaid", -"barman", -"barmkin", -"barmote", -"barmy", -"barn", -"barnard", -"barney", -"barnful", -"barnman", -"barny", -"baroi", -"barolo", -"baron", -"baronet", -"barong", -"baronry", -"barony", -"baroque", -"baroto", -"barpost", -"barra", -"barrack", -"barrad", -"barrage", -"barras", -"barred", -"barrel", -"barren", -"barrer", -"barret", -"barrico", -"barrier", -"barring", -"barrio", -"barroom", -"barrow", -"barruly", -"barry", -"barse", -"barsom", -"barter", -"barth", -"barton", -"baru", -"baruria", -"barvel", -"barwal", -"barway", -"barways", -"barwise", -"barwood", -"barye", -"baryta", -"barytes", -"barytic", -"baryton", -"bas", -"basal", -"basale", -"basalia", -"basally", -"basalt", -"basaree", -"bascule", -"base", -"based", -"basely", -"baseman", -"basenji", -"bases", -"bash", -"bashaw", -"bashful", -"bashlyk", -"basial", -"basiate", -"basic", -"basidia", -"basify", -"basil", -"basilar", -"basilic", -"basin", -"basined", -"basinet", -"basion", -"basis", -"bask", -"basker", -"basket", -"basoid", -"bason", -"basos", -"basote", -"basque", -"basqued", -"bass", -"bassan", -"bassara", -"basset", -"bassie", -"bassine", -"bassist", -"basso", -"bassoon", -"bassus", -"bast", -"basta", -"bastard", -"baste", -"basten", -"baster", -"bastide", -"basting", -"bastion", -"bastite", -"basto", -"baston", -"bat", -"bataan", -"batad", -"batakan", -"batara", -"batata", -"batch", -"batcher", -"bate", -"batea", -"bateau", -"bateaux", -"bated", -"batel", -"bateman", -"bater", -"batfish", -"batfowl", -"bath", -"bathe", -"bather", -"bathic", -"bathing", -"bathman", -"bathmic", -"bathos", -"bathtub", -"bathyal", -"batik", -"batiker", -"bating", -"batino", -"batiste", -"batlan", -"batlike", -"batling", -"batlon", -"batman", -"batoid", -"baton", -"batonne", -"bats", -"batsman", -"batster", -"batt", -"batta", -"battel", -"batten", -"batter", -"battery", -"battik", -"batting", -"battish", -"battle", -"battled", -"battler", -"battue", -"batty", -"batule", -"batwing", -"batz", -"batzen", -"bauble", -"bauch", -"bauchle", -"bauckie", -"baud", -"baul", -"bauleah", -"baun", -"bauno", -"bauson", -"bausond", -"bauta", -"bauxite", -"bavaroy", -"bavary", -"bavian", -"baviere", -"bavin", -"bavoso", -"baw", -"bawbee", -"bawcock", -"bawd", -"bawdily", -"bawdry", -"bawl", -"bawler", -"bawley", -"bawn", -"bawtie", -"baxter", -"baxtone", -"bay", -"baya", -"bayal", -"bayamo", -"bayard", -"baybolt", -"baybush", -"baycuru", -"bayed", -"bayeta", -"baygall", -"bayhead", -"bayish", -"baylet", -"baylike", -"bayman", -"bayness", -"bayok", -"bayonet", -"bayou", -"baywood", -"bazaar", -"baze", -"bazoo", -"bazooka", -"bazzite", -"bdellid", -"be", -"beach", -"beached", -"beachy", -"beacon", -"bead", -"beaded", -"beader", -"beadily", -"beading", -"beadle", -"beadlet", -"beadman", -"beadrow", -"beady", -"beagle", -"beak", -"beaked", -"beaker", -"beakful", -"beaky", -"beal", -"beala", -"bealing", -"beam", -"beamage", -"beamed", -"beamer", -"beamful", -"beamily", -"beaming", -"beamish", -"beamlet", -"beamman", -"beamy", -"bean", -"beanbag", -"beancod", -"beanery", -"beanie", -"beano", -"beant", -"beany", -"bear", -"beard", -"bearded", -"bearder", -"beardie", -"beardom", -"beardy", -"bearer", -"bearess", -"bearing", -"bearish", -"bearlet", -"bearm", -"beast", -"beastie", -"beastly", -"beat", -"beata", -"beatae", -"beatee", -"beaten", -"beater", -"beath", -"beatify", -"beating", -"beatus", -"beau", -"beaufin", -"beauish", -"beauism", -"beauti", -"beauty", -"beaux", -"beaver", -"beavery", -"beback", -"bebait", -"bebang", -"bebar", -"bebaron", -"bebaste", -"bebat", -"bebathe", -"bebay", -"bebeast", -"bebed", -"bebeeru", -"bebilya", -"bebite", -"beblain", -"beblear", -"bebled", -"bebless", -"beblood", -"bebloom", -"bebog", -"bebop", -"beboss", -"bebotch", -"bebrave", -"bebrine", -"bebrush", -"bebump", -"bebusy", -"becall", -"becalm", -"becap", -"becard", -"becarve", -"becater", -"because", -"becense", -"bechalk", -"becharm", -"bechase", -"becheck", -"becher", -"bechern", -"bechirp", -"becivet", -"beck", -"becker", -"becket", -"beckon", -"beclad", -"beclang", -"beclart", -"beclasp", -"beclaw", -"becloak", -"beclog", -"becloud", -"beclout", -"beclown", -"becolme", -"becolor", -"become", -"becomes", -"becomma", -"becoom", -"becost", -"becovet", -"becram", -"becramp", -"becrawl", -"becreep", -"becrime", -"becroak", -"becross", -"becrowd", -"becrown", -"becrush", -"becrust", -"becry", -"becuiba", -"becuna", -"becurl", -"becurry", -"becurse", -"becut", -"bed", -"bedad", -"bedamn", -"bedamp", -"bedare", -"bedark", -"bedash", -"bedaub", -"bedawn", -"beday", -"bedaze", -"bedbug", -"bedcap", -"bedcase", -"bedcord", -"bedded", -"bedder", -"bedding", -"bedead", -"bedeaf", -"bedebt", -"bedeck", -"bedel", -"beden", -"bedene", -"bedevil", -"bedew", -"bedewer", -"bedfast", -"bedfoot", -"bedgery", -"bedgoer", -"bedgown", -"bedight", -"bedikah", -"bedim", -"bedin", -"bedip", -"bedirt", -"bedirty", -"bedizen", -"bedkey", -"bedlam", -"bedlar", -"bedless", -"bedlids", -"bedman", -"bedmate", -"bedog", -"bedolt", -"bedot", -"bedote", -"bedouse", -"bedown", -"bedoyo", -"bedpan", -"bedpost", -"bedrail", -"bedral", -"bedrape", -"bedress", -"bedrid", -"bedrift", -"bedrip", -"bedrock", -"bedroll", -"bedroom", -"bedrop", -"bedrown", -"bedrug", -"bedsick", -"bedside", -"bedsite", -"bedsock", -"bedsore", -"bedtick", -"bedtime", -"bedub", -"beduck", -"beduke", -"bedull", -"bedumb", -"bedunce", -"bedunch", -"bedung", -"bedur", -"bedusk", -"bedust", -"bedwarf", -"bedway", -"bedways", -"bedwell", -"bedye", -"bee", -"beearn", -"beech", -"beechen", -"beechy", -"beedged", -"beedom", -"beef", -"beefer", -"beefily", -"beefin", -"beefish", -"beefy", -"beehead", -"beeherd", -"beehive", -"beeish", -"beek", -"beekite", -"beelbow", -"beelike", -"beeline", -"beelol", -"beeman", -"been", -"beennut", -"beer", -"beerage", -"beerily", -"beerish", -"beery", -"bees", -"beest", -"beeswax", -"beet", -"beeth", -"beetle", -"beetled", -"beetler", -"beety", -"beeve", -"beevish", -"beeware", -"beeway", -"beeweed", -"beewise", -"beewort", -"befall", -"befame", -"befan", -"befancy", -"befavor", -"befilch", -"befile", -"befilth", -"befire", -"befist", -"befit", -"beflag", -"beflap", -"beflea", -"befleck", -"beflour", -"beflout", -"beflum", -"befoam", -"befog", -"befool", -"befop", -"before", -"befoul", -"befret", -"befrill", -"befriz", -"befume", -"beg", -"begad", -"begall", -"begani", -"begar", -"begari", -"begash", -"begat", -"begaud", -"begaudy", -"begay", -"begaze", -"begeck", -"begem", -"beget", -"beggar", -"beggary", -"begging", -"begift", -"begild", -"begin", -"begird", -"beglad", -"beglare", -"beglic", -"beglide", -"begloom", -"begloze", -"begluc", -"beglue", -"begnaw", -"bego", -"begob", -"begobs", -"begohm", -"begone", -"begonia", -"begorra", -"begorry", -"begoud", -"begowk", -"begrace", -"begrain", -"begrave", -"begray", -"begreen", -"begrett", -"begrim", -"begrime", -"begroan", -"begrown", -"beguard", -"beguess", -"beguile", -"beguine", -"begulf", -"begum", -"begun", -"begunk", -"begut", -"behale", -"behalf", -"behap", -"behave", -"behead", -"behear", -"behears", -"behedge", -"beheld", -"behelp", -"behen", -"behenic", -"behest", -"behind", -"behint", -"behn", -"behold", -"behoney", -"behoof", -"behoot", -"behoove", -"behorn", -"behowl", -"behung", -"behymn", -"beice", -"beige", -"being", -"beinked", -"beira", -"beisa", -"bejade", -"bejan", -"bejant", -"bejazz", -"bejel", -"bejewel", -"bejig", -"bekah", -"bekick", -"beking", -"bekiss", -"bekko", -"beknave", -"beknit", -"beknow", -"beknown", -"bel", -"bela", -"belabor", -"belaced", -"beladle", -"belady", -"belage", -"belah", -"belam", -"belanda", -"belar", -"belard", -"belash", -"belate", -"belated", -"belaud", -"belay", -"belayer", -"belch", -"belcher", -"beld", -"beldam", -"beleaf", -"beleap", -"beleave", -"belee", -"belfry", -"belga", -"belibel", -"belick", -"belie", -"belief", -"belier", -"believe", -"belight", -"beliked", -"belion", -"belite", -"belive", -"bell", -"bellboy", -"belle", -"belled", -"bellhop", -"bellied", -"belling", -"bellite", -"bellman", -"bellote", -"bellow", -"bellows", -"belly", -"bellyer", -"beloam", -"beloid", -"belong", -"belonid", -"belord", -"belout", -"belove", -"beloved", -"below", -"belsire", -"belt", -"belted", -"belter", -"beltie", -"beltine", -"belting", -"beltman", -"belton", -"beluga", -"belute", -"belve", -"bely", -"belying", -"bema", -"bemad", -"bemadam", -"bemail", -"bemaim", -"beman", -"bemar", -"bemask", -"bemat", -"bemata", -"bemaul", -"bemazed", -"bemeal", -"bemean", -"bemercy", -"bemire", -"bemist", -"bemix", -"bemoan", -"bemoat", -"bemock", -"bemoil", -"bemole", -"bemolt", -"bemoon", -"bemotto", -"bemoult", -"bemouth", -"bemuck", -"bemud", -"bemuddy", -"bemuse", -"bemused", -"bemusk", -"ben", -"bena", -"benab", -"bename", -"benami", -"benasty", -"benben", -"bench", -"bencher", -"benchy", -"bencite", -"bend", -"benda", -"bended", -"bender", -"bending", -"bendlet", -"bendy", -"bene", -"beneath", -"benefic", -"benefit", -"benempt", -"benet", -"beng", -"beni", -"benight", -"benign", -"benison", -"benj", -"benjy", -"benmost", -"benn", -"benne", -"bennel", -"bennet", -"benny", -"beno", -"benorth", -"benote", -"bensel", -"bensh", -"benshea", -"benshee", -"benshi", -"bent", -"bentang", -"benthal", -"benthic", -"benthon", -"benthos", -"benting", -"benty", -"benumb", -"benward", -"benweed", -"benzal", -"benzein", -"benzene", -"benzil", -"benzine", -"benzo", -"benzoic", -"benzoid", -"benzoin", -"benzol", -"benzole", -"benzoxy", -"benzoyl", -"benzyl", -"beode", -"bepaid", -"bepale", -"bepaper", -"beparch", -"beparse", -"bepart", -"bepaste", -"bepat", -"bepaw", -"bepearl", -"bepelt", -"bepen", -"bepewed", -"bepiece", -"bepile", -"bepill", -"bepinch", -"bepity", -"beprank", -"bepray", -"bepress", -"bepride", -"beprose", -"bepuff", -"bepun", -"bequalm", -"bequest", -"bequote", -"ber", -"berain", -"berakah", -"berake", -"berapt", -"berat", -"berate", -"beray", -"bere", -"bereave", -"bereft", -"berend", -"beret", -"berg", -"berger", -"berglet", -"bergut", -"bergy", -"bergylt", -"berhyme", -"beride", -"berinse", -"berith", -"berley", -"berlin", -"berline", -"berm", -"berne", -"berobed", -"beroll", -"beround", -"berret", -"berri", -"berried", -"berrier", -"berry", -"berseem", -"berserk", -"berth", -"berthed", -"berther", -"bertram", -"bertrum", -"berust", -"bervie", -"berycid", -"beryl", -"bes", -"besa", -"besagne", -"besaiel", -"besaint", -"besan", -"besauce", -"bescab", -"bescarf", -"bescent", -"bescorn", -"bescour", -"bescurf", -"beseam", -"besee", -"beseech", -"beseem", -"beseen", -"beset", -"beshade", -"beshag", -"beshake", -"beshame", -"beshear", -"beshell", -"beshine", -"beshlik", -"beshod", -"beshout", -"beshow", -"beshrew", -"beside", -"besides", -"besiege", -"besigh", -"besin", -"besing", -"besiren", -"besit", -"beslab", -"beslap", -"beslash", -"beslave", -"beslime", -"beslow", -"beslur", -"besmear", -"besmell", -"besmile", -"besmoke", -"besmut", -"besnare", -"besneer", -"besnow", -"besnuff", -"besogne", -"besoil", -"besom", -"besomer", -"besoot", -"besot", -"besoul", -"besour", -"bespate", -"bespawl", -"bespeak", -"besped", -"bespeed", -"bespell", -"bespend", -"bespete", -"bespew", -"bespice", -"bespill", -"bespin", -"bespit", -"besplit", -"bespoke", -"bespot", -"bespout", -"bespray", -"bespy", -"besquib", -"besra", -"best", -"bestab", -"bestain", -"bestamp", -"bestar", -"bestare", -"bestay", -"bestead", -"besteer", -"bester", -"bestial", -"bestick", -"bestill", -"bestink", -"bestir", -"bestock", -"bestore", -"bestorm", -"bestove", -"bestow", -"bestraw", -"bestrew", -"bestuck", -"bestud", -"besugar", -"besuit", -"besully", -"beswarm", -"beswim", -"bet", -"beta", -"betag", -"betail", -"betaine", -"betalk", -"betask", -"betaxed", -"betear", -"beteela", -"beteem", -"betel", -"beth", -"bethel", -"bethink", -"bethumb", -"bethump", -"betide", -"betimes", -"betinge", -"betire", -"betis", -"betitle", -"betoil", -"betoken", -"betone", -"betony", -"betoss", -"betowel", -"betrace", -"betrail", -"betrap", -"betray", -"betread", -"betrend", -"betrim", -"betroth", -"betrunk", -"betso", -"betted", -"better", -"betters", -"betting", -"bettong", -"bettor", -"betty", -"betulin", -"betutor", -"between", -"betwine", -"betwit", -"betwixt", -"beveil", -"bevel", -"beveled", -"beveler", -"bevenom", -"bever", -"beverse", -"beveto", -"bevined", -"bevomit", -"bevue", -"bevy", -"bewail", -"bewall", -"beware", -"bewash", -"bewaste", -"bewater", -"beweary", -"beweep", -"bewept", -"bewest", -"bewet", -"bewhig", -"bewhite", -"bewidow", -"bewig", -"bewired", -"bewitch", -"bewith", -"bework", -"beworm", -"beworn", -"beworry", -"bewrap", -"bewray", -"bewreck", -"bewrite", -"bey", -"beydom", -"beylic", -"beyond", -"beyship", -"bezant", -"bezanty", -"bezel", -"bezetta", -"bezique", -"bezoar", -"bezzi", -"bezzle", -"bezzo", -"bhabar", -"bhakta", -"bhakti", -"bhalu", -"bhandar", -"bhang", -"bhangi", -"bhara", -"bharal", -"bhat", -"bhava", -"bheesty", -"bhikku", -"bhikshu", -"bhoosa", -"bhoy", -"bhungi", -"bhut", -"biabo", -"biacid", -"biacuru", -"bialate", -"biallyl", -"bianco", -"biarchy", -"bias", -"biaxal", -"biaxial", -"bib", -"bibasic", -"bibb", -"bibber", -"bibble", -"bibbler", -"bibbons", -"bibcock", -"bibi", -"bibiri", -"bibless", -"biblus", -"bice", -"biceps", -"bicetyl", -"bichir", -"bichord", -"bichy", -"bick", -"bicker", -"bickern", -"bicolor", -"bicone", -"biconic", -"bicorn", -"bicorne", -"bicron", -"bicycle", -"bicyclo", -"bid", -"bidar", -"bidarka", -"bidcock", -"bidder", -"bidding", -"biddy", -"bide", -"bident", -"bider", -"bidet", -"biding", -"bidri", -"biduous", -"bield", -"bieldy", -"bien", -"bienly", -"biennia", -"bier", -"bietle", -"bifara", -"bifer", -"biff", -"biffin", -"bifid", -"bifidly", -"bifilar", -"biflex", -"bifocal", -"bifoil", -"bifold", -"bifolia", -"biform", -"bifront", -"big", -"biga", -"bigamic", -"bigamy", -"bigener", -"bigeye", -"bigg", -"biggah", -"biggen", -"bigger", -"biggest", -"biggin", -"biggish", -"bigha", -"bighead", -"bighorn", -"bight", -"biglot", -"bigness", -"bignou", -"bigot", -"bigoted", -"bigotry", -"bigotty", -"bigroot", -"bigwig", -"bija", -"bijasal", -"bijou", -"bijoux", -"bike", -"bikh", -"bikini", -"bilabe", -"bilalo", -"bilbie", -"bilbo", -"bilby", -"bilch", -"bilcock", -"bildar", -"bilders", -"bile", -"bilge", -"bilgy", -"biliary", -"biliate", -"bilic", -"bilify", -"bilimbi", -"bilio", -"bilious", -"bilith", -"bilk", -"bilker", -"bill", -"billa", -"billbug", -"billed", -"biller", -"billet", -"billety", -"billian", -"billing", -"billion", -"billman", -"billon", -"billot", -"billow", -"billowy", -"billy", -"billyer", -"bilo", -"bilobe", -"bilobed", -"bilsh", -"bilsted", -"biltong", -"bimalar", -"bimanal", -"bimane", -"bimasty", -"bimbil", -"bimeby", -"bimodal", -"bin", -"binal", -"binary", -"binate", -"bind", -"binder", -"bindery", -"binding", -"bindle", -"bindlet", -"bindweb", -"bine", -"bing", -"binge", -"bingey", -"binghi", -"bingle", -"bingo", -"bingy", -"binh", -"bink", -"binman", -"binna", -"binning", -"binnite", -"bino", -"binocle", -"binodal", -"binode", -"binotic", -"binous", -"bint", -"binukau", -"biod", -"biodyne", -"biogen", -"biogeny", -"bioherm", -"biolith", -"biology", -"biome", -"bion", -"bionomy", -"biopsic", -"biopsy", -"bioral", -"biorgan", -"bios", -"biose", -"biosis", -"biota", -"biotaxy", -"biotic", -"biotics", -"biotin", -"biotite", -"biotome", -"biotomy", -"biotope", -"biotype", -"bioxide", -"bipack", -"biparty", -"biped", -"bipedal", -"biphase", -"biplane", -"bipod", -"bipolar", -"biprism", -"biprong", -"birch", -"birchen", -"bird", -"birddom", -"birdeen", -"birder", -"birdie", -"birding", -"birdlet", -"birdman", -"birdy", -"bireme", -"biretta", -"biri", -"biriba", -"birk", -"birken", -"birkie", -"birl", -"birle", -"birler", -"birlie", -"birlinn", -"birma", -"birn", -"birny", -"birr", -"birse", -"birsle", -"birsy", -"birth", -"birthy", -"bis", -"bisabol", -"bisalt", -"biscuit", -"bisect", -"bisexed", -"bisext", -"bishop", -"bismar", -"bismite", -"bismuth", -"bisnaga", -"bison", -"bispore", -"bisque", -"bissext", -"bisson", -"bistate", -"bister", -"bisti", -"bistort", -"bistro", -"bit", -"bitable", -"bitch", -"bite", -"biter", -"biti", -"biting", -"bitless", -"bito", -"bitolyl", -"bitt", -"bitted", -"bitten", -"bitter", -"bittern", -"bitters", -"bittie", -"bittock", -"bitty", -"bitume", -"bitumed", -"bitumen", -"bitwise", -"bityite", -"bitypic", -"biune", -"biunial", -"biunity", -"biurate", -"biurea", -"biuret", -"bivalve", -"bivinyl", -"bivious", -"bivocal", -"bivouac", -"biwa", -"bixin", -"biz", -"bizarre", -"bizet", -"bizonal", -"bizone", -"bizz", -"blab", -"blabber", -"black", -"blacken", -"blacker", -"blackey", -"blackie", -"blackit", -"blackly", -"blacky", -"blad", -"bladder", -"blade", -"bladed", -"blader", -"blading", -"bladish", -"blady", -"blae", -"blaff", -"blaflum", -"blah", -"blain", -"blair", -"blake", -"blame", -"blamed", -"blamer", -"blaming", -"blan", -"blanc", -"blanca", -"blanch", -"blanco", -"bland", -"blanda", -"blandly", -"blank", -"blanked", -"blanket", -"blankly", -"blanky", -"blanque", -"blare", -"blarney", -"blarnid", -"blarny", -"blart", -"blas", -"blase", -"blash", -"blashy", -"blast", -"blasted", -"blaster", -"blastid", -"blastie", -"blasty", -"blat", -"blatant", -"blate", -"blately", -"blather", -"blatta", -"blatter", -"blatti", -"blattid", -"blaubok", -"blaver", -"blaw", -"blawort", -"blay", -"blaze", -"blazer", -"blazing", -"blazon", -"blazy", -"bleach", -"bleak", -"bleakly", -"bleaky", -"blear", -"bleared", -"bleary", -"bleat", -"bleater", -"bleaty", -"bleb", -"blebby", -"bleck", -"blee", -"bleed", -"bleeder", -"bleery", -"bleeze", -"bleezy", -"blellum", -"blemish", -"blench", -"blend", -"blende", -"blended", -"blender", -"blendor", -"blenny", -"blent", -"bleo", -"blesbok", -"bless", -"blessed", -"blesser", -"blest", -"blet", -"blewits", -"blibe", -"blick", -"blickey", -"blight", -"blighty", -"blimp", -"blimy", -"blind", -"blinded", -"blinder", -"blindly", -"blink", -"blinked", -"blinker", -"blinks", -"blinky", -"blinter", -"blintze", -"blip", -"bliss", -"blissom", -"blister", -"blite", -"blithe", -"blithen", -"blither", -"blitter", -"blitz", -"blizz", -"blo", -"bloat", -"bloated", -"bloater", -"blob", -"blobbed", -"blobber", -"blobby", -"bloc", -"block", -"blocked", -"blocker", -"blocky", -"blodite", -"bloke", -"blolly", -"blonde", -"blood", -"blooded", -"bloody", -"blooey", -"bloom", -"bloomer", -"bloomy", -"bloop", -"blooper", -"blore", -"blosmy", -"blossom", -"blot", -"blotch", -"blotchy", -"blotter", -"blotto", -"blotty", -"blouse", -"bloused", -"blout", -"blow", -"blowen", -"blower", -"blowfly", -"blowgun", -"blowing", -"blown", -"blowoff", -"blowout", -"blowth", -"blowup", -"blowy", -"blowze", -"blowzed", -"blowzy", -"blub", -"blubber", -"blucher", -"blue", -"bluecap", -"bluecup", -"blueing", -"blueleg", -"bluely", -"bluer", -"blues", -"bluet", -"bluetop", -"bluey", -"bluff", -"bluffer", -"bluffly", -"bluffy", -"bluggy", -"bluing", -"bluish", -"bluism", -"blunder", -"blunge", -"blunger", -"blunk", -"blunker", -"blunks", -"blunnen", -"blunt", -"blunter", -"bluntie", -"bluntly", -"blup", -"blur", -"blurb", -"blurred", -"blurrer", -"blurry", -"blurt", -"blush", -"blusher", -"blushy", -"bluster", -"blype", -"bo", -"boa", -"boagane", -"boar", -"board", -"boarder", -"boardly", -"boardy", -"boarish", -"boast", -"boaster", -"boat", -"boatage", -"boater", -"boatful", -"boatie", -"boating", -"boatlip", -"boatly", -"boatman", -"bob", -"boba", -"bobac", -"bobbed", -"bobber", -"bobbery", -"bobbin", -"bobbing", -"bobbish", -"bobble", -"bobby", -"bobcat", -"bobcoat", -"bobeche", -"bobfly", -"bobo", -"bobotie", -"bobsled", -"bobstay", -"bobtail", -"bobwood", -"bocal", -"bocardo", -"bocca", -"boccale", -"boccaro", -"bocce", -"boce", -"bocher", -"bock", -"bocking", -"bocoy", -"bod", -"bodach", -"bode", -"bodeful", -"bodega", -"boden", -"boder", -"bodge", -"bodger", -"bodgery", -"bodhi", -"bodice", -"bodiced", -"bodied", -"bodier", -"bodikin", -"bodily", -"boding", -"bodkin", -"bodle", -"bodock", -"body", -"bog", -"boga", -"bogan", -"bogard", -"bogart", -"bogey", -"boggart", -"boggin", -"boggish", -"boggle", -"boggler", -"boggy", -"boghole", -"bogie", -"bogier", -"bogland", -"bogle", -"boglet", -"bogman", -"bogmire", -"bogo", -"bogong", -"bogtrot", -"bogue", -"bogum", -"bogus", -"bogway", -"bogwood", -"bogwort", -"bogy", -"bogydom", -"bogyism", -"bohawn", -"bohea", -"boho", -"bohor", -"bohunk", -"boid", -"boil", -"boiled", -"boiler", -"boilery", -"boiling", -"boily", -"boist", -"bojite", -"bojo", -"bokadam", -"bokard", -"bokark", -"boke", -"bokom", -"bola", -"bolar", -"bold", -"bolden", -"boldine", -"boldly", -"boldo", -"bole", -"boled", -"boleite", -"bolero", -"bolete", -"bolide", -"bolimba", -"bolis", -"bolivar", -"bolivia", -"bolk", -"boll", -"bollard", -"bolled", -"boller", -"bolling", -"bollock", -"bolly", -"bolo", -"boloman", -"boloney", -"bolson", -"bolster", -"bolt", -"boltage", -"boltant", -"boltel", -"bolter", -"bolti", -"bolting", -"bolus", -"bom", -"boma", -"bomb", -"bombard", -"bombast", -"bombed", -"bomber", -"bombo", -"bombola", -"bombous", -"bon", -"bonaci", -"bonagh", -"bonaght", -"bonair", -"bonally", -"bonang", -"bonanza", -"bonasus", -"bonbon", -"bonce", -"bond", -"bondage", -"bondar", -"bonded", -"bonder", -"bonding", -"bondman", -"bonduc", -"bone", -"boned", -"bonedog", -"bonelet", -"boner", -"boneset", -"bonfire", -"bong", -"bongo", -"boniata", -"bonify", -"bonito", -"bonk", -"bonnaz", -"bonnet", -"bonnily", -"bonny", -"bonsai", -"bonus", -"bonxie", -"bony", -"bonze", -"bonzer", -"bonzery", -"bonzian", -"boo", -"boob", -"boobery", -"boobily", -"boobook", -"booby", -"bood", -"boodie", -"boodle", -"boodler", -"boody", -"boof", -"booger", -"boohoo", -"boojum", -"book", -"bookdom", -"booked", -"booker", -"bookery", -"bookful", -"bookie", -"booking", -"bookish", -"bookism", -"booklet", -"bookman", -"booky", -"bool", -"booly", -"boolya", -"boom", -"boomage", -"boomah", -"boomdas", -"boomer", -"booming", -"boomlet", -"boomy", -"boon", -"boonk", -"boopis", -"boor", -"boorish", -"boort", -"boose", -"boost", -"booster", -"boosy", -"boot", -"bootboy", -"booted", -"bootee", -"booter", -"bootery", -"bootful", -"booth", -"boother", -"bootied", -"booting", -"bootleg", -"boots", -"booty", -"booze", -"boozed", -"boozer", -"boozily", -"boozy", -"bop", -"bopeep", -"boppist", -"bopyrid", -"bor", -"bora", -"borable", -"boracic", -"borage", -"borak", -"boral", -"borasca", -"borate", -"borax", -"bord", -"bordage", -"bordar", -"bordel", -"border", -"bordure", -"bore", -"boread", -"boreal", -"borean", -"boredom", -"boree", -"boreen", -"boregat", -"boreism", -"borele", -"borer", -"borg", -"borgh", -"borh", -"boric", -"boride", -"borine", -"boring", -"borish", -"borism", -"bority", -"borize", -"borlase", -"born", -"borne", -"borneol", -"borning", -"bornite", -"bornyl", -"boro", -"boron", -"boronic", -"borough", -"borrel", -"borrow", -"borsch", -"borscht", -"borsht", -"bort", -"bortsch", -"borty", -"bortz", -"borwort", -"boryl", -"borzoi", -"boscage", -"bosch", -"bose", -"boser", -"bosh", -"bosher", -"bosk", -"bosker", -"bosket", -"bosky", -"bosn", -"bosom", -"bosomed", -"bosomer", -"bosomy", -"boss", -"bossage", -"bossdom", -"bossed", -"bosser", -"bosset", -"bossing", -"bossism", -"bosslet", -"bossy", -"boston", -"bostryx", -"bosun", -"bot", -"bota", -"botanic", -"botany", -"botargo", -"botch", -"botched", -"botcher", -"botchka", -"botchy", -"bote", -"botella", -"boterol", -"botfly", -"both", -"bother", -"bothros", -"bothway", -"bothy", -"botonee", -"botong", -"bott", -"bottine", -"bottle", -"bottled", -"bottler", -"bottom", -"botulin", -"bouchal", -"bouche", -"boucher", -"boud", -"boudoir", -"bougar", -"bouge", -"bouget", -"bough", -"boughed", -"bought", -"boughy", -"bougie", -"bouk", -"boukit", -"boulder", -"boule", -"boultel", -"boulter", -"boun", -"bounce", -"bouncer", -"bound", -"bounded", -"bounden", -"bounder", -"boundly", -"bounty", -"bouquet", -"bourbon", -"bourd", -"bourder", -"bourdon", -"bourg", -"bourn", -"bourock", -"bourse", -"bouse", -"bouser", -"bousy", -"bout", -"boutade", -"bouto", -"bouw", -"bovate", -"bovid", -"bovine", -"bovoid", -"bow", -"bowable", -"bowback", -"bowbent", -"bowboy", -"bowed", -"bowel", -"boweled", -"bowels", -"bower", -"bowery", -"bowet", -"bowfin", -"bowhead", -"bowie", -"bowing", -"bowk", -"bowkail", -"bowker", -"bowknot", -"bowl", -"bowla", -"bowleg", -"bowler", -"bowless", -"bowlful", -"bowlike", -"bowline", -"bowling", -"bowls", -"bowly", -"bowman", -"bowpin", -"bowshot", -"bowwood", -"bowwort", -"bowwow", -"bowyer", -"boxbush", -"boxcar", -"boxen", -"boxer", -"boxfish", -"boxful", -"boxhaul", -"boxhead", -"boxing", -"boxlike", -"boxman", -"boxty", -"boxwood", -"boxwork", -"boxy", -"boy", -"boyang", -"boyar", -"boyard", -"boycott", -"boydom", -"boyer", -"boyhood", -"boyish", -"boyism", -"boyla", -"boylike", -"boyship", -"boza", -"bozal", -"bozo", -"bozze", -"bra", -"brab", -"brabant", -"brabble", -"braca", -"braccia", -"braccio", -"brace", -"braced", -"bracer", -"bracero", -"braces", -"brach", -"brachet", -"bracing", -"brack", -"bracken", -"bracker", -"bracket", -"bracky", -"bract", -"bractea", -"bracted", -"brad", -"bradawl", -"bradsot", -"brae", -"braeman", -"brag", -"braggat", -"bragger", -"bragget", -"bragite", -"braid", -"braided", -"braider", -"brail", -"brain", -"brainer", -"brainge", -"brains", -"brainy", -"braird", -"brairo", -"braise", -"brake", -"braker", -"brakie", -"braky", -"bramble", -"brambly", -"bran", -"branch", -"branchi", -"branchy", -"brand", -"branded", -"brander", -"brandy", -"brangle", -"branial", -"brank", -"brankie", -"branle", -"branner", -"branny", -"bransle", -"brant", -"brash", -"brashy", -"brasque", -"brass", -"brasse", -"brasser", -"brasset", -"brassic", -"brassie", -"brassy", -"brat", -"brattie", -"brattle", -"brauna", -"bravade", -"bravado", -"brave", -"bravely", -"braver", -"bravery", -"braving", -"bravish", -"bravo", -"bravura", -"braw", -"brawl", -"brawler", -"brawly", -"brawlys", -"brawn", -"brawned", -"brawner", -"brawny", -"braws", -"braxy", -"bray", -"brayer", -"brayera", -"braza", -"braze", -"brazen", -"brazer", -"brazera", -"brazier", -"brazil", -"breach", -"breachy", -"bread", -"breaden", -"breadth", -"breaghe", -"break", -"breakax", -"breaker", -"breakup", -"bream", -"breards", -"breast", -"breath", -"breathe", -"breathy", -"breba", -"breccia", -"brecham", -"breck", -"brecken", -"bred", -"brede", -"bredi", -"bree", -"breech", -"breed", -"breeder", -"breedy", -"breek", -"breeze", -"breezy", -"bregma", -"brehon", -"brei", -"brekkle", -"brelaw", -"breme", -"bremely", -"brent", -"brephic", -"bret", -"breth", -"brett", -"breva", -"breve", -"brevet", -"brevier", -"brevit", -"brevity", -"brew", -"brewage", -"brewer", -"brewery", -"brewing", -"brewis", -"brewst", -"brey", -"briar", -"bribe", -"bribee", -"briber", -"bribery", -"brichen", -"brick", -"brickel", -"bricken", -"brickle", -"brickly", -"bricky", -"bricole", -"bridal", -"bridale", -"bride", -"bridely", -"bridge", -"bridged", -"bridger", -"bridle", -"bridled", -"bridler", -"bridoon", -"brief", -"briefly", -"briefs", -"brier", -"briered", -"briery", -"brieve", -"brig", -"brigade", -"brigand", -"bright", -"brill", -"brills", -"brim", -"brimful", -"briming", -"brimmed", -"brimmer", -"brin", -"brine", -"briner", -"bring", -"bringal", -"bringer", -"brinish", -"brinjal", -"brink", -"briny", -"brioche", -"brique", -"brisk", -"brisken", -"brisket", -"briskly", -"brisque", -"briss", -"bristle", -"bristly", -"brisure", -"brit", -"brith", -"brither", -"britska", -"britten", -"brittle", -"brizz", -"broach", -"broad", -"broadax", -"broaden", -"broadly", -"brob", -"brocade", -"brocard", -"broch", -"brochan", -"broche", -"brocho", -"brock", -"brocked", -"brocket", -"brockle", -"brod", -"brodder", -"brog", -"brogan", -"brogger", -"broggle", -"brogue", -"broguer", -"broider", -"broigne", -"broil", -"broiler", -"brokage", -"broke", -"broken", -"broker", -"broking", -"brolga", -"broll", -"brolly", -"broma", -"bromal", -"bromate", -"brome", -"bromic", -"bromide", -"bromine", -"bromism", -"bromite", -"bromize", -"bromoil", -"bromol", -"bromous", -"bronc", -"bronchi", -"bronco", -"bronk", -"bronze", -"bronzed", -"bronzen", -"bronzer", -"bronzy", -"broo", -"brooch", -"brood", -"brooder", -"broody", -"brook", -"brooked", -"brookie", -"brooky", -"brool", -"broom", -"broomer", -"broomy", -"broon", -"broose", -"brose", -"brosot", -"brosy", -"brot", -"brotan", -"brotany", -"broth", -"brothel", -"brother", -"brothy", -"brough", -"brought", -"brow", -"browden", -"browed", -"browis", -"browman", -"brown", -"browner", -"brownie", -"brownly", -"browny", -"browse", -"browser", -"browst", -"bruang", -"brucia", -"brucina", -"brucine", -"brucite", -"bruckle", -"brugh", -"bruin", -"bruise", -"bruiser", -"bruit", -"bruiter", -"bruke", -"brulee", -"brulyie", -"brumal", -"brumby", -"brume", -"brumous", -"brunch", -"brunet", -"brunt", -"bruscus", -"brush", -"brushed", -"brusher", -"brushes", -"brushet", -"brushy", -"brusque", -"brustle", -"brut", -"brutage", -"brutal", -"brute", -"brutely", -"brutify", -"bruting", -"brutish", -"brutism", -"brutter", -"bruzz", -"bryonin", -"bryony", -"bu", -"bual", -"buaze", -"bub", -"buba", -"bubal", -"bubalis", -"bubble", -"bubbler", -"bubbly", -"bubby", -"bubinga", -"bubo", -"buboed", -"bubonic", -"bubukle", -"bucare", -"bucca", -"buccal", -"buccan", -"buccate", -"buccina", -"buccula", -"buchite", -"buchu", -"buck", -"bucked", -"buckeen", -"bucker", -"bucket", -"buckety", -"buckeye", -"buckie", -"bucking", -"buckish", -"buckle", -"buckled", -"buckler", -"bucklum", -"bucko", -"buckpot", -"buckra", -"buckram", -"bucksaw", -"bucky", -"bucolic", -"bucrane", -"bud", -"buda", -"buddage", -"budder", -"buddhi", -"budding", -"buddle", -"buddler", -"buddy", -"budge", -"budger", -"budget", -"budless", -"budlet", -"budlike", -"budmash", -"budtime", -"budwood", -"budworm", -"budzat", -"bufagin", -"buff", -"buffalo", -"buffed", -"buffer", -"buffet", -"buffing", -"buffle", -"buffont", -"buffoon", -"buffy", -"bufidin", -"bufo", -"bug", -"bugaboo", -"bugan", -"bugbane", -"bugbear", -"bugbite", -"bugdom", -"bugfish", -"bugger", -"buggery", -"buggy", -"bughead", -"bugle", -"bugled", -"bugler", -"buglet", -"bugloss", -"bugre", -"bugseed", -"bugweed", -"bugwort", -"buhl", -"buhr", -"build", -"builder", -"buildup", -"built", -"buirdly", -"buisson", -"buist", -"bukh", -"bukshi", -"bulak", -"bulb", -"bulbar", -"bulbed", -"bulbil", -"bulblet", -"bulbose", -"bulbous", -"bulbul", -"bulbule", -"bulby", -"bulchin", -"bulge", -"bulger", -"bulgy", -"bulimia", -"bulimic", -"bulimy", -"bulk", -"bulked", -"bulker", -"bulkily", -"bulkish", -"bulky", -"bull", -"bulla", -"bullace", -"bullan", -"bullary", -"bullate", -"bullbat", -"bulldog", -"buller", -"bullet", -"bullety", -"bulling", -"bullion", -"bullish", -"bullism", -"bullit", -"bullnut", -"bullock", -"bullous", -"bullule", -"bully", -"bulrush", -"bulse", -"bult", -"bulter", -"bultey", -"bultong", -"bultow", -"bulwand", -"bulwark", -"bum", -"bumbaze", -"bumbee", -"bumble", -"bumbler", -"bumbo", -"bumboat", -"bumicky", -"bummalo", -"bummed", -"bummer", -"bummie", -"bumming", -"bummler", -"bummock", -"bump", -"bumpee", -"bumper", -"bumpily", -"bumping", -"bumpkin", -"bumpy", -"bumtrap", -"bumwood", -"bun", -"buna", -"buncal", -"bunce", -"bunch", -"buncher", -"bunchy", -"bund", -"bunder", -"bundle", -"bundler", -"bundlet", -"bundook", -"bundy", -"bung", -"bungee", -"bungey", -"bungfu", -"bungle", -"bungler", -"bungo", -"bungy", -"bunion", -"bunk", -"bunker", -"bunkery", -"bunkie", -"bunko", -"bunkum", -"bunnell", -"bunny", -"bunt", -"buntal", -"bunted", -"bunter", -"bunting", -"bunton", -"bunty", -"bunya", -"bunyah", -"bunyip", -"buoy", -"buoyage", -"buoyant", -"bur", -"buran", -"burao", -"burbank", -"burbark", -"burble", -"burbler", -"burbly", -"burbot", -"burbush", -"burd", -"burden", -"burdie", -"burdock", -"burdon", -"bure", -"bureau", -"bureaux", -"burel", -"burele", -"buret", -"burette", -"burfish", -"burg", -"burgage", -"burgall", -"burgee", -"burgeon", -"burgess", -"burgh", -"burghal", -"burgher", -"burglar", -"burgle", -"burgoo", -"burgul", -"burgus", -"burhead", -"buri", -"burial", -"burian", -"buried", -"burier", -"burin", -"burion", -"buriti", -"burka", -"burke", -"burker", -"burl", -"burlap", -"burled", -"burler", -"burlet", -"burlily", -"burly", -"burmite", -"burn", -"burned", -"burner", -"burnet", -"burnie", -"burning", -"burnish", -"burnous", -"burnout", -"burnt", -"burnut", -"burny", -"buro", -"burp", -"burr", -"burrah", -"burred", -"burrel", -"burrer", -"burring", -"burrish", -"burrito", -"burro", -"burrow", -"burry", -"bursa", -"bursal", -"bursar", -"bursary", -"bursate", -"burse", -"burseed", -"burst", -"burster", -"burt", -"burton", -"burucha", -"burweed", -"bury", -"burying", -"bus", -"busby", -"buscarl", -"bush", -"bushed", -"bushel", -"busher", -"bushful", -"bushi", -"bushily", -"bushing", -"bushlet", -"bushwa", -"bushy", -"busied", -"busily", -"busine", -"busk", -"busked", -"busker", -"busket", -"buskin", -"buskle", -"busky", -"busman", -"buss", -"busser", -"bussock", -"bussu", -"bust", -"bustard", -"busted", -"bustee", -"buster", -"bustic", -"bustle", -"bustled", -"bustler", -"busy", -"busying", -"busyish", -"but", -"butanal", -"butane", -"butanol", -"butch", -"butcher", -"butein", -"butene", -"butenyl", -"butic", -"butine", -"butler", -"butlery", -"butment", -"butoxy", -"butoxyl", -"butt", -"butte", -"butter", -"buttery", -"butting", -"buttle", -"buttock", -"button", -"buttons", -"buttony", -"butty", -"butyl", -"butylic", -"butyne", -"butyr", -"butyral", -"butyric", -"butyrin", -"butyryl", -"buxerry", -"buxom", -"buxomly", -"buy", -"buyable", -"buyer", -"buzane", -"buzz", -"buzzard", -"buzzer", -"buzzies", -"buzzing", -"buzzle", -"buzzwig", -"buzzy", -"by", -"bycoket", -"bye", -"byee", -"byeman", -"byepath", -"byerite", -"bygane", -"bygo", -"bygoing", -"bygone", -"byhand", -"bylaw", -"byname", -"byon", -"byous", -"byously", -"bypass", -"bypast", -"bypath", -"byplay", -"byre", -"byreman", -"byrlaw", -"byrnie", -"byroad", -"byrrus", -"bysen", -"byspell", -"byssal", -"byssin", -"byssine", -"byssoid", -"byssus", -"byth", -"bytime", -"bywalk", -"byway", -"bywoner", -"byword", -"bywork", -"c", -"ca", -"caam", -"caama", -"caaming", -"caapeba", -"cab", -"caba", -"cabaan", -"caback", -"cabaho", -"cabal", -"cabala", -"cabalic", -"caban", -"cabana", -"cabaret", -"cabas", -"cabbage", -"cabbagy", -"cabber", -"cabble", -"cabbler", -"cabby", -"cabda", -"caber", -"cabezon", -"cabin", -"cabinet", -"cabio", -"cable", -"cabled", -"cabler", -"cablet", -"cabling", -"cabman", -"cabob", -"cabocle", -"cabook", -"caboose", -"cabot", -"cabree", -"cabrit", -"cabuya", -"cacam", -"cacao", -"cachaza", -"cache", -"cachet", -"cachexy", -"cachou", -"cachrys", -"cacique", -"cack", -"cackle", -"cackler", -"cacodyl", -"cacoepy", -"caconym", -"cacoon", -"cacti", -"cactoid", -"cacur", -"cad", -"cadamba", -"cadaver", -"cadbait", -"cadbit", -"cadbote", -"caddice", -"caddie", -"caddis", -"caddish", -"caddle", -"caddow", -"caddy", -"cade", -"cadelle", -"cadence", -"cadency", -"cadent", -"cadenza", -"cader", -"caderas", -"cadet", -"cadetcy", -"cadette", -"cadew", -"cadge", -"cadger", -"cadgily", -"cadgy", -"cadi", -"cadism", -"cadjan", -"cadlock", -"cadmia", -"cadmic", -"cadmide", -"cadmium", -"cados", -"cadrans", -"cadre", -"cadua", -"caduac", -"caduca", -"cadus", -"cadweed", -"caeca", -"caecal", -"caecum", -"caeoma", -"caesura", -"cafeneh", -"cafenet", -"caffa", -"caffeic", -"caffeol", -"caffiso", -"caffle", -"caffoy", -"cafh", -"cafiz", -"caftan", -"cag", -"cage", -"caged", -"cageful", -"cageman", -"cager", -"cagey", -"caggy", -"cagily", -"cagit", -"cagmag", -"cahiz", -"cahoot", -"cahot", -"cahow", -"caickle", -"caid", -"caiman", -"caimito", -"cain", -"caique", -"caird", -"cairn", -"cairned", -"cairny", -"caisson", -"caitiff", -"cajeput", -"cajole", -"cajoler", -"cajuela", -"cajun", -"cajuput", -"cake", -"cakebox", -"caker", -"cakette", -"cakey", -"caky", -"cal", -"calaba", -"calaber", -"calade", -"calais", -"calalu", -"calamus", -"calash", -"calcar", -"calced", -"calcic", -"calcify", -"calcine", -"calcite", -"calcium", -"calculi", -"calden", -"caldron", -"calean", -"calends", -"calepin", -"calf", -"calfish", -"caliber", -"calibre", -"calices", -"calicle", -"calico", -"calid", -"caliga", -"caligo", -"calinda", -"calinut", -"calipee", -"caliper", -"caliph", -"caliver", -"calix", -"calk", -"calkage", -"calker", -"calkin", -"calking", -"call", -"callant", -"callboy", -"caller", -"callet", -"calli", -"callid", -"calling", -"callo", -"callose", -"callous", -"callow", -"callus", -"calm", -"calmant", -"calmer", -"calmly", -"calmy", -"calomba", -"calomel", -"calool", -"calor", -"caloric", -"calorie", -"caloris", -"calotte", -"caloyer", -"calp", -"calpac", -"calpack", -"caltrap", -"caltrop", -"calumba", -"calumet", -"calumny", -"calve", -"calved", -"calver", -"calves", -"calvish", -"calvity", -"calvous", -"calx", -"calyces", -"calycle", -"calymma", -"calypso", -"calyx", -"cam", -"camaca", -"camagon", -"camail", -"caman", -"camansi", -"camara", -"camass", -"camata", -"camb", -"cambaye", -"camber", -"cambial", -"cambism", -"cambist", -"cambium", -"cambrel", -"cambuca", -"came", -"cameist", -"camel", -"camelry", -"cameo", -"camera", -"cameral", -"camilla", -"camion", -"camise", -"camisia", -"camlet", -"cammed", -"cammock", -"camoodi", -"camp", -"campana", -"campane", -"camper", -"campho", -"camphol", -"camphor", -"campion", -"cample", -"campo", -"campody", -"campoo", -"campus", -"camus", -"camused", -"camwood", -"can", -"canaba", -"canada", -"canadol", -"canal", -"canamo", -"canape", -"canard", -"canari", -"canarin", -"canary", -"canasta", -"canaut", -"cancan", -"cancel", -"cancer", -"canch", -"cancrum", -"cand", -"candela", -"candent", -"candid", -"candied", -"candier", -"candify", -"candiru", -"candle", -"candler", -"candock", -"candor", -"candroy", -"candy", -"candys", -"cane", -"canel", -"canella", -"canelo", -"caner", -"canette", -"canful", -"cangan", -"cangia", -"cangle", -"cangler", -"cangue", -"canhoop", -"canid", -"canille", -"caninal", -"canine", -"caninus", -"canions", -"canjac", -"cank", -"canker", -"cankery", -"canman", -"canna", -"cannach", -"canned", -"cannel", -"canner", -"cannery", -"cannet", -"cannily", -"canning", -"cannon", -"cannot", -"cannula", -"canny", -"canoe", -"canon", -"canonic", -"canonry", -"canopic", -"canopy", -"canroy", -"canso", -"cant", -"cantala", -"cantar", -"cantara", -"cantaro", -"cantata", -"canted", -"canteen", -"canter", -"canthal", -"canthus", -"cantic", -"cantico", -"cantily", -"cantina", -"canting", -"cantion", -"cantish", -"cantle", -"cantlet", -"canto", -"canton", -"cantoon", -"cantor", -"cantred", -"cantref", -"cantrip", -"cantus", -"canty", -"canun", -"canvas", -"canvass", -"cany", -"canyon", -"canzon", -"caoba", -"cap", -"capable", -"capably", -"capanna", -"capanne", -"capax", -"capcase", -"cape", -"caped", -"capel", -"capelet", -"capelin", -"caper", -"caperer", -"capes", -"capful", -"caph", -"caphar", -"caphite", -"capias", -"capicha", -"capital", -"capitan", -"capivi", -"capkin", -"capless", -"caplin", -"capman", -"capmint", -"capomo", -"capon", -"caporal", -"capot", -"capote", -"capped", -"capper", -"cappie", -"capping", -"capple", -"cappy", -"caprate", -"capreol", -"capric", -"caprice", -"caprid", -"caprin", -"caprine", -"caproic", -"caproin", -"caprone", -"caproyl", -"capryl", -"capsa", -"capsid", -"capsize", -"capstan", -"capsula", -"capsule", -"captain", -"caption", -"captive", -"captor", -"capture", -"capuche", -"capulet", -"capulin", -"car", -"carabao", -"carabid", -"carabin", -"carabus", -"caracal", -"caracol", -"caract", -"carafe", -"caraibe", -"caraipi", -"caramba", -"caramel", -"caranda", -"carane", -"caranna", -"carapax", -"carapo", -"carat", -"caratch", -"caravan", -"caravel", -"caraway", -"carbarn", -"carbeen", -"carbene", -"carbide", -"carbine", -"carbo", -"carbon", -"carbona", -"carbora", -"carboxy", -"carboy", -"carbro", -"carbure", -"carbyl", -"carcake", -"carcass", -"carceag", -"carcel", -"carcoon", -"card", -"cardecu", -"carded", -"cardel", -"carder", -"cardia", -"cardiac", -"cardial", -"cardin", -"carding", -"cardo", -"cardol", -"cardon", -"cardona", -"cardoon", -"care", -"careen", -"career", -"careful", -"carene", -"carer", -"caress", -"carest", -"caret", -"carfare", -"carfax", -"carful", -"carga", -"cargo", -"carhop", -"cariama", -"caribou", -"carid", -"caries", -"carina", -"carinal", -"cariole", -"carious", -"cark", -"carking", -"carkled", -"carl", -"carless", -"carlet", -"carlie", -"carlin", -"carline", -"carling", -"carlish", -"carload", -"carlot", -"carls", -"carman", -"carmele", -"carmine", -"carmot", -"carnage", -"carnal", -"carnate", -"carneol", -"carney", -"carnic", -"carnify", -"carnose", -"carnous", -"caroa", -"carob", -"caroba", -"caroche", -"carol", -"caroler", -"caroli", -"carolin", -"carolus", -"carom", -"carone", -"caronic", -"caroome", -"caroon", -"carotic", -"carotid", -"carotin", -"carouse", -"carp", -"carpal", -"carpale", -"carpel", -"carpent", -"carper", -"carpet", -"carpid", -"carping", -"carpium", -"carport", -"carpos", -"carpus", -"carr", -"carrack", -"carrel", -"carrick", -"carried", -"carrier", -"carrion", -"carrizo", -"carroch", -"carrot", -"carroty", -"carrow", -"carry", -"carse", -"carshop", -"carsick", -"cart", -"cartage", -"carte", -"cartel", -"carter", -"cartful", -"cartman", -"carton", -"cartoon", -"cartway", -"carty", -"carua", -"carucal", -"carval", -"carve", -"carvel", -"carven", -"carvene", -"carver", -"carving", -"carvol", -"carvone", -"carvyl", -"caryl", -"casaba", -"casabe", -"casal", -"casalty", -"casate", -"casaun", -"casava", -"casave", -"casavi", -"casbah", -"cascade", -"cascado", -"cascara", -"casco", -"cascol", -"case", -"casease", -"caseate", -"casebox", -"cased", -"caseful", -"casefy", -"caseic", -"casein", -"caseose", -"caseous", -"caser", -"casern", -"caseum", -"cash", -"casha", -"cashaw", -"cashbox", -"cashboy", -"cashel", -"cashew", -"cashier", -"casing", -"casino", -"casiri", -"cask", -"casket", -"casking", -"casque", -"casqued", -"casquet", -"cass", -"cassady", -"casse", -"cassena", -"cassia", -"cassie", -"cassina", -"cassine", -"cassino", -"cassis", -"cassock", -"casson", -"cassoon", -"cast", -"caste", -"caster", -"castice", -"casting", -"castle", -"castled", -"castlet", -"castock", -"castoff", -"castor", -"castory", -"castra", -"castral", -"castrum", -"castuli", -"casual", -"casuary", -"casuist", -"casula", -"cat", -"catalpa", -"catan", -"catapan", -"cataria", -"catarrh", -"catasta", -"catbird", -"catboat", -"catcall", -"catch", -"catcher", -"catchup", -"catchy", -"catclaw", -"catdom", -"cate", -"catechu", -"catella", -"catena", -"catenae", -"cater", -"cateran", -"caterer", -"caterva", -"cateye", -"catface", -"catfall", -"catfish", -"catfoot", -"catgut", -"cathead", -"cathect", -"catheti", -"cathin", -"cathine", -"cathion", -"cathode", -"cathole", -"cathood", -"cathop", -"cathro", -"cation", -"cativo", -"catjang", -"catkin", -"catlap", -"catlike", -"catlin", -"catling", -"catmint", -"catnip", -"catpipe", -"catskin", -"catstep", -"catsup", -"cattabu", -"cattail", -"cattalo", -"cattery", -"cattily", -"catting", -"cattish", -"cattle", -"catty", -"catvine", -"catwalk", -"catwise", -"catwood", -"catwort", -"caubeen", -"cauboge", -"cauch", -"caucho", -"caucus", -"cauda", -"caudad", -"caudae", -"caudal", -"caudata", -"caudate", -"caudex", -"caudle", -"caught", -"cauk", -"caul", -"cauld", -"caules", -"cauline", -"caulis", -"caulome", -"caulote", -"caum", -"cauma", -"caunch", -"caup", -"caupo", -"caurale", -"causal", -"causate", -"cause", -"causer", -"causey", -"causing", -"causse", -"causson", -"caustic", -"cautel", -"cauter", -"cautery", -"caution", -"cautivo", -"cava", -"cavae", -"caval", -"cavalla", -"cavalry", -"cavate", -"cave", -"caveat", -"cavel", -"cavelet", -"cavern", -"cavetto", -"caviar", -"cavie", -"cavil", -"caviler", -"caving", -"cavings", -"cavish", -"cavity", -"caviya", -"cavort", -"cavus", -"cavy", -"caw", -"cawk", -"cawky", -"cawney", -"cawquaw", -"caxiri", -"caxon", -"cay", -"cayenne", -"cayman", -"caza", -"cazimi", -"ce", -"cearin", -"cease", -"ceasmic", -"cebell", -"cebian", -"cebid", -"cebil", -"cebine", -"ceboid", -"cebur", -"cecils", -"cecity", -"cedar", -"cedared", -"cedarn", -"cedary", -"cede", -"cedent", -"ceder", -"cedilla", -"cedrat", -"cedrate", -"cedre", -"cedrene", -"cedrin", -"cedrine", -"cedrium", -"cedrol", -"cedron", -"cedry", -"cedula", -"cee", -"ceibo", -"ceil", -"ceile", -"ceiler", -"ceilidh", -"ceiling", -"celadon", -"celemin", -"celery", -"celesta", -"celeste", -"celiac", -"celite", -"cell", -"cella", -"cellae", -"cellar", -"celled", -"cellist", -"cello", -"celloid", -"cellose", -"cellule", -"celsian", -"celt", -"celtium", -"celtuce", -"cembalo", -"cement", -"cenacle", -"cendre", -"cenoby", -"cense", -"censer", -"censive", -"censor", -"censual", -"censure", -"census", -"cent", -"centage", -"cental", -"centare", -"centaur", -"centavo", -"centena", -"center", -"centiar", -"centile", -"centime", -"centimo", -"centner", -"cento", -"centrad", -"central", -"centric", -"centrum", -"centry", -"centum", -"century", -"ceorl", -"cep", -"cepa", -"cepe", -"cephid", -"ceps", -"ceptor", -"cequi", -"cerago", -"ceral", -"ceramal", -"ceramic", -"ceras", -"cerasin", -"cerata", -"cerate", -"cerated", -"cercal", -"cerci", -"cercus", -"cere", -"cereal", -"cerebra", -"cered", -"cereous", -"cerer", -"ceresin", -"cerevis", -"ceria", -"ceric", -"ceride", -"cerillo", -"ceriman", -"cerin", -"cerine", -"ceriops", -"cerise", -"cerite", -"cerium", -"cermet", -"cern", -"cero", -"ceroma", -"cerote", -"cerotic", -"cerotin", -"cerous", -"cerrero", -"cerrial", -"cerris", -"certain", -"certie", -"certify", -"certis", -"certy", -"cerule", -"cerumen", -"ceruse", -"cervid", -"cervine", -"cervix", -"cervoid", -"ceryl", -"cesious", -"cesium", -"cess", -"cesser", -"cession", -"cessor", -"cesspit", -"cest", -"cestode", -"cestoid", -"cestrum", -"cestus", -"cetane", -"cetene", -"ceti", -"cetic", -"cetin", -"cetyl", -"cetylic", -"cevine", -"cha", -"chaa", -"chab", -"chabot", -"chabouk", -"chabuk", -"chacate", -"chack", -"chacker", -"chackle", -"chacma", -"chacona", -"chacte", -"chad", -"chaeta", -"chafe", -"chafer", -"chafery", -"chaff", -"chaffer", -"chaffy", -"chaft", -"chafted", -"chagan", -"chagrin", -"chaguar", -"chagul", -"chahar", -"chai", -"chain", -"chained", -"chainer", -"chainon", -"chair", -"chairer", -"chais", -"chaise", -"chaitya", -"chaja", -"chaka", -"chakar", -"chakari", -"chakazi", -"chakdar", -"chakobu", -"chakra", -"chakram", -"chaksi", -"chal", -"chalaco", -"chalana", -"chalaza", -"chalaze", -"chalcid", -"chalcon", -"chalcus", -"chalder", -"chalet", -"chalice", -"chalk", -"chalker", -"chalky", -"challah", -"challie", -"challis", -"chalmer", -"chalon", -"chalone", -"chalque", -"chalta", -"chalutz", -"cham", -"chamal", -"chamar", -"chamber", -"chambul", -"chamfer", -"chamiso", -"chamite", -"chamma", -"chamois", -"champ", -"champac", -"champer", -"champy", -"chance", -"chancel", -"chancer", -"chanche", -"chanco", -"chancre", -"chancy", -"chandam", -"chandi", -"chandoo", -"chandu", -"chandul", -"chang", -"changa", -"changar", -"change", -"changer", -"chank", -"channel", -"channer", -"chanson", -"chanst", -"chant", -"chanter", -"chantey", -"chantry", -"chao", -"chaos", -"chaotic", -"chap", -"chapah", -"chape", -"chapeau", -"chaped", -"chapel", -"chapin", -"chaplet", -"chapman", -"chapped", -"chapper", -"chappie", -"chappin", -"chappow", -"chappy", -"chaps", -"chapt", -"chapter", -"char", -"charac", -"charade", -"charas", -"charbon", -"chard", -"chare", -"charer", -"charet", -"charge", -"chargee", -"charger", -"charier", -"charily", -"chariot", -"charism", -"charity", -"chark", -"charka", -"charkha", -"charm", -"charmel", -"charmer", -"charnel", -"charpit", -"charpoy", -"charqui", -"charr", -"charry", -"chart", -"charter", -"charuk", -"chary", -"chase", -"chaser", -"chasing", -"chasm", -"chasma", -"chasmal", -"chasmed", -"chasmic", -"chasmy", -"chasse", -"chassis", -"chaste", -"chasten", -"chat", -"chataka", -"chateau", -"chati", -"chatta", -"chattel", -"chatter", -"chatty", -"chauk", -"chaus", -"chaute", -"chauth", -"chavish", -"chaw", -"chawan", -"chawer", -"chawk", -"chawl", -"chay", -"chaya", -"chayote", -"chazan", -"che", -"cheap", -"cheapen", -"cheaply", -"cheat", -"cheatee", -"cheater", -"chebec", -"chebel", -"chebog", -"chebule", -"check", -"checked", -"checker", -"checkup", -"checky", -"cheder", -"chee", -"cheecha", -"cheek", -"cheeker", -"cheeky", -"cheep", -"cheeper", -"cheepy", -"cheer", -"cheered", -"cheerer", -"cheerio", -"cheerly", -"cheery", -"cheese", -"cheeser", -"cheesy", -"cheet", -"cheetah", -"cheeter", -"cheetie", -"chef", -"chegoe", -"chegre", -"cheir", -"chekan", -"cheke", -"cheki", -"chekmak", -"chela", -"chelate", -"chelem", -"chelide", -"chello", -"chelone", -"chelp", -"chelys", -"chemic", -"chemis", -"chemise", -"chemism", -"chemist", -"chena", -"chende", -"cheng", -"chenica", -"cheque", -"cherem", -"cherish", -"cheroot", -"cherry", -"chert", -"cherte", -"cherty", -"cherub", -"chervil", -"cheson", -"chess", -"chessel", -"chesser", -"chest", -"chester", -"chesty", -"cheth", -"chettik", -"chetty", -"chevage", -"cheval", -"cheve", -"cheven", -"chevin", -"chevise", -"chevon", -"chevron", -"chevy", -"chew", -"chewer", -"chewink", -"chewy", -"cheyney", -"chhatri", -"chi", -"chia", -"chiasm", -"chiasma", -"chiaus", -"chibouk", -"chibrit", -"chic", -"chicane", -"chichi", -"chick", -"chicken", -"chicker", -"chicky", -"chicle", -"chico", -"chicory", -"chicot", -"chicote", -"chid", -"chidden", -"chide", -"chider", -"chiding", -"chidra", -"chief", -"chiefly", -"chield", -"chien", -"chiffer", -"chiffon", -"chiggak", -"chigger", -"chignon", -"chigoe", -"chih", -"chihfu", -"chikara", -"chil", -"child", -"childe", -"childed", -"childly", -"chile", -"chili", -"chiliad", -"chill", -"chilla", -"chilled", -"chiller", -"chillo", -"chillum", -"chilly", -"chiloma", -"chilver", -"chimble", -"chime", -"chimer", -"chimera", -"chimney", -"chin", -"china", -"chinar", -"chinch", -"chincha", -"chinche", -"chine", -"chined", -"ching", -"chingma", -"chinik", -"chinin", -"chink", -"chinker", -"chinkle", -"chinks", -"chinky", -"chinnam", -"chinned", -"chinny", -"chino", -"chinoa", -"chinol", -"chinse", -"chint", -"chintz", -"chip", -"chiplet", -"chipped", -"chipper", -"chippy", -"chips", -"chiral", -"chirata", -"chiripa", -"chirk", -"chirm", -"chiro", -"chirp", -"chirper", -"chirpy", -"chirr", -"chirrup", -"chisel", -"chit", -"chitak", -"chital", -"chitin", -"chiton", -"chitose", -"chitra", -"chitter", -"chitty", -"chive", -"chivey", -"chkalik", -"chlamyd", -"chlamys", -"chlor", -"chloral", -"chlore", -"chloric", -"chloryl", -"cho", -"choana", -"choate", -"choaty", -"chob", -"choca", -"chocard", -"chocho", -"chock", -"chocker", -"choel", -"choenix", -"choffer", -"choga", -"chogak", -"chogset", -"choice", -"choicy", -"choil", -"choiler", -"choir", -"chokage", -"choke", -"choker", -"choking", -"chokra", -"choky", -"chol", -"chola", -"cholane", -"cholate", -"chold", -"choleic", -"choler", -"cholera", -"choli", -"cholic", -"choline", -"cholla", -"choller", -"cholum", -"chomp", -"chondre", -"chonta", -"choop", -"choose", -"chooser", -"choosy", -"chop", -"chopa", -"chopin", -"chopine", -"chopped", -"chopper", -"choppy", -"choragy", -"choral", -"chord", -"chorda", -"chordal", -"chorded", -"chore", -"chorea", -"choreal", -"choree", -"choregy", -"choreic", -"choreus", -"chorial", -"choric", -"chorine", -"chorion", -"chorism", -"chorist", -"chorogi", -"choroid", -"chorook", -"chort", -"chorten", -"chortle", -"chorus", -"choryos", -"chose", -"chosen", -"chott", -"chough", -"chouka", -"choup", -"chous", -"chouse", -"chouser", -"chow", -"chowder", -"chowk", -"chowry", -"choya", -"chria", -"chrism", -"chrisma", -"chrisom", -"chroma", -"chrome", -"chromic", -"chromid", -"chromo", -"chromy", -"chromyl", -"chronal", -"chronic", -"chrotta", -"chrysal", -"chrysid", -"chrysin", -"chub", -"chubbed", -"chubby", -"chuck", -"chucker", -"chuckle", -"chucky", -"chuddar", -"chufa", -"chuff", -"chuffy", -"chug", -"chugger", -"chuhra", -"chukar", -"chukker", -"chukor", -"chulan", -"chullpa", -"chum", -"chummer", -"chummy", -"chump", -"chumpy", -"chun", -"chunari", -"chunga", -"chunk", -"chunky", -"chunner", -"chunnia", -"chunter", -"chupak", -"chupon", -"church", -"churchy", -"churel", -"churl", -"churled", -"churly", -"churm", -"churn", -"churr", -"churrus", -"chut", -"chute", -"chuter", -"chutney", -"chyack", -"chyak", -"chyle", -"chylify", -"chyloid", -"chylous", -"chymase", -"chyme", -"chymia", -"chymic", -"chymify", -"chymous", -"chypre", -"chytra", -"chytrid", -"cibol", -"cibory", -"ciboule", -"cicad", -"cicada", -"cicadid", -"cicala", -"cicely", -"cicer", -"cichlid", -"cidarid", -"cidaris", -"cider", -"cig", -"cigala", -"cigar", -"cigua", -"cilia", -"ciliary", -"ciliate", -"cilice", -"cilium", -"cimbia", -"cimelia", -"cimex", -"cimicid", -"cimline", -"cinch", -"cincher", -"cinclis", -"cinct", -"cinder", -"cindery", -"cine", -"cinel", -"cinema", -"cinene", -"cineole", -"cinerea", -"cingle", -"cinnyl", -"cinque", -"cinter", -"cinuran", -"cion", -"cipher", -"cipo", -"cipolin", -"cippus", -"circa", -"circle", -"circled", -"circler", -"circlet", -"circuit", -"circus", -"circusy", -"cirque", -"cirrate", -"cirri", -"cirrose", -"cirrous", -"cirrus", -"cirsoid", -"ciruela", -"cisco", -"cise", -"cisele", -"cissing", -"cissoid", -"cist", -"cista", -"cistae", -"cisted", -"cistern", -"cistic", -"cit", -"citable", -"citadel", -"citator", -"cite", -"citee", -"citer", -"citess", -"cithara", -"cither", -"citied", -"citify", -"citizen", -"citole", -"citral", -"citrate", -"citrean", -"citrene", -"citric", -"citril", -"citrin", -"citrine", -"citron", -"citrous", -"citrus", -"cittern", -"citua", -"city", -"citydom", -"cityful", -"cityish", -"cive", -"civet", -"civic", -"civics", -"civil", -"civilly", -"civism", -"civvy", -"cixiid", -"clabber", -"clachan", -"clack", -"clacker", -"clacket", -"clad", -"cladine", -"cladode", -"cladose", -"cladus", -"clag", -"claggum", -"claggy", -"claim", -"claimer", -"clairce", -"claith", -"claiver", -"clam", -"clamant", -"clamb", -"clamber", -"clame", -"clamer", -"clammed", -"clammer", -"clammy", -"clamor", -"clamp", -"clamper", -"clan", -"clang", -"clangor", -"clank", -"clanned", -"clap", -"clapnet", -"clapped", -"clapper", -"clapt", -"claque", -"claquer", -"clarain", -"claret", -"clarify", -"clarin", -"clarion", -"clarity", -"clark", -"claro", -"clart", -"clarty", -"clary", -"clash", -"clasher", -"clashy", -"clasp", -"clasper", -"claspt", -"class", -"classed", -"classer", -"classes", -"classic", -"classis", -"classy", -"clastic", -"clat", -"clatch", -"clatter", -"clatty", -"claught", -"clausal", -"clause", -"claut", -"clava", -"claval", -"clavate", -"clave", -"clavel", -"claver", -"clavial", -"clavier", -"claviol", -"clavis", -"clavola", -"clavus", -"clavy", -"claw", -"clawed", -"clawer", -"clawk", -"clawker", -"clay", -"clayen", -"clayer", -"clayey", -"clayish", -"clayman", -"claypan", -"cleach", -"clead", -"cleaded", -"cleam", -"cleamer", -"clean", -"cleaner", -"cleanly", -"cleanse", -"cleanup", -"clear", -"clearer", -"clearly", -"cleat", -"cleave", -"cleaver", -"cleche", -"cleck", -"cled", -"cledge", -"cledgy", -"clee", -"cleek", -"cleeked", -"cleeky", -"clef", -"cleft", -"clefted", -"cleg", -"clem", -"clement", -"clench", -"cleoid", -"clep", -"clergy", -"cleric", -"clerid", -"clerisy", -"clerk", -"clerkly", -"cleruch", -"cletch", -"cleuch", -"cleve", -"clever", -"clevis", -"clew", -"cliack", -"cliche", -"click", -"clicker", -"clicket", -"clicky", -"cliency", -"client", -"cliff", -"cliffed", -"cliffy", -"clift", -"clifty", -"clima", -"climata", -"climate", -"climath", -"climax", -"climb", -"climber", -"clime", -"clinal", -"clinch", -"cline", -"cling", -"clinger", -"clingy", -"clinia", -"clinic", -"clinium", -"clink", -"clinker", -"clinkum", -"clinoid", -"clint", -"clinty", -"clip", -"clipei", -"clipeus", -"clipped", -"clipper", -"clips", -"clipse", -"clipt", -"clique", -"cliquy", -"clisere", -"clit", -"clitch", -"clite", -"clites", -"clithe", -"clitia", -"clition", -"clitter", -"clival", -"clive", -"clivers", -"clivis", -"clivus", -"cloaca", -"cloacal", -"cloak", -"cloaked", -"cloam", -"cloamen", -"cloamer", -"clobber", -"clochan", -"cloche", -"clocher", -"clock", -"clocked", -"clocker", -"clod", -"clodder", -"cloddy", -"clodlet", -"cloff", -"clog", -"clogger", -"cloggy", -"cloghad", -"clogwyn", -"cloit", -"clomb", -"clomben", -"clonal", -"clone", -"clonic", -"clonism", -"clonus", -"cloof", -"cloop", -"cloot", -"clootie", -"clop", -"close", -"closed", -"closely", -"closen", -"closer", -"closet", -"closh", -"closish", -"closter", -"closure", -"clot", -"clotbur", -"clote", -"cloth", -"clothe", -"clothes", -"clothy", -"clotter", -"clotty", -"cloture", -"cloud", -"clouded", -"cloudy", -"clough", -"clour", -"clout", -"clouted", -"clouter", -"clouty", -"clove", -"cloven", -"clovene", -"clover", -"clovery", -"clow", -"clown", -"cloy", -"cloyer", -"cloying", -"club", -"clubbed", -"clubber", -"clubby", -"clubdom", -"clubman", -"cluck", -"clue", -"cluff", -"clump", -"clumpy", -"clumse", -"clumsy", -"clunch", -"clung", -"clunk", -"clupeid", -"cluster", -"clutch", -"cluther", -"clutter", -"cly", -"clyer", -"clype", -"clypeal", -"clypeus", -"clysis", -"clysma", -"clysmic", -"clyster", -"cnemial", -"cnemis", -"cnicin", -"cnida", -"coabode", -"coach", -"coachee", -"coacher", -"coachy", -"coact", -"coactor", -"coadapt", -"coadmit", -"coadore", -"coaged", -"coagent", -"coagula", -"coaid", -"coaita", -"coak", -"coakum", -"coal", -"coalbag", -"coalbin", -"coalbox", -"coaler", -"coalify", -"coalize", -"coalpit", -"coaly", -"coaming", -"coannex", -"coapt", -"coarb", -"coarse", -"coarsen", -"coast", -"coastal", -"coaster", -"coat", -"coated", -"coatee", -"coater", -"coati", -"coatie", -"coating", -"coax", -"coaxal", -"coaxer", -"coaxial", -"coaxing", -"coaxy", -"cob", -"cobaea", -"cobalt", -"cobang", -"cobbed", -"cobber", -"cobbing", -"cobble", -"cobbler", -"cobbly", -"cobbra", -"cobby", -"cobcab", -"cobego", -"cobhead", -"cobia", -"cobiron", -"coble", -"cobless", -"cobloaf", -"cobnut", -"cobola", -"cobourg", -"cobra", -"coburg", -"cobweb", -"cobwork", -"coca", -"cocaine", -"cocash", -"cocause", -"coccal", -"cocci", -"coccid", -"cocco", -"coccoid", -"coccous", -"coccule", -"coccus", -"coccyx", -"cochal", -"cochief", -"cochlea", -"cock", -"cockade", -"cockal", -"cocked", -"cocker", -"cocket", -"cockeye", -"cockily", -"cocking", -"cockish", -"cockle", -"cockled", -"cockler", -"cocklet", -"cockly", -"cockney", -"cockpit", -"cockshy", -"cockup", -"cocky", -"coco", -"cocoa", -"cocoach", -"coconut", -"cocoon", -"cocotte", -"coctile", -"coction", -"cocuisa", -"cocullo", -"cocuyo", -"cod", -"coda", -"codbank", -"codder", -"codding", -"coddle", -"coddler", -"code", -"codeine", -"coder", -"codex", -"codfish", -"codger", -"codhead", -"codical", -"codices", -"codicil", -"codify", -"codilla", -"codille", -"codist", -"codling", -"codman", -"codo", -"codol", -"codon", -"codworm", -"coe", -"coecal", -"coecum", -"coed", -"coelar", -"coelder", -"coelect", -"coelho", -"coelia", -"coeliac", -"coelian", -"coelin", -"coeline", -"coelom", -"coeloma", -"coempt", -"coenact", -"coenjoy", -"coenobe", -"coequal", -"coerce", -"coercer", -"coetus", -"coeval", -"coexert", -"coexist", -"coff", -"coffee", -"coffer", -"coffin", -"coffle", -"coffret", -"coft", -"cog", -"cogence", -"cogency", -"cogener", -"cogent", -"cogged", -"cogger", -"coggie", -"cogging", -"coggle", -"coggly", -"coghle", -"cogman", -"cognac", -"cognate", -"cognize", -"cogon", -"cogonal", -"cograil", -"cogroad", -"cogue", -"cogway", -"cogwood", -"cohabit", -"coheir", -"cohere", -"coherer", -"cohibit", -"coho", -"cohoba", -"cohol", -"cohort", -"cohosh", -"cohune", -"coif", -"coifed", -"coign", -"coigue", -"coil", -"coiled", -"coiler", -"coiling", -"coin", -"coinage", -"coiner", -"coinfer", -"coining", -"cointer", -"coiny", -"coir", -"coital", -"coition", -"coiture", -"coitus", -"cojudge", -"cojuror", -"coke", -"cokeman", -"coker", -"cokery", -"coking", -"coky", -"col", -"cola", -"colane", -"colarin", -"colate", -"colauxe", -"colback", -"cold", -"colder", -"coldish", -"coldly", -"cole", -"coletit", -"coleur", -"coli", -"colibri", -"colic", -"colical", -"colicky", -"colima", -"colin", -"coling", -"colitic", -"colitis", -"colk", -"coll", -"collage", -"collar", -"collard", -"collare", -"collate", -"collaud", -"collect", -"colleen", -"college", -"collery", -"collet", -"colley", -"collide", -"collie", -"collied", -"collier", -"collin", -"colline", -"colling", -"collins", -"collock", -"colloid", -"collop", -"collude", -"collum", -"colly", -"collyba", -"colmar", -"colobin", -"colon", -"colonel", -"colonic", -"colony", -"color", -"colored", -"colorer", -"colorin", -"colors", -"colory", -"coloss", -"colossi", -"colove", -"colp", -"colpeo", -"colport", -"colpus", -"colt", -"colter", -"coltish", -"colugo", -"columbo", -"column", -"colunar", -"colure", -"coly", -"colyone", -"colytic", -"colyum", -"colza", -"coma", -"comaker", -"comal", -"comamie", -"comanic", -"comart", -"comate", -"comb", -"combat", -"combed", -"comber", -"combine", -"combing", -"comble", -"comboy", -"combure", -"combust", -"comby", -"come", -"comedic", -"comedo", -"comedy", -"comely", -"comenic", -"comer", -"comes", -"comet", -"cometic", -"comfit", -"comfort", -"comfrey", -"comfy", -"comic", -"comical", -"comicry", -"coming", -"comino", -"comism", -"comital", -"comitia", -"comity", -"comma", -"command", -"commend", -"comment", -"commie", -"commit", -"commix", -"commixt", -"commode", -"common", -"commons", -"commot", -"commove", -"communa", -"commune", -"commute", -"comoid", -"comose", -"comourn", -"comous", -"compact", -"company", -"compare", -"compart", -"compass", -"compear", -"compeer", -"compel", -"compend", -"compete", -"compile", -"complex", -"complin", -"complot", -"comply", -"compo", -"compoer", -"compole", -"compone", -"compony", -"comport", -"compos", -"compose", -"compost", -"compote", -"compreg", -"compter", -"compute", -"comrade", -"con", -"conacre", -"conal", -"conamed", -"conatus", -"concave", -"conceal", -"concede", -"conceit", -"concent", -"concept", -"concern", -"concert", -"conch", -"concha", -"conchal", -"conche", -"conched", -"concher", -"conchy", -"concile", -"concise", -"concoct", -"concord", -"concupy", -"concur", -"concuss", -"cond", -"condemn", -"condign", -"condite", -"condole", -"condone", -"condor", -"conduce", -"conduct", -"conduit", -"condyle", -"cone", -"coned", -"coneen", -"coneine", -"conelet", -"coner", -"cones", -"confab", -"confact", -"confect", -"confess", -"confide", -"confine", -"confirm", -"confix", -"conflow", -"conflux", -"conform", -"confuse", -"confute", -"conga", -"congeal", -"congee", -"conger", -"congest", -"congius", -"congou", -"conic", -"conical", -"conicle", -"conics", -"conidia", -"conifer", -"conima", -"conin", -"conine", -"conject", -"conjoin", -"conjure", -"conjury", -"conk", -"conker", -"conkers", -"conky", -"conn", -"connach", -"connate", -"connect", -"conner", -"connex", -"conning", -"connive", -"connote", -"conoid", -"conopid", -"conquer", -"conred", -"consent", -"consign", -"consist", -"consol", -"console", -"consort", -"conspue", -"constat", -"consul", -"consult", -"consume", -"consute", -"contact", -"contain", -"conte", -"contect", -"contemn", -"content", -"conter", -"contest", -"context", -"contise", -"conto", -"contort", -"contour", -"contra", -"control", -"contund", -"contuse", -"conure", -"conus", -"conusee", -"conusor", -"conuzee", -"conuzor", -"convect", -"convene", -"convent", -"convert", -"conveth", -"convex", -"convey", -"convict", -"convive", -"convoke", -"convoy", -"cony", -"coo", -"cooba", -"coodle", -"cooee", -"cooer", -"coof", -"cooing", -"cooja", -"cook", -"cookdom", -"cookee", -"cooker", -"cookery", -"cooking", -"cookish", -"cookout", -"cooky", -"cool", -"coolant", -"coolen", -"cooler", -"coolie", -"cooling", -"coolish", -"coolly", -"coolth", -"coolung", -"cooly", -"coom", -"coomb", -"coomy", -"coon", -"cooncan", -"coonily", -"coontie", -"coony", -"coop", -"cooper", -"coopery", -"cooree", -"coorie", -"cooser", -"coost", -"coot", -"cooter", -"coothay", -"cootie", -"cop", -"copa", -"copable", -"copaene", -"copaiba", -"copaiye", -"copal", -"copalm", -"copart", -"coparty", -"cope", -"copei", -"copeman", -"copen", -"copepod", -"coper", -"coperta", -"copied", -"copier", -"copilot", -"coping", -"copious", -"copis", -"copist", -"copita", -"copolar", -"copped", -"copper", -"coppery", -"coppet", -"coppice", -"coppin", -"copping", -"copple", -"coppled", -"coppy", -"copr", -"copra", -"coprose", -"copse", -"copsing", -"copsy", -"copter", -"copula", -"copular", -"copus", -"copy", -"copycat", -"copyism", -"copyist", -"copyman", -"coque", -"coquet", -"coquina", -"coquita", -"coquito", -"cor", -"cora", -"corach", -"coracle", -"corah", -"coraise", -"coral", -"coraled", -"coram", -"coranto", -"corban", -"corbeau", -"corbeil", -"corbel", -"corbie", -"corbula", -"corcass", -"corcir", -"cord", -"cordage", -"cordant", -"cordate", -"cordax", -"corded", -"cordel", -"corder", -"cordial", -"cordies", -"cording", -"cordite", -"cordoba", -"cordon", -"cordy", -"cordyl", -"core", -"corebel", -"cored", -"coreid", -"coreign", -"corella", -"corer", -"corf", -"corge", -"corgi", -"corial", -"coriin", -"coring", -"corinne", -"corium", -"cork", -"corkage", -"corke", -"corked", -"corker", -"corking", -"corkish", -"corkite", -"corky", -"corm", -"cormel", -"cormoid", -"cormous", -"cormus", -"corn", -"cornage", -"cornbin", -"corncob", -"cornea", -"corneal", -"cornein", -"cornel", -"corner", -"cornet", -"corneum", -"cornic", -"cornice", -"cornin", -"corning", -"cornu", -"cornual", -"cornule", -"cornute", -"cornuto", -"corny", -"coroa", -"corody", -"corol", -"corolla", -"corona", -"coronad", -"coronae", -"coronal", -"coroner", -"coronet", -"corozo", -"corp", -"corpora", -"corps", -"corpse", -"corpus", -"corrade", -"corral", -"correal", -"correct", -"corrie", -"corrige", -"corrode", -"corrupt", -"corsac", -"corsage", -"corsair", -"corse", -"corset", -"corsie", -"corsite", -"corta", -"cortege", -"cortex", -"cortez", -"cortin", -"cortina", -"coruco", -"coruler", -"corupay", -"corver", -"corvina", -"corvine", -"corvoid", -"coryl", -"corylin", -"corymb", -"coryza", -"cos", -"cosaque", -"coscet", -"coseat", -"cosec", -"cosech", -"coseism", -"coset", -"cosh", -"cosher", -"coshery", -"cosily", -"cosine", -"cosmic", -"cosmism", -"cosmist", -"cosmos", -"coss", -"cossas", -"cosse", -"cosset", -"cossid", -"cost", -"costa", -"costal", -"costar", -"costard", -"costate", -"costean", -"coster", -"costing", -"costive", -"costly", -"costrel", -"costula", -"costume", -"cosy", -"cot", -"cotch", -"cote", -"coteful", -"coterie", -"coth", -"cothe", -"cothish", -"cothon", -"cothurn", -"cothy", -"cotidal", -"cotise", -"cotland", -"cotman", -"coto", -"cotoin", -"cotoro", -"cotrine", -"cotset", -"cotta", -"cottage", -"cotte", -"cotted", -"cotter", -"cottid", -"cottier", -"cottoid", -"cotton", -"cottony", -"cotty", -"cotuit", -"cotula", -"cotutor", -"cotwin", -"cotwist", -"cotyla", -"cotylar", -"cotype", -"couac", -"coucal", -"couch", -"couched", -"couchee", -"coucher", -"couchy", -"coude", -"coudee", -"coue", -"cougar", -"cough", -"cougher", -"cougnar", -"coul", -"could", -"coulee", -"coulomb", -"coulure", -"couma", -"coumara", -"council", -"counite", -"counsel", -"count", -"counter", -"countor", -"country", -"county", -"coup", -"coupage", -"coupe", -"couped", -"coupee", -"couper", -"couple", -"coupled", -"coupler", -"couplet", -"coupon", -"coupure", -"courage", -"courant", -"courap", -"courb", -"courge", -"courida", -"courier", -"couril", -"courlan", -"course", -"coursed", -"courser", -"court", -"courter", -"courtin", -"courtly", -"cousin", -"cousiny", -"coutel", -"couter", -"couth", -"couthie", -"coutil", -"couvade", -"couxia", -"covado", -"cove", -"coved", -"covent", -"cover", -"covered", -"coverer", -"covert", -"covet", -"coveter", -"covey", -"covid", -"covin", -"coving", -"covisit", -"covite", -"cow", -"cowal", -"coward", -"cowardy", -"cowbane", -"cowbell", -"cowbind", -"cowbird", -"cowboy", -"cowdie", -"coween", -"cower", -"cowfish", -"cowgate", -"cowgram", -"cowhage", -"cowheel", -"cowherb", -"cowherd", -"cowhide", -"cowhorn", -"cowish", -"cowitch", -"cowl", -"cowle", -"cowled", -"cowlick", -"cowlike", -"cowling", -"cowman", -"cowpath", -"cowpea", -"cowpen", -"cowpock", -"cowpox", -"cowrie", -"cowroid", -"cowshed", -"cowskin", -"cowslip", -"cowtail", -"cowweed", -"cowy", -"cowyard", -"cox", -"coxa", -"coxal", -"coxcomb", -"coxite", -"coxitis", -"coxy", -"coy", -"coyan", -"coydog", -"coyish", -"coyly", -"coyness", -"coynye", -"coyo", -"coyol", -"coyote", -"coypu", -"coyure", -"coz", -"coze", -"cozen", -"cozener", -"cozier", -"cozily", -"cozy", -"crab", -"crabbed", -"crabber", -"crabby", -"craber", -"crablet", -"crabman", -"crack", -"cracked", -"cracker", -"crackle", -"crackly", -"cracky", -"craddy", -"cradge", -"cradle", -"cradler", -"craft", -"crafty", -"crag", -"craggan", -"cragged", -"craggy", -"craichy", -"crain", -"craisey", -"craizey", -"crajuru", -"crake", -"crakow", -"cram", -"crambe", -"crambid", -"cramble", -"crambly", -"crambo", -"crammer", -"cramp", -"cramped", -"cramper", -"crampet", -"crampon", -"crampy", -"cran", -"cranage", -"crance", -"crane", -"craner", -"craney", -"crania", -"craniad", -"cranial", -"cranian", -"cranic", -"cranium", -"crank", -"cranked", -"cranker", -"crankle", -"crankly", -"crankum", -"cranky", -"crannog", -"cranny", -"crants", -"crap", -"crapaud", -"crape", -"crappie", -"crappin", -"crapple", -"crappo", -"craps", -"crapy", -"crare", -"crash", -"crasher", -"crasis", -"crass", -"crassly", -"cratch", -"crate", -"crater", -"craunch", -"cravat", -"crave", -"craven", -"craver", -"craving", -"cravo", -"craw", -"crawdad", -"crawful", -"crawl", -"crawler", -"crawley", -"crawly", -"crawm", -"crawtae", -"crayer", -"crayon", -"craze", -"crazed", -"crazily", -"crazy", -"crea", -"creagh", -"creaght", -"creak", -"creaker", -"creaky", -"cream", -"creamer", -"creamy", -"creance", -"creant", -"crease", -"creaser", -"creasy", -"creat", -"create", -"creatic", -"creator", -"creche", -"credent", -"credit", -"cree", -"creed", -"creedal", -"creeded", -"creek", -"creeker", -"creeky", -"creel", -"creeler", -"creem", -"creen", -"creep", -"creeper", -"creepie", -"creepy", -"creese", -"creesh", -"creeshy", -"cremate", -"cremone", -"cremor", -"cremule", -"crena", -"crenate", -"crenel", -"crenele", -"crenic", -"crenula", -"creole", -"creosol", -"crepe", -"crepine", -"crepon", -"crept", -"crepy", -"cresol", -"cresoxy", -"cress", -"cressed", -"cresset", -"cresson", -"cressy", -"crest", -"crested", -"cresyl", -"creta", -"cretic", -"cretify", -"cretin", -"cretion", -"crevice", -"crew", -"crewel", -"crewer", -"crewman", -"crib", -"cribber", -"cribble", -"cribo", -"cribral", -"cric", -"crick", -"cricket", -"crickey", -"crickle", -"cricoid", -"cried", -"crier", -"criey", -"crig", -"crile", -"crime", -"crimine", -"crimp", -"crimper", -"crimple", -"crimpy", -"crimson", -"crin", -"crinal", -"crine", -"crined", -"crinet", -"cringe", -"cringer", -"cringle", -"crinite", -"crink", -"crinkle", -"crinkly", -"crinoid", -"crinose", -"crinula", -"cripes", -"cripple", -"cripply", -"crises", -"crisic", -"crisis", -"crisp", -"crisped", -"crisper", -"crisply", -"crispy", -"criss", -"crissal", -"crissum", -"crista", -"critch", -"crith", -"critic", -"crizzle", -"cro", -"croak", -"croaker", -"croaky", -"croc", -"crocard", -"croceic", -"crocein", -"croche", -"crochet", -"croci", -"crocin", -"crock", -"crocker", -"crocket", -"crocky", -"crocus", -"croft", -"crofter", -"crome", -"crone", -"cronet", -"cronish", -"cronk", -"crony", -"crood", -"croodle", -"crook", -"crooked", -"crooken", -"crookle", -"crool", -"croon", -"crooner", -"crop", -"cropman", -"croppa", -"cropper", -"croppie", -"croppy", -"croquet", -"crore", -"crosa", -"crosier", -"crosnes", -"cross", -"crosse", -"crossed", -"crosser", -"crossly", -"crotal", -"crotalo", -"crotch", -"crotchy", -"crotin", -"crottle", -"crotyl", -"crouch", -"croup", -"croupal", -"croupe", -"croupy", -"crouse", -"crout", -"croute", -"crouton", -"crow", -"crowbar", -"crowd", -"crowded", -"crowder", -"crowdy", -"crower", -"crowhop", -"crowing", -"crowl", -"crown", -"crowned", -"crowner", -"crowtoe", -"croy", -"croyden", -"croydon", -"croze", -"crozer", -"crozzle", -"crozzly", -"crubeen", -"cruce", -"cruces", -"cruche", -"crucial", -"crucian", -"crucify", -"crucily", -"cruck", -"crude", -"crudely", -"crudity", -"cruel", -"cruelly", -"cruels", -"cruelty", -"cruent", -"cruet", -"cruety", -"cruise", -"cruiser", -"cruive", -"cruller", -"crum", -"crumb", -"crumber", -"crumble", -"crumbly", -"crumby", -"crumen", -"crumlet", -"crummie", -"crummy", -"crump", -"crumper", -"crumpet", -"crumple", -"crumply", -"crumpy", -"crunch", -"crunchy", -"crunk", -"crunkle", -"crunode", -"crunt", -"cruor", -"crupper", -"crural", -"crureus", -"crus", -"crusade", -"crusado", -"cruse", -"crush", -"crushed", -"crusher", -"crusie", -"crusily", -"crust", -"crusta", -"crustal", -"crusted", -"cruster", -"crusty", -"crutch", -"cruth", -"crutter", -"crux", -"cry", -"cryable", -"crybaby", -"crying", -"cryogen", -"cryosel", -"crypt", -"crypta", -"cryptal", -"crypted", -"cryptic", -"crystal", -"crystic", -"csardas", -"ctene", -"ctenoid", -"cuadra", -"cuarta", -"cub", -"cubage", -"cubbing", -"cubbish", -"cubby", -"cubdom", -"cube", -"cubeb", -"cubelet", -"cuber", -"cubhood", -"cubi", -"cubic", -"cubica", -"cubical", -"cubicle", -"cubicly", -"cubism", -"cubist", -"cubit", -"cubital", -"cubited", -"cubito", -"cubitus", -"cuboid", -"cuck", -"cuckold", -"cuckoo", -"cuculla", -"cud", -"cudava", -"cudbear", -"cudden", -"cuddle", -"cuddly", -"cuddy", -"cudgel", -"cudweed", -"cue", -"cueball", -"cueca", -"cueist", -"cueman", -"cuerda", -"cuesta", -"cuff", -"cuffer", -"cuffin", -"cuffy", -"cuinage", -"cuir", -"cuirass", -"cuisine", -"cuisse", -"cuissen", -"cuisten", -"cuke", -"culbut", -"culebra", -"culet", -"culeus", -"culgee", -"culicid", -"cull", -"culla", -"cullage", -"culler", -"cullet", -"culling", -"cullion", -"cullis", -"cully", -"culm", -"culmen", -"culmy", -"culotte", -"culpa", -"culpose", -"culprit", -"cult", -"cultch", -"cultic", -"cultish", -"cultism", -"cultist", -"cultual", -"culture", -"cultus", -"culver", -"culvert", -"cum", -"cumal", -"cumay", -"cumbent", -"cumber", -"cumbha", -"cumbly", -"cumbre", -"cumbu", -"cumene", -"cumenyl", -"cumhal", -"cumic", -"cumidin", -"cumin", -"cuminal", -"cuminic", -"cuminol", -"cuminyl", -"cummer", -"cummin", -"cumol", -"cump", -"cumshaw", -"cumular", -"cumuli", -"cumulus", -"cumyl", -"cuneal", -"cuneate", -"cunette", -"cuneus", -"cunila", -"cunjah", -"cunjer", -"cunner", -"cunning", -"cunye", -"cuorin", -"cup", -"cupay", -"cupcake", -"cupel", -"cupeler", -"cupful", -"cuphead", -"cupidon", -"cupless", -"cupman", -"cupmate", -"cupola", -"cupolar", -"cupped", -"cupper", -"cupping", -"cuppy", -"cuprene", -"cupric", -"cupride", -"cuprite", -"cuproid", -"cuprose", -"cuprous", -"cuprum", -"cupseed", -"cupula", -"cupule", -"cur", -"curable", -"curably", -"curacao", -"curacy", -"curare", -"curate", -"curatel", -"curatic", -"curator", -"curb", -"curber", -"curbing", -"curby", -"curcas", -"curch", -"curd", -"curdle", -"curdler", -"curdly", -"curdy", -"cure", -"curer", -"curette", -"curfew", -"curial", -"curiate", -"curie", -"curin", -"curine", -"curing", -"curio", -"curiosa", -"curioso", -"curious", -"curite", -"curium", -"curl", -"curled", -"curler", -"curlew", -"curlike", -"curlily", -"curling", -"curly", -"curn", -"curney", -"curnock", -"curple", -"curr", -"currach", -"currack", -"curragh", -"currant", -"current", -"curried", -"currier", -"currish", -"curry", -"cursal", -"curse", -"cursed", -"curser", -"curship", -"cursive", -"cursor", -"cursory", -"curst", -"curstly", -"cursus", -"curt", -"curtail", -"curtain", -"curtal", -"curtate", -"curtesy", -"curtly", -"curtsy", -"curua", -"curuba", -"curule", -"cururo", -"curvant", -"curvate", -"curve", -"curved", -"curver", -"curvet", -"curvity", -"curvous", -"curvy", -"cuscus", -"cusec", -"cush", -"cushag", -"cushat", -"cushaw", -"cushion", -"cushy", -"cusie", -"cusk", -"cusp", -"cuspal", -"cuspate", -"cusped", -"cuspid", -"cuspule", -"cuss", -"cussed", -"cusser", -"cusso", -"custard", -"custody", -"custom", -"customs", -"cut", -"cutaway", -"cutback", -"cutch", -"cutcher", -"cute", -"cutely", -"cutheal", -"cuticle", -"cutie", -"cutin", -"cutis", -"cutitis", -"cutlass", -"cutler", -"cutlery", -"cutlet", -"cutling", -"cutlips", -"cutoff", -"cutout", -"cutover", -"cuttage", -"cuttail", -"cutted", -"cutter", -"cutting", -"cuttle", -"cuttler", -"cuttoo", -"cutty", -"cutup", -"cutweed", -"cutwork", -"cutworm", -"cuvette", -"cuvy", -"cuya", -"cwierc", -"cwm", -"cyan", -"cyanate", -"cyanean", -"cyanic", -"cyanide", -"cyanin", -"cyanine", -"cyanite", -"cyanize", -"cyanol", -"cyanole", -"cyanose", -"cyanus", -"cyath", -"cyathos", -"cyathus", -"cycad", -"cyclane", -"cyclar", -"cyclas", -"cycle", -"cyclene", -"cycler", -"cyclian", -"cyclic", -"cyclide", -"cycling", -"cyclism", -"cyclist", -"cyclize", -"cycloid", -"cyclone", -"cyclope", -"cyclopy", -"cyclose", -"cyclus", -"cyesis", -"cygnet", -"cygnine", -"cyke", -"cylix", -"cyma", -"cymar", -"cymba", -"cymbal", -"cymbalo", -"cymbate", -"cyme", -"cymelet", -"cymene", -"cymling", -"cymoid", -"cymose", -"cymous", -"cymule", -"cynebot", -"cynic", -"cynical", -"cynipid", -"cynism", -"cynoid", -"cyp", -"cypre", -"cypres", -"cypress", -"cyprine", -"cypsela", -"cyrus", -"cyst", -"cystal", -"cysted", -"cystic", -"cystid", -"cystine", -"cystis", -"cystoid", -"cystoma", -"cystose", -"cystous", -"cytase", -"cytasic", -"cytitis", -"cytode", -"cytoid", -"cytoma", -"cyton", -"cytost", -"cytula", -"czar", -"czardas", -"czardom", -"czarian", -"czaric", -"czarina", -"czarish", -"czarism", -"czarist", -"d", -"da", -"daalder", -"dab", -"dabb", -"dabba", -"dabber", -"dabble", -"dabbler", -"dabby", -"dablet", -"daboia", -"daboya", -"dabster", -"dace", -"dacite", -"dacitic", -"dacker", -"dacoit", -"dacoity", -"dacryon", -"dactyl", -"dad", -"dada", -"dadap", -"dadder", -"daddle", -"daddock", -"daddy", -"dade", -"dado", -"dae", -"daedal", -"daemon", -"daemony", -"daer", -"daff", -"daffery", -"daffing", -"daffish", -"daffle", -"daffy", -"daft", -"daftly", -"dag", -"dagaba", -"dagame", -"dagassa", -"dagesh", -"dagga", -"dagger", -"daggers", -"daggle", -"daggly", -"daggy", -"daghesh", -"daglock", -"dagoba", -"dags", -"dah", -"dahoon", -"daidle", -"daidly", -"daiker", -"daikon", -"daily", -"daimen", -"daimio", -"daimon", -"dain", -"daincha", -"dainty", -"daira", -"dairi", -"dairy", -"dais", -"daisied", -"daisy", -"daitya", -"daiva", -"dak", -"daker", -"dakir", -"dal", -"dalar", -"dale", -"daleman", -"daler", -"daleth", -"dali", -"dalk", -"dallack", -"dalle", -"dalles", -"dallier", -"dally", -"dalt", -"dalteen", -"dalton", -"dam", -"dama", -"damage", -"damager", -"damages", -"daman", -"damask", -"damasse", -"dambose", -"dambrod", -"dame", -"damiana", -"damie", -"damier", -"damine", -"damlike", -"dammar", -"damme", -"dammer", -"dammish", -"damn", -"damned", -"damner", -"damnify", -"damning", -"damnous", -"damp", -"dampang", -"damped", -"dampen", -"damper", -"damping", -"dampish", -"damply", -"dampy", -"damsel", -"damson", -"dan", -"danaid", -"danaide", -"danaine", -"danaite", -"dance", -"dancer", -"dancery", -"dancing", -"dand", -"danda", -"dander", -"dandify", -"dandily", -"dandle", -"dandler", -"dandy", -"dang", -"danger", -"dangle", -"dangler", -"danglin", -"danio", -"dank", -"dankish", -"dankly", -"danli", -"danner", -"dannock", -"dansant", -"danta", -"danton", -"dao", -"daoine", -"dap", -"daphnin", -"dapicho", -"dapico", -"dapifer", -"dapper", -"dapple", -"dappled", -"dar", -"darac", -"daraf", -"darat", -"darbha", -"darby", -"dardaol", -"dare", -"dareall", -"dareful", -"darer", -"daresay", -"darg", -"dargah", -"darger", -"dargue", -"dari", -"daribah", -"daric", -"daring", -"dariole", -"dark", -"darken", -"darkful", -"darkish", -"darkle", -"darkly", -"darky", -"darling", -"darn", -"darned", -"darnel", -"darner", -"darnex", -"darning", -"daroga", -"daroo", -"darr", -"darrein", -"darst", -"dart", -"dartars", -"darter", -"darting", -"dartle", -"dartman", -"dartoic", -"dartoid", -"dartos", -"dartre", -"darts", -"darzee", -"das", -"dash", -"dashed", -"dashee", -"dasheen", -"dasher", -"dashing", -"dashpot", -"dashy", -"dasi", -"dasnt", -"dassie", -"dassy", -"dastard", -"dastur", -"dasturi", -"dasyure", -"data", -"datable", -"datably", -"dataria", -"datary", -"datch", -"datcha", -"date", -"dater", -"datil", -"dating", -"dation", -"datival", -"dative", -"dattock", -"datum", -"daturic", -"daub", -"daube", -"dauber", -"daubery", -"daubing", -"dauby", -"daud", -"daunch", -"dauncy", -"daunt", -"daunter", -"daunton", -"dauphin", -"daut", -"dautie", -"dauw", -"davach", -"daven", -"daver", -"daverdy", -"davit", -"davoch", -"davy", -"davyne", -"daw", -"dawdle", -"dawdler", -"dawdy", -"dawish", -"dawkin", -"dawn", -"dawning", -"dawny", -"dawtet", -"dawtit", -"dawut", -"day", -"dayal", -"daybeam", -"daybook", -"daydawn", -"dayfly", -"dayless", -"daylit", -"daylong", -"dayman", -"daymare", -"daymark", -"dayroom", -"days", -"daysman", -"daystar", -"daytale", -"daytide", -"daytime", -"dayward", -"daywork", -"daywrit", -"daze", -"dazed", -"dazedly", -"dazy", -"dazzle", -"dazzler", -"de", -"deacon", -"dead", -"deaden", -"deader", -"deadeye", -"deading", -"deadish", -"deadly", -"deadman", -"deadpan", -"deadpay", -"deaf", -"deafen", -"deafish", -"deafly", -"deair", -"deal", -"dealate", -"dealer", -"dealing", -"dealt", -"dean", -"deaner", -"deanery", -"deaness", -"dear", -"dearie", -"dearly", -"dearth", -"deary", -"deash", -"deasil", -"death", -"deathin", -"deathly", -"deathy", -"deave", -"deavely", -"deb", -"debacle", -"debadge", -"debar", -"debark", -"debase", -"debaser", -"debate", -"debater", -"debauch", -"debby", -"debeige", -"deben", -"debile", -"debind", -"debit", -"debord", -"debosh", -"debouch", -"debride", -"debrief", -"debris", -"debt", -"debtee", -"debtful", -"debtor", -"debunk", -"debus", -"debut", -"decad", -"decadal", -"decade", -"decadic", -"decafid", -"decagon", -"decal", -"decamp", -"decan", -"decanal", -"decane", -"decani", -"decant", -"decap", -"decapod", -"decarch", -"decare", -"decart", -"decast", -"decate", -"decator", -"decatyl", -"decay", -"decayed", -"decayer", -"decease", -"deceit", -"deceive", -"decence", -"decency", -"decene", -"decent", -"decenyl", -"decern", -"decess", -"deciare", -"decibel", -"decide", -"decided", -"decider", -"decidua", -"decil", -"decile", -"decima", -"decimal", -"deck", -"decke", -"decked", -"deckel", -"decker", -"deckie", -"decking", -"deckle", -"declaim", -"declare", -"declass", -"decline", -"declive", -"decoat", -"decoct", -"decode", -"decoic", -"decoke", -"decolor", -"decorum", -"decoy", -"decoyer", -"decream", -"decree", -"decreer", -"decreet", -"decrete", -"decrew", -"decrial", -"decried", -"decrier", -"decrown", -"decry", -"decuman", -"decuple", -"decuria", -"decurve", -"decury", -"decus", -"decyl", -"decylic", -"decyne", -"dedimus", -"dedo", -"deduce", -"deduct", -"dee", -"deed", -"deedbox", -"deedeed", -"deedful", -"deedily", -"deedy", -"deem", -"deemer", -"deemie", -"deep", -"deepen", -"deeping", -"deepish", -"deeply", -"deer", -"deerdog", -"deerlet", -"deevey", -"deface", -"defacer", -"defalk", -"defame", -"defamed", -"defamer", -"defassa", -"defat", -"default", -"defease", -"defeat", -"defect", -"defence", -"defend", -"defense", -"defer", -"defial", -"defiant", -"defiber", -"deficit", -"defier", -"defile", -"defiled", -"defiler", -"define", -"defined", -"definer", -"deflate", -"deflect", -"deflesh", -"deflex", -"defog", -"deforce", -"deform", -"defoul", -"defraud", -"defray", -"defrock", -"defrost", -"deft", -"deftly", -"defunct", -"defuse", -"defy", -"deg", -"degas", -"degauss", -"degerm", -"degged", -"degger", -"deglaze", -"degorge", -"degrade", -"degrain", -"degree", -"degu", -"degum", -"degust", -"dehair", -"dehisce", -"dehorn", -"dehors", -"dehort", -"dehull", -"dehusk", -"deice", -"deicer", -"deicide", -"deictic", -"deific", -"deifier", -"deiform", -"deify", -"deign", -"deink", -"deinos", -"deiseal", -"deism", -"deist", -"deistic", -"deity", -"deject", -"dejecta", -"dejeune", -"dekko", -"dekle", -"delaine", -"delapse", -"delate", -"delater", -"delator", -"delawn", -"delay", -"delayer", -"dele", -"delead", -"delenda", -"delete", -"delf", -"delft", -"delible", -"delict", -"delight", -"delime", -"delimit", -"delint", -"deliver", -"dell", -"deloul", -"delouse", -"delta", -"deltaic", -"deltal", -"deltic", -"deltoid", -"delude", -"deluder", -"deluge", -"deluxe", -"delve", -"delver", -"demagog", -"demal", -"demand", -"demarch", -"demark", -"demast", -"deme", -"demean", -"demency", -"dement", -"demerit", -"demesne", -"demi", -"demibob", -"demidog", -"demigod", -"demihag", -"demiman", -"demiowl", -"demiox", -"demiram", -"demirep", -"demise", -"demiss", -"demit", -"demivol", -"demob", -"demoded", -"demoid", -"demon", -"demonic", -"demonry", -"demos", -"demote", -"demotic", -"demount", -"demulce", -"demure", -"demy", -"den", -"denaro", -"denary", -"denat", -"denda", -"dendral", -"dendric", -"dendron", -"dene", -"dengue", -"denial", -"denier", -"denim", -"denizen", -"dennet", -"denote", -"dense", -"densely", -"densen", -"densher", -"densify", -"density", -"dent", -"dental", -"dentale", -"dentary", -"dentata", -"dentate", -"dentel", -"denter", -"dentex", -"dentil", -"dentile", -"dentin", -"dentine", -"dentist", -"dentoid", -"denture", -"denty", -"denude", -"denuder", -"deny", -"deodand", -"deodara", -"deota", -"depa", -"depaint", -"depark", -"depart", -"depas", -"depass", -"depend", -"depeter", -"dephase", -"depict", -"deplane", -"deplete", -"deplore", -"deploy", -"deplume", -"deplump", -"depoh", -"depone", -"deport", -"deposal", -"depose", -"deposer", -"deposit", -"depot", -"deprave", -"depress", -"deprint", -"deprive", -"depside", -"depth", -"depthen", -"depute", -"deputy", -"dequeen", -"derah", -"deraign", -"derail", -"derange", -"derat", -"derate", -"derater", -"deray", -"derby", -"dere", -"dereism", -"deric", -"deride", -"derider", -"derival", -"derive", -"derived", -"deriver", -"derm", -"derma", -"dermad", -"dermal", -"dermic", -"dermis", -"dermoid", -"dermol", -"dern", -"dernier", -"derout", -"derrick", -"derride", -"derries", -"derry", -"dertrum", -"derust", -"dervish", -"desalt", -"desand", -"descale", -"descant", -"descend", -"descent", -"descort", -"descry", -"deseed", -"deseret", -"desert", -"deserve", -"desex", -"desi", -"desight", -"design", -"desire", -"desired", -"desirer", -"desist", -"desize", -"desk", -"deslime", -"desma", -"desman", -"desmic", -"desmid", -"desmine", -"desmoid", -"desmoma", -"desmon", -"despair", -"despect", -"despise", -"despite", -"despoil", -"despond", -"despot", -"dess", -"dessa", -"dessert", -"dessil", -"destain", -"destine", -"destiny", -"destour", -"destroy", -"desuete", -"desugar", -"desyl", -"detach", -"detail", -"detain", -"detar", -"detax", -"detect", -"detent", -"deter", -"deterge", -"detest", -"detin", -"detinet", -"detinue", -"detour", -"detract", -"detrain", -"detrude", -"detune", -"detur", -"deuce", -"deuced", -"deul", -"deuton", -"dev", -"deva", -"devall", -"devalue", -"devance", -"devast", -"devata", -"develin", -"develop", -"devest", -"deviant", -"deviate", -"device", -"devil", -"deviled", -"deviler", -"devilet", -"devilry", -"devily", -"devious", -"devisal", -"devise", -"devisee", -"deviser", -"devisor", -"devoice", -"devoid", -"devoir", -"devolve", -"devote", -"devoted", -"devotee", -"devoter", -"devour", -"devout", -"devow", -"devvel", -"dew", -"dewan", -"dewanee", -"dewater", -"dewax", -"dewbeam", -"dewclaw", -"dewcup", -"dewdamp", -"dewdrop", -"dewer", -"dewfall", -"dewily", -"dewlap", -"dewless", -"dewlike", -"dewool", -"deworm", -"dewret", -"dewtry", -"dewworm", -"dewy", -"dexter", -"dextrad", -"dextral", -"dextran", -"dextrin", -"dextro", -"dey", -"deyship", -"dezinc", -"dha", -"dhabb", -"dhai", -"dhak", -"dhamnoo", -"dhan", -"dhangar", -"dhanuk", -"dhanush", -"dharana", -"dharani", -"dharma", -"dharna", -"dhaura", -"dhauri", -"dhava", -"dhaw", -"dheri", -"dhobi", -"dhole", -"dhoni", -"dhoon", -"dhoti", -"dhoul", -"dhow", -"dhu", -"dhunchi", -"dhurra", -"dhyal", -"dhyana", -"di", -"diabase", -"diacid", -"diacle", -"diacope", -"diact", -"diactin", -"diadem", -"diaderm", -"diaene", -"diagram", -"dial", -"dialect", -"dialer", -"dialin", -"dialing", -"dialist", -"dialkyl", -"diallel", -"diallyl", -"dialyze", -"diamb", -"diambic", -"diamide", -"diamine", -"diamond", -"dian", -"diander", -"dianite", -"diapase", -"diapasm", -"diaper", -"diaplex", -"diapsid", -"diarch", -"diarchy", -"diarial", -"diarian", -"diarist", -"diarize", -"diary", -"diastem", -"diaster", -"diasyrm", -"diatom", -"diaulic", -"diaulos", -"diaxial", -"diaxon", -"diazide", -"diazine", -"diazoic", -"diazole", -"diazoma", -"dib", -"dibase", -"dibasic", -"dibatag", -"dibber", -"dibble", -"dibbler", -"dibbuk", -"dibhole", -"dibrach", -"dibrom", -"dibs", -"dicast", -"dice", -"dicebox", -"dicecup", -"diceman", -"dicer", -"dicetyl", -"dich", -"dichas", -"dichord", -"dicing", -"dick", -"dickens", -"dicker", -"dickey", -"dicky", -"dicolic", -"dicolon", -"dicot", -"dicotyl", -"dicta", -"dictate", -"dictic", -"diction", -"dictum", -"dicycle", -"did", -"didder", -"diddle", -"diddler", -"diddy", -"didelph", -"didie", -"didine", -"didle", -"didna", -"didnt", -"didromy", -"didst", -"didym", -"didymia", -"didymus", -"die", -"dieb", -"dieback", -"diedral", -"diedric", -"diehard", -"dielike", -"diem", -"diene", -"dier", -"diesel", -"diesis", -"diet", -"dietal", -"dietary", -"dieter", -"diethyl", -"dietic", -"dietics", -"dietine", -"dietist", -"diewise", -"diffame", -"differ", -"diffide", -"difform", -"diffuse", -"dig", -"digamma", -"digamy", -"digenic", -"digeny", -"digest", -"digger", -"digging", -"dight", -"dighter", -"digit", -"digital", -"digitus", -"diglot", -"diglyph", -"digmeat", -"dignify", -"dignity", -"digram", -"digraph", -"digress", -"digs", -"dihalo", -"diiamb", -"diiodo", -"dika", -"dikage", -"dike", -"diker", -"diketo", -"dikkop", -"dilate", -"dilated", -"dilater", -"dilator", -"dildo", -"dilemma", -"dilker", -"dill", -"dilli", -"dillier", -"dilling", -"dillue", -"dilluer", -"dilly", -"dilo", -"dilogy", -"diluent", -"dilute", -"diluted", -"dilutee", -"diluter", -"dilutor", -"diluvia", -"dim", -"dimber", -"dimble", -"dime", -"dimer", -"dimeran", -"dimeric", -"dimeter", -"dimiss", -"dimit", -"dimity", -"dimly", -"dimmed", -"dimmer", -"dimmest", -"dimmet", -"dimmish", -"dimness", -"dimoric", -"dimorph", -"dimple", -"dimply", -"dimps", -"dimpsy", -"din", -"dinar", -"dinder", -"dindle", -"dine", -"diner", -"dineric", -"dinero", -"dinette", -"ding", -"dingar", -"dingbat", -"dinge", -"dingee", -"dinghee", -"dinghy", -"dingily", -"dingle", -"dingly", -"dingo", -"dingus", -"dingy", -"dinic", -"dinical", -"dining", -"dinitro", -"dink", -"dinkey", -"dinkum", -"dinky", -"dinmont", -"dinner", -"dinnery", -"dinomic", -"dinsome", -"dint", -"dinus", -"diobely", -"diobol", -"diocese", -"diode", -"diodont", -"dioecy", -"diol", -"dionise", -"dionym", -"diopter", -"dioptra", -"dioptry", -"diorama", -"diorite", -"diose", -"diosmin", -"diota", -"diotic", -"dioxane", -"dioxide", -"dioxime", -"dioxy", -"dip", -"dipetto", -"diphase", -"diphead", -"diplex", -"diploe", -"diploic", -"diploid", -"diplois", -"diploma", -"diplont", -"diplopy", -"dipnoan", -"dipnoid", -"dipode", -"dipodic", -"dipody", -"dipolar", -"dipole", -"diporpa", -"dipped", -"dipper", -"dipping", -"dipsas", -"dipsey", -"dipter", -"diptote", -"diptych", -"dipware", -"dipygus", -"dipylon", -"dipyre", -"dird", -"dirdum", -"dire", -"direct", -"direful", -"direly", -"dirempt", -"dirge", -"dirgler", -"dirhem", -"dirk", -"dirl", -"dirndl", -"dirt", -"dirten", -"dirtily", -"dirty", -"dis", -"disable", -"disagio", -"disally", -"disarm", -"disavow", -"disawa", -"disazo", -"disband", -"disbar", -"disbark", -"disbody", -"disbud", -"disbury", -"disc", -"discage", -"discal", -"discard", -"discase", -"discept", -"discern", -"discerp", -"discoid", -"discord", -"discous", -"discus", -"discuss", -"disdain", -"disdub", -"disease", -"disedge", -"diseme", -"disemic", -"disfame", -"disfen", -"disgig", -"disglut", -"disgood", -"disgown", -"disgulf", -"disgust", -"dish", -"dished", -"dishelm", -"disher", -"dishful", -"dishome", -"dishorn", -"dishpan", -"dishrag", -"disject", -"disjoin", -"disjune", -"disk", -"disleaf", -"dislike", -"dislimn", -"dislink", -"dislip", -"disload", -"dislove", -"dismain", -"dismal", -"disman", -"dismark", -"dismask", -"dismast", -"dismay", -"disme", -"dismiss", -"disna", -"disnest", -"disnew", -"disobey", -"disodic", -"disomic", -"disomus", -"disorb", -"disown", -"dispark", -"dispart", -"dispel", -"dispend", -"display", -"dispone", -"dispope", -"disport", -"dispose", -"dispost", -"dispulp", -"dispute", -"disrank", -"disrate", -"disring", -"disrobe", -"disroof", -"disroot", -"disrump", -"disrupt", -"diss", -"disseat", -"dissect", -"dissent", -"dissert", -"dissoul", -"dissuit", -"distad", -"distaff", -"distain", -"distal", -"distale", -"distant", -"distend", -"distent", -"distich", -"distill", -"distome", -"distort", -"distune", -"disturb", -"disturn", -"disuse", -"diswood", -"disyoke", -"dit", -"dita", -"dital", -"ditch", -"ditcher", -"dite", -"diter", -"dither", -"dithery", -"dithion", -"ditolyl", -"ditone", -"dittamy", -"dittany", -"dittay", -"dittied", -"ditto", -"ditty", -"diurnal", -"diurne", -"div", -"diva", -"divan", -"divata", -"dive", -"divel", -"diver", -"diverge", -"divers", -"diverse", -"divert", -"divest", -"divide", -"divided", -"divider", -"divine", -"diviner", -"diving", -"divinyl", -"divisor", -"divorce", -"divot", -"divoto", -"divulge", -"divulse", -"divus", -"divvy", -"diwata", -"dixie", -"dixit", -"dixy", -"dizain", -"dizen", -"dizoic", -"dizzard", -"dizzily", -"dizzy", -"djave", -"djehad", -"djerib", -"djersa", -"do", -"doab", -"doable", -"doarium", -"doat", -"doated", -"doater", -"doating", -"doatish", -"dob", -"dobbed", -"dobber", -"dobbin", -"dobbing", -"dobby", -"dobe", -"dobla", -"doblon", -"dobra", -"dobrao", -"dobson", -"doby", -"doc", -"docent", -"docible", -"docile", -"docity", -"dock", -"dockage", -"docken", -"docker", -"docket", -"dockize", -"dockman", -"docmac", -"doctor", -"doctrix", -"dod", -"dodd", -"doddart", -"dodded", -"dodder", -"doddery", -"doddie", -"dodding", -"doddle", -"doddy", -"dodecyl", -"dodge", -"dodger", -"dodgery", -"dodgily", -"dodgy", -"dodkin", -"dodlet", -"dodman", -"dodo", -"dodoism", -"dodrans", -"doe", -"doebird", -"doeglic", -"doer", -"does", -"doeskin", -"doesnt", -"doest", -"doff", -"doffer", -"dog", -"dogal", -"dogate", -"dogbane", -"dogbite", -"dogblow", -"dogboat", -"dogbolt", -"dogbush", -"dogcart", -"dogdom", -"doge", -"dogedom", -"dogface", -"dogfall", -"dogfish", -"dogfoot", -"dogged", -"dogger", -"doggery", -"doggess", -"doggish", -"doggo", -"doggone", -"doggrel", -"doggy", -"doghead", -"doghole", -"doghood", -"dogie", -"dogless", -"doglike", -"dogly", -"dogma", -"dogman", -"dogmata", -"dogs", -"dogship", -"dogskin", -"dogtail", -"dogtie", -"dogtrot", -"dogvane", -"dogwood", -"dogy", -"doigt", -"doiled", -"doily", -"doina", -"doing", -"doings", -"doit", -"doited", -"doitkin", -"doke", -"dokhma", -"dola", -"dolabra", -"dolcan", -"dolcian", -"dolcino", -"doldrum", -"dole", -"doleful", -"dolent", -"doless", -"doli", -"dolia", -"dolina", -"doline", -"dolium", -"doll", -"dollar", -"dolldom", -"dollier", -"dollish", -"dollop", -"dolly", -"dolman", -"dolmen", -"dolor", -"dolose", -"dolous", -"dolphin", -"dolt", -"doltish", -"dom", -"domain", -"domal", -"domba", -"dome", -"doment", -"domer", -"domett", -"domic", -"domical", -"domine", -"dominie", -"domino", -"dominus", -"domite", -"domitic", -"domn", -"domnei", -"domoid", -"dompt", -"domy", -"don", -"donable", -"donary", -"donate", -"donated", -"donatee", -"donator", -"donax", -"done", -"donee", -"doney", -"dong", -"donga", -"dongon", -"donjon", -"donkey", -"donna", -"donnert", -"donnish", -"donnism", -"donnot", -"donor", -"donship", -"donsie", -"dont", -"donum", -"doob", -"doocot", -"doodab", -"doodad", -"doodle", -"doodler", -"dooja", -"dook", -"dooket", -"dookit", -"dool", -"doolee", -"dooley", -"dooli", -"doolie", -"dooly", -"doom", -"doomage", -"doomer", -"doomful", -"dooms", -"doon", -"door", -"doorba", -"doorboy", -"doored", -"doorman", -"doorway", -"dop", -"dopa", -"dopatta", -"dope", -"doper", -"dopey", -"dopper", -"doppia", -"dor", -"dorab", -"dorad", -"dorado", -"doree", -"dorhawk", -"doria", -"dorje", -"dorlach", -"dorlot", -"dorm", -"dormant", -"dormer", -"dormie", -"dormy", -"dorn", -"dorneck", -"dornic", -"dornick", -"dornock", -"dorp", -"dorsad", -"dorsal", -"dorsale", -"dorsel", -"dorser", -"dorsum", -"dorter", -"dorts", -"dorty", -"doruck", -"dory", -"dos", -"dosa", -"dosadh", -"dosage", -"dose", -"doser", -"dosis", -"doss", -"dossal", -"dossel", -"dosser", -"dossier", -"dossil", -"dossman", -"dot", -"dotage", -"dotal", -"dotard", -"dotardy", -"dotate", -"dotchin", -"dote", -"doted", -"doter", -"doting", -"dotish", -"dotkin", -"dotless", -"dotlike", -"dotted", -"dotter", -"dottily", -"dotting", -"dottle", -"dottler", -"dotty", -"doty", -"douar", -"double", -"doubled", -"doubler", -"doublet", -"doubly", -"doubt", -"doubter", -"douc", -"douce", -"doucely", -"doucet", -"douche", -"doucin", -"doucine", -"doudle", -"dough", -"dought", -"doughty", -"doughy", -"doum", -"doup", -"douping", -"dour", -"dourine", -"dourly", -"douse", -"douser", -"dout", -"douter", -"doutous", -"dove", -"dovecot", -"dovekey", -"dovekie", -"dovelet", -"dover", -"dovish", -"dow", -"dowable", -"dowager", -"dowcet", -"dowd", -"dowdily", -"dowdy", -"dowed", -"dowel", -"dower", -"doweral", -"dowery", -"dowf", -"dowie", -"dowily", -"dowitch", -"dowl", -"dowlas", -"dowless", -"down", -"downby", -"downcry", -"downcut", -"downer", -"downily", -"downlie", -"downset", -"downway", -"downy", -"dowp", -"dowry", -"dowse", -"dowser", -"dowset", -"doxa", -"doxy", -"doze", -"dozed", -"dozen", -"dozener", -"dozenth", -"dozer", -"dozily", -"dozy", -"dozzled", -"drab", -"drabbet", -"drabble", -"drabby", -"drably", -"drachm", -"drachma", -"dracma", -"draff", -"draffy", -"draft", -"draftee", -"drafter", -"drafty", -"drag", -"dragade", -"dragbar", -"dragged", -"dragger", -"draggle", -"draggly", -"draggy", -"dragman", -"dragnet", -"drago", -"dragon", -"dragoon", -"dragsaw", -"drail", -"drain", -"draine", -"drained", -"drainer", -"drake", -"dram", -"drama", -"dramm", -"dramme", -"drammed", -"drammer", -"drang", -"drank", -"drant", -"drape", -"draper", -"drapery", -"drassid", -"drastic", -"drat", -"drate", -"dratted", -"draught", -"dravya", -"draw", -"drawarm", -"drawbar", -"drawboy", -"drawcut", -"drawee", -"drawer", -"drawers", -"drawing", -"drawk", -"drawl", -"drawler", -"drawly", -"drawn", -"drawnet", -"drawoff", -"drawout", -"drawrod", -"dray", -"drayage", -"drayman", -"drazel", -"dread", -"dreader", -"dreadly", -"dream", -"dreamer", -"dreamsy", -"dreamt", -"dreamy", -"drear", -"drearly", -"dreary", -"dredge", -"dredger", -"dree", -"dreep", -"dreepy", -"dreg", -"dreggy", -"dregs", -"drench", -"dreng", -"dress", -"dressed", -"dresser", -"dressy", -"drest", -"drew", -"drewite", -"drias", -"drib", -"dribble", -"driblet", -"driddle", -"dried", -"drier", -"driest", -"drift", -"drifter", -"drifty", -"drill", -"driller", -"drillet", -"dringle", -"drink", -"drinker", -"drinn", -"drip", -"dripper", -"dripple", -"drippy", -"drisk", -"drivage", -"drive", -"drivel", -"driven", -"driver", -"driving", -"drizzle", -"drizzly", -"droddum", -"drogh", -"drogher", -"drogue", -"droit", -"droll", -"drolly", -"drome", -"dromic", -"dromond", -"dromos", -"drona", -"dronage", -"drone", -"droner", -"drongo", -"dronish", -"drony", -"drool", -"droop", -"drooper", -"droopt", -"droopy", -"drop", -"droplet", -"dropman", -"dropout", -"dropper", -"droppy", -"dropsy", -"dropt", -"droshky", -"drosky", -"dross", -"drossel", -"drosser", -"drossy", -"drostdy", -"droud", -"drought", -"drouk", -"drove", -"drover", -"drovy", -"drow", -"drown", -"drowner", -"drowse", -"drowsy", -"drub", -"drubber", -"drubbly", -"drucken", -"drudge", -"drudger", -"druery", -"drug", -"drugger", -"drugget", -"druggy", -"drugman", -"druid", -"druidic", -"druidry", -"druith", -"drum", -"drumble", -"drumlin", -"drumly", -"drummer", -"drummy", -"drung", -"drungar", -"drunk", -"drunken", -"drupal", -"drupe", -"drupel", -"druse", -"drusy", -"druxy", -"dry", -"dryad", -"dryadic", -"dryas", -"drycoal", -"dryfoot", -"drying", -"dryish", -"dryly", -"dryness", -"dryster", -"dryth", -"duad", -"duadic", -"dual", -"duali", -"dualin", -"dualism", -"dualist", -"duality", -"dualize", -"dually", -"duarch", -"duarchy", -"dub", -"dubash", -"dubb", -"dubba", -"dubbah", -"dubber", -"dubbing", -"dubby", -"dubiety", -"dubious", -"dubs", -"ducal", -"ducally", -"ducape", -"ducat", -"ducato", -"ducdame", -"duces", -"duchess", -"duchy", -"duck", -"ducker", -"duckery", -"duckie", -"ducking", -"duckpin", -"duct", -"ducted", -"ductile", -"duction", -"ductor", -"ductule", -"dud", -"dudaim", -"dudder", -"duddery", -"duddies", -"dude", -"dudeen", -"dudgeon", -"dudine", -"dudish", -"dudism", -"dudler", -"dudley", -"dudman", -"due", -"duel", -"dueler", -"dueling", -"duelist", -"duello", -"dueness", -"duenna", -"duer", -"duet", -"duff", -"duffel", -"duffer", -"duffing", -"dufoil", -"dufter", -"duftery", -"dug", -"dugal", -"dugdug", -"duggler", -"dugong", -"dugout", -"dugway", -"duhat", -"duiker", -"duim", -"duit", -"dujan", -"duke", -"dukedom", -"dukely", -"dukery", -"dukhn", -"dukker", -"dulbert", -"dulcet", -"dulcian", -"dulcify", -"dulcose", -"duledge", -"duler", -"dulia", -"dull", -"dullard", -"duller", -"dullery", -"dullify", -"dullish", -"dullity", -"dully", -"dulosis", -"dulotic", -"dulse", -"dult", -"dultie", -"duly", -"dum", -"duma", -"dumaist", -"dumb", -"dumba", -"dumbcow", -"dumbly", -"dumdum", -"dummel", -"dummy", -"dumose", -"dump", -"dumpage", -"dumper", -"dumpily", -"dumping", -"dumpish", -"dumple", -"dumpoke", -"dumpy", -"dumsola", -"dun", -"dunair", -"dunal", -"dunbird", -"dunce", -"duncery", -"dunch", -"duncify", -"duncish", -"dunder", -"dune", -"dunfish", -"dung", -"dungeon", -"dunger", -"dungol", -"dungon", -"dungy", -"dunite", -"dunk", -"dunker", -"dunlin", -"dunnage", -"dunne", -"dunner", -"dunness", -"dunnish", -"dunnite", -"dunnock", -"dunny", -"dunst", -"dunt", -"duntle", -"duny", -"duo", -"duodena", -"duodene", -"duole", -"duopod", -"duopoly", -"duotone", -"duotype", -"dup", -"dupable", -"dupe", -"dupedom", -"duper", -"dupery", -"dupion", -"dupla", -"duple", -"duplet", -"duplex", -"duplify", -"duplone", -"duppy", -"dura", -"durable", -"durably", -"durain", -"dural", -"duramen", -"durance", -"durant", -"durax", -"durbar", -"dure", -"durene", -"durenol", -"duress", -"durgan", -"durian", -"during", -"durity", -"durmast", -"durn", -"duro", -"durra", -"durrie", -"durrin", -"durry", -"durst", -"durwaun", -"duryl", -"dusack", -"duscle", -"dush", -"dusio", -"dusk", -"dusken", -"duskily", -"duskish", -"duskly", -"dusky", -"dust", -"dustbin", -"dustbox", -"dustee", -"duster", -"dustily", -"dusting", -"dustman", -"dustpan", -"dustuck", -"dusty", -"dutch", -"duteous", -"dutied", -"dutiful", -"dutra", -"duty", -"duumvir", -"duvet", -"duvetyn", -"dux", -"duyker", -"dvaita", -"dvandva", -"dwale", -"dwalm", -"dwang", -"dwarf", -"dwarfy", -"dwell", -"dwelled", -"dweller", -"dwelt", -"dwindle", -"dwine", -"dyad", -"dyadic", -"dyarchy", -"dyaster", -"dyce", -"dye", -"dyeable", -"dyeing", -"dyer", -"dyester", -"dyeware", -"dyeweed", -"dyewood", -"dying", -"dyingly", -"dyke", -"dyker", -"dynamic", -"dynamis", -"dynamo", -"dynast", -"dynasty", -"dyne", -"dyphone", -"dyslogy", -"dysnomy", -"dyspnea", -"dystome", -"dysuria", -"dysuric", -"dzeren", -"e", -"ea", -"each", -"eager", -"eagerly", -"eagle", -"eagless", -"eaglet", -"eagre", -"ean", -"ear", -"earache", -"earbob", -"earcap", -"eardrop", -"eardrum", -"eared", -"earful", -"earhole", -"earing", -"earl", -"earlap", -"earldom", -"earless", -"earlet", -"earlike", -"earlish", -"earlock", -"early", -"earmark", -"earn", -"earner", -"earnest", -"earnful", -"earning", -"earpick", -"earplug", -"earring", -"earshot", -"earsore", -"eartab", -"earth", -"earthed", -"earthen", -"earthly", -"earthy", -"earwax", -"earwig", -"earworm", -"earwort", -"ease", -"easeful", -"easel", -"easer", -"easier", -"easiest", -"easily", -"easing", -"east", -"easter", -"eastern", -"easting", -"easy", -"eat", -"eatable", -"eatage", -"eaten", -"eater", -"eatery", -"eating", -"eats", -"eave", -"eaved", -"eaver", -"eaves", -"ebb", -"ebbman", -"eboe", -"ebon", -"ebonist", -"ebonite", -"ebonize", -"ebony", -"ebriate", -"ebriety", -"ebrious", -"ebulus", -"eburine", -"ecad", -"ecanda", -"ecarte", -"ecbatic", -"ecbole", -"ecbolic", -"ecdemic", -"ecderon", -"ecdysis", -"ecesic", -"ecesis", -"eche", -"echea", -"echelon", -"echidna", -"echinal", -"echinid", -"echinus", -"echo", -"echoer", -"echoic", -"echoism", -"echoist", -"echoize", -"ecize", -"ecklein", -"eclair", -"eclat", -"eclegm", -"eclegma", -"eclipse", -"eclogue", -"ecoid", -"ecole", -"ecology", -"economy", -"ecotone", -"ecotype", -"ecphore", -"ecru", -"ecstasy", -"ectad", -"ectal", -"ectally", -"ectasia", -"ectasis", -"ectatic", -"ectene", -"ecthyma", -"ectiris", -"ectopia", -"ectopic", -"ectopy", -"ectozoa", -"ectypal", -"ectype", -"eczema", -"edacity", -"edaphic", -"edaphon", -"edder", -"eddish", -"eddo", -"eddy", -"edea", -"edeagra", -"edeitis", -"edema", -"edemic", -"edenite", -"edental", -"edestan", -"edestin", -"edge", -"edged", -"edgeman", -"edger", -"edging", -"edgrew", -"edgy", -"edh", -"edible", -"edict", -"edictal", -"edicule", -"edifice", -"edifier", -"edify", -"edit", -"edital", -"edition", -"editor", -"educand", -"educate", -"educe", -"educive", -"educt", -"eductor", -"eegrass", -"eel", -"eelboat", -"eelbob", -"eelcake", -"eeler", -"eelery", -"eelfare", -"eelfish", -"eellike", -"eelpot", -"eelpout", -"eelshop", -"eelskin", -"eelware", -"eelworm", -"eely", -"eer", -"eerie", -"eerily", -"effable", -"efface", -"effacer", -"effect", -"effects", -"effendi", -"effete", -"effigy", -"efflate", -"efflux", -"efform", -"effort", -"effulge", -"effund", -"effuse", -"eft", -"eftest", -"egad", -"egality", -"egence", -"egeran", -"egest", -"egesta", -"egg", -"eggcup", -"egger", -"eggfish", -"egghead", -"egghot", -"egging", -"eggler", -"eggless", -"egglike", -"eggnog", -"eggy", -"egilops", -"egipto", -"egma", -"ego", -"egohood", -"egoism", -"egoist", -"egoity", -"egoize", -"egoizer", -"egol", -"egomism", -"egotism", -"egotist", -"egotize", -"egress", -"egret", -"eh", -"eheu", -"ehlite", -"ehuawa", -"eident", -"eider", -"eidetic", -"eidolic", -"eidolon", -"eight", -"eighth", -"eighty", -"eigne", -"eimer", -"einkorn", -"eisodic", -"either", -"eject", -"ejecta", -"ejector", -"ejoo", -"ekaha", -"eke", -"eker", -"ekerite", -"eking", -"ekka", -"ekphore", -"ektene", -"ektenes", -"el", -"elaidic", -"elaidin", -"elain", -"elaine", -"elance", -"eland", -"elanet", -"elapid", -"elapine", -"elapoid", -"elapse", -"elastic", -"elastin", -"elatcha", -"elate", -"elated", -"elater", -"elation", -"elative", -"elator", -"elb", -"elbow", -"elbowed", -"elbower", -"elbowy", -"elcaja", -"elchee", -"eld", -"elder", -"elderly", -"eldest", -"eldin", -"elding", -"eldress", -"elect", -"electee", -"electly", -"elector", -"electro", -"elegant", -"elegiac", -"elegist", -"elegit", -"elegize", -"elegy", -"eleidin", -"element", -"elemi", -"elemin", -"elench", -"elenchi", -"elenge", -"elevate", -"eleven", -"elevon", -"elf", -"elfhood", -"elfic", -"elfin", -"elfish", -"elfkin", -"elfland", -"elflike", -"elflock", -"elfship", -"elfwife", -"elfwort", -"elicit", -"elide", -"elision", -"elisor", -"elite", -"elixir", -"elk", -"elkhorn", -"elkslip", -"elkwood", -"ell", -"ellagic", -"elle", -"elleck", -"ellfish", -"ellipse", -"ellops", -"ellwand", -"elm", -"elmy", -"elocute", -"elod", -"eloge", -"elogium", -"eloign", -"elope", -"eloper", -"elops", -"els", -"else", -"elsehow", -"elsin", -"elt", -"eluate", -"elude", -"eluder", -"elusion", -"elusive", -"elusory", -"elute", -"elution", -"elutor", -"eluvial", -"eluvium", -"elvan", -"elver", -"elves", -"elvet", -"elvish", -"elysia", -"elytral", -"elytrin", -"elytron", -"elytrum", -"em", -"emanant", -"emanate", -"emanium", -"emarcid", -"emball", -"embalm", -"embank", -"embar", -"embargo", -"embark", -"embassy", -"embathe", -"embay", -"embed", -"embelic", -"ember", -"embind", -"embira", -"emblaze", -"emblem", -"emblema", -"emblic", -"embody", -"embog", -"embole", -"embolic", -"embolo", -"embolum", -"embolus", -"emboly", -"embosom", -"emboss", -"embound", -"embow", -"embowed", -"embowel", -"embower", -"embox", -"embrace", -"embrail", -"embroil", -"embrown", -"embryo", -"embryon", -"embuia", -"embus", -"embusk", -"emcee", -"eme", -"emeer", -"emend", -"emender", -"emerald", -"emerge", -"emerize", -"emerse", -"emersed", -"emery", -"emesis", -"emetic", -"emetine", -"emgalla", -"emigree", -"eminent", -"emir", -"emirate", -"emit", -"emitter", -"emma", -"emmenic", -"emmer", -"emmet", -"emodin", -"emoloa", -"emote", -"emotion", -"emotive", -"empall", -"empanel", -"empaper", -"empark", -"empasm", -"empathy", -"emperor", -"empery", -"empire", -"empiric", -"emplace", -"emplane", -"employ", -"emplume", -"emporia", -"empower", -"empress", -"emprise", -"empt", -"emptier", -"emptily", -"emptins", -"emption", -"emptor", -"empty", -"empyema", -"emu", -"emulant", -"emulate", -"emulous", -"emulsin", -"emulsor", -"emyd", -"emydian", -"en", -"enable", -"enabler", -"enact", -"enactor", -"enaena", -"enage", -"enalid", -"enam", -"enamber", -"enamdar", -"enamel", -"enamor", -"enapt", -"enarbor", -"enarch", -"enarm", -"enarme", -"enate", -"enatic", -"enation", -"enbrave", -"encage", -"encake", -"encamp", -"encase", -"encash", -"encauma", -"encave", -"encell", -"enchain", -"enchair", -"enchant", -"enchase", -"enchest", -"encina", -"encinal", -"encist", -"enclasp", -"enclave", -"encloak", -"enclose", -"encloud", -"encoach", -"encode", -"encoil", -"encolor", -"encomia", -"encomic", -"encoop", -"encore", -"encowl", -"encraal", -"encraty", -"encreel", -"encrisp", -"encrown", -"encrust", -"encrypt", -"encup", -"encurl", -"encyst", -"end", -"endable", -"endarch", -"endaze", -"endear", -"ended", -"endemic", -"ender", -"endere", -"enderon", -"endevil", -"endew", -"endgate", -"ending", -"endite", -"endive", -"endless", -"endlong", -"endmost", -"endogen", -"endome", -"endopod", -"endoral", -"endore", -"endorse", -"endoss", -"endotys", -"endow", -"endower", -"endozoa", -"endue", -"endura", -"endure", -"endurer", -"endways", -"endwise", -"endyma", -"endymal", -"endysis", -"enema", -"enemy", -"energic", -"energid", -"energy", -"eneuch", -"eneugh", -"enface", -"enfelon", -"enfeoff", -"enfever", -"enfile", -"enfiled", -"enflesh", -"enfoil", -"enfold", -"enforce", -"enfork", -"enfoul", -"enframe", -"enfree", -"engage", -"engaged", -"engager", -"engaol", -"engarb", -"engaud", -"engaze", -"engem", -"engild", -"engine", -"engird", -"engirt", -"englad", -"englobe", -"engloom", -"englory", -"englut", -"englyn", -"engobe", -"engold", -"engore", -"engorge", -"engrace", -"engraff", -"engraft", -"engrail", -"engrain", -"engram", -"engrasp", -"engrave", -"engreen", -"engross", -"enguard", -"engulf", -"enhalo", -"enhance", -"enhat", -"enhaunt", -"enheart", -"enhedge", -"enhelm", -"enherit", -"enhusk", -"eniac", -"enigma", -"enisle", -"enjail", -"enjamb", -"enjelly", -"enjewel", -"enjoin", -"enjoy", -"enjoyer", -"enkraal", -"enlace", -"enlard", -"enlarge", -"enleaf", -"enlief", -"enlife", -"enlight", -"enlink", -"enlist", -"enliven", -"enlock", -"enlodge", -"enmask", -"enmass", -"enmesh", -"enmist", -"enmity", -"enmoss", -"ennead", -"ennerve", -"enniche", -"ennoble", -"ennoic", -"ennomic", -"ennui", -"enocyte", -"enodal", -"enoil", -"enol", -"enolate", -"enolic", -"enolize", -"enomoty", -"enoplan", -"enorm", -"enough", -"enounce", -"enow", -"enplane", -"enquire", -"enquiry", -"enrace", -"enrage", -"enraged", -"enrange", -"enrank", -"enrapt", -"enray", -"enrib", -"enrich", -"enring", -"enrive", -"enrobe", -"enrober", -"enrol", -"enroll", -"enroot", -"enrough", -"enruin", -"enrut", -"ens", -"ensaint", -"ensand", -"ensate", -"enscene", -"ense", -"enseam", -"enseat", -"enseem", -"enserf", -"ensete", -"enshade", -"enshawl", -"enshell", -"ensign", -"ensile", -"ensky", -"enslave", -"ensmall", -"ensnare", -"ensnarl", -"ensnow", -"ensoul", -"enspell", -"enstamp", -"enstar", -"enstate", -"ensteel", -"enstool", -"enstore", -"ensuant", -"ensue", -"ensuer", -"ensure", -"ensurer", -"ensweep", -"entach", -"entad", -"entail", -"ental", -"entame", -"entasia", -"entasis", -"entelam", -"entente", -"enter", -"enteral", -"enterer", -"enteria", -"enteric", -"enteron", -"entheal", -"enthral", -"enthuse", -"entia", -"entice", -"enticer", -"entify", -"entire", -"entiris", -"entitle", -"entity", -"entoil", -"entomb", -"entomic", -"entone", -"entopic", -"entotic", -"entozoa", -"entrail", -"entrain", -"entrant", -"entrap", -"entreat", -"entree", -"entropy", -"entrust", -"entry", -"entwine", -"entwist", -"enure", -"enurny", -"envapor", -"envault", -"enveil", -"envelop", -"envenom", -"envied", -"envier", -"envious", -"environ", -"envoy", -"envy", -"envying", -"enwiden", -"enwind", -"enwisen", -"enwoman", -"enwomb", -"enwood", -"enwound", -"enwrap", -"enwrite", -"enzone", -"enzooty", -"enzym", -"enzyme", -"enzymic", -"eoan", -"eolith", -"eon", -"eonism", -"eophyte", -"eosate", -"eoside", -"eosin", -"eosinic", -"eozoon", -"epacme", -"epacrid", -"epact", -"epactal", -"epagoge", -"epanody", -"eparch", -"eparchy", -"epaule", -"epaulet", -"epaxial", -"epee", -"epeeist", -"epeiric", -"epeirid", -"epergne", -"epha", -"ephah", -"ephebe", -"ephebic", -"ephebos", -"ephebus", -"ephelis", -"ephetae", -"ephete", -"ephetic", -"ephod", -"ephor", -"ephoral", -"ephoric", -"ephorus", -"ephyra", -"epibole", -"epiboly", -"epic", -"epical", -"epicarp", -"epicede", -"epicele", -"epicene", -"epichil", -"epicism", -"epicist", -"epicly", -"epicure", -"epicyte", -"epidemy", -"epiderm", -"epidote", -"epigeal", -"epigean", -"epigeic", -"epigene", -"epigone", -"epigram", -"epigyne", -"epigyny", -"epihyal", -"epikeia", -"epilate", -"epilobe", -"epimer", -"epimere", -"epimyth", -"epinaos", -"epinine", -"epiotic", -"epipial", -"episode", -"epistle", -"epitaph", -"epitela", -"epithem", -"epithet", -"epitoke", -"epitome", -"epiural", -"epizoa", -"epizoal", -"epizoan", -"epizoic", -"epizoon", -"epoch", -"epocha", -"epochal", -"epode", -"epodic", -"eponym", -"eponymy", -"epopee", -"epopt", -"epoptes", -"epoptic", -"epos", -"epsilon", -"epulary", -"epulis", -"epulo", -"epuloid", -"epural", -"epurate", -"equable", -"equably", -"equal", -"equally", -"equant", -"equate", -"equator", -"equerry", -"equid", -"equine", -"equinia", -"equinox", -"equinus", -"equip", -"equiped", -"equison", -"equites", -"equity", -"equoid", -"er", -"era", -"erade", -"eral", -"eranist", -"erase", -"erased", -"eraser", -"erasion", -"erasure", -"erbia", -"erbium", -"erd", -"erdvark", -"ere", -"erect", -"erecter", -"erectly", -"erector", -"erelong", -"eremic", -"eremite", -"erenach", -"erenow", -"erepsin", -"erept", -"ereptic", -"erethic", -"erg", -"ergal", -"ergasia", -"ergates", -"ergodic", -"ergoism", -"ergon", -"ergot", -"ergoted", -"ergotic", -"ergotin", -"ergusia", -"eria", -"eric", -"ericad", -"erical", -"ericius", -"ericoid", -"erika", -"erikite", -"erineum", -"erinite", -"erinose", -"eristic", -"erizo", -"erlking", -"ermelin", -"ermine", -"ermined", -"erminee", -"ermines", -"erne", -"erode", -"eroded", -"erodent", -"erogeny", -"eros", -"erose", -"erosely", -"erosion", -"erosive", -"eroteme", -"erotic", -"erotica", -"erotism", -"err", -"errable", -"errancy", -"errand", -"errant", -"errata", -"erratic", -"erratum", -"errhine", -"erring", -"errite", -"error", -"ers", -"ersatz", -"erth", -"erthen", -"erthly", -"eruc", -"eruca", -"erucic", -"erucin", -"eruct", -"erudit", -"erudite", -"erugate", -"erupt", -"eryngo", -"es", -"esca", -"escalan", -"escalin", -"escalop", -"escape", -"escapee", -"escaper", -"escarp", -"eschar", -"eschara", -"escheat", -"eschew", -"escoba", -"escolar", -"escort", -"escribe", -"escrol", -"escrow", -"escudo", -"esculin", -"esere", -"eserine", -"esexual", -"eshin", -"esker", -"esne", -"esodic", -"esotery", -"espadon", -"esparto", -"espave", -"espial", -"espier", -"espinal", -"espino", -"esplees", -"espouse", -"espy", -"esquire", -"ess", -"essang", -"essay", -"essayer", -"essed", -"essence", -"essency", -"essling", -"essoin", -"estadal", -"estadio", -"estado", -"estamp", -"estate", -"esteem", -"ester", -"estevin", -"estival", -"estmark", -"estoc", -"estoile", -"estop", -"estrade", -"estray", -"estre", -"estreat", -"estrepe", -"estrin", -"estriol", -"estrone", -"estrous", -"estrual", -"estuary", -"estufa", -"estuous", -"estus", -"eta", -"etacism", -"etacist", -"etalon", -"etamine", -"etch", -"etcher", -"etching", -"eternal", -"etesian", -"ethal", -"ethanal", -"ethane", -"ethanol", -"ethel", -"ethene", -"ethenic", -"ethenol", -"ethenyl", -"ether", -"ethered", -"etheric", -"etherin", -"ethic", -"ethical", -"ethics", -"ethid", -"ethide", -"ethine", -"ethiops", -"ethmoid", -"ethnal", -"ethnic", -"ethnize", -"ethnos", -"ethos", -"ethoxyl", -"ethrog", -"ethyl", -"ethylic", -"ethylin", -"ethyne", -"ethynyl", -"etiolin", -"etna", -"ettle", -"etua", -"etude", -"etui", -"etym", -"etymic", -"etymon", -"etypic", -"eu", -"euaster", -"eucaine", -"euchre", -"euchred", -"euclase", -"eucone", -"euconic", -"eucrasy", -"eucrite", -"euge", -"eugenic", -"eugenol", -"eugeny", -"eulalia", -"eulogia", -"eulogic", -"eulogy", -"eumenid", -"eunicid", -"eunomy", -"eunuch", -"euonym", -"euonymy", -"euouae", -"eupad", -"eupathy", -"eupepsy", -"euphemy", -"euphon", -"euphone", -"euphony", -"euphory", -"euphroe", -"eupione", -"euploid", -"eupnea", -"eureka", -"euripus", -"eurite", -"eurobin", -"euryon", -"eusol", -"eustyle", -"eutaxic", -"eutaxy", -"eutexia", -"eutony", -"evacue", -"evacuee", -"evade", -"evader", -"evalue", -"evangel", -"evanish", -"evase", -"evasion", -"evasive", -"eve", -"evejar", -"evelong", -"even", -"evener", -"evening", -"evenly", -"evens", -"event", -"eveque", -"ever", -"evert", -"evertor", -"everwho", -"every", -"evestar", -"evetide", -"eveweed", -"evict", -"evictor", -"evident", -"evil", -"evilly", -"evince", -"evirate", -"evisite", -"evitate", -"evocate", -"evoe", -"evoke", -"evoker", -"evolute", -"evolve", -"evolver", -"evovae", -"evulse", -"evzone", -"ewder", -"ewe", -"ewer", -"ewerer", -"ewery", -"ewry", -"ex", -"exact", -"exacter", -"exactly", -"exactor", -"exalate", -"exalt", -"exalted", -"exalter", -"exam", -"examen", -"examine", -"example", -"exarate", -"exarch", -"exarchy", -"excamb", -"excave", -"exceed", -"excel", -"except", -"excerpt", -"excess", -"excide", -"exciple", -"excise", -"excisor", -"excite", -"excited", -"exciter", -"excitor", -"exclaim", -"exclave", -"exclude", -"excreta", -"excrete", -"excurse", -"excusal", -"excuse", -"excuser", -"excuss", -"excyst", -"exdie", -"exeat", -"execute", -"exedent", -"exedra", -"exegete", -"exempt", -"exequy", -"exergue", -"exert", -"exes", -"exeunt", -"exflect", -"exhale", -"exhaust", -"exhibit", -"exhort", -"exhume", -"exhumer", -"exigent", -"exile", -"exiler", -"exilian", -"exilic", -"exility", -"exist", -"exister", -"exit", -"exite", -"exition", -"exitus", -"exlex", -"exocarp", -"exocone", -"exode", -"exoderm", -"exodic", -"exodist", -"exodos", -"exodus", -"exody", -"exogamy", -"exogen", -"exogeny", -"exomion", -"exomis", -"exon", -"exoner", -"exopod", -"exordia", -"exormia", -"exosmic", -"exostra", -"exotic", -"exotism", -"expand", -"expanse", -"expect", -"expede", -"expel", -"expend", -"expense", -"expert", -"expiate", -"expire", -"expiree", -"expirer", -"expiry", -"explain", -"explant", -"explode", -"exploit", -"explore", -"expone", -"export", -"exposal", -"expose", -"exposed", -"exposer", -"exposit", -"expound", -"express", -"expugn", -"expulse", -"expunge", -"expurge", -"exradio", -"exscind", -"exsect", -"exsert", -"exship", -"exsurge", -"extant", -"extend", -"extense", -"extent", -"exter", -"extern", -"externe", -"extima", -"extinct", -"extine", -"extol", -"extoll", -"extort", -"extra", -"extract", -"extrait", -"extreme", -"extrude", -"extund", -"exudate", -"exude", -"exult", -"exultet", -"exuviae", -"exuvial", -"ey", -"eyah", -"eyalet", -"eyas", -"eye", -"eyeball", -"eyebalm", -"eyebar", -"eyebeam", -"eyebolt", -"eyebree", -"eyebrow", -"eyecup", -"eyed", -"eyedot", -"eyedrop", -"eyeflap", -"eyeful", -"eyehole", -"eyelash", -"eyeless", -"eyelet", -"eyelid", -"eyelike", -"eyeline", -"eyemark", -"eyen", -"eyepit", -"eyer", -"eyeroot", -"eyeseed", -"eyeshot", -"eyesome", -"eyesore", -"eyespot", -"eyewash", -"eyewear", -"eyewink", -"eyewort", -"eyey", -"eying", -"eyn", -"eyne", -"eyot", -"eyoty", -"eyra", -"eyre", -"eyrie", -"eyrir", -"ezba", -"f", -"fa", -"fabella", -"fabes", -"fable", -"fabled", -"fabler", -"fabliau", -"fabling", -"fabric", -"fabular", -"facadal", -"facade", -"face", -"faced", -"faceman", -"facer", -"facet", -"facete", -"faceted", -"facia", -"facial", -"faciend", -"facient", -"facies", -"facile", -"facing", -"fack", -"fackins", -"facks", -"fact", -"factful", -"faction", -"factish", -"factive", -"factor", -"factory", -"factrix", -"factual", -"factum", -"facture", -"facty", -"facula", -"facular", -"faculty", -"facund", -"facy", -"fad", -"fadable", -"faddish", -"faddism", -"faddist", -"faddle", -"faddy", -"fade", -"faded", -"fadedly", -"faden", -"fader", -"fadge", -"fading", -"fady", -"fae", -"faerie", -"faery", -"faff", -"faffle", -"faffy", -"fag", -"fagald", -"fage", -"fager", -"fagger", -"faggery", -"fagging", -"fagine", -"fagot", -"fagoter", -"fagoty", -"faham", -"fahlerz", -"fahlore", -"faience", -"fail", -"failing", -"faille", -"failure", -"fain", -"fainly", -"fains", -"faint", -"fainter", -"faintly", -"faints", -"fainty", -"faipule", -"fair", -"fairer", -"fairily", -"fairing", -"fairish", -"fairly", -"fairm", -"fairway", -"fairy", -"faith", -"faitour", -"fake", -"faker", -"fakery", -"fakir", -"faky", -"falbala", -"falcade", -"falcate", -"falcer", -"falces", -"falcial", -"falcon", -"falcula", -"faldage", -"faldfee", -"fall", -"fallace", -"fallacy", -"fallage", -"fallen", -"faller", -"falling", -"fallow", -"fallway", -"fally", -"falsary", -"false", -"falsely", -"falsen", -"falser", -"falsie", -"falsify", -"falsism", -"faltche", -"falter", -"falutin", -"falx", -"fam", -"famble", -"fame", -"fameful", -"familia", -"family", -"famine", -"famish", -"famous", -"famulus", -"fan", -"fana", -"fanal", -"fanam", -"fanatic", -"fanback", -"fancied", -"fancier", -"fancify", -"fancy", -"fand", -"fandom", -"fanega", -"fanfare", -"fanfoot", -"fang", -"fanged", -"fangle", -"fangled", -"fanglet", -"fangot", -"fangy", -"fanion", -"fanlike", -"fanman", -"fannel", -"fanner", -"fannier", -"fanning", -"fanon", -"fant", -"fantail", -"fantast", -"fantasy", -"fantod", -"fanweed", -"fanwise", -"fanwork", -"fanwort", -"faon", -"far", -"farad", -"faraday", -"faradic", -"faraway", -"farce", -"farcer", -"farcial", -"farcied", -"farcify", -"farcing", -"farcist", -"farcy", -"farde", -"fardel", -"fardh", -"fardo", -"fare", -"farer", -"farfara", -"farfel", -"fargood", -"farina", -"faring", -"farish", -"farl", -"farleu", -"farm", -"farmage", -"farmer", -"farmery", -"farming", -"farmost", -"farmy", -"farness", -"faro", -"farrago", -"farrand", -"farrier", -"farrow", -"farruca", -"farse", -"farseer", -"farset", -"farther", -"fasces", -"fascet", -"fascia", -"fascial", -"fascine", -"fascis", -"fascism", -"fascist", -"fash", -"fasher", -"fashery", -"fashion", -"fass", -"fast", -"fasten", -"faster", -"fasting", -"fastish", -"fastus", -"fat", -"fatal", -"fatally", -"fatbird", -"fate", -"fated", -"fateful", -"fathead", -"father", -"fathmur", -"fathom", -"fatidic", -"fatigue", -"fatiha", -"fatil", -"fatless", -"fatling", -"fatly", -"fatness", -"fatsia", -"fatten", -"fatter", -"fattily", -"fattish", -"fatty", -"fatuism", -"fatuity", -"fatuoid", -"fatuous", -"fatwood", -"faucal", -"fauces", -"faucet", -"faucial", -"faucre", -"faugh", -"fauld", -"fault", -"faulter", -"faulty", -"faun", -"faunal", -"faunish", -"faunist", -"faunule", -"fause", -"faust", -"fautor", -"fauve", -"favella", -"favilla", -"favism", -"favissa", -"favn", -"favor", -"favored", -"favorer", -"favose", -"favous", -"favus", -"fawn", -"fawner", -"fawnery", -"fawning", -"fawny", -"fay", -"fayles", -"faze", -"fazenda", -"fe", -"feague", -"feak", -"feal", -"fealty", -"fear", -"feared", -"fearer", -"fearful", -"feasor", -"feast", -"feasten", -"feaster", -"feat", -"feather", -"featly", -"featous", -"feature", -"featy", -"feaze", -"febrile", -"fecal", -"feces", -"feck", -"feckful", -"feckly", -"fecula", -"fecund", -"fed", -"feddan", -"federal", -"fee", -"feeable", -"feeble", -"feebly", -"feed", -"feedbin", -"feedbox", -"feeder", -"feeding", -"feedman", -"feedway", -"feedy", -"feel", -"feeler", -"feeless", -"feeling", -"feer", -"feere", -"feering", -"feetage", -"feeze", -"fegary", -"fei", -"feif", -"feigher", -"feign", -"feigned", -"feigner", -"feil", -"feint", -"feis", -"feist", -"feisty", -"felid", -"feline", -"fell", -"fellage", -"fellah", -"fellen", -"feller", -"fellic", -"felling", -"felloe", -"fellow", -"felly", -"feloid", -"felon", -"felonry", -"felony", -"fels", -"felsite", -"felt", -"felted", -"felter", -"felting", -"felty", -"felucca", -"felwort", -"female", -"feme", -"femic", -"feminal", -"feminie", -"feminin", -"femora", -"femoral", -"femur", -"fen", -"fenbank", -"fence", -"fencer", -"fenchyl", -"fencing", -"fend", -"fender", -"fendy", -"fenite", -"fenks", -"fenland", -"fenman", -"fennec", -"fennel", -"fennig", -"fennish", -"fenny", -"fensive", -"fent", -"fenter", -"feod", -"feodal", -"feodary", -"feoff", -"feoffee", -"feoffor", -"feower", -"feral", -"feralin", -"ferash", -"ferdwit", -"ferfet", -"feria", -"ferial", -"feridgi", -"ferie", -"ferine", -"ferity", -"ferk", -"ferling", -"ferly", -"fermail", -"ferme", -"ferment", -"fermery", -"fermila", -"fern", -"ferned", -"fernery", -"ferny", -"feroher", -"ferrado", -"ferrate", -"ferrean", -"ferret", -"ferrety", -"ferri", -"ferric", -"ferrier", -"ferrite", -"ferrous", -"ferrule", -"ferrum", -"ferry", -"fertile", -"feru", -"ferula", -"ferule", -"ferulic", -"fervent", -"fervid", -"fervor", -"fescue", -"fess", -"fessely", -"fest", -"festal", -"fester", -"festine", -"festive", -"festoon", -"festuca", -"fet", -"fetal", -"fetch", -"fetched", -"fetcher", -"fetial", -"fetid", -"fetidly", -"fetish", -"fetlock", -"fetlow", -"fetor", -"fetter", -"fettle", -"fettler", -"fetus", -"feu", -"feuage", -"feuar", -"feucht", -"feud", -"feudal", -"feudee", -"feudist", -"feued", -"feuille", -"fever", -"feveret", -"few", -"fewness", -"fewsome", -"fewter", -"fey", -"feyness", -"fez", -"fezzed", -"fezzy", -"fi", -"fiacre", -"fiance", -"fiancee", -"fiar", -"fiard", -"fiasco", -"fiat", -"fib", -"fibber", -"fibbery", -"fibdom", -"fiber", -"fibered", -"fibril", -"fibrin", -"fibrine", -"fibroid", -"fibroin", -"fibroma", -"fibrose", -"fibrous", -"fibry", -"fibster", -"fibula", -"fibulae", -"fibular", -"ficary", -"fice", -"ficelle", -"fiche", -"fichu", -"fickle", -"fickly", -"fico", -"ficoid", -"fictile", -"fiction", -"fictive", -"fid", -"fidalgo", -"fidate", -"fiddle", -"fiddler", -"fiddley", -"fide", -"fideism", -"fideist", -"fidfad", -"fidge", -"fidget", -"fidgety", -"fiducia", -"fie", -"fiefdom", -"field", -"fielded", -"fielder", -"fieldy", -"fiend", -"fiendly", -"fient", -"fierce", -"fiercen", -"fierily", -"fiery", -"fiesta", -"fife", -"fifer", -"fifie", -"fifish", -"fifo", -"fifteen", -"fifth", -"fifthly", -"fifty", -"fig", -"figaro", -"figbird", -"figent", -"figged", -"figgery", -"figging", -"figgle", -"figgy", -"fight", -"fighter", -"figless", -"figlike", -"figment", -"figural", -"figure", -"figured", -"figurer", -"figury", -"figworm", -"figwort", -"fike", -"fikie", -"filace", -"filacer", -"filao", -"filar", -"filaria", -"filasse", -"filate", -"filator", -"filbert", -"filch", -"filcher", -"file", -"filemot", -"filer", -"filet", -"filial", -"filiate", -"filibeg", -"filical", -"filicic", -"filicin", -"filiety", -"filing", -"filings", -"filippo", -"filite", -"fill", -"filled", -"filler", -"fillet", -"filleul", -"filling", -"fillip", -"fillock", -"filly", -"film", -"filmdom", -"filmet", -"filmic", -"filmily", -"filmish", -"filmist", -"filmize", -"filmy", -"filo", -"filose", -"fils", -"filter", -"filth", -"filthy", -"fimble", -"fimbria", -"fin", -"finable", -"finagle", -"final", -"finale", -"finally", -"finance", -"finback", -"finch", -"finched", -"find", -"findal", -"finder", -"finding", -"findjan", -"fine", -"fineish", -"finely", -"finer", -"finery", -"finesse", -"finetop", -"finfish", -"finfoot", -"fingent", -"finger", -"fingery", -"finial", -"finical", -"finick", -"finific", -"finify", -"finikin", -"fining", -"finis", -"finish", -"finite", -"finity", -"finjan", -"fink", -"finkel", -"finland", -"finless", -"finlet", -"finlike", -"finnac", -"finned", -"finner", -"finnip", -"finny", -"fiord", -"fiorded", -"fiorin", -"fiorite", -"fip", -"fipenny", -"fipple", -"fique", -"fir", -"firca", -"fire", -"firearm", -"firebox", -"fireboy", -"firebug", -"fired", -"firedog", -"firefly", -"firelit", -"fireman", -"firer", -"firetop", -"firing", -"firk", -"firker", -"firkin", -"firlot", -"firm", -"firman", -"firmer", -"firmly", -"firn", -"firring", -"firry", -"first", -"firstly", -"firth", -"fisc", -"fiscal", -"fise", -"fisetin", -"fish", -"fishbed", -"fished", -"fisher", -"fishery", -"fishet", -"fisheye", -"fishful", -"fishgig", -"fishify", -"fishily", -"fishing", -"fishlet", -"fishman", -"fishpot", -"fishway", -"fishy", -"fisnoga", -"fissate", -"fissile", -"fission", -"fissive", -"fissure", -"fissury", -"fist", -"fisted", -"fister", -"fistful", -"fistic", -"fistify", -"fisting", -"fistuca", -"fistula", -"fistule", -"fisty", -"fit", -"fitch", -"fitched", -"fitchee", -"fitcher", -"fitchet", -"fitchew", -"fitful", -"fitly", -"fitment", -"fitness", -"fitout", -"fitroot", -"fittage", -"fitted", -"fitten", -"fitter", -"fitters", -"fittily", -"fitting", -"fitty", -"fitweed", -"five", -"fivebar", -"fiver", -"fives", -"fix", -"fixable", -"fixage", -"fixate", -"fixatif", -"fixator", -"fixed", -"fixedly", -"fixer", -"fixing", -"fixity", -"fixture", -"fixure", -"fizgig", -"fizz", -"fizzer", -"fizzle", -"fizzy", -"fjeld", -"flabby", -"flabrum", -"flaccid", -"flack", -"flacked", -"flacker", -"flacket", -"flaff", -"flaffer", -"flag", -"flagger", -"flaggy", -"flaglet", -"flagman", -"flagon", -"flail", -"flair", -"flaith", -"flak", -"flakage", -"flake", -"flaker", -"flakily", -"flaky", -"flam", -"flamant", -"flamb", -"flame", -"flamed", -"flamen", -"flamer", -"flamfew", -"flaming", -"flamy", -"flan", -"flanch", -"flandan", -"flane", -"flange", -"flanger", -"flank", -"flanked", -"flanker", -"flanky", -"flannel", -"flanque", -"flap", -"flapper", -"flare", -"flaring", -"flary", -"flaser", -"flash", -"flasher", -"flashet", -"flashly", -"flashy", -"flask", -"flasker", -"flasket", -"flasque", -"flat", -"flatcap", -"flatcar", -"flatdom", -"flated", -"flathat", -"flatlet", -"flatly", -"flatman", -"flatten", -"flatter", -"flattie", -"flattop", -"flatus", -"flatway", -"flaught", -"flaunt", -"flaunty", -"flavedo", -"flavic", -"flavid", -"flavin", -"flavine", -"flavo", -"flavone", -"flavor", -"flavory", -"flavour", -"flaw", -"flawed", -"flawful", -"flawn", -"flawy", -"flax", -"flaxen", -"flaxman", -"flaxy", -"flay", -"flayer", -"flea", -"fleam", -"fleay", -"flebile", -"fleche", -"fleck", -"flecken", -"flecker", -"flecky", -"flector", -"fled", -"fledge", -"fledgy", -"flee", -"fleece", -"fleeced", -"fleecer", -"fleech", -"fleecy", -"fleer", -"fleerer", -"fleet", -"fleeter", -"fleetly", -"flemish", -"flench", -"flense", -"flenser", -"flerry", -"flesh", -"fleshed", -"fleshen", -"flesher", -"fleshly", -"fleshy", -"flet", -"fletch", -"flether", -"fleuret", -"fleury", -"flew", -"flewed", -"flewit", -"flews", -"flex", -"flexed", -"flexile", -"flexion", -"flexor", -"flexure", -"fley", -"flick", -"flicker", -"flicky", -"flidder", -"flier", -"fligger", -"flight", -"flighty", -"flimmer", -"flimp", -"flimsy", -"flinch", -"flinder", -"fling", -"flinger", -"flingy", -"flint", -"flinter", -"flinty", -"flioma", -"flip", -"flipe", -"flipper", -"flirt", -"flirter", -"flirty", -"flisk", -"flisky", -"flit", -"flitch", -"flite", -"fliting", -"flitter", -"flivver", -"flix", -"float", -"floater", -"floaty", -"flob", -"flobby", -"floc", -"floccus", -"flock", -"flocker", -"flocky", -"flocoon", -"flodge", -"floe", -"floey", -"flog", -"flogger", -"flokite", -"flong", -"flood", -"flooded", -"flooder", -"floody", -"floor", -"floorer", -"floozy", -"flop", -"flopper", -"floppy", -"flora", -"floral", -"floran", -"florate", -"floreal", -"florent", -"flores", -"floret", -"florid", -"florin", -"florist", -"floroon", -"florula", -"flory", -"flosh", -"floss", -"flosser", -"flossy", -"flot", -"flota", -"flotage", -"flotant", -"flotsam", -"flounce", -"flour", -"floury", -"flouse", -"flout", -"flouter", -"flow", -"flowage", -"flower", -"flowery", -"flowing", -"flown", -"flowoff", -"flu", -"fluate", -"fluavil", -"flub", -"flubdub", -"flucan", -"flue", -"flued", -"flueman", -"fluency", -"fluent", -"fluer", -"fluey", -"fluff", -"fluffer", -"fluffy", -"fluible", -"fluid", -"fluidal", -"fluidic", -"fluidly", -"fluke", -"fluked", -"flukily", -"fluking", -"fluky", -"flume", -"flummer", -"flummox", -"flump", -"flung", -"flunk", -"flunker", -"flunky", -"fluor", -"fluoran", -"fluoric", -"fluoryl", -"flurn", -"flurr", -"flurry", -"flush", -"flusher", -"flushy", -"flusk", -"flusker", -"fluster", -"flute", -"fluted", -"fluter", -"flutina", -"fluting", -"flutist", -"flutter", -"fluty", -"fluvial", -"flux", -"fluxer", -"fluxile", -"fluxion", -"fly", -"flyable", -"flyaway", -"flyback", -"flyball", -"flybane", -"flybelt", -"flyblow", -"flyboat", -"flyboy", -"flyer", -"flyflap", -"flying", -"flyleaf", -"flyless", -"flyman", -"flyness", -"flype", -"flytail", -"flytier", -"flytrap", -"flyway", -"flywort", -"foal", -"foaly", -"foam", -"foambow", -"foamer", -"foamily", -"foaming", -"foamy", -"fob", -"focal", -"focally", -"foci", -"focoids", -"focsle", -"focus", -"focuser", -"fod", -"fodda", -"fodder", -"foder", -"fodge", -"fodgel", -"fodient", -"foe", -"foehn", -"foeish", -"foeless", -"foelike", -"foeman", -"foeship", -"fog", -"fogbow", -"fogdog", -"fogdom", -"fogey", -"foggage", -"fogged", -"fogger", -"foggily", -"foggish", -"foggy", -"foghorn", -"fogle", -"fogless", -"fogman", -"fogo", -"fogon", -"fogou", -"fogram", -"fogus", -"fogy", -"fogydom", -"fogyish", -"fogyism", -"fohat", -"foible", -"foil", -"foiler", -"foiling", -"foining", -"foison", -"foist", -"foister", -"foisty", -"foiter", -"fold", -"foldage", -"folded", -"folden", -"folder", -"folding", -"foldure", -"foldy", -"fole", -"folia", -"foliage", -"folial", -"foliar", -"foliary", -"foliate", -"folie", -"folio", -"foliole", -"foliose", -"foliot", -"folious", -"folium", -"folk", -"folkmot", -"folksy", -"folkway", -"folky", -"folles", -"follis", -"follow", -"folly", -"foment", -"fomes", -"fomites", -"fondak", -"fondant", -"fondish", -"fondle", -"fondler", -"fondly", -"fondu", -"fondue", -"fonduk", -"fonly", -"fonnish", -"fono", -"fons", -"font", -"fontal", -"fonted", -"fontful", -"fontlet", -"foo", -"food", -"fooder", -"foodful", -"foody", -"fool", -"fooldom", -"foolery", -"fooless", -"fooling", -"foolish", -"fooner", -"fooster", -"foot", -"footage", -"footboy", -"footed", -"footer", -"footful", -"foothot", -"footing", -"footle", -"footler", -"footman", -"footpad", -"foots", -"footway", -"footy", -"foozle", -"foozler", -"fop", -"fopling", -"foppery", -"foppish", -"foppy", -"fopship", -"for", -"fora", -"forage", -"forager", -"foramen", -"forane", -"foray", -"forayer", -"forb", -"forbade", -"forbar", -"forbear", -"forbid", -"forbit", -"forbled", -"forblow", -"forbore", -"forbow", -"forby", -"force", -"forced", -"forceps", -"forcer", -"forche", -"forcing", -"ford", -"fordays", -"fording", -"fordo", -"fordone", -"fordy", -"fore", -"foreact", -"forearm", -"forebay", -"forecar", -"foreday", -"forefin", -"forefit", -"forego", -"foreign", -"forel", -"forelay", -"foreleg", -"foreman", -"forepad", -"forepaw", -"foreran", -"forerib", -"forerun", -"foresay", -"foresee", -"foreset", -"foresin", -"forest", -"foresty", -"foretop", -"foreuse", -"forever", -"forevow", -"forfar", -"forfare", -"forfars", -"forfeit", -"forfend", -"forge", -"forged", -"forger", -"forgery", -"forget", -"forgie", -"forging", -"forgive", -"forgo", -"forgoer", -"forgot", -"forgrow", -"forhoo", -"forhooy", -"forhow", -"forint", -"fork", -"forked", -"forker", -"forkful", -"forkman", -"forky", -"forleft", -"forlet", -"forlorn", -"form", -"formal", -"formant", -"format", -"formate", -"forme", -"formed", -"formee", -"formel", -"formene", -"former", -"formful", -"formic", -"formin", -"forming", -"formose", -"formula", -"formule", -"formy", -"formyl", -"fornent", -"fornix", -"forpet", -"forpine", -"forpit", -"forrad", -"forrard", -"forride", -"forrit", -"forrue", -"forsake", -"forset", -"forslow", -"fort", -"forte", -"forth", -"forthgo", -"forthy", -"forties", -"fortify", -"fortin", -"fortis", -"fortlet", -"fortune", -"forty", -"forum", -"forward", -"forwean", -"forwent", -"fosh", -"fosie", -"fossa", -"fossage", -"fossane", -"fosse", -"fossed", -"fossick", -"fossil", -"fossor", -"fossula", -"fossule", -"fostell", -"foster", -"fot", -"fotch", -"fother", -"fotmal", -"fotui", -"fou", -"foud", -"fouette", -"fougade", -"fought", -"foughty", -"foujdar", -"foul", -"foulage", -"foulard", -"fouler", -"fouling", -"foulish", -"foully", -"foumart", -"foun", -"found", -"founder", -"foundry", -"fount", -"four", -"fourble", -"fourche", -"fourer", -"fourre", -"fourth", -"foussa", -"foute", -"fouter", -"fouth", -"fovea", -"foveal", -"foveate", -"foveola", -"foveole", -"fow", -"fowk", -"fowl", -"fowler", -"fowlery", -"fowling", -"fox", -"foxbane", -"foxchop", -"foxer", -"foxery", -"foxfeet", -"foxfish", -"foxhole", -"foxily", -"foxing", -"foxish", -"foxlike", -"foxship", -"foxskin", -"foxtail", -"foxwood", -"foxy", -"foy", -"foyaite", -"foyboat", -"foyer", -"fozy", -"fra", -"frab", -"frabbit", -"frabous", -"fracas", -"frache", -"frack", -"fracted", -"frae", -"fraghan", -"fragile", -"fraid", -"fraik", -"frail", -"frailly", -"frailty", -"fraise", -"fraiser", -"frame", -"framea", -"framed", -"framer", -"framing", -"frammit", -"franc", -"franco", -"frank", -"franker", -"frankly", -"frantic", -"franzy", -"frap", -"frappe", -"frasco", -"frase", -"frasier", -"frass", -"frat", -"fratch", -"fratchy", -"frater", -"fratery", -"fratry", -"fraud", -"fraught", -"frawn", -"fraxin", -"fray", -"frayed", -"fraying", -"frayn", -"fraze", -"frazer", -"frazil", -"frazzle", -"freak", -"freaky", -"fream", -"freath", -"freck", -"frecken", -"frecket", -"freckle", -"freckly", -"free", -"freed", -"freedom", -"freeing", -"freeish", -"freely", -"freeman", -"freer", -"freet", -"freety", -"freeway", -"freeze", -"freezer", -"freight", -"freir", -"freit", -"freity", -"fremd", -"fremdly", -"frenal", -"frenate", -"frenum", -"frenzy", -"fresco", -"fresh", -"freshen", -"freshet", -"freshly", -"fresnel", -"fresno", -"fret", -"fretful", -"frett", -"frette", -"fretted", -"fretter", -"fretty", -"fretum", -"friable", -"friand", -"friar", -"friarly", -"friary", -"frib", -"fribble", -"fribby", -"fried", -"friend", -"frier", -"frieze", -"friezer", -"friezy", -"frig", -"frigate", -"friggle", -"fright", -"frighty", -"frigid", -"frijol", -"frike", -"frill", -"frilled", -"friller", -"frilly", -"frim", -"fringe", -"fringed", -"fringy", -"frisca", -"frisk", -"frisker", -"frisket", -"frisky", -"frison", -"frist", -"frisure", -"frit", -"frith", -"fritt", -"fritter", -"frivol", -"frixion", -"friz", -"frize", -"frizer", -"frizz", -"frizzer", -"frizzle", -"frizzly", -"frizzy", -"fro", -"frock", -"froe", -"frog", -"frogbit", -"frogeye", -"frogged", -"froggy", -"frogleg", -"froglet", -"frogman", -"froise", -"frolic", -"from", -"frond", -"fronded", -"front", -"frontad", -"frontal", -"fronted", -"fronter", -"froom", -"frore", -"frory", -"frosh", -"frost", -"frosted", -"froster", -"frosty", -"frot", -"froth", -"frother", -"frothy", -"frotton", -"frough", -"froughy", -"frounce", -"frow", -"froward", -"frower", -"frowl", -"frown", -"frowner", -"frowny", -"frowst", -"frowsty", -"frowy", -"frowze", -"frowzly", -"frowzy", -"froze", -"frozen", -"fructed", -"frugal", -"fruggan", -"fruit", -"fruited", -"fruiter", -"fruity", -"frump", -"frumple", -"frumpy", -"frush", -"frustum", -"frutify", -"fry", -"fryer", -"fu", -"fub", -"fubby", -"fubsy", -"fucate", -"fuchsin", -"fuci", -"fucoid", -"fucosan", -"fucose", -"fucous", -"fucus", -"fud", -"fuddle", -"fuddler", -"fuder", -"fudge", -"fudger", -"fudgy", -"fuel", -"fueler", -"fuerte", -"fuff", -"fuffy", -"fugal", -"fugally", -"fuggy", -"fugient", -"fugle", -"fugler", -"fugu", -"fugue", -"fuguist", -"fuidhir", -"fuji", -"fulcral", -"fulcrum", -"fulfill", -"fulgent", -"fulgid", -"fulgide", -"fulgor", -"fulham", -"fulk", -"full", -"fullam", -"fuller", -"fullery", -"fulling", -"fullish", -"fullom", -"fully", -"fulmar", -"fulmine", -"fulsome", -"fulth", -"fulvene", -"fulvid", -"fulvous", -"fulwa", -"fulyie", -"fulzie", -"fum", -"fumado", -"fumage", -"fumaric", -"fumaryl", -"fumble", -"fumbler", -"fume", -"fumer", -"fumet", -"fumette", -"fumily", -"fuming", -"fumose", -"fumous", -"fumy", -"fun", -"fund", -"fundal", -"funded", -"funder", -"fundi", -"fundic", -"funds", -"fundus", -"funeral", -"funest", -"fungal", -"fungate", -"fungi", -"fungian", -"fungic", -"fungin", -"fungo", -"fungoid", -"fungose", -"fungous", -"fungus", -"fungusy", -"funicle", -"funis", -"funk", -"funker", -"funky", -"funnel", -"funnily", -"funny", -"funori", -"funt", -"fur", -"fural", -"furan", -"furazan", -"furbish", -"furca", -"furcal", -"furcate", -"furcula", -"furdel", -"furfur", -"furiant", -"furied", -"furify", -"furil", -"furilic", -"furiosa", -"furioso", -"furious", -"furison", -"furl", -"furler", -"furless", -"furlong", -"furnace", -"furnage", -"furner", -"furnish", -"furoic", -"furoid", -"furoin", -"furole", -"furor", -"furore", -"furphy", -"furred", -"furrier", -"furrily", -"furring", -"furrow", -"furrowy", -"furry", -"further", -"furtive", -"fury", -"furyl", -"furze", -"furzed", -"furzery", -"furzy", -"fusain", -"fusate", -"fusc", -"fuscin", -"fuscous", -"fuse", -"fused", -"fusee", -"fusht", -"fusible", -"fusibly", -"fusil", -"fusilly", -"fusion", -"fusoid", -"fuss", -"fusser", -"fussify", -"fussily", -"fussock", -"fussy", -"fust", -"fustee", -"fustet", -"fustian", -"fustic", -"fustily", -"fustin", -"fustle", -"fusty", -"fusuma", -"fusure", -"fut", -"futchel", -"fute", -"futhorc", -"futile", -"futtock", -"futural", -"future", -"futuric", -"futwa", -"fuye", -"fuze", -"fuzz", -"fuzzily", -"fuzzy", -"fyke", -"fylfot", -"fyrd", -"g", -"ga", -"gab", -"gabbard", -"gabber", -"gabble", -"gabbler", -"gabbro", -"gabby", -"gabelle", -"gabgab", -"gabi", -"gabion", -"gable", -"gablet", -"gablock", -"gaby", -"gad", -"gadbee", -"gadbush", -"gadded", -"gadder", -"gaddi", -"gadding", -"gaddish", -"gade", -"gadfly", -"gadge", -"gadger", -"gadget", -"gadid", -"gadling", -"gadman", -"gadoid", -"gadroon", -"gadsman", -"gaduin", -"gadwall", -"gaen", -"gaet", -"gaff", -"gaffe", -"gaffer", -"gaffle", -"gag", -"gagate", -"gage", -"gagee", -"gageite", -"gager", -"gagger", -"gaggery", -"gaggle", -"gaggler", -"gagman", -"gagor", -"gagroot", -"gahnite", -"gaiassa", -"gaiety", -"gaily", -"gain", -"gainage", -"gaine", -"gainer", -"gainful", -"gaining", -"gainly", -"gains", -"gainsay", -"gainset", -"gainst", -"gair", -"gait", -"gaited", -"gaiter", -"gaiting", -"gaize", -"gaj", -"gal", -"gala", -"galah", -"galanas", -"galanga", -"galant", -"galany", -"galatea", -"galaxy", -"galban", -"gale", -"galea", -"galeage", -"galeate", -"galee", -"galeeny", -"galeid", -"galena", -"galenic", -"galeoid", -"galera", -"galerum", -"galerus", -"galet", -"galey", -"galgal", -"gali", -"galilee", -"galiot", -"galipot", -"gall", -"galla", -"gallah", -"gallant", -"gallate", -"galled", -"gallein", -"galleon", -"galler", -"gallery", -"gallet", -"galley", -"gallfly", -"gallic", -"galline", -"galling", -"gallium", -"gallnut", -"gallon", -"galloon", -"gallop", -"gallous", -"gallows", -"gally", -"galoot", -"galop", -"galore", -"galosh", -"galp", -"galt", -"galumph", -"galuth", -"galyac", -"galyak", -"gam", -"gamahe", -"gamasid", -"gamb", -"gamba", -"gambade", -"gambado", -"gambang", -"gambeer", -"gambet", -"gambia", -"gambier", -"gambist", -"gambit", -"gamble", -"gambler", -"gamboge", -"gambol", -"gambrel", -"game", -"gamebag", -"gameful", -"gamely", -"gamene", -"gametal", -"gamete", -"gametic", -"gamic", -"gamily", -"gamin", -"gaming", -"gamma", -"gammer", -"gammick", -"gammock", -"gammon", -"gammy", -"gamont", -"gamori", -"gamp", -"gamut", -"gamy", -"gan", -"ganam", -"ganch", -"gander", -"gandul", -"gandum", -"gane", -"ganef", -"gang", -"ganga", -"gangan", -"gangava", -"gangdom", -"gange", -"ganger", -"ganging", -"gangism", -"ganglia", -"gangly", -"gangman", -"gangrel", -"gangue", -"gangway", -"ganja", -"ganner", -"gannet", -"ganoid", -"ganoin", -"ganosis", -"gansel", -"gansey", -"gansy", -"gant", -"ganta", -"gantang", -"gantlet", -"ganton", -"gantry", -"gantsl", -"ganza", -"ganzie", -"gaol", -"gaoler", -"gap", -"gapa", -"gape", -"gaper", -"gapes", -"gaping", -"gapo", -"gappy", -"gapy", -"gar", -"gara", -"garad", -"garage", -"garance", -"garava", -"garawi", -"garb", -"garbage", -"garbel", -"garbell", -"garbill", -"garble", -"garbler", -"garboil", -"garbure", -"garce", -"gardant", -"gardeen", -"garden", -"gardeny", -"gardy", -"gare", -"gareh", -"garetta", -"garfish", -"garget", -"gargety", -"gargle", -"gargol", -"garial", -"gariba", -"garish", -"garland", -"garle", -"garlic", -"garment", -"garn", -"garnel", -"garner", -"garnet", -"garnets", -"garnett", -"garnetz", -"garnice", -"garniec", -"garnish", -"garoo", -"garrafa", -"garran", -"garret", -"garrot", -"garrote", -"garrupa", -"garse", -"garsil", -"garston", -"garten", -"garter", -"garth", -"garum", -"garvey", -"garvock", -"gas", -"gasbag", -"gaseity", -"gaseous", -"gash", -"gashes", -"gashful", -"gashly", -"gashy", -"gasify", -"gasket", -"gaskin", -"gasking", -"gaskins", -"gasless", -"gaslit", -"gaslock", -"gasman", -"gasp", -"gasper", -"gasping", -"gaspy", -"gasser", -"gassing", -"gassy", -"gast", -"gaster", -"gastral", -"gastric", -"gastrin", -"gat", -"gata", -"gatch", -"gate", -"gateado", -"gateage", -"gated", -"gateman", -"gater", -"gateway", -"gather", -"gating", -"gator", -"gatter", -"gau", -"gaub", -"gauby", -"gauche", -"gaud", -"gaudery", -"gaudful", -"gaudily", -"gaudy", -"gaufer", -"gauffer", -"gauffre", -"gaufre", -"gauge", -"gauger", -"gauging", -"gaulin", -"gault", -"gaulter", -"gaum", -"gaumish", -"gaumy", -"gaun", -"gaunt", -"gaunted", -"gauntly", -"gauntry", -"gaunty", -"gaup", -"gaupus", -"gaur", -"gaus", -"gauss", -"gauster", -"gaut", -"gauze", -"gauzily", -"gauzy", -"gavall", -"gave", -"gavel", -"gaveler", -"gavial", -"gavotte", -"gavyuti", -"gaw", -"gawby", -"gawcie", -"gawk", -"gawkily", -"gawkish", -"gawky", -"gawm", -"gawn", -"gawney", -"gawsie", -"gay", -"gayal", -"gayatri", -"gaybine", -"gaycat", -"gayish", -"gayment", -"gayness", -"gaysome", -"gayyou", -"gaz", -"gazabo", -"gaze", -"gazebo", -"gazee", -"gazel", -"gazelle", -"gazer", -"gazette", -"gazi", -"gazing", -"gazon", -"gazy", -"ge", -"geal", -"gean", -"gear", -"gearbox", -"geared", -"gearing", -"gearman", -"gearset", -"gease", -"geason", -"geat", -"gebang", -"gebanga", -"gebbie", -"gebur", -"geck", -"gecko", -"geckoid", -"ged", -"gedackt", -"gedder", -"gedeckt", -"gedrite", -"gee", -"geebong", -"geebung", -"geejee", -"geek", -"geelbec", -"geerah", -"geest", -"geet", -"geezer", -"gegg", -"geggee", -"gegger", -"geggery", -"gein", -"geira", -"geisha", -"geison", -"geitjie", -"gel", -"gelable", -"gelada", -"gelatin", -"geld", -"geldant", -"gelder", -"gelding", -"gelid", -"gelidly", -"gelilah", -"gell", -"gelly", -"gelong", -"gelose", -"gelosin", -"gelt", -"gem", -"gemauve", -"gemel", -"gemeled", -"gemless", -"gemlike", -"gemma", -"gemmae", -"gemmate", -"gemmer", -"gemmily", -"gemmoid", -"gemmula", -"gemmule", -"gemmy", -"gemot", -"gemsbok", -"gemul", -"gemuti", -"gemwork", -"gen", -"gena", -"genal", -"genapp", -"genarch", -"gender", -"gene", -"genear", -"geneat", -"geneki", -"genep", -"genera", -"general", -"generic", -"genesic", -"genesis", -"genet", -"genetic", -"geneva", -"genial", -"genian", -"genic", -"genie", -"genii", -"genin", -"genion", -"genip", -"genipa", -"genipap", -"genista", -"genital", -"genitor", -"genius", -"genizah", -"genoese", -"genom", -"genome", -"genomic", -"genos", -"genre", -"genro", -"gens", -"genson", -"gent", -"genteel", -"gentes", -"gentian", -"gentile", -"gentle", -"gently", -"gentman", -"gentry", -"genty", -"genu", -"genua", -"genual", -"genuine", -"genus", -"genys", -"geo", -"geobios", -"geodal", -"geode", -"geodesy", -"geodete", -"geodic", -"geodist", -"geoduck", -"geoform", -"geogeny", -"geogony", -"geoid", -"geoidal", -"geology", -"geomaly", -"geomant", -"geomyid", -"geonoma", -"geopony", -"georama", -"georgic", -"geosid", -"geoside", -"geotaxy", -"geotic", -"geoty", -"ger", -"gerah", -"geranic", -"geranyl", -"gerate", -"gerated", -"geratic", -"geraty", -"gerb", -"gerbe", -"gerbil", -"gercrow", -"gerefa", -"gerenda", -"gerent", -"gerenuk", -"gerim", -"gerip", -"germ", -"germal", -"german", -"germane", -"germen", -"germin", -"germina", -"germing", -"germon", -"germule", -"germy", -"gernitz", -"geront", -"geronto", -"gers", -"gersum", -"gerund", -"gerusia", -"gervao", -"gesith", -"gesning", -"gesso", -"gest", -"gestant", -"gestate", -"geste", -"gested", -"gesten", -"gestic", -"gestion", -"gesture", -"get", -"geta", -"getah", -"getaway", -"gether", -"getling", -"getter", -"getting", -"getup", -"geum", -"gewgaw", -"gewgawy", -"gey", -"geyan", -"geyser", -"gez", -"ghafir", -"ghaist", -"ghalva", -"gharial", -"gharnao", -"gharry", -"ghastly", -"ghat", -"ghatti", -"ghatwal", -"ghazi", -"ghazism", -"ghebeta", -"ghee", -"gheleem", -"gherkin", -"ghetti", -"ghetto", -"ghizite", -"ghoom", -"ghost", -"ghoster", -"ghostly", -"ghosty", -"ghoul", -"ghrush", -"ghurry", -"giant", -"giantly", -"giantry", -"giardia", -"giarra", -"giarre", -"gib", -"gibaro", -"gibbals", -"gibbed", -"gibber", -"gibbet", -"gibbles", -"gibbon", -"gibbose", -"gibbous", -"gibbus", -"gibby", -"gibe", -"gibel", -"giber", -"gibing", -"gibleh", -"giblet", -"giblets", -"gibus", -"gid", -"giddap", -"giddea", -"giddify", -"giddily", -"giddy", -"gidgee", -"gie", -"gied", -"gien", -"gif", -"gift", -"gifted", -"giftie", -"gig", -"gigback", -"gigeria", -"gigful", -"gigger", -"giggish", -"giggit", -"giggle", -"giggler", -"giggly", -"giglet", -"giglot", -"gigman", -"gignate", -"gigolo", -"gigot", -"gigsman", -"gigster", -"gigtree", -"gigunu", -"gilbert", -"gild", -"gilded", -"gilden", -"gilder", -"gilding", -"gilguy", -"gilia", -"gilim", -"gill", -"gilled", -"giller", -"gillie", -"gilling", -"gilly", -"gilo", -"gilpy", -"gilse", -"gilt", -"giltcup", -"gim", -"gimbal", -"gimble", -"gimel", -"gimlet", -"gimlety", -"gimmal", -"gimmer", -"gimmick", -"gimp", -"gimped", -"gimper", -"gimping", -"gin", -"ging", -"ginger", -"gingery", -"gingham", -"gingili", -"gingiva", -"gink", -"ginkgo", -"ginned", -"ginner", -"ginners", -"ginnery", -"ginney", -"ginning", -"ginnle", -"ginny", -"ginseng", -"ginward", -"gio", -"gip", -"gipon", -"gipper", -"gipser", -"gipsire", -"giraffe", -"girasol", -"girba", -"gird", -"girder", -"girding", -"girdle", -"girdler", -"girl", -"girleen", -"girlery", -"girlie", -"girling", -"girlish", -"girlism", -"girly", -"girn", -"girny", -"giro", -"girr", -"girse", -"girsh", -"girsle", -"girt", -"girth", -"gisarme", -"gish", -"gisla", -"gisler", -"gist", -"git", -"gitalin", -"gith", -"gitonin", -"gitoxin", -"gittern", -"gittith", -"give", -"given", -"giver", -"givey", -"giving", -"gizz", -"gizzard", -"gizzen", -"gizzern", -"glace", -"glaceed", -"glacial", -"glacier", -"glacis", -"glack", -"glad", -"gladden", -"gladdon", -"gladdy", -"glade", -"gladeye", -"gladful", -"gladify", -"gladii", -"gladius", -"gladly", -"glady", -"glaga", -"glaieul", -"glaik", -"glaiket", -"glair", -"glairy", -"glaive", -"glaived", -"glaked", -"glaky", -"glam", -"glamour", -"glance", -"glancer", -"gland", -"glandes", -"glans", -"glar", -"glare", -"glarily", -"glaring", -"glarry", -"glary", -"glashan", -"glass", -"glassen", -"glasser", -"glasses", -"glassie", -"glassy", -"glaucin", -"glaum", -"glaur", -"glaury", -"glaver", -"glaze", -"glazed", -"glazen", -"glazer", -"glazier", -"glazily", -"glazing", -"glazy", -"gleam", -"gleamy", -"glean", -"gleaner", -"gleary", -"gleba", -"glebal", -"glebe", -"glebous", -"glede", -"gledy", -"glee", -"gleed", -"gleeful", -"gleek", -"gleeman", -"gleet", -"gleety", -"gleg", -"glegly", -"glen", -"glenoid", -"glent", -"gleyde", -"glia", -"gliadin", -"glial", -"glib", -"glibly", -"glidder", -"glide", -"glider", -"gliding", -"gliff", -"glime", -"glimmer", -"glimpse", -"glink", -"glint", -"glioma", -"gliosa", -"gliosis", -"glirine", -"glisk", -"glisky", -"glisten", -"glister", -"glitter", -"gloam", -"gloat", -"gloater", -"global", -"globate", -"globe", -"globed", -"globin", -"globoid", -"globose", -"globous", -"globule", -"globy", -"glochid", -"glochis", -"gloea", -"gloeal", -"glom", -"glome", -"glommox", -"glomus", -"glonoin", -"gloom", -"gloomth", -"gloomy", -"glop", -"gloppen", -"glor", -"glore", -"glorify", -"glory", -"gloss", -"glossa", -"glossal", -"glossed", -"glosser", -"glossic", -"glossy", -"glost", -"glottal", -"glottic", -"glottid", -"glottis", -"glout", -"glove", -"glover", -"glovey", -"gloving", -"glow", -"glower", -"glowfly", -"glowing", -"gloy", -"gloze", -"glozing", -"glub", -"glucase", -"glucid", -"glucide", -"glucina", -"glucine", -"gluck", -"glucose", -"glue", -"glued", -"gluepot", -"gluer", -"gluey", -"glug", -"gluish", -"glum", -"gluma", -"glumal", -"glume", -"glumly", -"glummy", -"glumose", -"glump", -"glumpy", -"glunch", -"glusid", -"gluside", -"glut", -"glutch", -"gluteal", -"gluten", -"gluteus", -"glutin", -"glutoid", -"glutose", -"glutter", -"glutton", -"glycid", -"glycide", -"glycine", -"glycol", -"glycose", -"glycyl", -"glyoxal", -"glyoxim", -"glyoxyl", -"glyph", -"glyphic", -"glyptic", -"glyster", -"gnabble", -"gnar", -"gnarl", -"gnarled", -"gnarly", -"gnash", -"gnat", -"gnathal", -"gnathic", -"gnatter", -"gnatty", -"gnaw", -"gnawer", -"gnawing", -"gnawn", -"gneiss", -"gneissy", -"gnome", -"gnomed", -"gnomic", -"gnomide", -"gnomish", -"gnomist", -"gnomon", -"gnosis", -"gnostic", -"gnu", -"go", -"goa", -"goad", -"goaf", -"goal", -"goalage", -"goalee", -"goalie", -"goanna", -"goat", -"goatee", -"goateed", -"goatish", -"goatly", -"goaty", -"goave", -"gob", -"goback", -"goban", -"gobang", -"gobbe", -"gobber", -"gobbet", -"gobbin", -"gobbing", -"gobble", -"gobbler", -"gobby", -"gobelin", -"gobi", -"gobiid", -"gobioid", -"goblet", -"goblin", -"gobline", -"gobo", -"gobony", -"goburra", -"goby", -"gocart", -"god", -"goddard", -"godded", -"goddess", -"goddize", -"gode", -"godet", -"godhead", -"godhood", -"godkin", -"godless", -"godlet", -"godlike", -"godlily", -"godling", -"godly", -"godown", -"godpapa", -"godsend", -"godship", -"godson", -"godwit", -"goeduck", -"goel", -"goelism", -"goer", -"goes", -"goetia", -"goetic", -"goety", -"goff", -"goffer", -"goffle", -"gog", -"gogga", -"goggan", -"goggle", -"goggled", -"goggler", -"goggly", -"goglet", -"gogo", -"goi", -"going", -"goitcho", -"goiter", -"goitral", -"gol", -"gola", -"golach", -"goladar", -"gold", -"goldbug", -"goldcup", -"golden", -"golder", -"goldie", -"goldin", -"goldish", -"goldtit", -"goldy", -"golee", -"golem", -"golf", -"golfdom", -"golfer", -"goli", -"goliard", -"goliath", -"golland", -"gollar", -"golly", -"goloe", -"golpe", -"gomari", -"gomart", -"gomavel", -"gombay", -"gombeen", -"gomer", -"gomeral", -"gomlah", -"gomuti", -"gon", -"gonad", -"gonadal", -"gonadic", -"gonagra", -"gonakie", -"gonal", -"gonapod", -"gondang", -"gondite", -"gondola", -"gone", -"goner", -"gong", -"gongman", -"gonia", -"goniac", -"gonial", -"goniale", -"gonid", -"gonidia", -"gonidic", -"gonimic", -"gonion", -"gonitis", -"gonium", -"gonne", -"gony", -"gonys", -"goo", -"goober", -"good", -"gooding", -"goodish", -"goodly", -"goodman", -"goods", -"goody", -"goof", -"goofer", -"goofily", -"goofy", -"googly", -"googol", -"googul", -"gook", -"gool", -"goolah", -"gools", -"gooma", -"goon", -"goondie", -"goonie", -"goose", -"goosery", -"goosish", -"goosy", -"gopher", -"gopura", -"gor", -"gora", -"goracco", -"goral", -"goran", -"gorb", -"gorbal", -"gorbet", -"gorble", -"gorce", -"gorcock", -"gorcrow", -"gore", -"gorer", -"gorevan", -"gorfly", -"gorge", -"gorged", -"gorger", -"gorget", -"gorglin", -"gorhen", -"goric", -"gorilla", -"gorily", -"goring", -"gorlin", -"gorlois", -"gormaw", -"gormed", -"gorra", -"gorraf", -"gorry", -"gorse", -"gorsedd", -"gorsy", -"gory", -"gos", -"gosain", -"goschen", -"gosh", -"goshawk", -"goslet", -"gosling", -"gosmore", -"gospel", -"gosport", -"gossan", -"gossard", -"gossip", -"gossipy", -"gossoon", -"gossy", -"got", -"gotch", -"gote", -"gothite", -"gotra", -"gotraja", -"gotten", -"gouaree", -"gouge", -"gouger", -"goujon", -"goulash", -"goumi", -"goup", -"gourami", -"gourd", -"gourde", -"gourdy", -"gourmet", -"gousty", -"gout", -"goutify", -"goutily", -"goutish", -"goutte", -"gouty", -"gove", -"govern", -"gowan", -"gowdnie", -"gowf", -"gowfer", -"gowk", -"gowked", -"gowkit", -"gowl", -"gown", -"gownlet", -"gowpen", -"goy", -"goyim", -"goyin", -"goyle", -"gozell", -"gozzard", -"gra", -"grab", -"grabber", -"grabble", -"graben", -"grace", -"gracer", -"gracile", -"grackle", -"grad", -"gradal", -"gradate", -"graddan", -"grade", -"graded", -"gradely", -"grader", -"gradin", -"gradine", -"grading", -"gradual", -"gradus", -"graff", -"graffer", -"graft", -"grafted", -"grafter", -"graham", -"grail", -"grailer", -"grain", -"grained", -"grainer", -"grainy", -"graip", -"graisse", -"graith", -"grallic", -"gram", -"grama", -"grame", -"grammar", -"gramme", -"gramp", -"grampa", -"grampus", -"granada", -"granage", -"granary", -"granate", -"granch", -"grand", -"grandam", -"grandee", -"grandly", -"grandma", -"grandpa", -"grane", -"grange", -"granger", -"granite", -"grank", -"grannom", -"granny", -"grano", -"granose", -"grant", -"grantee", -"granter", -"grantor", -"granula", -"granule", -"granza", -"grape", -"graped", -"grapery", -"graph", -"graphic", -"graphy", -"graping", -"grapnel", -"grappa", -"grapple", -"grapy", -"grasp", -"grasper", -"grass", -"grassed", -"grasser", -"grasset", -"grassy", -"grat", -"grate", -"grater", -"grather", -"gratify", -"grating", -"gratis", -"gratten", -"graupel", -"grave", -"graved", -"gravel", -"gravely", -"graven", -"graver", -"gravic", -"gravid", -"graving", -"gravity", -"gravure", -"gravy", -"grawls", -"gray", -"grayfly", -"grayish", -"graylag", -"grayly", -"graze", -"grazer", -"grazier", -"grazing", -"grease", -"greaser", -"greasy", -"great", -"greaten", -"greater", -"greatly", -"greave", -"greaved", -"greaves", -"grebe", -"grece", -"gree", -"greed", -"greedy", -"green", -"greener", -"greeney", -"greenly", -"greenth", -"greenuk", -"greeny", -"greet", -"greeter", -"gregal", -"gregale", -"grege", -"greggle", -"grego", -"greige", -"grein", -"greisen", -"gremial", -"gremlin", -"grenade", -"greund", -"grew", -"grey", -"greyly", -"gribble", -"grice", -"grid", -"griddle", -"gride", -"griece", -"grieced", -"grief", -"grieve", -"grieved", -"griever", -"griff", -"griffe", -"griffin", -"griffon", -"grift", -"grifter", -"grig", -"grignet", -"grigri", -"grike", -"grill", -"grille", -"grilled", -"griller", -"grilse", -"grim", -"grimace", -"grime", -"grimful", -"grimily", -"grimly", -"grimme", -"grimp", -"grimy", -"grin", -"grinch", -"grind", -"grinder", -"grindle", -"gringo", -"grinner", -"grinny", -"grip", -"gripe", -"griper", -"griping", -"gripman", -"grippal", -"grippe", -"gripper", -"gripple", -"grippy", -"gripy", -"gris", -"grisard", -"griskin", -"grisly", -"grison", -"grist", -"grister", -"gristle", -"gristly", -"gristy", -"grit", -"grith", -"grits", -"gritten", -"gritter", -"grittle", -"gritty", -"grivet", -"grivna", -"grizzle", -"grizzly", -"groan", -"groaner", -"groat", -"groats", -"grobian", -"grocer", -"grocery", -"groff", -"grog", -"groggy", -"grogram", -"groin", -"groined", -"grommet", -"groom", -"groomer", -"groomy", -"groop", -"groose", -"groot", -"grooty", -"groove", -"groover", -"groovy", -"grope", -"groper", -"groping", -"gropple", -"gros", -"groser", -"groset", -"gross", -"grossen", -"grosser", -"grossly", -"grosso", -"grosz", -"groszy", -"grot", -"grotto", -"grouch", -"grouchy", -"grouf", -"grough", -"ground", -"grounds", -"groundy", -"group", -"grouped", -"grouper", -"grouse", -"grouser", -"grousy", -"grout", -"grouter", -"grouts", -"grouty", -"grouze", -"grove", -"groved", -"grovel", -"grovy", -"grow", -"growan", -"growed", -"grower", -"growing", -"growl", -"growler", -"growly", -"grown", -"grownup", -"growse", -"growth", -"growthy", -"grozart", -"grozet", -"grr", -"grub", -"grubbed", -"grubber", -"grubby", -"grubs", -"grudge", -"grudger", -"grue", -"gruel", -"grueler", -"gruelly", -"gruff", -"gruffly", -"gruffs", -"gruffy", -"grufted", -"grugru", -"gruine", -"grum", -"grumble", -"grumbly", -"grume", -"grumly", -"grummel", -"grummet", -"grumose", -"grumous", -"grump", -"grumph", -"grumphy", -"grumpy", -"grun", -"grundy", -"grunion", -"grunt", -"grunter", -"gruntle", -"grush", -"grushie", -"gruss", -"grutch", -"grutten", -"gryde", -"grylli", -"gryllid", -"gryllos", -"gryllus", -"grysbok", -"guaba", -"guacimo", -"guacin", -"guaco", -"guaiac", -"guaiol", -"guaka", -"guama", -"guan", -"guana", -"guanaco", -"guanase", -"guanay", -"guango", -"guanine", -"guanize", -"guano", -"guanyl", -"guao", -"guapena", -"guar", -"guara", -"guarabu", -"guarana", -"guarani", -"guard", -"guarded", -"guarder", -"guardo", -"guariba", -"guarri", -"guasa", -"guava", -"guavina", -"guayaba", -"guayabi", -"guayabo", -"guayule", -"guaza", -"gubbo", -"gucki", -"gud", -"gudame", -"guddle", -"gude", -"gudge", -"gudgeon", -"gudget", -"gudok", -"gue", -"guebucu", -"guemal", -"guenepe", -"guenon", -"guepard", -"guerdon", -"guereza", -"guess", -"guesser", -"guest", -"guesten", -"guester", -"gufa", -"guff", -"guffaw", -"guffer", -"guffin", -"guffy", -"gugal", -"guggle", -"gugglet", -"guglet", -"guglia", -"guglio", -"gugu", -"guhr", -"guib", -"guiba", -"guidage", -"guide", -"guider", -"guidman", -"guidon", -"guige", -"guignol", -"guijo", -"guild", -"guilder", -"guildic", -"guildry", -"guile", -"guilery", -"guilt", -"guilty", -"guily", -"guimpe", -"guinea", -"guipure", -"guisard", -"guise", -"guiser", -"guising", -"guitar", -"gul", -"gula", -"gulae", -"gulaman", -"gular", -"gularis", -"gulch", -"gulden", -"gule", -"gules", -"gulf", -"gulfy", -"gulgul", -"gulix", -"gull", -"gullery", -"gullet", -"gullion", -"gullish", -"gully", -"gulonic", -"gulose", -"gulp", -"gulper", -"gulpin", -"gulping", -"gulpy", -"gulsach", -"gum", -"gumbo", -"gumboil", -"gumby", -"gumdrop", -"gumihan", -"gumless", -"gumlike", -"gumly", -"gumma", -"gummage", -"gummata", -"gummed", -"gummer", -"gumming", -"gummite", -"gummose", -"gummous", -"gummy", -"gump", -"gumpus", -"gumshoe", -"gumweed", -"gumwood", -"gun", -"guna", -"gunate", -"gunboat", -"gundi", -"gundy", -"gunebo", -"gunfire", -"gunge", -"gunite", -"gunj", -"gunk", -"gunl", -"gunless", -"gunlock", -"gunman", -"gunnage", -"gunne", -"gunnel", -"gunner", -"gunnery", -"gunnies", -"gunning", -"gunnung", -"gunny", -"gunong", -"gunplay", -"gunrack", -"gunsel", -"gunshop", -"gunshot", -"gunsman", -"gunster", -"gunter", -"gunwale", -"gunyah", -"gunyang", -"gunyeh", -"gup", -"guppy", -"gur", -"gurdle", -"gurge", -"gurgeon", -"gurges", -"gurgle", -"gurglet", -"gurgly", -"gurjun", -"gurk", -"gurl", -"gurly", -"gurnard", -"gurnet", -"gurniad", -"gurr", -"gurrah", -"gurry", -"gurt", -"guru", -"gush", -"gusher", -"gushet", -"gushily", -"gushing", -"gushy", -"gusla", -"gusle", -"guss", -"gusset", -"gussie", -"gust", -"gustful", -"gustily", -"gusto", -"gusty", -"gut", -"gutless", -"gutlike", -"gutling", -"gutt", -"gutta", -"guttate", -"gutte", -"gutter", -"guttery", -"gutti", -"guttide", -"guttie", -"guttle", -"guttler", -"guttula", -"guttule", -"guttus", -"gutty", -"gutweed", -"gutwise", -"gutwort", -"guy", -"guydom", -"guyer", -"guz", -"guze", -"guzzle", -"guzzler", -"gwag", -"gweduc", -"gweed", -"gweeon", -"gwely", -"gwine", -"gwyniad", -"gyle", -"gym", -"gymel", -"gymnast", -"gymnic", -"gymnics", -"gymnite", -"gymnure", -"gympie", -"gyn", -"gyne", -"gynecic", -"gynic", -"gynics", -"gyp", -"gype", -"gypper", -"gyps", -"gypsine", -"gypsite", -"gypsous", -"gypster", -"gypsum", -"gypsy", -"gypsyfy", -"gypsyry", -"gyral", -"gyrally", -"gyrant", -"gyrate", -"gyrator", -"gyre", -"gyrene", -"gyri", -"gyric", -"gyrinid", -"gyro", -"gyrocar", -"gyroma", -"gyron", -"gyronny", -"gyrose", -"gyrous", -"gyrus", -"gyte", -"gytling", -"gyve", -"h", -"ha", -"haab", -"haaf", -"habble", -"habeas", -"habena", -"habenal", -"habenar", -"habile", -"habille", -"habit", -"habitan", -"habitat", -"habited", -"habitue", -"habitus", -"habnab", -"haboob", -"habu", -"habutai", -"hache", -"hachure", -"hack", -"hackbut", -"hacked", -"hackee", -"hacker", -"hackery", -"hackin", -"hacking", -"hackle", -"hackler", -"hacklog", -"hackly", -"hackman", -"hackney", -"hacksaw", -"hacky", -"had", -"hadbot", -"hadden", -"haddie", -"haddo", -"haddock", -"hade", -"hading", -"hadj", -"hadji", -"hadland", -"hadrome", -"haec", -"haem", -"haemony", -"haet", -"haff", -"haffet", -"haffle", -"hafiz", -"hafnium", -"hafnyl", -"haft", -"hafter", -"hag", -"hagboat", -"hagborn", -"hagbush", -"hagdon", -"hageen", -"hagfish", -"haggada", -"haggard", -"hagged", -"hagger", -"haggis", -"haggish", -"haggle", -"haggler", -"haggly", -"haggy", -"hagi", -"hagia", -"haglet", -"haglike", -"haglin", -"hagride", -"hagrope", -"hagseed", -"hagship", -"hagweed", -"hagworm", -"hah", -"haik", -"haikai", -"haikal", -"haikwan", -"hail", -"hailer", -"hailse", -"haily", -"hain", -"haine", -"hair", -"haircut", -"hairdo", -"haire", -"haired", -"hairen", -"hairif", -"hairlet", -"hairpin", -"hairup", -"hairy", -"haje", -"hajib", -"hajilij", -"hak", -"hakam", -"hakdar", -"hake", -"hakeem", -"hakim", -"hako", -"haku", -"hala", -"halakah", -"halakic", -"halal", -"halberd", -"halbert", -"halch", -"halcyon", -"hale", -"halebi", -"haler", -"halerz", -"half", -"halfer", -"halfman", -"halfway", -"halibiu", -"halibut", -"halide", -"halidom", -"halite", -"halitus", -"hall", -"hallage", -"hallah", -"hallan", -"hallel", -"hallex", -"halling", -"hallman", -"halloo", -"hallow", -"hallux", -"hallway", -"halma", -"halo", -"halogen", -"haloid", -"hals", -"halse", -"halsen", -"halt", -"halter", -"halting", -"halurgy", -"halutz", -"halvans", -"halve", -"halved", -"halver", -"halves", -"halyard", -"ham", -"hamal", -"hamald", -"hamate", -"hamated", -"hamatum", -"hamble", -"hame", -"hameil", -"hamel", -"hamfat", -"hami", -"hamlah", -"hamlet", -"hammada", -"hammam", -"hammer", -"hammock", -"hammy", -"hamose", -"hamous", -"hamper", -"hamsa", -"hamster", -"hamular", -"hamule", -"hamulus", -"hamus", -"hamza", -"han", -"hanaper", -"hanbury", -"hance", -"hanced", -"hanch", -"hand", -"handbag", -"handbow", -"handcar", -"handed", -"hander", -"handful", -"handgun", -"handily", -"handle", -"handled", -"handler", -"handout", -"handsaw", -"handsel", -"handset", -"handy", -"hangar", -"hangby", -"hangdog", -"hange", -"hangee", -"hanger", -"hangie", -"hanging", -"hangle", -"hangman", -"hangout", -"hangul", -"hanif", -"hank", -"hanker", -"hankie", -"hankle", -"hanky", -"hanna", -"hansa", -"hanse", -"hansel", -"hansom", -"hant", -"hantle", -"hao", -"haole", -"haoma", -"haori", -"hap", -"hapless", -"haplite", -"haploid", -"haploma", -"haplont", -"haply", -"happen", -"happier", -"happify", -"happily", -"happing", -"happy", -"hapten", -"haptene", -"haptere", -"haptic", -"haptics", -"hapu", -"hapuku", -"harass", -"haratch", -"harbi", -"harbor", -"hard", -"harden", -"harder", -"hardily", -"hardim", -"hardish", -"hardly", -"hardock", -"hardpan", -"hardy", -"hare", -"harebur", -"harelip", -"harem", -"harfang", -"haricot", -"harish", -"hark", -"harka", -"harl", -"harling", -"harlock", -"harlot", -"harm", -"harmal", -"harmala", -"harman", -"harmel", -"harmer", -"harmful", -"harmine", -"harmony", -"harmost", -"harn", -"harness", -"harnpan", -"harp", -"harpago", -"harper", -"harpier", -"harpist", -"harpoon", -"harpula", -"harr", -"harrier", -"harrow", -"harry", -"harsh", -"harshen", -"harshly", -"hart", -"hartal", -"hartin", -"hartite", -"harvest", -"hasan", -"hash", -"hashab", -"hasher", -"hashish", -"hashy", -"hask", -"hasky", -"haslet", -"haslock", -"hasp", -"hassar", -"hassel", -"hassle", -"hassock", -"hasta", -"hastate", -"hastati", -"haste", -"hasten", -"haster", -"hastily", -"hastish", -"hastler", -"hasty", -"hat", -"hatable", -"hatband", -"hatbox", -"hatbrim", -"hatch", -"hatchel", -"hatcher", -"hatchet", -"hate", -"hateful", -"hater", -"hatful", -"hath", -"hathi", -"hatless", -"hatlike", -"hatpin", -"hatrack", -"hatrail", -"hatred", -"hatress", -"hatt", -"hatted", -"hatter", -"hattery", -"hatting", -"hattock", -"hatty", -"hau", -"hauberk", -"haugh", -"haught", -"haughty", -"haul", -"haulage", -"hauld", -"hauler", -"haulier", -"haulm", -"haulmy", -"haunch", -"haunchy", -"haunt", -"haunter", -"haunty", -"hause", -"hausen", -"hausse", -"hautboy", -"hauteur", -"havage", -"have", -"haveage", -"havel", -"haven", -"havener", -"havenet", -"havent", -"haver", -"haverel", -"haverer", -"havers", -"havier", -"havoc", -"haw", -"hawbuck", -"hawer", -"hawk", -"hawkbit", -"hawked", -"hawker", -"hawkery", -"hawkie", -"hawking", -"hawkish", -"hawknut", -"hawky", -"hawm", -"hawok", -"hawse", -"hawser", -"hay", -"haya", -"hayband", -"haybird", -"haybote", -"haycap", -"haycart", -"haycock", -"hayey", -"hayfork", -"haylift", -"hayloft", -"haymow", -"hayrack", -"hayrake", -"hayrick", -"hayseed", -"haysel", -"haysuck", -"haytime", -"hayward", -"hayweed", -"haywire", -"hayz", -"hazard", -"haze", -"hazel", -"hazeled", -"hazelly", -"hazen", -"hazer", -"hazily", -"hazing", -"hazle", -"hazy", -"hazzan", -"he", -"head", -"headcap", -"headed", -"header", -"headful", -"headily", -"heading", -"headman", -"headset", -"headway", -"heady", -"heaf", -"heal", -"heald", -"healder", -"healer", -"healful", -"healing", -"health", -"healthy", -"heap", -"heaper", -"heaps", -"heapy", -"hear", -"hearer", -"hearing", -"hearken", -"hearsay", -"hearse", -"hearst", -"heart", -"hearted", -"hearten", -"hearth", -"heartly", -"hearts", -"hearty", -"heat", -"heater", -"heatful", -"heath", -"heathen", -"heather", -"heathy", -"heating", -"heaume", -"heaumer", -"heave", -"heaven", -"heavens", -"heaver", -"heavies", -"heavily", -"heaving", -"heavity", -"heavy", -"hebamic", -"hebenon", -"hebete", -"hebetic", -"hech", -"heck", -"heckle", -"heckler", -"hectare", -"hecte", -"hectic", -"hector", -"heddle", -"heddler", -"hedebo", -"heder", -"hederic", -"hederin", -"hedge", -"hedger", -"hedging", -"hedgy", -"hedonic", -"heed", -"heeder", -"heedful", -"heedily", -"heedy", -"heehaw", -"heel", -"heelcap", -"heeled", -"heeler", -"heeltap", -"heer", -"heeze", -"heezie", -"heezy", -"heft", -"hefter", -"heftily", -"hefty", -"hegari", -"hegemon", -"hegira", -"hegumen", -"hei", -"heiau", -"heifer", -"heigh", -"height", -"heii", -"heimin", -"heinous", -"heir", -"heirdom", -"heiress", -"heitiki", -"hekteus", -"helbeh", -"helcoid", -"helder", -"hele", -"helenin", -"heliast", -"helical", -"heliced", -"helices", -"helicin", -"helicon", -"helide", -"heling", -"helio", -"helioid", -"helium", -"helix", -"hell", -"hellbox", -"hellcat", -"helldog", -"heller", -"helleri", -"hellhag", -"hellier", -"hellion", -"hellish", -"hello", -"helluo", -"helly", -"helm", -"helmage", -"helmed", -"helmet", -"helodes", -"heloe", -"heloma", -"helonin", -"helosis", -"helotry", -"help", -"helper", -"helpful", -"helping", -"helply", -"helve", -"helvell", -"helver", -"helvite", -"hem", -"hemad", -"hemal", -"hemapod", -"hemase", -"hematal", -"hematic", -"hematid", -"hematin", -"heme", -"hemen", -"hemera", -"hemiamb", -"hemic", -"hemin", -"hemina", -"hemine", -"heminee", -"hemiope", -"hemipic", -"heml", -"hemlock", -"hemmel", -"hemmer", -"hemocry", -"hemoid", -"hemol", -"hemopod", -"hemp", -"hempen", -"hempy", -"hen", -"henad", -"henbane", -"henbill", -"henbit", -"hence", -"hencoop", -"hencote", -"hend", -"hendly", -"henfish", -"henism", -"henlike", -"henna", -"hennery", -"hennin", -"hennish", -"henny", -"henotic", -"henpeck", -"henpen", -"henry", -"hent", -"henter", -"henware", -"henwife", -"henwise", -"henyard", -"hep", -"hepar", -"heparin", -"hepatic", -"hepcat", -"heppen", -"hepper", -"heptace", -"heptad", -"heptal", -"heptane", -"heptene", -"heptine", -"heptite", -"heptoic", -"heptose", -"heptyl", -"heptyne", -"her", -"herald", -"herb", -"herbage", -"herbal", -"herbane", -"herbary", -"herbish", -"herbist", -"herblet", -"herbman", -"herbose", -"herbous", -"herby", -"herd", -"herdboy", -"herder", -"herdic", -"herding", -"here", -"hereat", -"hereby", -"herein", -"herem", -"hereof", -"hereon", -"heresy", -"heretic", -"hereto", -"herile", -"heriot", -"heritor", -"herl", -"herling", -"herma", -"hermaic", -"hermit", -"hern", -"hernani", -"hernant", -"herne", -"hernia", -"hernial", -"hero", -"heroess", -"heroic", -"heroid", -"heroify", -"heroin", -"heroine", -"heroism", -"heroize", -"heron", -"heroner", -"heronry", -"herpes", -"herring", -"hers", -"herse", -"hersed", -"herself", -"hership", -"hersir", -"hertz", -"hessite", -"hest", -"hestern", -"het", -"hetaera", -"hetaery", -"heteric", -"hetero", -"hething", -"hetman", -"hetter", -"heuau", -"heugh", -"heumite", -"hevi", -"hew", -"hewable", -"hewel", -"hewer", -"hewhall", -"hewn", -"hewt", -"hex", -"hexa", -"hexace", -"hexacid", -"hexact", -"hexad", -"hexadic", -"hexagon", -"hexagyn", -"hexane", -"hexaped", -"hexapla", -"hexapod", -"hexarch", -"hexene", -"hexer", -"hexerei", -"hexeris", -"hexine", -"hexis", -"hexitol", -"hexode", -"hexogen", -"hexoic", -"hexone", -"hexonic", -"hexosan", -"hexose", -"hexyl", -"hexylic", -"hexyne", -"hey", -"heyday", -"hi", -"hia", -"hiant", -"hiatal", -"hiate", -"hiation", -"hiatus", -"hibbin", -"hic", -"hicatee", -"hiccup", -"hick", -"hickey", -"hickory", -"hidable", -"hidage", -"hidalgo", -"hidated", -"hidden", -"hide", -"hided", -"hideous", -"hider", -"hidling", -"hie", -"hieder", -"hield", -"hiemal", -"hieron", -"hieros", -"higdon", -"higgle", -"higgler", -"high", -"highboy", -"higher", -"highest", -"highish", -"highly", -"highman", -"hight", -"hightop", -"highway", -"higuero", -"hijack", -"hike", -"hiker", -"hilch", -"hilding", -"hill", -"hiller", -"hillet", -"hillman", -"hillock", -"hilltop", -"hilly", -"hilsa", -"hilt", -"hilum", -"hilus", -"him", -"himp", -"himself", -"himward", -"hin", -"hinau", -"hinch", -"hind", -"hinder", -"hing", -"hinge", -"hinger", -"hingle", -"hinney", -"hinny", -"hinoid", -"hinoki", -"hint", -"hinter", -"hiodont", -"hip", -"hipbone", -"hipe", -"hiper", -"hiphalt", -"hipless", -"hipmold", -"hipped", -"hippen", -"hippian", -"hippic", -"hipping", -"hippish", -"hipple", -"hippo", -"hippoid", -"hippus", -"hippy", -"hipshot", -"hipwort", -"hirable", -"hircine", -"hire", -"hired", -"hireman", -"hirer", -"hirmos", -"hiro", -"hirple", -"hirse", -"hirsel", -"hirsle", -"hirsute", -"his", -"hish", -"hisn", -"hispid", -"hiss", -"hisser", -"hissing", -"hist", -"histie", -"histoid", -"histon", -"histone", -"history", -"histrio", -"hit", -"hitch", -"hitcher", -"hitchy", -"hithe", -"hither", -"hitless", -"hitter", -"hive", -"hiver", -"hives", -"hizz", -"ho", -"hoar", -"hoard", -"hoarder", -"hoarily", -"hoarish", -"hoarse", -"hoarsen", -"hoary", -"hoast", -"hoatzin", -"hoax", -"hoaxee", -"hoaxer", -"hob", -"hobber", -"hobbet", -"hobbil", -"hobble", -"hobbler", -"hobbly", -"hobby", -"hoblike", -"hobnail", -"hobnob", -"hobo", -"hoboism", -"hocco", -"hock", -"hocker", -"hocket", -"hockey", -"hocky", -"hocus", -"hod", -"hodden", -"hodder", -"hoddle", -"hoddy", -"hodful", -"hodman", -"hoe", -"hoecake", -"hoedown", -"hoeful", -"hoer", -"hog", -"hoga", -"hogan", -"hogback", -"hogbush", -"hogfish", -"hogged", -"hogger", -"hoggery", -"hogget", -"hoggie", -"hoggin", -"hoggish", -"hoggism", -"hoggy", -"hogherd", -"hoghide", -"hoghood", -"hoglike", -"hogling", -"hogmace", -"hognose", -"hognut", -"hogpen", -"hogship", -"hogskin", -"hogsty", -"hogward", -"hogwash", -"hogweed", -"hogwort", -"hogyard", -"hoi", -"hoick", -"hoin", -"hoise", -"hoist", -"hoister", -"hoit", -"hoju", -"hokey", -"hokum", -"holard", -"holcad", -"hold", -"holdall", -"holden", -"holder", -"holding", -"holdout", -"holdup", -"hole", -"holeman", -"holer", -"holey", -"holia", -"holiday", -"holily", -"holing", -"holism", -"holl", -"holla", -"holler", -"hollin", -"hollo", -"hollock", -"hollong", -"hollow", -"holly", -"holm", -"holmia", -"holmic", -"holmium", -"holmos", -"holour", -"holster", -"holt", -"holy", -"holyday", -"homage", -"homager", -"home", -"homelet", -"homely", -"homelyn", -"homeoid", -"homer", -"homey", -"homily", -"hominal", -"hominid", -"hominy", -"homish", -"homo", -"homodox", -"homogen", -"homonym", -"homrai", -"homy", -"honda", -"hondo", -"hone", -"honest", -"honesty", -"honey", -"honeyed", -"hong", -"honied", -"honily", -"honk", -"honker", -"honor", -"honoree", -"honorer", -"hontish", -"hontous", -"hooch", -"hood", -"hoodcap", -"hooded", -"hoodful", -"hoodie", -"hoodlum", -"hoodman", -"hoodoo", -"hoodshy", -"hooey", -"hoof", -"hoofed", -"hoofer", -"hoofish", -"hooflet", -"hoofrot", -"hoofs", -"hoofy", -"hook", -"hookah", -"hooked", -"hooker", -"hookers", -"hookish", -"hooklet", -"hookman", -"hooktip", -"hookum", -"hookup", -"hooky", -"hoolock", -"hooly", -"hoon", -"hoop", -"hooped", -"hooper", -"hooping", -"hoopla", -"hoople", -"hoopman", -"hoopoe", -"hoose", -"hoosh", -"hoot", -"hootay", -"hooter", -"hoove", -"hooven", -"hoovey", -"hop", -"hopbine", -"hopbush", -"hope", -"hoped", -"hopeful", -"hopeite", -"hoper", -"hopi", -"hoplite", -"hopoff", -"hopped", -"hopper", -"hoppers", -"hoppet", -"hoppity", -"hopple", -"hoppy", -"hoptoad", -"hopvine", -"hopyard", -"hora", -"horal", -"horary", -"hordary", -"horde", -"hordein", -"horizon", -"horme", -"hormic", -"hormigo", -"hormion", -"hormist", -"hormone", -"hormos", -"horn", -"horned", -"horner", -"hornet", -"hornety", -"hornful", -"hornify", -"hornily", -"horning", -"hornish", -"hornist", -"hornito", -"hornlet", -"horntip", -"horny", -"horrent", -"horreum", -"horrid", -"horrify", -"horror", -"horse", -"horser", -"horsify", -"horsily", -"horsing", -"horst", -"horsy", -"hortite", -"hory", -"hosanna", -"hose", -"hosed", -"hosel", -"hoseman", -"hosier", -"hosiery", -"hospice", -"host", -"hostage", -"hostel", -"hoster", -"hostess", -"hostie", -"hostile", -"hosting", -"hostler", -"hostly", -"hostry", -"hot", -"hotbed", -"hotbox", -"hotch", -"hotel", -"hotfoot", -"hothead", -"hoti", -"hotly", -"hotness", -"hotspur", -"hotter", -"hottery", -"hottish", -"houbara", -"hough", -"hougher", -"hounce", -"hound", -"hounder", -"houndy", -"hour", -"hourful", -"houri", -"hourly", -"housage", -"housal", -"house", -"housel", -"houser", -"housing", -"housty", -"housy", -"houtou", -"houvari", -"hove", -"hovel", -"hoveler", -"hoven", -"hover", -"hoverer", -"hoverly", -"how", -"howadji", -"howbeit", -"howdah", -"howder", -"howdie", -"howdy", -"howe", -"howel", -"however", -"howff", -"howish", -"howk", -"howkit", -"howl", -"howler", -"howlet", -"howling", -"howlite", -"howso", -"hox", -"hoy", -"hoyden", -"hoyle", -"hoyman", -"huaca", -"huaco", -"huarizo", -"hub", -"hubb", -"hubba", -"hubber", -"hubble", -"hubbly", -"hubbub", -"hubby", -"hubshi", -"huchen", -"hucho", -"huck", -"huckle", -"hud", -"huddle", -"huddler", -"huddock", -"huddup", -"hue", -"hued", -"hueful", -"hueless", -"huer", -"huff", -"huffier", -"huffily", -"huffish", -"huffle", -"huffler", -"huffy", -"hug", -"huge", -"hugely", -"hugeous", -"hugger", -"hugging", -"huggle", -"hugsome", -"huh", -"huia", -"huipil", -"huitain", -"huke", -"hula", -"huldee", -"hulk", -"hulkage", -"hulking", -"hulky", -"hull", -"huller", -"hullock", -"hulloo", -"hulsite", -"hulster", -"hulu", -"hulver", -"hum", -"human", -"humane", -"humanly", -"humate", -"humble", -"humbler", -"humblie", -"humbly", -"humbo", -"humbug", -"humbuzz", -"humdrum", -"humect", -"humeral", -"humeri", -"humerus", -"humet", -"humetty", -"humhum", -"humic", -"humid", -"humidly", -"humidor", -"humific", -"humify", -"humin", -"humite", -"humlie", -"hummel", -"hummer", -"hummie", -"humming", -"hummock", -"humor", -"humoral", -"humous", -"hump", -"humped", -"humph", -"humpty", -"humpy", -"humus", -"hunch", -"hunchet", -"hunchy", -"hundi", -"hundred", -"hung", -"hunger", -"hungry", -"hunh", -"hunk", -"hunker", -"hunkers", -"hunkies", -"hunks", -"hunky", -"hunt", -"hunting", -"hup", -"hura", -"hurdies", -"hurdis", -"hurdle", -"hurdler", -"hurds", -"hure", -"hureek", -"hurgila", -"hurkle", -"hurl", -"hurled", -"hurler", -"hurley", -"hurling", -"hurlock", -"hurly", -"huron", -"hurr", -"hurrah", -"hurried", -"hurrier", -"hurrock", -"hurroo", -"hurry", -"hurst", -"hurt", -"hurted", -"hurter", -"hurtful", -"hurting", -"hurtle", -"hurty", -"husband", -"huse", -"hush", -"hushaby", -"husheen", -"hushel", -"husher", -"hushful", -"hushing", -"hushion", -"husho", -"husk", -"husked", -"husker", -"huskily", -"husking", -"husky", -"huso", -"huspil", -"huss", -"hussar", -"hussy", -"husting", -"hustle", -"hustler", -"hut", -"hutch", -"hutcher", -"hutchet", -"huthold", -"hutia", -"hutlet", -"hutment", -"huvelyk", -"huzoor", -"huzz", -"huzza", -"huzzard", -"hyaena", -"hyaline", -"hyalite", -"hyaloid", -"hybosis", -"hybrid", -"hydatid", -"hydnoid", -"hydrant", -"hydrate", -"hydrazo", -"hydria", -"hydric", -"hydride", -"hydro", -"hydroa", -"hydroid", -"hydrol", -"hydrome", -"hydrone", -"hydrops", -"hydrous", -"hydroxy", -"hydrula", -"hyena", -"hyenic", -"hyenine", -"hyenoid", -"hyetal", -"hygeist", -"hygiene", -"hygric", -"hygrine", -"hygroma", -"hying", -"hyke", -"hyle", -"hyleg", -"hylic", -"hylism", -"hylist", -"hyloid", -"hymen", -"hymenal", -"hymenic", -"hymn", -"hymnal", -"hymnary", -"hymner", -"hymnic", -"hymnist", -"hymnode", -"hymnody", -"hynde", -"hyne", -"hyoid", -"hyoidal", -"hyoidan", -"hyoides", -"hyp", -"hypate", -"hypaton", -"hyper", -"hypha", -"hyphal", -"hyphema", -"hyphen", -"hypho", -"hypnody", -"hypnoid", -"hypnone", -"hypo", -"hypogee", -"hypoid", -"hyponym", -"hypopus", -"hyporit", -"hyppish", -"hypural", -"hyraces", -"hyracid", -"hyrax", -"hyson", -"hyssop", -"i", -"iamb", -"iambi", -"iambic", -"iambist", -"iambize", -"iambus", -"iao", -"iatric", -"iba", -"iberite", -"ibex", -"ibices", -"ibid", -"ibidine", -"ibis", -"ibolium", -"ibota", -"icaco", -"ice", -"iceberg", -"iceboat", -"icebone", -"icebox", -"icecap", -"iced", -"icefall", -"icefish", -"iceland", -"iceleaf", -"iceless", -"icelike", -"iceman", -"iceroot", -"icework", -"ich", -"ichnite", -"icho", -"ichor", -"ichthus", -"ichu", -"icica", -"icicle", -"icicled", -"icily", -"iciness", -"icing", -"icon", -"iconic", -"iconism", -"icosian", -"icotype", -"icteric", -"icterus", -"ictic", -"ictuate", -"ictus", -"icy", -"id", -"idalia", -"idant", -"iddat", -"ide", -"idea", -"ideaed", -"ideaful", -"ideal", -"ideally", -"ideate", -"ideist", -"identic", -"ides", -"idgah", -"idiasm", -"idic", -"idiocy", -"idiom", -"idiot", -"idiotcy", -"idiotic", -"idiotry", -"idite", -"iditol", -"idle", -"idleful", -"idleman", -"idler", -"idleset", -"idlety", -"idlish", -"idly", -"idol", -"idola", -"idolify", -"idolism", -"idolist", -"idolize", -"idolous", -"idolum", -"idoneal", -"idorgan", -"idose", -"idryl", -"idyl", -"idyler", -"idylism", -"idylist", -"idylize", -"idyllic", -"ie", -"if", -"ife", -"iffy", -"igloo", -"ignatia", -"ignavia", -"igneous", -"ignify", -"ignite", -"igniter", -"ignitor", -"ignoble", -"ignobly", -"ignore", -"ignorer", -"ignote", -"iguana", -"iguanid", -"ihi", -"ihleite", -"ihram", -"iiwi", -"ijma", -"ijolite", -"ikat", -"ikey", -"ikona", -"ikra", -"ileac", -"ileitis", -"ileon", -"ilesite", -"ileum", -"ileus", -"ilex", -"ilia", -"iliac", -"iliacus", -"iliahi", -"ilial", -"iliau", -"ilicic", -"ilicin", -"ilima", -"ilium", -"ilk", -"ilka", -"ilkane", -"ill", -"illapse", -"illeck", -"illegal", -"illeism", -"illeist", -"illess", -"illfare", -"illicit", -"illish", -"illium", -"illness", -"illocal", -"illogic", -"illoyal", -"illth", -"illude", -"illuder", -"illume", -"illumer", -"illupi", -"illure", -"illusor", -"illy", -"ilot", -"ilvaite", -"image", -"imager", -"imagery", -"imagine", -"imagism", -"imagist", -"imago", -"imam", -"imamah", -"imamate", -"imamic", -"imaret", -"imban", -"imband", -"imbarge", -"imbark", -"imbarn", -"imbased", -"imbat", -"imbauba", -"imbe", -"imbed", -"imber", -"imbibe", -"imbiber", -"imbondo", -"imbosom", -"imbower", -"imbrex", -"imbrue", -"imbrute", -"imbue", -"imburse", -"imi", -"imide", -"imidic", -"imine", -"imino", -"imitant", -"imitate", -"immane", -"immask", -"immense", -"immerd", -"immerge", -"immerit", -"immerse", -"immew", -"immi", -"immit", -"immix", -"immoral", -"immound", -"immund", -"immune", -"immure", -"immute", -"imonium", -"imp", -"impack", -"impact", -"impages", -"impaint", -"impair", -"impala", -"impale", -"impaler", -"impall", -"impalm", -"impalsy", -"impane", -"impanel", -"impar", -"impark", -"imparl", -"impart", -"impasse", -"impaste", -"impasto", -"impave", -"impavid", -"impawn", -"impeach", -"impearl", -"impede", -"impeder", -"impel", -"impen", -"impend", -"impent", -"imperia", -"imperil", -"impest", -"impetre", -"impetus", -"imphee", -"impi", -"impiety", -"impinge", -"impious", -"impish", -"implant", -"implate", -"implead", -"implete", -"implex", -"implial", -"impling", -"implode", -"implore", -"implume", -"imply", -"impofo", -"impone", -"impoor", -"import", -"imposal", -"impose", -"imposer", -"impost", -"impot", -"impound", -"impreg", -"impregn", -"impresa", -"imprese", -"impress", -"imprest", -"imprime", -"imprint", -"improof", -"improve", -"impship", -"impubic", -"impugn", -"impulse", -"impure", -"impute", -"imputer", -"impy", -"imshi", -"imsonic", -"imu", -"in", -"inachid", -"inadept", -"inagile", -"inaja", -"inane", -"inanely", -"inanga", -"inanity", -"inapt", -"inaptly", -"inarch", -"inarm", -"inaugur", -"inaxon", -"inbe", -"inbeing", -"inbent", -"inbirth", -"inblow", -"inblown", -"inboard", -"inbond", -"inborn", -"inbound", -"inbread", -"inbreak", -"inbred", -"inbreed", -"inbring", -"inbuilt", -"inburnt", -"inburst", -"inby", -"incarn", -"incase", -"incast", -"incense", -"incept", -"incest", -"inch", -"inched", -"inchpin", -"incide", -"incisal", -"incise", -"incisor", -"incite", -"inciter", -"incivic", -"incline", -"inclip", -"inclose", -"include", -"inclusa", -"incluse", -"incog", -"income", -"incomer", -"inconnu", -"incrash", -"increep", -"increst", -"incross", -"incrust", -"incubi", -"incubus", -"incudal", -"incudes", -"incult", -"incur", -"incurse", -"incurve", -"incus", -"incuse", -"incut", -"indaba", -"indan", -"indane", -"indart", -"indazin", -"indazol", -"inde", -"indebt", -"indeed", -"indeedy", -"indene", -"indent", -"index", -"indexed", -"indexer", -"indic", -"indican", -"indices", -"indicia", -"indict", -"indign", -"indigo", -"indite", -"inditer", -"indium", -"indogen", -"indole", -"indoles", -"indolyl", -"indoor", -"indoors", -"indorse", -"indoxyl", -"indraft", -"indrawn", -"indri", -"induce", -"induced", -"inducer", -"induct", -"indue", -"indulge", -"indult", -"indulto", -"induna", -"indwell", -"indy", -"indyl", -"indylic", -"inearth", -"inept", -"ineptly", -"inequal", -"inerm", -"inert", -"inertia", -"inertly", -"inesite", -"ineunt", -"inexact", -"inexist", -"inface", -"infall", -"infame", -"infamy", -"infancy", -"infand", -"infang", -"infant", -"infanta", -"infante", -"infarct", -"infare", -"infaust", -"infect", -"infeed", -"infeft", -"infelt", -"infer", -"infern", -"inferno", -"infest", -"infidel", -"infield", -"infill", -"infilm", -"infirm", -"infit", -"infix", -"inflame", -"inflate", -"inflect", -"inflex", -"inflict", -"inflood", -"inflow", -"influx", -"infold", -"inform", -"infra", -"infract", -"infula", -"infuse", -"infuser", -"ing", -"ingate", -"ingenit", -"ingenue", -"ingest", -"ingesta", -"ingiver", -"ingle", -"inglobe", -"ingoing", -"ingot", -"ingraft", -"ingrain", -"ingrate", -"ingress", -"ingross", -"ingrow", -"ingrown", -"inguen", -"ingulf", -"inhabit", -"inhale", -"inhaler", -"inhaul", -"inhaust", -"inhere", -"inherit", -"inhiate", -"inhibit", -"inhuman", -"inhume", -"inhumer", -"inial", -"iniome", -"inion", -"initial", -"initis", -"initive", -"inject", -"injelly", -"injunct", -"injure", -"injured", -"injurer", -"injury", -"ink", -"inkbush", -"inken", -"inker", -"inket", -"inkfish", -"inkhorn", -"inkish", -"inkle", -"inkless", -"inklike", -"inkling", -"inknot", -"inkosi", -"inkpot", -"inkroot", -"inks", -"inkshed", -"inkweed", -"inkwell", -"inkwood", -"inky", -"inlaid", -"inlaik", -"inlake", -"inland", -"inlaut", -"inlaw", -"inlawry", -"inlay", -"inlayer", -"inleak", -"inlet", -"inlier", -"inlook", -"inly", -"inlying", -"inmate", -"inmeats", -"inmost", -"inn", -"innate", -"inneity", -"inner", -"innerly", -"innerve", -"inness", -"innest", -"innet", -"inning", -"innless", -"innyard", -"inocyte", -"inogen", -"inoglia", -"inolith", -"inoma", -"inone", -"inopine", -"inorb", -"inosic", -"inosin", -"inosite", -"inower", -"inphase", -"inport", -"inpour", -"inpush", -"input", -"inquest", -"inquiet", -"inquire", -"inquiry", -"inring", -"inro", -"inroad", -"inroll", -"inrub", -"inrun", -"inrush", -"insack", -"insane", -"insculp", -"insea", -"inseam", -"insect", -"insee", -"inseer", -"insense", -"insert", -"inset", -"inshave", -"inshell", -"inship", -"inshoe", -"inshoot", -"inshore", -"inside", -"insider", -"insight", -"insigne", -"insipid", -"insist", -"insnare", -"insofar", -"insole", -"insolid", -"insooth", -"insorb", -"insoul", -"inspan", -"inspeak", -"inspect", -"inspire", -"inspoke", -"install", -"instant", -"instar", -"instate", -"instead", -"insteam", -"insteep", -"instep", -"instill", -"insula", -"insular", -"insulin", -"insulse", -"insult", -"insunk", -"insure", -"insured", -"insurer", -"insurge", -"inswamp", -"inswell", -"inswept", -"inswing", -"intact", -"intake", -"intaker", -"integer", -"inteind", -"intend", -"intense", -"intent", -"inter", -"interim", -"intern", -"intext", -"inthrow", -"intil", -"intima", -"intimal", -"intine", -"into", -"intoed", -"intone", -"intoner", -"intort", -"intown", -"intrada", -"intrait", -"intrant", -"intreat", -"intrine", -"introit", -"intrude", -"intruse", -"intrust", -"intube", -"intue", -"intuent", -"intuit", -"inturn", -"intwist", -"inula", -"inulase", -"inulin", -"inuloid", -"inunct", -"inure", -"inured", -"inurn", -"inutile", -"invade", -"invader", -"invalid", -"inveigh", -"inveil", -"invein", -"invent", -"inverse", -"invert", -"invest", -"invigor", -"invised", -"invital", -"invite", -"invitee", -"inviter", -"invivid", -"invoice", -"invoke", -"invoker", -"involve", -"inwale", -"inwall", -"inward", -"inwards", -"inweave", -"inweed", -"inwick", -"inwind", -"inwit", -"inwith", -"inwood", -"inwork", -"inworn", -"inwound", -"inwoven", -"inwrap", -"inwrit", -"inyoite", -"inyoke", -"io", -"iodate", -"iodic", -"iodide", -"iodine", -"iodism", -"iodite", -"iodize", -"iodizer", -"iodo", -"iodol", -"iodoso", -"iodous", -"iodoxy", -"iolite", -"ion", -"ionic", -"ionium", -"ionize", -"ionizer", -"ionogen", -"ionone", -"iota", -"iotize", -"ipecac", -"ipid", -"ipil", -"ipomea", -"ipseand", -"ipseity", -"iracund", -"irade", -"irate", -"irately", -"ire", -"ireful", -"ireless", -"irene", -"irenic", -"irenics", -"irian", -"irid", -"iridal", -"iridate", -"irides", -"iridial", -"iridian", -"iridic", -"iridin", -"iridine", -"iridite", -"iridium", -"iridize", -"iris", -"irised", -"irisin", -"iritic", -"iritis", -"irk", -"irksome", -"irok", -"iroko", -"iron", -"irone", -"ironer", -"ironice", -"ironish", -"ironism", -"ironist", -"ironize", -"ironly", -"ironman", -"irony", -"irrisor", -"irrupt", -"is", -"isagoge", -"isagon", -"isamine", -"isatate", -"isatic", -"isatide", -"isatin", -"isazoxy", -"isba", -"ischiac", -"ischial", -"ischium", -"ischury", -"iserine", -"iserite", -"isidium", -"isidoid", -"island", -"islandy", -"islay", -"isle", -"islet", -"isleted", -"islot", -"ism", -"ismal", -"ismatic", -"ismdom", -"ismy", -"iso", -"isoamyl", -"isobar", -"isobare", -"isobase", -"isobath", -"isochor", -"isocola", -"isocrat", -"isodont", -"isoflor", -"isogamy", -"isogen", -"isogeny", -"isogon", -"isogram", -"isohel", -"isohyet", -"isolate", -"isology", -"isomer", -"isomere", -"isomery", -"isoneph", -"isonomy", -"isonym", -"isonymy", -"isopag", -"isopod", -"isopoly", -"isoptic", -"isopyre", -"isotac", -"isotely", -"isotome", -"isotony", -"isotope", -"isotopy", -"isotron", -"isotype", -"isoxime", -"issei", -"issite", -"issuant", -"issue", -"issuer", -"issuing", -"ist", -"isthmi", -"isthmic", -"isthmus", -"istle", -"istoke", -"isuret", -"isuroid", -"it", -"itacism", -"itacist", -"italics", -"italite", -"itch", -"itching", -"itchy", -"itcze", -"item", -"iteming", -"itemize", -"itemy", -"iter", -"iterant", -"iterate", -"ither", -"itmo", -"itoubou", -"its", -"itself", -"iturite", -"itzebu", -"iva", -"ivied", -"ivin", -"ivoried", -"ivorine", -"ivorist", -"ivory", -"ivy", -"ivylike", -"ivyweed", -"ivywood", -"ivywort", -"iwa", -"iwaiwa", -"iwis", -"ixodian", -"ixodic", -"ixodid", -"iyo", -"izar", -"izard", -"izle", -"izote", -"iztle", -"izzard", -"j", -"jab", -"jabbed", -"jabber", -"jabbing", -"jabble", -"jabers", -"jabia", -"jabiru", -"jabot", -"jabul", -"jacal", -"jacamar", -"jacami", -"jacamin", -"jacana", -"jacare", -"jacate", -"jacchus", -"jacent", -"jacinth", -"jack", -"jackal", -"jackass", -"jackbox", -"jackboy", -"jackdaw", -"jackeen", -"jacker", -"jacket", -"jackety", -"jackleg", -"jackman", -"jacko", -"jackrod", -"jacksaw", -"jacktan", -"jacobus", -"jacoby", -"jaconet", -"jactant", -"jacu", -"jacuaru", -"jadder", -"jade", -"jaded", -"jadedly", -"jadeite", -"jadery", -"jadish", -"jady", -"jaeger", -"jag", -"jagat", -"jager", -"jagged", -"jagger", -"jaggery", -"jaggy", -"jagir", -"jagla", -"jagless", -"jagong", -"jagrata", -"jagua", -"jaguar", -"jail", -"jailage", -"jaildom", -"jailer", -"jailish", -"jajman", -"jake", -"jakes", -"jako", -"jalap", -"jalapa", -"jalapin", -"jalkar", -"jalopy", -"jalouse", -"jam", -"jama", -"jaman", -"jamb", -"jambeau", -"jambo", -"jambone", -"jambool", -"jambosa", -"jamdani", -"jami", -"jamlike", -"jammer", -"jammy", -"jampan", -"jampani", -"jamwood", -"janapa", -"janapan", -"jane", -"jangada", -"jangkar", -"jangle", -"jangler", -"jangly", -"janitor", -"jank", -"janker", -"jann", -"jannock", -"jantu", -"janua", -"jaob", -"jap", -"japan", -"jape", -"japer", -"japery", -"japing", -"japish", -"jaquima", -"jar", -"jara", -"jaragua", -"jarbird", -"jarble", -"jarbot", -"jarfly", -"jarful", -"jarg", -"jargon", -"jarkman", -"jarl", -"jarldom", -"jarless", -"jarnut", -"jarool", -"jarra", -"jarrah", -"jarring", -"jarry", -"jarvey", -"jasey", -"jaseyed", -"jasmine", -"jasmone", -"jasper", -"jaspery", -"jaspis", -"jaspoid", -"jass", -"jassid", -"jassoid", -"jatha", -"jati", -"jato", -"jaudie", -"jauk", -"jaun", -"jaunce", -"jaunder", -"jaunt", -"jauntie", -"jaunty", -"jaup", -"javali", -"javelin", -"javer", -"jaw", -"jawab", -"jawbone", -"jawed", -"jawfall", -"jawfish", -"jawfoot", -"jawless", -"jawy", -"jay", -"jayhawk", -"jaypie", -"jaywalk", -"jazz", -"jazzer", -"jazzily", -"jazzy", -"jealous", -"jean", -"jeans", -"jecoral", -"jecorin", -"jed", -"jedcock", -"jedding", -"jeddock", -"jeel", -"jeep", -"jeer", -"jeerer", -"jeering", -"jeery", -"jeff", -"jehu", -"jehup", -"jejunal", -"jejune", -"jejunum", -"jelab", -"jelick", -"jell", -"jellica", -"jellico", -"jellied", -"jellify", -"jellily", -"jelloid", -"jelly", -"jemadar", -"jemmily", -"jemmy", -"jenkin", -"jenna", -"jennet", -"jennier", -"jenny", -"jeofail", -"jeopard", -"jerboa", -"jereed", -"jerez", -"jerib", -"jerk", -"jerker", -"jerkily", -"jerkin", -"jerkish", -"jerky", -"jerl", -"jerm", -"jerque", -"jerquer", -"jerry", -"jersey", -"jert", -"jervia", -"jervina", -"jervine", -"jess", -"jessamy", -"jessant", -"jessed", -"jessur", -"jest", -"jestee", -"jester", -"jestful", -"jesting", -"jet", -"jetbead", -"jete", -"jetsam", -"jettage", -"jetted", -"jetter", -"jettied", -"jetton", -"jetty", -"jetware", -"jewbird", -"jewbush", -"jewel", -"jeweler", -"jewelry", -"jewely", -"jewfish", -"jezail", -"jeziah", -"jharal", -"jheel", -"jhool", -"jhow", -"jib", -"jibbah", -"jibber", -"jibby", -"jibe", -"jibhead", -"jibi", -"jibman", -"jiboa", -"jibstay", -"jicama", -"jicara", -"jiff", -"jiffle", -"jiffy", -"jig", -"jigger", -"jiggers", -"jigget", -"jiggety", -"jiggish", -"jiggle", -"jiggly", -"jiggy", -"jiglike", -"jigman", -"jihad", -"jikungu", -"jillet", -"jilt", -"jiltee", -"jilter", -"jiltish", -"jimbang", -"jimjam", -"jimmy", -"jimp", -"jimply", -"jina", -"jing", -"jingal", -"jingle", -"jingled", -"jingler", -"jinglet", -"jingly", -"jingo", -"jinja", -"jinjili", -"jink", -"jinker", -"jinket", -"jinkle", -"jinks", -"jinn", -"jinni", -"jinny", -"jinriki", -"jinx", -"jipper", -"jiqui", -"jirble", -"jirga", -"jiti", -"jitneur", -"jitney", -"jitro", -"jitter", -"jitters", -"jittery", -"jiva", -"jive", -"jixie", -"jo", -"job", -"jobade", -"jobarbe", -"jobber", -"jobbery", -"jobbet", -"jobbing", -"jobbish", -"jobble", -"jobless", -"jobman", -"jobo", -"joch", -"jock", -"jocker", -"jockey", -"jocko", -"jocoque", -"jocose", -"jocote", -"jocu", -"jocular", -"jocum", -"jocuma", -"jocund", -"jodel", -"jodelr", -"joe", -"joebush", -"joewood", -"joey", -"jog", -"jogger", -"joggle", -"joggler", -"joggly", -"johnin", -"join", -"joinant", -"joinder", -"joiner", -"joinery", -"joining", -"joint", -"jointed", -"jointer", -"jointly", -"jointy", -"joist", -"jojoba", -"joke", -"jokelet", -"joker", -"jokish", -"jokist", -"jokul", -"joky", -"joll", -"jollier", -"jollify", -"jollily", -"jollity", -"jollop", -"jolly", -"jolt", -"jolter", -"jolting", -"jolty", -"jonque", -"jonquil", -"joola", -"joom", -"jordan", -"joree", -"jorum", -"joseite", -"josh", -"josher", -"joshi", -"josie", -"joskin", -"joss", -"josser", -"jostle", -"jostler", -"jot", -"jota", -"jotisi", -"jotter", -"jotting", -"jotty", -"joubarb", -"joug", -"jough", -"jouk", -"joule", -"joulean", -"jounce", -"journal", -"journey", -"jours", -"joust", -"jouster", -"jovial", -"jow", -"jowar", -"jowari", -"jowel", -"jower", -"jowery", -"jowl", -"jowler", -"jowlish", -"jowlop", -"jowly", -"jowpy", -"jowser", -"jowter", -"joy", -"joyance", -"joyancy", -"joyant", -"joyful", -"joyhop", -"joyleaf", -"joyless", -"joylet", -"joyous", -"joysome", -"joyweed", -"juba", -"jubate", -"jubbah", -"jubbe", -"jube", -"jubilee", -"jubilus", -"juck", -"juckies", -"jud", -"judcock", -"judex", -"judge", -"judger", -"judices", -"judo", -"jufti", -"jug", -"jugal", -"jugale", -"jugate", -"jugated", -"juger", -"jugerum", -"jugful", -"jugger", -"juggins", -"juggle", -"juggler", -"juglone", -"jugular", -"jugulum", -"jugum", -"juice", -"juicily", -"juicy", -"jujitsu", -"juju", -"jujube", -"jujuism", -"jujuist", -"juke", -"jukebox", -"julep", -"julid", -"julidan", -"julio", -"juloid", -"julole", -"julolin", -"jumart", -"jumba", -"jumble", -"jumbler", -"jumbly", -"jumbo", -"jumbuck", -"jumby", -"jumelle", -"jument", -"jumfru", -"jumma", -"jump", -"jumper", -"jumpy", -"juncite", -"juncous", -"june", -"jungle", -"jungled", -"jungli", -"jungly", -"juniata", -"junior", -"juniper", -"junk", -"junker", -"junket", -"junking", -"junkman", -"junt", -"junta", -"junto", -"jupati", -"jupe", -"jupon", -"jural", -"jurally", -"jurant", -"jurara", -"jurat", -"jurator", -"jure", -"jurel", -"juridic", -"juring", -"jurist", -"juror", -"jury", -"juryman", -"jussel", -"jussion", -"jussive", -"jussory", -"just", -"justen", -"justice", -"justify", -"justly", -"justo", -"jut", -"jute", -"jutka", -"jutting", -"jutty", -"juvenal", -"juvia", -"juvite", -"jyngine", -"jynx", -"k", -"ka", -"kabaya", -"kabel", -"kaberu", -"kabiet", -"kabuki", -"kachin", -"kadaya", -"kadein", -"kados", -"kaffir", -"kafir", -"kafirin", -"kafiz", -"kafta", -"kago", -"kagu", -"kaha", -"kahar", -"kahau", -"kahili", -"kahu", -"kahuna", -"kai", -"kaid", -"kaik", -"kaikara", -"kail", -"kainga", -"kainite", -"kainsi", -"kainyn", -"kairine", -"kaiser", -"kaitaka", -"kaiwi", -"kajawah", -"kaka", -"kakapo", -"kakar", -"kaki", -"kakkak", -"kakke", -"kala", -"kalasie", -"kale", -"kalema", -"kalends", -"kali", -"kalian", -"kalium", -"kallah", -"kallege", -"kalo", -"kalon", -"kalong", -"kalpis", -"kamahi", -"kamala", -"kamansi", -"kamao", -"kamas", -"kamassi", -"kambal", -"kamboh", -"kame", -"kamerad", -"kamias", -"kamichi", -"kamik", -"kampong", -"kan", -"kana", -"kanae", -"kanagi", -"kanap", -"kanara", -"kanari", -"kanat", -"kanchil", -"kande", -"kandol", -"kaneh", -"kang", -"kanga", -"kangani", -"kankie", -"kannume", -"kanoon", -"kans", -"kantele", -"kanten", -"kaolin", -"kapa", -"kapai", -"kapeika", -"kapok", -"kapp", -"kappa", -"kappe", -"kapur", -"kaput", -"karagan", -"karaka", -"karakul", -"karamu", -"karaoke", -"karate", -"karaya", -"karbi", -"karch", -"kareao", -"kareeta", -"karela", -"karite", -"karma", -"karmic", -"karo", -"kaross", -"karou", -"karree", -"karri", -"karroo", -"karsha", -"karst", -"karstic", -"kartel", -"kartos", -"karwar", -"karyon", -"kasa", -"kasbah", -"kasbeke", -"kasher", -"kashga", -"kashi", -"kashima", -"kasida", -"kasm", -"kassu", -"kastura", -"kat", -"katar", -"katcina", -"kath", -"katha", -"kathal", -"katipo", -"katmon", -"katogle", -"katsup", -"katuka", -"katun", -"katurai", -"katydid", -"kauri", -"kava", -"kavaic", -"kavass", -"kawaka", -"kawika", -"kay", -"kayak", -"kayaker", -"kayles", -"kayo", -"kazi", -"kazoo", -"kea", -"keach", -"keacorn", -"keawe", -"keb", -"kebab", -"kebbie", -"kebbuck", -"kechel", -"keck", -"keckle", -"kecksy", -"kecky", -"ked", -"keddah", -"kedge", -"kedger", -"kedlock", -"keech", -"keek", -"keeker", -"keel", -"keelage", -"keeled", -"keeler", -"keelfat", -"keelie", -"keeling", -"keelman", -"keelson", -"keen", -"keena", -"keened", -"keener", -"keenly", -"keep", -"keeper", -"keeping", -"keest", -"keet", -"keeve", -"kef", -"keffel", -"kefir", -"kefiric", -"keg", -"kegler", -"kehaya", -"keita", -"keitloa", -"kekuna", -"kelchin", -"keld", -"kele", -"kelebe", -"keleh", -"kelek", -"kelep", -"kelk", -"kell", -"kella", -"kellion", -"kelly", -"keloid", -"kelp", -"kelper", -"kelpie", -"kelpy", -"kelt", -"kelter", -"kelty", -"kelvin", -"kemb", -"kemp", -"kempite", -"kemple", -"kempt", -"kempy", -"ken", -"kenaf", -"kenareh", -"kench", -"kend", -"kendir", -"kendyr", -"kenlore", -"kenmark", -"kennel", -"kenner", -"kenning", -"kenno", -"keno", -"kenosis", -"kenotic", -"kenspac", -"kent", -"kenyte", -"kep", -"kepi", -"kept", -"kerana", -"kerasin", -"kerat", -"keratin", -"keratto", -"kerchoo", -"kerchug", -"kerel", -"kerf", -"kerflap", -"kerflop", -"kermes", -"kermis", -"kern", -"kernel", -"kerner", -"kernish", -"kernite", -"kernos", -"kerogen", -"kerrie", -"kerril", -"kerrite", -"kerry", -"kersey", -"kerslam", -"kerugma", -"kerwham", -"kerygma", -"kestrel", -"ket", -"keta", -"ketal", -"ketch", -"ketchup", -"keten", -"ketene", -"ketipic", -"keto", -"ketogen", -"ketol", -"ketole", -"ketone", -"ketonic", -"ketose", -"ketosis", -"kette", -"ketting", -"kettle", -"kettler", -"ketty", -"ketuba", -"ketupa", -"ketyl", -"keup", -"kevalin", -"kevel", -"kewpie", -"kex", -"kexy", -"key", -"keyage", -"keyed", -"keyhole", -"keyless", -"keylet", -"keylock", -"keynote", -"keyway", -"khaddar", -"khadi", -"khahoon", -"khaiki", -"khair", -"khaja", -"khajur", -"khaki", -"khakied", -"khalifa", -"khalsa", -"khamsin", -"khan", -"khanate", -"khanda", -"khanjar", -"khanjee", -"khankah", -"khanum", -"khar", -"kharaj", -"kharua", -"khass", -"khat", -"khatib", -"khatri", -"khediva", -"khedive", -"khepesh", -"khet", -"khilat", -"khir", -"khirka", -"khoja", -"khoka", -"khot", -"khu", -"khubber", -"khula", -"khutbah", -"khvat", -"kiack", -"kiaki", -"kialee", -"kiang", -"kiaugh", -"kibber", -"kibble", -"kibbler", -"kibe", -"kibei", -"kibitka", -"kibitz", -"kiblah", -"kibosh", -"kiby", -"kick", -"kickee", -"kicker", -"kicking", -"kickish", -"kickoff", -"kickout", -"kickup", -"kidder", -"kiddier", -"kiddish", -"kiddush", -"kiddy", -"kidhood", -"kidlet", -"kidling", -"kidnap", -"kidney", -"kidskin", -"kidsman", -"kiekie", -"kiel", -"kier", -"kieye", -"kikar", -"kike", -"kiki", -"kiku", -"kikuel", -"kikumon", -"kil", -"kiladja", -"kilah", -"kilan", -"kildee", -"kileh", -"kilerg", -"kiley", -"kilhig", -"kiliare", -"kilim", -"kill", -"killas", -"killcu", -"killeen", -"killer", -"killick", -"killing", -"killy", -"kiln", -"kilneye", -"kilnman", -"kilnrib", -"kilo", -"kilobar", -"kiloton", -"kilovar", -"kilp", -"kilt", -"kilter", -"kiltie", -"kilting", -"kim", -"kimbang", -"kimnel", -"kimono", -"kin", -"kina", -"kinah", -"kinase", -"kinbote", -"kinch", -"kinchin", -"kincob", -"kind", -"kindle", -"kindler", -"kindly", -"kindred", -"kinepox", -"kinesic", -"kinesis", -"kinetic", -"king", -"kingcob", -"kingcup", -"kingdom", -"kinglet", -"kingly", -"kingpin", -"kingrow", -"kink", -"kinkhab", -"kinkily", -"kinkle", -"kinkled", -"kinkly", -"kinky", -"kinless", -"kino", -"kinship", -"kinsman", -"kintar", -"kioea", -"kiosk", -"kiotome", -"kip", -"kipage", -"kipe", -"kippeen", -"kipper", -"kippy", -"kipsey", -"kipskin", -"kiri", -"kirimon", -"kirk", -"kirker", -"kirkify", -"kirking", -"kirkman", -"kirmew", -"kirn", -"kirombo", -"kirsch", -"kirtle", -"kirtled", -"kirve", -"kirver", -"kischen", -"kish", -"kishen", -"kishon", -"kishy", -"kismet", -"kisra", -"kiss", -"kissage", -"kissar", -"kisser", -"kissing", -"kissy", -"kist", -"kistful", -"kiswa", -"kit", -"kitab", -"kitabis", -"kitar", -"kitcat", -"kitchen", -"kite", -"kith", -"kithe", -"kitish", -"kitling", -"kittel", -"kitten", -"kitter", -"kittle", -"kittles", -"kittly", -"kittock", -"kittul", -"kitty", -"kiva", -"kiver", -"kivu", -"kiwi", -"kiyas", -"kiyi", -"klafter", -"klam", -"klavern", -"klaxon", -"klepht", -"kleptic", -"klicket", -"klip", -"klipbok", -"klipdas", -"klippe", -"klippen", -"klister", -"klom", -"klop", -"klops", -"klosh", -"kmet", -"knab", -"knabble", -"knack", -"knacker", -"knacky", -"knag", -"knagged", -"knaggy", -"knap", -"knape", -"knappan", -"knapper", -"knar", -"knark", -"knarred", -"knarry", -"knave", -"knavery", -"knavess", -"knavish", -"knawel", -"knead", -"kneader", -"knee", -"kneecap", -"kneed", -"kneel", -"kneeler", -"kneelet", -"kneepad", -"kneepan", -"knell", -"knelt", -"knet", -"knew", -"knez", -"knezi", -"kniaz", -"kniazi", -"knick", -"knicker", -"knife", -"knifer", -"knight", -"knit", -"knitch", -"knitted", -"knitter", -"knittle", -"knived", -"knivey", -"knob", -"knobbed", -"knobber", -"knobble", -"knobbly", -"knobby", -"knock", -"knocker", -"knockup", -"knoll", -"knoller", -"knolly", -"knop", -"knopite", -"knopped", -"knopper", -"knoppy", -"knosp", -"knosped", -"knot", -"knotted", -"knotter", -"knotty", -"knout", -"know", -"knowe", -"knower", -"knowing", -"known", -"knub", -"knubbly", -"knubby", -"knublet", -"knuckle", -"knuckly", -"knur", -"knurl", -"knurled", -"knurly", -"knut", -"knutty", -"knyaz", -"knyazi", -"ko", -"koa", -"koae", -"koala", -"koali", -"kob", -"koban", -"kobi", -"kobird", -"kobold", -"kobong", -"kobu", -"koda", -"kodak", -"kodaker", -"kodakry", -"kodro", -"koel", -"koff", -"koft", -"koftgar", -"kohemp", -"kohl", -"kohua", -"koi", -"koil", -"koila", -"koilon", -"koine", -"koinon", -"kojang", -"kokako", -"kokam", -"kokan", -"kokil", -"kokio", -"koklas", -"koklass", -"koko", -"kokoon", -"kokowai", -"kokra", -"koku", -"kokum", -"kokumin", -"kola", -"kolach", -"kolea", -"kolhoz", -"kolkhos", -"kolkhoz", -"kollast", -"koller", -"kolo", -"kolobus", -"kolsun", -"komatik", -"kombu", -"kommos", -"kompeni", -"kon", -"kona", -"konak", -"kongoni", -"kongu", -"konini", -"konjak", -"kooka", -"kookery", -"kookri", -"koolah", -"koombar", -"koomkie", -"kootcha", -"kop", -"kopeck", -"koph", -"kopi", -"koppa", -"koppen", -"koppite", -"kor", -"kora", -"koradji", -"korait", -"korakan", -"korari", -"kore", -"korec", -"koreci", -"korero", -"kori", -"korin", -"korona", -"korova", -"korrel", -"koruna", -"korzec", -"kos", -"kosher", -"kosin", -"kosong", -"koswite", -"kotal", -"koto", -"kotuku", -"kotwal", -"kotyle", -"kotylos", -"kou", -"koulan", -"kouza", -"kovil", -"kowhai", -"kowtow", -"koyan", -"kozo", -"kra", -"kraal", -"kraft", -"krait", -"kraken", -"kral", -"krama", -"kran", -"kras", -"krasis", -"krausen", -"kraut", -"kreis", -"krelos", -"kremlin", -"krems", -"kreng", -"krieker", -"krimmer", -"krina", -"krocket", -"krome", -"krona", -"krone", -"kronen", -"kroner", -"kronor", -"kronur", -"kroon", -"krosa", -"krypsis", -"kryptic", -"kryptol", -"krypton", -"kuan", -"kuba", -"kubba", -"kuchen", -"kudize", -"kudos", -"kudu", -"kudzu", -"kuei", -"kuge", -"kugel", -"kuichua", -"kukri", -"kuku", -"kukui", -"kukupa", -"kula", -"kulack", -"kulah", -"kulaite", -"kulak", -"kulang", -"kulimit", -"kulm", -"kulmet", -"kumbi", -"kumhar", -"kumiss", -"kummel", -"kumquat", -"kumrah", -"kunai", -"kung", -"kunk", -"kunkur", -"kunzite", -"kuphar", -"kupper", -"kurbash", -"kurgan", -"kuruma", -"kurung", -"kurus", -"kurvey", -"kusa", -"kusam", -"kusha", -"kuskite", -"kuskos", -"kuskus", -"kusti", -"kusum", -"kutcha", -"kuttab", -"kuttar", -"kuttaur", -"kuvasz", -"kvass", -"kvint", -"kvinter", -"kwamme", -"kwan", -"kwarta", -"kwazoku", -"kyack", -"kyah", -"kyar", -"kyat", -"kyaung", -"kyl", -"kyle", -"kylite", -"kylix", -"kyrine", -"kyte", -"l", -"la", -"laager", -"laang", -"lab", -"labara", -"labarum", -"labba", -"labber", -"labefy", -"label", -"labeler", -"labella", -"labia", -"labial", -"labiate", -"labile", -"labiose", -"labis", -"labium", -"lablab", -"labor", -"labored", -"laborer", -"labour", -"labra", -"labral", -"labret", -"labroid", -"labrose", -"labrum", -"labrys", -"lac", -"lacca", -"laccaic", -"laccase", -"laccol", -"lace", -"laced", -"laceman", -"lacepod", -"lacer", -"lacery", -"lacet", -"lache", -"laches", -"lachsa", -"lacily", -"lacing", -"lacinia", -"lacis", -"lack", -"lacker", -"lackey", -"lackwit", -"lacmoid", -"lacmus", -"laconic", -"lacquer", -"lacrym", -"lactam", -"lactant", -"lactary", -"lactase", -"lactate", -"lacteal", -"lactean", -"lactic", -"lactid", -"lactide", -"lactify", -"lactim", -"lacto", -"lactoid", -"lactol", -"lactone", -"lactose", -"lactyl", -"lacuna", -"lacunae", -"lacunal", -"lacunar", -"lacune", -"lacwork", -"lacy", -"lad", -"ladakin", -"ladanum", -"ladder", -"laddery", -"laddess", -"laddie", -"laddish", -"laddock", -"lade", -"lademan", -"laden", -"lader", -"ladhood", -"ladies", -"ladify", -"lading", -"ladkin", -"ladle", -"ladler", -"ladrone", -"lady", -"ladybug", -"ladydom", -"ladyfly", -"ladyfy", -"ladyish", -"ladyism", -"ladykin", -"ladyly", -"laet", -"laeti", -"laetic", -"lag", -"lagan", -"lagarto", -"lagen", -"lagena", -"lagend", -"lager", -"lagetto", -"laggar", -"laggard", -"lagged", -"laggen", -"lagger", -"laggin", -"lagging", -"laglast", -"lagna", -"lagoon", -"lagwort", -"lai", -"laic", -"laical", -"laich", -"laicism", -"laicity", -"laicize", -"laid", -"laigh", -"lain", -"laine", -"laiose", -"lair", -"lairage", -"laird", -"lairdie", -"lairdly", -"lairman", -"lairy", -"laity", -"lak", -"lakatoi", -"lake", -"lakelet", -"laker", -"lakie", -"laking", -"lakish", -"lakism", -"lakist", -"laky", -"lalang", -"lall", -"lalling", -"lalo", -"lam", -"lama", -"lamaic", -"lamany", -"lamb", -"lamba", -"lambale", -"lambda", -"lambeau", -"lambent", -"lamber", -"lambert", -"lambie", -"lambish", -"lambkin", -"lambly", -"lamboys", -"lamby", -"lame", -"lamedh", -"lamel", -"lamella", -"lamely", -"lament", -"lameter", -"lametta", -"lamia", -"lamiger", -"lamiid", -"lamin", -"lamina", -"laminae", -"laminar", -"lamish", -"lamiter", -"lammas", -"lammer", -"lammock", -"lammy", -"lamnid", -"lamnoid", -"lamp", -"lampad", -"lampas", -"lamper", -"lampern", -"lampers", -"lampfly", -"lampful", -"lamping", -"lampion", -"lampist", -"lamplet", -"lamplit", -"lampman", -"lampoon", -"lamprey", -"lan", -"lanas", -"lanate", -"lanated", -"lanaz", -"lance", -"lanced", -"lancely", -"lancer", -"lances", -"lancet", -"lancha", -"land", -"landau", -"landed", -"lander", -"landing", -"landman", -"landmil", -"lane", -"lanete", -"laneway", -"laney", -"langaha", -"langca", -"langi", -"langite", -"langle", -"langoon", -"langsat", -"langued", -"languet", -"languid", -"languor", -"langur", -"laniary", -"laniate", -"lanific", -"lanioid", -"lanista", -"lank", -"lanket", -"lankily", -"lankish", -"lankly", -"lanky", -"lanner", -"lanolin", -"lanose", -"lansat", -"lanseh", -"lanson", -"lant", -"lantaca", -"lantern", -"lantum", -"lanugo", -"lanum", -"lanx", -"lanyard", -"lap", -"lapacho", -"lapcock", -"lapel", -"lapeler", -"lapful", -"lapillo", -"lapon", -"lappage", -"lapped", -"lapper", -"lappet", -"lapping", -"lapse", -"lapsed", -"lapser", -"lapsi", -"lapsing", -"lapwing", -"lapwork", -"laquear", -"laqueus", -"lar", -"larceny", -"larch", -"larchen", -"lard", -"larder", -"lardite", -"lardon", -"lardy", -"large", -"largely", -"largen", -"largess", -"largish", -"largo", -"lari", -"lariat", -"larick", -"larid", -"larigo", -"larigot", -"lariid", -"larin", -"larine", -"larixin", -"lark", -"larker", -"larking", -"larkish", -"larky", -"larmier", -"larnax", -"laroid", -"larrup", -"larry", -"larva", -"larvae", -"larval", -"larvate", -"larve", -"larvule", -"larynx", -"las", -"lasa", -"lascar", -"laser", -"lash", -"lasher", -"lask", -"lasket", -"lasque", -"lass", -"lasset", -"lassie", -"lasso", -"lassock", -"lassoer", -"last", -"lastage", -"laster", -"lasting", -"lastly", -"lastre", -"lasty", -"lat", -"lata", -"latah", -"latch", -"latcher", -"latchet", -"late", -"latebra", -"lated", -"lateen", -"lately", -"laten", -"latence", -"latency", -"latent", -"later", -"latera", -"laterad", -"lateral", -"latest", -"latex", -"lath", -"lathe", -"lathee", -"lathen", -"lather", -"lathery", -"lathing", -"lathy", -"latices", -"latigo", -"lation", -"latish", -"latitat", -"latite", -"latomy", -"latrant", -"latria", -"latrine", -"latro", -"latrobe", -"latron", -"latten", -"latter", -"lattice", -"latus", -"lauan", -"laud", -"lauder", -"laudist", -"laugh", -"laughee", -"laugher", -"laughy", -"lauia", -"laun", -"launce", -"launch", -"laund", -"launder", -"laundry", -"laur", -"laura", -"laurate", -"laurel", -"lauric", -"laurin", -"laurite", -"laurone", -"lauryl", -"lava", -"lavable", -"lavabo", -"lavacre", -"lavage", -"lavanga", -"lavant", -"lavaret", -"lavatic", -"lave", -"laveer", -"laver", -"lavic", -"lavish", -"lavolta", -"law", -"lawbook", -"lawful", -"lawing", -"lawish", -"lawk", -"lawless", -"lawlike", -"lawman", -"lawn", -"lawned", -"lawner", -"lawnlet", -"lawny", -"lawsuit", -"lawter", -"lawyer", -"lawyery", -"lawzy", -"lax", -"laxate", -"laxism", -"laxist", -"laxity", -"laxly", -"laxness", -"lay", -"layaway", -"layback", -"layboy", -"layer", -"layered", -"layery", -"layette", -"laying", -"layland", -"layman", -"layne", -"layoff", -"layout", -"layover", -"layship", -"laystow", -"lazar", -"lazaret", -"lazarly", -"laze", -"lazily", -"lazule", -"lazuli", -"lazy", -"lazyish", -"lea", -"leach", -"leacher", -"leachy", -"lead", -"leadage", -"leaded", -"leaden", -"leader", -"leadin", -"leading", -"leadman", -"leadoff", -"leadout", -"leadway", -"leady", -"leaf", -"leafage", -"leafboy", -"leafcup", -"leafdom", -"leafed", -"leafen", -"leafer", -"leafery", -"leafit", -"leaflet", -"leafy", -"league", -"leaguer", -"leak", -"leakage", -"leaker", -"leaky", -"leal", -"lealand", -"leally", -"lealty", -"leam", -"leamer", -"lean", -"leaner", -"leaning", -"leanish", -"leanly", -"leant", -"leap", -"leaper", -"leaping", -"leapt", -"lear", -"learn", -"learned", -"learner", -"learnt", -"lease", -"leaser", -"leash", -"leasing", -"leasow", -"least", -"leat", -"leath", -"leather", -"leatman", -"leave", -"leaved", -"leaven", -"leaver", -"leaves", -"leaving", -"leavy", -"leawill", -"leban", -"lebbek", -"lecama", -"lech", -"lecher", -"lechery", -"lechwe", -"leck", -"lecker", -"lectern", -"lection", -"lector", -"lectual", -"lecture", -"lecyth", -"led", -"lede", -"leden", -"ledge", -"ledged", -"ledger", -"ledging", -"ledgy", -"ledol", -"lee", -"leech", -"leecher", -"leeches", -"leed", -"leefang", -"leek", -"leekish", -"leeky", -"leep", -"leepit", -"leer", -"leerily", -"leerish", -"leery", -"lees", -"leet", -"leetman", -"leewan", -"leeward", -"leeway", -"leewill", -"left", -"leftish", -"leftism", -"leftist", -"leg", -"legacy", -"legal", -"legally", -"legate", -"legatee", -"legato", -"legator", -"legend", -"legenda", -"leger", -"leges", -"legged", -"legger", -"legging", -"leggy", -"leghorn", -"legible", -"legibly", -"legific", -"legion", -"legist", -"legit", -"legitim", -"leglen", -"legless", -"leglet", -"leglike", -"legman", -"legoa", -"legpull", -"legrope", -"legua", -"leguan", -"legume", -"legumen", -"legumin", -"lehr", -"lehrman", -"lehua", -"lei", -"leister", -"leisure", -"lek", -"lekach", -"lekane", -"lekha", -"leman", -"lemel", -"lemma", -"lemmata", -"lemming", -"lemnad", -"lemon", -"lemony", -"lempira", -"lemur", -"lemures", -"lemurid", -"lenad", -"lenard", -"lench", -"lend", -"lendee", -"lender", -"lene", -"length", -"lengthy", -"lenient", -"lenify", -"lenis", -"lenitic", -"lenity", -"lennow", -"leno", -"lens", -"lensed", -"lent", -"lenth", -"lentigo", -"lentil", -"lentisc", -"lentisk", -"lento", -"lentoid", -"lentor", -"lentous", -"lenvoi", -"lenvoy", -"leonine", -"leonite", -"leopard", -"leotard", -"lepa", -"leper", -"lepered", -"leporid", -"lepra", -"lepric", -"leproid", -"leproma", -"leprose", -"leprosy", -"leprous", -"leptid", -"leptite", -"leptome", -"lepton", -"leptus", -"lerot", -"lerp", -"lerret", -"lesche", -"lesion", -"lesiy", -"less", -"lessee", -"lessen", -"lesser", -"lessive", -"lessn", -"lesson", -"lessor", -"lest", -"lestrad", -"let", -"letch", -"letchy", -"letdown", -"lete", -"lethal", -"letoff", -"letten", -"letter", -"lettrin", -"lettuce", -"letup", -"leu", -"leuch", -"leucine", -"leucism", -"leucite", -"leuco", -"leucoid", -"leucoma", -"leucon", -"leucous", -"leucyl", -"leud", -"leuk", -"leuma", -"lev", -"levance", -"levant", -"levator", -"levee", -"level", -"leveler", -"levelly", -"lever", -"leverer", -"leveret", -"levers", -"levier", -"levin", -"levir", -"levity", -"levo", -"levulic", -"levulin", -"levy", -"levyist", -"lew", -"lewd", -"lewdly", -"lewis", -"lewth", -"lexia", -"lexical", -"lexicon", -"ley", -"leyland", -"leysing", -"li", -"liable", -"liaison", -"liana", -"liang", -"liar", -"liard", -"libant", -"libate", -"libber", -"libbet", -"libbra", -"libel", -"libelee", -"libeler", -"liber", -"liberal", -"liberty", -"libido", -"libken", -"libra", -"libral", -"library", -"librate", -"licca", -"license", -"lich", -"licham", -"lichen", -"licheny", -"lichi", -"licit", -"licitly", -"lick", -"licker", -"licking", -"licorn", -"licorne", -"lictor", -"lid", -"lidded", -"lidder", -"lidgate", -"lidless", -"lie", -"lied", -"lief", -"liege", -"liegely", -"lieger", -"lien", -"lienal", -"lienee", -"lienic", -"lienor", -"lier", -"lierne", -"lierre", -"liesh", -"lieu", -"lieue", -"lieve", -"life", -"lifeday", -"lifeful", -"lifelet", -"lifer", -"lifey", -"lifo", -"lift", -"lifter", -"lifting", -"liftman", -"ligable", -"ligas", -"ligate", -"ligator", -"ligger", -"light", -"lighten", -"lighter", -"lightly", -"ligne", -"lignify", -"lignin", -"lignite", -"lignone", -"lignose", -"lignum", -"ligula", -"ligular", -"ligule", -"ligulin", -"ligure", -"liin", -"lija", -"likable", -"like", -"likely", -"liken", -"liker", -"likin", -"liking", -"liknon", -"lilac", -"lilacin", -"lilacky", -"lile", -"lilied", -"lill", -"lilt", -"lily", -"lilyfy", -"lim", -"limacel", -"limacon", -"liman", -"limb", -"limbal", -"limbat", -"limbate", -"limbeck", -"limbed", -"limber", -"limbers", -"limbic", -"limbie", -"limbo", -"limbous", -"limbus", -"limby", -"lime", -"limeade", -"limeman", -"limen", -"limer", -"limes", -"limetta", -"limey", -"liminal", -"liming", -"limit", -"limital", -"limited", -"limiter", -"limma", -"limmer", -"limmock", -"limmu", -"limn", -"limner", -"limnery", -"limniad", -"limnite", -"limoid", -"limonin", -"limose", -"limous", -"limp", -"limper", -"limpet", -"limpid", -"limpily", -"limpin", -"limping", -"limpish", -"limpkin", -"limply", -"limpsy", -"limpy", -"limsy", -"limu", -"limulid", -"limy", -"lin", -"lina", -"linable", -"linaga", -"linage", -"linaloa", -"linalol", -"linch", -"linchet", -"linctus", -"lindane", -"linden", -"linder", -"lindo", -"line", -"linea", -"lineage", -"lineal", -"linear", -"lineate", -"linecut", -"lined", -"linelet", -"lineman", -"linen", -"liner", -"ling", -"linga", -"linge", -"lingel", -"linger", -"lingo", -"lingtow", -"lingua", -"lingual", -"linguet", -"lingula", -"lingy", -"linha", -"linhay", -"linie", -"linin", -"lining", -"linitis", -"liniya", -"linja", -"linje", -"link", -"linkage", -"linkboy", -"linked", -"linker", -"linking", -"linkman", -"links", -"linky", -"linn", -"linnet", -"lino", -"linolic", -"linolin", -"linon", -"linous", -"linoxin", -"linoxyn", -"linpin", -"linseed", -"linsey", -"lint", -"lintel", -"linten", -"linter", -"lintern", -"lintie", -"linty", -"linwood", -"liny", -"lion", -"lioncel", -"lionel", -"lioness", -"lionet", -"lionism", -"lionize", -"lionly", -"lip", -"lipa", -"liparid", -"lipase", -"lipemia", -"lipide", -"lipin", -"lipless", -"liplet", -"liplike", -"lipoid", -"lipoma", -"lipopod", -"liposis", -"lipped", -"lippen", -"lipper", -"lipping", -"lippy", -"lipuria", -"lipwork", -"liquate", -"liquefy", -"liqueur", -"liquid", -"liquidy", -"liquor", -"lira", -"lirate", -"lire", -"lirella", -"lis", -"lisere", -"lish", -"lisk", -"lisle", -"lisp", -"lisper", -"lispund", -"liss", -"lissom", -"lissome", -"list", -"listed", -"listel", -"listen", -"lister", -"listing", -"listred", -"lit", -"litany", -"litas", -"litch", -"litchi", -"lite", -"liter", -"literal", -"lith", -"lithe", -"lithely", -"lithi", -"lithia", -"lithic", -"lithify", -"lithite", -"lithium", -"litho", -"lithoid", -"lithous", -"lithy", -"litmus", -"litotes", -"litra", -"litster", -"litten", -"litter", -"littery", -"little", -"lituite", -"liturgy", -"litus", -"lituus", -"litz", -"livable", -"live", -"lived", -"livedo", -"lively", -"liven", -"liver", -"livered", -"livery", -"livid", -"lividly", -"livier", -"living", -"livor", -"livre", -"liwan", -"lixive", -"lizard", -"llama", -"llano", -"llautu", -"llyn", -"lo", -"loa", -"loach", -"load", -"loadage", -"loaded", -"loaden", -"loader", -"loading", -"loaf", -"loafer", -"loafing", -"loaflet", -"loam", -"loamily", -"loaming", -"loamy", -"loan", -"loaner", -"loanin", -"loath", -"loathe", -"loather", -"loathly", -"loave", -"lob", -"lobal", -"lobar", -"lobate", -"lobated", -"lobber", -"lobbish", -"lobby", -"lobbyer", -"lobcock", -"lobe", -"lobed", -"lobelet", -"lobelin", -"lobfig", -"lobing", -"lobiped", -"lobo", -"lobola", -"lobose", -"lobster", -"lobtail", -"lobular", -"lobule", -"lobworm", -"loca", -"locable", -"local", -"locale", -"locally", -"locanda", -"locate", -"locator", -"loch", -"lochage", -"lochan", -"lochia", -"lochial", -"lochus", -"lochy", -"loci", -"lock", -"lockage", -"lockbox", -"locked", -"locker", -"locket", -"lockful", -"locking", -"lockjaw", -"locklet", -"lockman", -"lockout", -"lockpin", -"lockram", -"lockup", -"locky", -"loco", -"locoism", -"locular", -"locule", -"loculus", -"locum", -"locus", -"locust", -"locusta", -"locutor", -"lod", -"lode", -"lodge", -"lodged", -"lodger", -"lodging", -"loess", -"loessal", -"loessic", -"lof", -"loft", -"lofter", -"loftily", -"lofting", -"loftman", -"lofty", -"log", -"loganin", -"logbook", -"logcock", -"loge", -"logeion", -"logeum", -"loggat", -"logged", -"logger", -"loggia", -"loggin", -"logging", -"loggish", -"loghead", -"logia", -"logic", -"logical", -"logie", -"login", -"logion", -"logium", -"loglet", -"loglike", -"logman", -"logoi", -"logos", -"logroll", -"logway", -"logwise", -"logwood", -"logwork", -"logy", -"lohan", -"lohoch", -"loimic", -"loin", -"loined", -"loir", -"loiter", -"loka", -"lokao", -"lokaose", -"loke", -"loket", -"lokiec", -"loll", -"loller", -"lollop", -"lollopy", -"lolly", -"loma", -"lombard", -"lomboy", -"loment", -"lomita", -"lommock", -"lone", -"lonely", -"long", -"longa", -"longan", -"longbow", -"longe", -"longear", -"longer", -"longfin", -"longful", -"longing", -"longish", -"longjaw", -"longly", -"longs", -"longue", -"longway", -"lontar", -"loo", -"looby", -"lood", -"loof", -"loofah", -"loofie", -"look", -"looker", -"looking", -"lookout", -"lookum", -"loom", -"loomer", -"loomery", -"looming", -"loon", -"loonery", -"looney", -"loony", -"loop", -"looper", -"loopful", -"looping", -"loopist", -"looplet", -"loopy", -"loose", -"loosely", -"loosen", -"looser", -"loosing", -"loosish", -"loot", -"looten", -"looter", -"lootie", -"lop", -"lope", -"loper", -"lophiid", -"lophine", -"loppard", -"lopper", -"loppet", -"lopping", -"loppy", -"lopseed", -"loquat", -"loquent", -"lora", -"loral", -"loran", -"lorate", -"lorcha", -"lord", -"lording", -"lordkin", -"lordlet", -"lordly", -"lordy", -"lore", -"loreal", -"lored", -"lori", -"loric", -"lorica", -"lorilet", -"lorimer", -"loriot", -"loris", -"lormery", -"lorn", -"loro", -"lorry", -"lors", -"lorum", -"lory", -"losable", -"lose", -"losel", -"loser", -"losh", -"losing", -"loss", -"lost", -"lot", -"lota", -"lotase", -"lote", -"lotic", -"lotion", -"lotment", -"lotrite", -"lots", -"lotter", -"lottery", -"lotto", -"lotus", -"lotusin", -"louch", -"loud", -"louden", -"loudish", -"loudly", -"louey", -"lough", -"louk", -"loukoum", -"loulu", -"lounder", -"lounge", -"lounger", -"loungy", -"loup", -"loupe", -"lour", -"lourdy", -"louse", -"lousily", -"louster", -"lousy", -"lout", -"louter", -"louther", -"loutish", -"louty", -"louvar", -"louver", -"lovable", -"lovably", -"lovage", -"love", -"loveful", -"lovely", -"loveman", -"lover", -"lovered", -"loverly", -"loving", -"low", -"lowa", -"lowan", -"lowbell", -"lowborn", -"lowboy", -"lowbred", -"lowdah", -"lowder", -"loweite", -"lower", -"lowerer", -"lowery", -"lowish", -"lowland", -"lowlily", -"lowly", -"lowmen", -"lowmost", -"lown", -"lowness", -"lownly", -"lowth", -"lowwood", -"lowy", -"lox", -"loxia", -"loxic", -"loxotic", -"loy", -"loyal", -"loyally", -"loyalty", -"lozenge", -"lozengy", -"lubber", -"lube", -"lubra", -"lubric", -"lubrify", -"lucanid", -"lucarne", -"lucban", -"luce", -"lucence", -"lucency", -"lucent", -"lucern", -"lucerne", -"lucet", -"lucible", -"lucid", -"lucida", -"lucidly", -"lucifee", -"lucific", -"lucigen", -"lucivee", -"luck", -"lucken", -"luckful", -"luckie", -"luckily", -"lucky", -"lucre", -"lucrify", -"lucule", -"lucumia", -"lucy", -"ludden", -"ludibry", -"ludo", -"lue", -"lues", -"luetic", -"lufbery", -"luff", -"lug", -"luge", -"luger", -"luggage", -"luggar", -"lugged", -"lugger", -"luggie", -"lugmark", -"lugsail", -"lugsome", -"lugworm", -"luhinga", -"luigino", -"luke", -"lukely", -"lulab", -"lull", -"lullaby", -"luller", -"lulu", -"lum", -"lumbago", -"lumbang", -"lumbar", -"lumber", -"lumen", -"luminal", -"lumine", -"lummox", -"lummy", -"lump", -"lumper", -"lumpet", -"lumpily", -"lumping", -"lumpish", -"lumpkin", -"lumpman", -"lumpy", -"luna", -"lunacy", -"lunar", -"lunare", -"lunary", -"lunate", -"lunatic", -"lunatum", -"lunch", -"luncher", -"lune", -"lunes", -"lunette", -"lung", -"lunge", -"lunged", -"lunger", -"lungful", -"lungi", -"lungie", -"lungis", -"lungy", -"lunn", -"lunoid", -"lunt", -"lunula", -"lunular", -"lunule", -"lunulet", -"lupe", -"lupeol", -"lupeose", -"lupine", -"lupinin", -"lupis", -"lupoid", -"lupous", -"lupulic", -"lupulin", -"lupulus", -"lupus", -"lura", -"lural", -"lurch", -"lurcher", -"lurdan", -"lure", -"lureful", -"lurer", -"lurg", -"lurid", -"luridly", -"lurk", -"lurker", -"lurky", -"lurrier", -"lurry", -"lush", -"lusher", -"lushly", -"lushy", -"lusk", -"lusky", -"lusory", -"lust", -"luster", -"lustful", -"lustily", -"lustra", -"lustral", -"lustrum", -"lusty", -"lut", -"lutany", -"lute", -"luteal", -"lutecia", -"lutein", -"lutelet", -"luteo", -"luteoma", -"luteous", -"luter", -"luteway", -"lutfisk", -"luthern", -"luthier", -"luting", -"lutist", -"lutose", -"lutrin", -"lutrine", -"lux", -"luxate", -"luxe", -"luxury", -"luxus", -"ly", -"lyam", -"lyard", -"lyceal", -"lyceum", -"lycid", -"lycopin", -"lycopod", -"lycosid", -"lyctid", -"lyddite", -"lydite", -"lye", -"lyery", -"lygaeid", -"lying", -"lyingly", -"lymph", -"lymphad", -"lymphy", -"lyncean", -"lynch", -"lyncher", -"lyncine", -"lynx", -"lyra", -"lyrate", -"lyrated", -"lyraway", -"lyre", -"lyreman", -"lyric", -"lyrical", -"lyrism", -"lyrist", -"lys", -"lysate", -"lyse", -"lysin", -"lysine", -"lysis", -"lysogen", -"lyssa", -"lyssic", -"lytic", -"lytta", -"lyxose", -"m", -"ma", -"maam", -"mabi", -"mabolo", -"mac", -"macabre", -"macaco", -"macadam", -"macan", -"macana", -"macao", -"macaque", -"macaw", -"macco", -"mace", -"maceman", -"macer", -"machan", -"machar", -"machete", -"machi", -"machila", -"machin", -"machine", -"machree", -"macies", -"mack", -"mackins", -"mackle", -"macle", -"macled", -"maco", -"macrame", -"macro", -"macron", -"macuca", -"macula", -"macular", -"macule", -"macuta", -"mad", -"madam", -"madame", -"madcap", -"madden", -"madder", -"madding", -"maddish", -"maddle", -"made", -"madefy", -"madhuca", -"madid", -"madling", -"madly", -"madman", -"madnep", -"madness", -"mado", -"madoqua", -"madrier", -"madrona", -"madship", -"maduro", -"madweed", -"madwort", -"mae", -"maenad", -"maestri", -"maestro", -"maffia", -"maffick", -"maffle", -"mafflin", -"mafic", -"mafoo", -"mafura", -"mag", -"magadis", -"magani", -"magas", -"mage", -"magenta", -"magged", -"maggle", -"maggot", -"maggoty", -"magi", -"magic", -"magical", -"magiric", -"magma", -"magnate", -"magnes", -"magnet", -"magneta", -"magneto", -"magnify", -"magnum", -"magot", -"magpie", -"magpied", -"magsman", -"maguari", -"maguey", -"maha", -"mahaleb", -"mahalla", -"mahant", -"mahar", -"maharao", -"mahatma", -"mahmal", -"mahmudi", -"mahoe", -"maholi", -"mahone", -"mahout", -"mahseer", -"mahua", -"mahuang", -"maid", -"maidan", -"maiden", -"maidish", -"maidism", -"maidkin", -"maidy", -"maiefic", -"maigre", -"maiid", -"mail", -"mailbag", -"mailbox", -"mailed", -"mailer", -"mailie", -"mailman", -"maim", -"maimed", -"maimer", -"maimon", -"main", -"mainly", -"mainour", -"mainpin", -"mains", -"maint", -"maintop", -"maioid", -"maire", -"maize", -"maizer", -"majagua", -"majesty", -"majo", -"majoon", -"major", -"makable", -"make", -"makedom", -"maker", -"makhzan", -"maki", -"making", -"makluk", -"mako", -"makuk", -"mal", -"mala", -"malacia", -"malacon", -"malady", -"malagma", -"malaise", -"malakin", -"malambo", -"malanga", -"malapi", -"malar", -"malaria", -"malarin", -"malate", -"malati", -"malax", -"malduck", -"male", -"malease", -"maleate", -"maleic", -"malella", -"maleo", -"malfed", -"mali", -"malic", -"malice", -"malicho", -"malign", -"malik", -"maline", -"malines", -"malism", -"malison", -"malist", -"malkin", -"mall", -"mallard", -"malleal", -"mallear", -"mallee", -"mallein", -"mallet", -"malleus", -"mallow", -"mallum", -"mallus", -"malm", -"malmsey", -"malmy", -"malo", -"malodor", -"malonic", -"malonyl", -"malouah", -"malpais", -"malt", -"maltase", -"malter", -"maltha", -"malting", -"maltman", -"maltose", -"malty", -"mamba", -"mambo", -"mamma", -"mammal", -"mammary", -"mammate", -"mammee", -"mammer", -"mammock", -"mammon", -"mammoth", -"mammula", -"mammy", -"mamo", -"man", -"mana", -"manacle", -"manage", -"managee", -"manager", -"manaism", -"manakin", -"manal", -"manas", -"manatee", -"manavel", -"manbird", -"manbot", -"manche", -"manchet", -"mancono", -"mancus", -"mand", -"mandala", -"mandant", -"mandate", -"mandil", -"mandola", -"mandom", -"mandora", -"mandore", -"mandra", -"mandrel", -"mandrin", -"mandua", -"mandyas", -"mane", -"maned", -"manege", -"manei", -"manent", -"manes", -"maness", -"maney", -"manful", -"mang", -"manga", -"mangal", -"mange", -"mangeao", -"mangel", -"manger", -"mangi", -"mangily", -"mangle", -"mangler", -"mango", -"mangona", -"mangue", -"mangy", -"manhead", -"manhole", -"manhood", -"mani", -"mania", -"maniac", -"manic", -"manid", -"manify", -"manikin", -"manila", -"manilla", -"manille", -"manioc", -"maniple", -"manism", -"manist", -"manito", -"maniu", -"manjak", -"mank", -"mankin", -"mankind", -"manless", -"manlet", -"manlike", -"manlily", -"manling", -"manly", -"manna", -"mannan", -"manner", -"manners", -"manness", -"mannide", -"mannie", -"mannify", -"manning", -"mannish", -"mannite", -"mannose", -"manny", -"mano", -"manoc", -"manomin", -"manor", -"manque", -"manred", -"manrent", -"manroot", -"manrope", -"mansard", -"manse", -"manship", -"mansion", -"manso", -"mant", -"manta", -"mantal", -"manteau", -"mantel", -"manter", -"mantes", -"mantic", -"mantid", -"mantis", -"mantle", -"mantled", -"mantlet", -"manto", -"mantoid", -"mantra", -"mantrap", -"mantua", -"manual", -"manuao", -"manuka", -"manul", -"manuma", -"manumea", -"manumit", -"manure", -"manurer", -"manus", -"manward", -"manway", -"manweed", -"manwise", -"many", -"manzana", -"manzil", -"mao", -"maomao", -"map", -"mapach", -"mapau", -"mapland", -"maple", -"mapo", -"mapper", -"mappist", -"mappy", -"mapwise", -"maqui", -"maquis", -"mar", -"marabou", -"maraca", -"maracan", -"marae", -"maral", -"marang", -"marara", -"mararie", -"marasca", -"maraud", -"marble", -"marbled", -"marbler", -"marbles", -"marbly", -"marc", -"marcel", -"march", -"marcher", -"marcid", -"marco", -"marconi", -"marcor", -"mardy", -"mare", -"maremma", -"marengo", -"marfire", -"margay", -"marge", -"margent", -"margin", -"margosa", -"marhala", -"maria", -"marid", -"marimba", -"marina", -"marine", -"mariner", -"mariola", -"maris", -"marish", -"marital", -"mark", -"marka", -"marked", -"marker", -"market", -"markhor", -"marking", -"markka", -"markman", -"markup", -"marl", -"marled", -"marler", -"marli", -"marlin", -"marline", -"marlite", -"marlock", -"marlpit", -"marly", -"marm", -"marmit", -"marmite", -"marmose", -"marmot", -"maro", -"marok", -"maroon", -"marplot", -"marque", -"marquee", -"marquis", -"marrano", -"marree", -"marrer", -"married", -"marrier", -"marron", -"marrot", -"marrow", -"marrowy", -"marry", -"marryer", -"marsh", -"marshal", -"marshy", -"marsoon", -"mart", -"martel", -"marten", -"martext", -"martial", -"martin", -"martite", -"martlet", -"martyr", -"martyry", -"maru", -"marvel", -"marver", -"mary", -"marybud", -"mas", -"masa", -"mascara", -"mascled", -"mascot", -"masculy", -"masdeu", -"mash", -"masha", -"mashal", -"masher", -"mashie", -"mashing", -"mashman", -"mashru", -"mashy", -"masjid", -"mask", -"masked", -"masker", -"maskoid", -"maslin", -"mason", -"masoned", -"masoner", -"masonic", -"masonry", -"masooka", -"masoola", -"masque", -"masquer", -"mass", -"massa", -"massage", -"masse", -"massel", -"masser", -"masseur", -"massier", -"massif", -"massily", -"massive", -"massoy", -"massula", -"massy", -"mast", -"mastaba", -"mastage", -"mastax", -"masted", -"master", -"mastery", -"mastful", -"mastic", -"mastiff", -"masting", -"mastman", -"mastoid", -"masty", -"masu", -"mat", -"mataco", -"matador", -"matai", -"matalan", -"matanza", -"matapan", -"matapi", -"matara", -"matax", -"match", -"matcher", -"matchy", -"mate", -"mately", -"mater", -"matey", -"math", -"mathes", -"matico", -"matin", -"matinal", -"matinee", -"mating", -"matins", -"matipo", -"matka", -"matless", -"matlow", -"matra", -"matral", -"matrass", -"matreed", -"matric", -"matris", -"matrix", -"matron", -"matross", -"matsu", -"matsuri", -"matta", -"mattaro", -"matte", -"matted", -"matter", -"mattery", -"matti", -"matting", -"mattock", -"mattoid", -"mattoir", -"mature", -"maturer", -"matweed", -"maty", -"matzo", -"matzoon", -"matzos", -"matzoth", -"mau", -"maud", -"maudle", -"maudlin", -"mauger", -"maugh", -"maul", -"mauler", -"mauley", -"mauling", -"maumet", -"maun", -"maund", -"maunder", -"maundy", -"maunge", -"mauther", -"mauve", -"mauvine", -"maux", -"mavis", -"maw", -"mawk", -"mawkish", -"mawky", -"mawp", -"maxilla", -"maxim", -"maxima", -"maximal", -"maximed", -"maximum", -"maximus", -"maxixe", -"maxwell", -"may", -"maya", -"maybe", -"maybush", -"maycock", -"mayday", -"mayfish", -"mayhap", -"mayhem", -"maynt", -"mayor", -"mayoral", -"maypop", -"maysin", -"mayten", -"mayweed", -"maza", -"mazame", -"mazard", -"maze", -"mazed", -"mazedly", -"mazeful", -"mazer", -"mazic", -"mazily", -"mazuca", -"mazuma", -"mazurka", -"mazut", -"mazy", -"mazzard", -"mbalolo", -"mbori", -"me", -"meable", -"mead", -"meader", -"meadow", -"meadowy", -"meager", -"meagre", -"meak", -"meal", -"mealer", -"mealies", -"mealily", -"mealman", -"mealy", -"mean", -"meander", -"meaned", -"meaner", -"meaning", -"meanish", -"meanly", -"meant", -"mease", -"measle", -"measled", -"measles", -"measly", -"measure", -"meat", -"meatal", -"meated", -"meatily", -"meatman", -"meatus", -"meaty", -"mecate", -"mecon", -"meconic", -"meconin", -"medal", -"medaled", -"medalet", -"meddle", -"meddler", -"media", -"mediacy", -"mediad", -"medial", -"median", -"mediant", -"mediate", -"medic", -"medical", -"medico", -"mediety", -"medimn", -"medimno", -"medino", -"medio", -"medium", -"medius", -"medlar", -"medley", -"medrick", -"medulla", -"medusal", -"medusan", -"meebos", -"meece", -"meed", -"meek", -"meeken", -"meekly", -"meered", -"meerkat", -"meese", -"meet", -"meeten", -"meeter", -"meeting", -"meetly", -"megabar", -"megaerg", -"megafog", -"megapod", -"megaron", -"megaton", -"megerg", -"megilp", -"megmho", -"megohm", -"megrim", -"mehalla", -"mehari", -"mehtar", -"meile", -"mein", -"meinie", -"meio", -"meiobar", -"meiosis", -"meiotic", -"meith", -"mel", -"mela", -"melada", -"melagra", -"melam", -"melamed", -"melange", -"melanic", -"melanin", -"melano", -"melasma", -"melch", -"meld", -"melder", -"meldrop", -"mele", -"melee", -"melena", -"melene", -"melenic", -"melic", -"melilot", -"meline", -"melisma", -"melitis", -"mell", -"mellate", -"mellay", -"meller", -"mellit", -"mellite", -"mellon", -"mellow", -"mellowy", -"melodia", -"melodic", -"melody", -"meloe", -"meloid", -"melon", -"melonry", -"melos", -"melosa", -"melt", -"meltage", -"melted", -"melter", -"melters", -"melting", -"melton", -"mem", -"member", -"membral", -"memento", -"meminna", -"memo", -"memoir", -"memoria", -"memory", -"men", -"menace", -"menacer", -"menacme", -"menage", -"menald", -"mend", -"mendee", -"mender", -"mending", -"mendole", -"mends", -"menfolk", -"meng", -"menhir", -"menial", -"meninx", -"menkind", -"mennom", -"mensa", -"mensal", -"mense", -"menses", -"mensk", -"mensual", -"mental", -"mentary", -"menthol", -"menthyl", -"mention", -"mentor", -"mentum", -"menu", -"meny", -"menyie", -"menzie", -"merbaby", -"mercal", -"mercer", -"mercery", -"merch", -"merchet", -"mercy", -"mere", -"merel", -"merely", -"merfold", -"merfolk", -"merge", -"merger", -"mergh", -"meriah", -"merice", -"meril", -"merism", -"merist", -"merit", -"merited", -"meriter", -"merk", -"merkhet", -"merkin", -"merl", -"merle", -"merlin", -"merlon", -"mermaid", -"merman", -"mero", -"merop", -"meropia", -"meros", -"merrily", -"merrow", -"merry", -"merse", -"mesa", -"mesad", -"mesail", -"mesal", -"mesally", -"mesange", -"mesarch", -"mescal", -"mese", -"mesem", -"mesenna", -"mesh", -"meshed", -"meshy", -"mesiad", -"mesial", -"mesian", -"mesic", -"mesilla", -"mesion", -"mesityl", -"mesne", -"meso", -"mesobar", -"mesode", -"mesodic", -"mesole", -"meson", -"mesonic", -"mesopic", -"mespil", -"mess", -"message", -"messan", -"messe", -"messer", -"messet", -"messily", -"messin", -"messing", -"messman", -"messor", -"messrs", -"messtin", -"messy", -"mestee", -"mester", -"mestiza", -"mestizo", -"mestome", -"met", -"meta", -"metad", -"metage", -"metal", -"metaler", -"metamer", -"metanym", -"metate", -"metayer", -"mete", -"metel", -"meteor", -"meter", -"methane", -"methene", -"mether", -"methid", -"methide", -"methine", -"method", -"methyl", -"metic", -"metier", -"metis", -"metochy", -"metonym", -"metope", -"metopic", -"metopon", -"metra", -"metreta", -"metrete", -"metria", -"metric", -"metrics", -"metrify", -"metrist", -"mettar", -"mettle", -"mettled", -"metusia", -"metze", -"meuse", -"meute", -"mew", -"meward", -"mewer", -"mewl", -"mewler", -"mezcal", -"mezuzah", -"mezzo", -"mho", -"mi", -"miamia", -"mian", -"miaow", -"miaower", -"mias", -"miasm", -"miasma", -"miasmal", -"miasmic", -"miaul", -"miauler", -"mib", -"mica", -"micate", -"mice", -"micelle", -"miche", -"micher", -"miching", -"micht", -"mick", -"mickle", -"mico", -"micrify", -"micro", -"microbe", -"microhm", -"micron", -"miction", -"mid", -"midday", -"midden", -"middle", -"middler", -"middy", -"mide", -"midge", -"midget", -"midgety", -"midgy", -"midiron", -"midland", -"midleg", -"midmain", -"midmorn", -"midmost", -"midnoon", -"midpit", -"midrash", -"midrib", -"midriff", -"mids", -"midship", -"midst", -"midtap", -"midvein", -"midward", -"midway", -"midweek", -"midwife", -"midwise", -"midyear", -"mien", -"miff", -"miffy", -"mig", -"might", -"mightnt", -"mighty", -"miglio", -"mignon", -"migrant", -"migrate", -"mihrab", -"mijl", -"mikado", -"mike", -"mikie", -"mil", -"mila", -"milady", -"milch", -"milcher", -"milchy", -"mild", -"milden", -"milder", -"mildew", -"mildewy", -"mildish", -"mildly", -"mile", -"mileage", -"miler", -"mileway", -"milfoil", -"milha", -"miliary", -"milieu", -"militia", -"milium", -"milk", -"milken", -"milker", -"milkily", -"milking", -"milkman", -"milksop", -"milky", -"mill", -"milla", -"millage", -"milldam", -"mille", -"milled", -"miller", -"millet", -"millful", -"milliad", -"millile", -"milline", -"milling", -"million", -"millman", -"milner", -"milo", -"milord", -"milpa", -"milreis", -"milsey", -"milsie", -"milt", -"milter", -"milty", -"milvine", -"mim", -"mima", -"mimbar", -"mimble", -"mime", -"mimeo", -"mimer", -"mimesis", -"mimetic", -"mimic", -"mimical", -"mimicry", -"mimine", -"mimly", -"mimmest", -"mimmock", -"mimmood", -"mimmoud", -"mimosis", -"mimp", -"mimsey", -"min", -"mina", -"minable", -"minar", -"minaret", -"minaway", -"mince", -"mincer", -"mincing", -"mind", -"minded", -"minder", -"mindful", -"minding", -"mine", -"miner", -"mineral", -"minery", -"mines", -"minette", -"ming", -"minge", -"mingle", -"mingler", -"mingy", -"minhag", -"minhah", -"miniate", -"minibus", -"minicam", -"minify", -"minikin", -"minim", -"minima", -"minimal", -"minimum", -"minimus", -"mining", -"minion", -"minish", -"minium", -"miniver", -"minivet", -"mink", -"minkery", -"minkish", -"minnie", -"minning", -"minnow", -"minny", -"mino", -"minoize", -"minor", -"minot", -"minster", -"mint", -"mintage", -"minter", -"mintman", -"minty", -"minuend", -"minuet", -"minus", -"minute", -"minuter", -"minutia", -"minx", -"minxish", -"miny", -"minyan", -"miqra", -"mir", -"mirach", -"miracle", -"mirador", -"mirage", -"miragy", -"mirate", -"mirbane", -"mird", -"mirdaha", -"mire", -"mirid", -"mirific", -"mirish", -"mirk", -"miro", -"mirror", -"mirrory", -"mirth", -"miry", -"mirza", -"misact", -"misadd", -"misaim", -"misally", -"misbias", -"misbill", -"misbind", -"misbode", -"misborn", -"misbusy", -"miscall", -"miscast", -"mischio", -"miscoin", -"miscook", -"miscrop", -"miscue", -"miscut", -"misdate", -"misdaub", -"misdeal", -"misdeed", -"misdeem", -"misdiet", -"misdo", -"misdoer", -"misdraw", -"mise", -"misease", -"misedit", -"miser", -"miserly", -"misery", -"misfare", -"misfile", -"misfire", -"misfit", -"misfond", -"misform", -"misgive", -"misgo", -"misgrow", -"mishap", -"mishmee", -"misjoin", -"miskeep", -"misken", -"miskill", -"misknow", -"misky", -"mislay", -"mislead", -"mislear", -"misled", -"mislest", -"mislike", -"mislive", -"mismade", -"mismake", -"mismate", -"mismove", -"misname", -"misobey", -"mispage", -"mispart", -"mispay", -"mispick", -"misplay", -"misput", -"misrate", -"misread", -"misrule", -"miss", -"missal", -"missay", -"misseem", -"missel", -"misset", -"missile", -"missing", -"mission", -"missis", -"missish", -"missive", -"misstay", -"misstep", -"missy", -"mist", -"mistake", -"mistbow", -"misted", -"mistell", -"mistend", -"mister", -"misterm", -"mistful", -"mistic", -"mistide", -"mistify", -"mistily", -"mistime", -"mistle", -"mistone", -"mistook", -"mistral", -"mistry", -"misturn", -"misty", -"misura", -"misuse", -"misuser", -"miswed", -"miswish", -"misword", -"misyoke", -"mite", -"miter", -"mitered", -"miterer", -"mitis", -"mitome", -"mitosis", -"mitotic", -"mitra", -"mitral", -"mitrate", -"mitre", -"mitrer", -"mitt", -"mitten", -"mitty", -"mity", -"miurus", -"mix", -"mixable", -"mixed", -"mixedly", -"mixen", -"mixer", -"mixhill", -"mixible", -"mixite", -"mixtion", -"mixture", -"mixy", -"mizmaze", -"mizzen", -"mizzle", -"mizzler", -"mizzly", -"mizzy", -"mneme", -"mnemic", -"mnesic", -"mnestic", -"mnioid", -"mo", -"moan", -"moanful", -"moaning", -"moat", -"mob", -"mobable", -"mobber", -"mobbish", -"mobbism", -"mobbist", -"mobby", -"mobcap", -"mobed", -"mobile", -"moble", -"moblike", -"mobship", -"mobsman", -"mobster", -"mocha", -"mochras", -"mock", -"mockado", -"mocker", -"mockery", -"mockful", -"mocmain", -"mocuck", -"modal", -"modally", -"mode", -"model", -"modeler", -"modena", -"modern", -"modest", -"modesty", -"modicum", -"modify", -"modish", -"modist", -"modiste", -"modius", -"modular", -"module", -"modulo", -"modulus", -"moellon", -"mofette", -"moff", -"mog", -"mogador", -"mogdad", -"moggan", -"moggy", -"mogo", -"moguey", -"moha", -"mohabat", -"mohair", -"mohar", -"mohel", -"moho", -"mohr", -"mohur", -"moider", -"moidore", -"moieter", -"moiety", -"moil", -"moiler", -"moiles", -"moiley", -"moiling", -"moineau", -"moio", -"moire", -"moise", -"moist", -"moisten", -"moistly", -"moisty", -"moit", -"moity", -"mojarra", -"mojo", -"moke", -"moki", -"moko", -"moksha", -"mokum", -"moky", -"mola", -"molal", -"molar", -"molary", -"molassy", -"molave", -"mold", -"molder", -"moldery", -"molding", -"moldy", -"mole", -"moleism", -"moler", -"molest", -"molimen", -"moline", -"molka", -"molland", -"molle", -"mollie", -"mollify", -"mollusk", -"molly", -"molman", -"moloid", -"moloker", -"molompi", -"molosse", -"molpe", -"molt", -"molten", -"molter", -"moly", -"mombin", -"momble", -"mome", -"moment", -"momenta", -"momism", -"momme", -"mommet", -"mommy", -"momo", -"mon", -"mona", -"monad", -"monadic", -"monaene", -"monal", -"monarch", -"monas", -"monase", -"monaxon", -"mone", -"monel", -"monepic", -"moner", -"moneral", -"moneran", -"moneric", -"moneron", -"monesia", -"money", -"moneyed", -"moneyer", -"mong", -"monger", -"mongery", -"mongler", -"mongrel", -"mongst", -"monial", -"moniker", -"monism", -"monist", -"monitor", -"monk", -"monkdom", -"monkery", -"monkess", -"monkey", -"monkish", -"monkism", -"monkly", -"monny", -"mono", -"monoazo", -"monocle", -"monocot", -"monodic", -"monody", -"monoid", -"monomer", -"mononch", -"monont", -"mononym", -"monose", -"monotic", -"monsoon", -"monster", -"montage", -"montana", -"montane", -"montant", -"monte", -"montem", -"month", -"monthly", -"monthon", -"montjoy", -"monton", -"monture", -"moo", -"mooch", -"moocha", -"moocher", -"mood", -"mooder", -"moodily", -"moodish", -"moodle", -"moody", -"mooing", -"mool", -"moolet", -"mools", -"moolum", -"moon", -"moonack", -"mooned", -"mooner", -"moonery", -"mooneye", -"moonily", -"mooning", -"moonish", -"moonite", -"moonja", -"moonjah", -"moonlet", -"moonlit", -"moonman", -"moonset", -"moonway", -"moony", -"moop", -"moor", -"moorage", -"mooring", -"moorish", -"moorman", -"moorn", -"moorpan", -"moors", -"moorup", -"moory", -"moosa", -"moose", -"moosey", -"moost", -"moot", -"mooter", -"mooth", -"mooting", -"mootman", -"mop", -"mopane", -"mope", -"moper", -"moph", -"mophead", -"moping", -"mopish", -"mopla", -"mopper", -"moppet", -"moppy", -"mopsy", -"mopus", -"mor", -"mora", -"moraine", -"moral", -"morale", -"morally", -"morals", -"morass", -"morassy", -"morat", -"morate", -"moray", -"morbid", -"morbify", -"mordant", -"mordent", -"mordore", -"more", -"moreen", -"moreish", -"morel", -"morella", -"morello", -"mores", -"morfrey", -"morg", -"morga", -"morgan", -"morgay", -"morgen", -"morglay", -"morgue", -"moric", -"moriche", -"morin", -"morinel", -"morion", -"morkin", -"morlop", -"mormaor", -"mormo", -"mormon", -"mormyr", -"mormyre", -"morn", -"morne", -"morned", -"morning", -"moro", -"moroc", -"morocco", -"moron", -"moroncy", -"morong", -"moronic", -"moronry", -"morose", -"morosis", -"morph", -"morphea", -"morphew", -"morphia", -"morphic", -"morphon", -"morris", -"morrow", -"morsal", -"morse", -"morsel", -"morsing", -"morsure", -"mort", -"mortal", -"mortar", -"mortary", -"morth", -"mortier", -"mortify", -"mortise", -"morula", -"morular", -"morule", -"morvin", -"morwong", -"mosaic", -"mosaist", -"mosette", -"mosey", -"mosker", -"mosque", -"moss", -"mossed", -"mosser", -"mossery", -"mossful", -"mossy", -"most", -"moste", -"mostly", -"mot", -"mote", -"moted", -"motel", -"moter", -"motet", -"motey", -"moth", -"mothed", -"mother", -"mothery", -"mothy", -"motif", -"motific", -"motile", -"motion", -"motive", -"motley", -"motmot", -"motor", -"motored", -"motoric", -"motory", -"mott", -"motte", -"mottle", -"mottled", -"mottler", -"motto", -"mottoed", -"motyka", -"mou", -"mouche", -"moud", -"moudie", -"moudy", -"mouflon", -"mouille", -"moujik", -"moul", -"mould", -"moulded", -"moule", -"moulin", -"mouls", -"moulter", -"mouly", -"mound", -"moundy", -"mount", -"mounted", -"mounter", -"moup", -"mourn", -"mourner", -"mouse", -"mouser", -"mousery", -"mousey", -"mousily", -"mousing", -"mousle", -"mousmee", -"mousse", -"moustoc", -"mousy", -"mout", -"moutan", -"mouth", -"mouthed", -"mouther", -"mouthy", -"mouton", -"mouzah", -"movable", -"movably", -"movant", -"move", -"mover", -"movie", -"moving", -"mow", -"mowable", -"mowana", -"mowburn", -"mowch", -"mowcht", -"mower", -"mowha", -"mowie", -"mowing", -"mowland", -"mown", -"mowra", -"mowrah", -"mowse", -"mowt", -"mowth", -"moxa", -"moy", -"moyen", -"moyenne", -"moyite", -"moyle", -"moyo", -"mozing", -"mpret", -"mu", -"muang", -"mubarat", -"mucago", -"mucaro", -"mucedin", -"much", -"muchly", -"mucic", -"mucid", -"mucific", -"mucigen", -"mucin", -"muck", -"mucker", -"mucket", -"muckite", -"muckle", -"muckman", -"muckna", -"mucksy", -"mucky", -"mucluc", -"mucoid", -"muconic", -"mucopus", -"mucor", -"mucosa", -"mucosal", -"mucose", -"mucous", -"mucro", -"mucus", -"mucusin", -"mud", -"mudar", -"mudbank", -"mudcap", -"mudd", -"mudde", -"mudden", -"muddify", -"muddily", -"mudding", -"muddish", -"muddle", -"muddler", -"muddy", -"mudee", -"mudfish", -"mudflow", -"mudhead", -"mudhole", -"mudir", -"mudiria", -"mudland", -"mudlark", -"mudless", -"mudra", -"mudsill", -"mudweed", -"mudwort", -"muermo", -"muezzin", -"muff", -"muffed", -"muffet", -"muffin", -"muffish", -"muffle", -"muffled", -"muffler", -"mufflin", -"muffy", -"mufti", -"mufty", -"mug", -"muga", -"mugful", -"mugg", -"mugger", -"mugget", -"muggily", -"muggins", -"muggish", -"muggles", -"muggy", -"mugient", -"mugweed", -"mugwort", -"mugwump", -"muid", -"muir", -"muist", -"mukluk", -"muktar", -"mukti", -"mulatta", -"mulatto", -"mulch", -"mulcher", -"mulct", -"mulder", -"mule", -"muleman", -"muleta", -"muletta", -"muley", -"mulga", -"mulier", -"mulish", -"mulism", -"mulita", -"mulk", -"mull", -"mulla", -"mullah", -"mullar", -"mullein", -"muller", -"mullet", -"mullets", -"mulley", -"mullid", -"mullion", -"mullite", -"mullock", -"mulloid", -"mulmul", -"mulse", -"mulsify", -"mult", -"multum", -"multure", -"mum", -"mumble", -"mumbler", -"mummer", -"mummery", -"mummick", -"mummied", -"mummify", -"mumming", -"mummy", -"mumness", -"mump", -"mumper", -"mumpish", -"mumps", -"mun", -"munch", -"muncher", -"munchet", -"mund", -"mundane", -"mundic", -"mundify", -"mundil", -"mundle", -"mung", -"munga", -"munge", -"mungey", -"mungo", -"mungofa", -"munguba", -"mungy", -"munific", -"munity", -"munj", -"munjeet", -"munnion", -"munshi", -"munt", -"muntin", -"muntjac", -"mura", -"murage", -"mural", -"muraled", -"murally", -"murchy", -"murder", -"murdrum", -"mure", -"murex", -"murexan", -"murga", -"murgavi", -"murgeon", -"muriate", -"muricid", -"murid", -"murine", -"murinus", -"muriti", -"murium", -"murk", -"murkily", -"murkish", -"murkly", -"murky", -"murlin", -"murly", -"murmur", -"murphy", -"murra", -"murrain", -"murre", -"murrey", -"murrina", -"murshid", -"muruxi", -"murva", -"murza", -"musal", -"musang", -"musar", -"muscade", -"muscat", -"muscid", -"muscle", -"muscled", -"muscly", -"muscoid", -"muscone", -"muscose", -"muscot", -"muscovy", -"muscule", -"muse", -"mused", -"museful", -"museist", -"muser", -"musery", -"musette", -"museum", -"mush", -"musha", -"mushaa", -"mushed", -"musher", -"mushily", -"mushla", -"mushru", -"mushy", -"music", -"musical", -"musico", -"musie", -"musily", -"musimon", -"musing", -"musk", -"muskat", -"muskeg", -"musket", -"muskie", -"muskish", -"muskrat", -"musky", -"muslin", -"musnud", -"musquaw", -"musrol", -"muss", -"mussal", -"mussel", -"mussily", -"mussuk", -"mussy", -"must", -"mustang", -"mustard", -"mustee", -"muster", -"mustify", -"mustily", -"mustnt", -"musty", -"muta", -"mutable", -"mutably", -"mutage", -"mutant", -"mutase", -"mutate", -"mutch", -"mute", -"mutedly", -"mutely", -"muth", -"mutic", -"mutiny", -"mutism", -"mutist", -"mutive", -"mutsje", -"mutt", -"mutter", -"mutton", -"muttony", -"mutual", -"mutuary", -"mutule", -"mutuum", -"mux", -"muyusa", -"muzhik", -"muzz", -"muzzily", -"muzzle", -"muzzler", -"muzzy", -"my", -"myal", -"myalgia", -"myalgic", -"myalism", -"myall", -"myarian", -"myatony", -"mycele", -"mycelia", -"mycoid", -"mycose", -"mycosin", -"mycosis", -"mycotic", -"mydine", -"myelic", -"myelin", -"myeloic", -"myeloid", -"myeloma", -"myelon", -"mygale", -"mygalid", -"myiasis", -"myiosis", -"myitis", -"mykiss", -"mymarid", -"myna", -"myocele", -"myocyte", -"myogen", -"myogram", -"myoid", -"myology", -"myoma", -"myomere", -"myoneme", -"myope", -"myophan", -"myopia", -"myopic", -"myops", -"myopy", -"myosin", -"myosis", -"myosote", -"myotic", -"myotome", -"myotomy", -"myotony", -"myowun", -"myoxine", -"myrcene", -"myrcia", -"myriad", -"myriare", -"myrica", -"myricin", -"myricyl", -"myringa", -"myron", -"myronic", -"myrosin", -"myrrh", -"myrrhed", -"myrrhic", -"myrrhol", -"myrrhy", -"myrtal", -"myrtle", -"myrtol", -"mysel", -"myself", -"mysell", -"mysid", -"mysoid", -"mysost", -"myst", -"mystax", -"mystery", -"mystes", -"mystic", -"mystify", -"myth", -"mythify", -"mythism", -"mythist", -"mythize", -"mythos", -"mythus", -"mytilid", -"myxa", -"myxemia", -"myxo", -"myxoid", -"myxoma", -"myxopod", -"myzont", -"n", -"na", -"naa", -"naam", -"nab", -"nabak", -"nabber", -"nabk", -"nabla", -"nable", -"nabob", -"nabobry", -"nabs", -"nacarat", -"nace", -"nacelle", -"nach", -"nachani", -"nacket", -"nacre", -"nacred", -"nacrine", -"nacrite", -"nacrous", -"nacry", -"nadder", -"nadir", -"nadiral", -"nae", -"naebody", -"naegate", -"nael", -"naether", -"nag", -"naga", -"nagaika", -"nagana", -"nagara", -"nagger", -"naggin", -"nagging", -"naggish", -"naggle", -"naggly", -"naggy", -"naght", -"nagmaal", -"nagman", -"nagnag", -"nagnail", -"nagor", -"nagsman", -"nagster", -"nagual", -"naiad", -"naiant", -"naid", -"naif", -"naifly", -"naig", -"naigie", -"naik", -"nail", -"nailbin", -"nailer", -"nailery", -"nailing", -"nailrod", -"naily", -"nain", -"nainsel", -"naio", -"naipkin", -"nairy", -"nais", -"naish", -"naither", -"naive", -"naively", -"naivete", -"naivety", -"nak", -"nake", -"naked", -"nakedly", -"naker", -"nakhod", -"nakhoda", -"nako", -"nakong", -"nakoo", -"nallah", -"nam", -"namable", -"namaqua", -"namaz", -"namda", -"name", -"namely", -"namer", -"naming", -"nammad", -"nan", -"nana", -"nancy", -"nandi", -"nandine", -"nandow", -"nandu", -"nane", -"nanes", -"nanga", -"nanism", -"nankeen", -"nankin", -"nanny", -"nanoid", -"nanpie", -"nant", -"nantle", -"naology", -"naos", -"nap", -"napa", -"napal", -"napalm", -"nape", -"napead", -"naperer", -"napery", -"naphtha", -"naphtho", -"naphtol", -"napkin", -"napless", -"napoo", -"nappe", -"napped", -"napper", -"napping", -"nappy", -"napron", -"napu", -"nar", -"narcism", -"narcist", -"narcoma", -"narcose", -"narcous", -"nard", -"nardine", -"nardoo", -"nares", -"nargil", -"narial", -"naric", -"narica", -"narine", -"nark", -"narky", -"narr", -"narra", -"narras", -"narrate", -"narrow", -"narrowy", -"narthex", -"narwhal", -"nary", -"nasab", -"nasal", -"nasalis", -"nasally", -"nasard", -"nascent", -"nasch", -"nash", -"nashgab", -"nashgob", -"nasi", -"nasial", -"nasion", -"nasitis", -"nasrol", -"nast", -"nastic", -"nastika", -"nastily", -"nasty", -"nasus", -"nasute", -"nasutus", -"nat", -"nataka", -"natal", -"natals", -"natant", -"natator", -"natch", -"nates", -"nathe", -"nather", -"nation", -"native", -"natr", -"natrium", -"natron", -"natter", -"nattily", -"nattle", -"natty", -"natuary", -"natural", -"nature", -"naucrar", -"nauger", -"naught", -"naughty", -"naumk", -"naunt", -"nauntle", -"nausea", -"naut", -"nautch", -"nauther", -"nautic", -"nautics", -"naval", -"navally", -"navar", -"navarch", -"nave", -"navel", -"naveled", -"navet", -"navette", -"navew", -"navite", -"navvy", -"navy", -"naw", -"nawab", -"nawt", -"nay", -"nayaur", -"naysay", -"nayward", -"nayword", -"naze", -"nazim", -"nazir", -"ne", -"nea", -"neal", -"neanic", -"neap", -"neaped", -"nearby", -"nearest", -"nearish", -"nearly", -"neat", -"neaten", -"neath", -"neatify", -"neatly", -"neb", -"neback", -"nebbed", -"nebbuck", -"nebbuk", -"nebby", -"nebel", -"nebris", -"nebula", -"nebulae", -"nebular", -"nebule", -"neck", -"neckar", -"necked", -"necker", -"neckful", -"necking", -"necklet", -"necktie", -"necrose", -"nectar", -"nectary", -"nedder", -"neddy", -"nee", -"neebor", -"neebour", -"need", -"needer", -"needful", -"needham", -"needily", -"needing", -"needle", -"needled", -"needler", -"needles", -"needly", -"needs", -"needy", -"neeger", -"neeld", -"neele", -"neem", -"neep", -"neepour", -"neer", -"neese", -"neet", -"neetup", -"neeze", -"nef", -"nefast", -"neffy", -"neftgil", -"negate", -"negator", -"neger", -"neglect", -"negrine", -"negro", -"negus", -"nei", -"neif", -"neigh", -"neigher", -"neiper", -"neist", -"neither", -"nekton", -"nelson", -"nema", -"nematic", -"nemeses", -"nemesic", -"nemoral", -"nenta", -"neo", -"neocyte", -"neogamy", -"neolith", -"neology", -"neon", -"neonate", -"neorama", -"neossin", -"neoteny", -"neotype", -"neoza", -"nep", -"neper", -"nephele", -"nephesh", -"nephew", -"nephria", -"nephric", -"nephron", -"nephros", -"nepman", -"nepotal", -"nepote", -"nepotic", -"nereite", -"nerine", -"neritic", -"nerval", -"nervate", -"nerve", -"nerver", -"nervid", -"nervily", -"nervine", -"nerving", -"nervish", -"nervism", -"nervose", -"nervous", -"nervule", -"nervure", -"nervy", -"nese", -"nesh", -"neshly", -"nesiote", -"ness", -"nest", -"nestage", -"nester", -"nestful", -"nestle", -"nestler", -"nesty", -"net", -"netball", -"netbush", -"netcha", -"nete", -"neter", -"netful", -"neth", -"nether", -"neti", -"netleaf", -"netlike", -"netman", -"netop", -"netsman", -"netsuke", -"netted", -"netter", -"netting", -"nettle", -"nettler", -"nettly", -"netty", -"netwise", -"network", -"neuma", -"neume", -"neumic", -"neurad", -"neural", -"neurale", -"neuric", -"neurin", -"neurine", -"neurism", -"neurite", -"neuroid", -"neuroma", -"neuron", -"neurone", -"neurula", -"neuter", -"neutral", -"neutron", -"neve", -"nevel", -"never", -"nevo", -"nevoid", -"nevoy", -"nevus", -"new", -"newcal", -"newcome", -"newel", -"newelty", -"newing", -"newings", -"newish", -"newly", -"newness", -"news", -"newsboy", -"newsful", -"newsman", -"newsy", -"newt", -"newtake", -"newton", -"nexal", -"next", -"nextly", -"nexum", -"nexus", -"neyanda", -"ngai", -"ngaio", -"ngapi", -"ni", -"niacin", -"niata", -"nib", -"nibbana", -"nibbed", -"nibber", -"nibble", -"nibbler", -"nibby", -"niblick", -"niblike", -"nibong", -"nibs", -"nibsome", -"nice", -"niceish", -"nicely", -"nicety", -"niche", -"nicher", -"nick", -"nickel", -"nicker", -"nickey", -"nicking", -"nickle", -"nicky", -"nicolo", -"nicotia", -"nicotic", -"nictate", -"nid", -"nidal", -"nidana", -"niddick", -"niddle", -"nide", -"nidge", -"nidget", -"nidgety", -"nidi", -"nidify", -"niding", -"nidor", -"nidulus", -"nidus", -"niece", -"nielled", -"niello", -"niepa", -"nieve", -"nieveta", -"nife", -"niffer", -"nific", -"nifle", -"nifling", -"nifty", -"nig", -"niggard", -"nigger", -"niggery", -"niggle", -"niggler", -"niggly", -"nigh", -"nighly", -"night", -"nighted", -"nightie", -"nightly", -"nights", -"nignay", -"nignye", -"nigori", -"nigre", -"nigrify", -"nigrine", -"nigrous", -"nigua", -"nikau", -"nil", -"nilgai", -"nim", -"nimb", -"nimbed", -"nimbi", -"nimble", -"nimbly", -"nimbose", -"nimbus", -"nimiety", -"niminy", -"nimious", -"nimmer", -"nimshi", -"nincom", -"nine", -"ninepin", -"nineted", -"ninety", -"ninny", -"ninon", -"ninth", -"ninthly", -"nintu", -"ninut", -"niobate", -"niobic", -"niobite", -"niobium", -"niobous", -"niog", -"niota", -"nip", -"nipa", -"nipper", -"nippers", -"nippily", -"nipping", -"nipple", -"nippy", -"nipter", -"nirles", -"nirvana", -"nisei", -"nishiki", -"nisnas", -"nispero", -"nisse", -"nisus", -"nit", -"nitch", -"nitency", -"niter", -"nitered", -"nither", -"nithing", -"nitid", -"nito", -"niton", -"nitrate", -"nitric", -"nitride", -"nitrify", -"nitrile", -"nitrite", -"nitro", -"nitrous", -"nitryl", -"nitter", -"nitty", -"nitwit", -"nival", -"niveous", -"nix", -"nixie", -"niyoga", -"nizam", -"nizamut", -"nizy", -"njave", -"no", -"noa", -"nob", -"nobber", -"nobbily", -"nobble", -"nobbler", -"nobbut", -"nobby", -"noble", -"nobley", -"nobly", -"nobody", -"nobs", -"nocake", -"nocent", -"nock", -"nocket", -"nocktat", -"noctuid", -"noctule", -"nocturn", -"nocuity", -"nocuous", -"nod", -"nodal", -"nodated", -"nodder", -"nodding", -"noddle", -"noddy", -"node", -"noded", -"nodi", -"nodiak", -"nodical", -"nodose", -"nodous", -"nodular", -"nodule", -"noduled", -"nodulus", -"nodus", -"noel", -"noetic", -"noetics", -"nog", -"nogada", -"nogal", -"noggen", -"noggin", -"nogging", -"noghead", -"nohow", -"noil", -"noilage", -"noiler", -"noily", -"noint", -"noir", -"noise", -"noisily", -"noisome", -"noisy", -"nokta", -"noll", -"nolle", -"nolo", -"noma", -"nomad", -"nomadic", -"nomancy", -"nomarch", -"nombril", -"nome", -"nomial", -"nomic", -"nomina", -"nominal", -"nominee", -"nominy", -"nomism", -"nomisma", -"nomos", -"non", -"nonacid", -"nonact", -"nonage", -"nonagon", -"nonaid", -"nonair", -"nonane", -"nonary", -"nonbase", -"nonce", -"noncock", -"noncom", -"noncome", -"noncon", -"nonda", -"nondo", -"none", -"nonego", -"nonene", -"nonent", -"nonepic", -"nones", -"nonet", -"nonevil", -"nonfact", -"nonfarm", -"nonfat", -"nonfood", -"nonform", -"nonfrat", -"nongas", -"nongod", -"nongold", -"nongray", -"nongrey", -"nonhero", -"nonic", -"nonion", -"nonius", -"nonjury", -"nonlife", -"nonly", -"nonnant", -"nonnat", -"nonoic", -"nonoily", -"nonomad", -"nonpaid", -"nonpar", -"nonpeak", -"nonplus", -"nonpoet", -"nonport", -"nonrun", -"nonsale", -"nonsane", -"nonself", -"nonsine", -"nonskid", -"nonslip", -"nonstop", -"nonsuit", -"nontan", -"nontax", -"nonterm", -"nonuple", -"nonuse", -"nonuser", -"nonwar", -"nonya", -"nonyl", -"nonylic", -"nonzero", -"noodle", -"nook", -"nooked", -"nookery", -"nooking", -"nooklet", -"nooky", -"noology", -"noon", -"noonday", -"nooning", -"noonlit", -"noop", -"noose", -"nooser", -"nopal", -"nopalry", -"nope", -"nor", -"norard", -"norate", -"noreast", -"norelin", -"norgine", -"nori", -"noria", -"norie", -"norimon", -"norite", -"norland", -"norm", -"norma", -"normal", -"norsel", -"north", -"norther", -"norward", -"norwest", -"nose", -"nosean", -"nosed", -"nosegay", -"noser", -"nosey", -"nosine", -"nosing", -"nosism", -"nostic", -"nostril", -"nostrum", -"nosy", -"not", -"notable", -"notably", -"notaeal", -"notaeum", -"notal", -"notan", -"notary", -"notate", -"notator", -"notch", -"notched", -"notchel", -"notcher", -"notchy", -"note", -"noted", -"notedly", -"notekin", -"notelet", -"noter", -"nother", -"nothing", -"nothous", -"notice", -"noticer", -"notify", -"notion", -"notitia", -"notour", -"notself", -"notum", -"nougat", -"nought", -"noun", -"nounal", -"nounize", -"noup", -"nourice", -"nourish", -"nous", -"nouther", -"nova", -"novalia", -"novate", -"novator", -"novcic", -"novel", -"novelet", -"novella", -"novelly", -"novelry", -"novelty", -"novem", -"novena", -"novene", -"novice", -"novity", -"now", -"nowaday", -"noway", -"noways", -"nowed", -"nowel", -"nowhat", -"nowhen", -"nowhere", -"nowhit", -"nowise", -"nowness", -"nowt", -"nowy", -"noxa", -"noxal", -"noxally", -"noxious", -"noy", -"noyade", -"noyau", -"nozzle", -"nozzler", -"nth", -"nu", -"nuance", -"nub", -"nubbin", -"nubble", -"nubbly", -"nubby", -"nubia", -"nubile", -"nucal", -"nucha", -"nuchal", -"nucin", -"nucleal", -"nuclear", -"nuclei", -"nuclein", -"nucleon", -"nucleus", -"nuclide", -"nucule", -"nuculid", -"nudate", -"nuddle", -"nude", -"nudely", -"nudge", -"nudger", -"nudiped", -"nudish", -"nudism", -"nudist", -"nudity", -"nugator", -"nuggar", -"nugget", -"nuggety", -"nugify", -"nuke", -"nul", -"null", -"nullah", -"nullify", -"nullism", -"nullity", -"nullo", -"numb", -"number", -"numbing", -"numble", -"numbles", -"numbly", -"numda", -"numdah", -"numen", -"numeral", -"numero", -"nummary", -"nummi", -"nummus", -"numud", -"nun", -"nunatak", -"nunbird", -"nunch", -"nuncio", -"nuncle", -"nundine", -"nunhood", -"nunky", -"nunlet", -"nunlike", -"nunnari", -"nunnery", -"nunni", -"nunnify", -"nunnish", -"nunship", -"nuptial", -"nuque", -"nuraghe", -"nurhag", -"nurly", -"nurse", -"nurser", -"nursery", -"nursing", -"nursle", -"nursy", -"nurture", -"nusfiah", -"nut", -"nutant", -"nutate", -"nutcake", -"nutgall", -"nuthook", -"nutlet", -"nutlike", -"nutmeg", -"nutpick", -"nutria", -"nutrice", -"nutrify", -"nutseed", -"nutted", -"nutter", -"nuttery", -"nuttily", -"nutting", -"nuttish", -"nutty", -"nuzzer", -"nuzzle", -"nyanza", -"nye", -"nylast", -"nylon", -"nymil", -"nymph", -"nympha", -"nymphae", -"nymphal", -"nymphet", -"nymphic", -"nymphid", -"nymphly", -"nyxis", -"o", -"oadal", -"oaf", -"oafdom", -"oafish", -"oak", -"oaken", -"oaklet", -"oaklike", -"oakling", -"oakum", -"oakweb", -"oakwood", -"oaky", -"oam", -"oar", -"oarage", -"oarcock", -"oared", -"oarfish", -"oarhole", -"oarial", -"oaric", -"oaritic", -"oaritis", -"oarium", -"oarless", -"oarlike", -"oarlock", -"oarlop", -"oarman", -"oarsman", -"oarweed", -"oary", -"oasal", -"oasean", -"oases", -"oasis", -"oasitic", -"oast", -"oat", -"oatbin", -"oatcake", -"oatear", -"oaten", -"oatfowl", -"oath", -"oathay", -"oathed", -"oathful", -"oathlet", -"oatland", -"oatlike", -"oatmeal", -"oatseed", -"oaty", -"oban", -"obclude", -"obe", -"obeah", -"obeche", -"obeism", -"obelia", -"obeliac", -"obelial", -"obelion", -"obelisk", -"obelism", -"obelize", -"obelus", -"obese", -"obesely", -"obesity", -"obex", -"obey", -"obeyer", -"obi", -"obispo", -"obit", -"obitual", -"object", -"objure", -"oblate", -"obley", -"oblige", -"obliged", -"obligee", -"obliger", -"obligor", -"oblique", -"oblong", -"obloquy", -"oboe", -"oboist", -"obol", -"obolary", -"obole", -"obolet", -"obolus", -"oboval", -"obovate", -"obovoid", -"obscene", -"obscure", -"obsede", -"obsequy", -"observe", -"obsess", -"obtain", -"obtect", -"obtest", -"obtrude", -"obtund", -"obtuse", -"obverse", -"obvert", -"obviate", -"obvious", -"obvolve", -"ocarina", -"occamy", -"occiput", -"occlude", -"occluse", -"occult", -"occupy", -"occur", -"ocean", -"oceaned", -"oceanet", -"oceanic", -"ocellar", -"ocelli", -"ocellus", -"oceloid", -"ocelot", -"och", -"ochava", -"ochavo", -"ocher", -"ochery", -"ochone", -"ochrea", -"ochro", -"ochroid", -"ochrous", -"ocht", -"ock", -"oclock", -"ocote", -"ocque", -"ocracy", -"ocrea", -"ocreate", -"octad", -"octadic", -"octagon", -"octan", -"octane", -"octant", -"octapla", -"octarch", -"octary", -"octaval", -"octave", -"octavic", -"octavo", -"octene", -"octet", -"octic", -"octine", -"octoad", -"octoate", -"octofid", -"octoic", -"octoid", -"octonal", -"octoon", -"octoped", -"octopi", -"octopod", -"octopus", -"octose", -"octoyl", -"octroi", -"octroy", -"octuor", -"octuple", -"octuply", -"octyl", -"octyne", -"ocuby", -"ocular", -"oculary", -"oculate", -"oculist", -"oculus", -"od", -"oda", -"odacoid", -"odal", -"odalisk", -"odaller", -"odalman", -"odd", -"oddish", -"oddity", -"oddlegs", -"oddly", -"oddman", -"oddment", -"oddness", -"odds", -"oddsman", -"ode", -"odel", -"odelet", -"odeon", -"odeum", -"odic", -"odinite", -"odious", -"odist", -"odium", -"odology", -"odontic", -"odoom", -"odor", -"odorant", -"odorate", -"odored", -"odorful", -"odorize", -"odorous", -"odso", -"odum", -"odyl", -"odylic", -"odylism", -"odylist", -"odylize", -"oe", -"oecist", -"oecus", -"oenin", -"oenolin", -"oenomel", -"oer", -"oersted", -"oes", -"oestrid", -"oestrin", -"oestrum", -"oestrus", -"of", -"off", -"offal", -"offbeat", -"offcast", -"offcome", -"offcut", -"offend", -"offense", -"offer", -"offeree", -"offerer", -"offeror", -"offhand", -"office", -"officer", -"offing", -"offish", -"offlet", -"offlook", -"offscum", -"offset", -"offtake", -"offtype", -"offward", -"oflete", -"oft", -"often", -"oftens", -"ofter", -"oftest", -"oftly", -"oftness", -"ofttime", -"ogaire", -"ogam", -"ogamic", -"ogdoad", -"ogdoas", -"ogee", -"ogeed", -"ogham", -"oghamic", -"ogival", -"ogive", -"ogived", -"ogle", -"ogler", -"ogmic", -"ogre", -"ogreish", -"ogreism", -"ogress", -"ogrish", -"ogrism", -"ogtiern", -"ogum", -"oh", -"ohelo", -"ohia", -"ohm", -"ohmage", -"ohmic", -"oho", -"ohoy", -"oidioid", -"oii", -"oil", -"oilbird", -"oilcan", -"oilcoat", -"oilcup", -"oildom", -"oiled", -"oiler", -"oilery", -"oilfish", -"oilhole", -"oilily", -"oilless", -"oillet", -"oillike", -"oilman", -"oilseed", -"oilskin", -"oilway", -"oily", -"oilyish", -"oime", -"oinomel", -"oint", -"oisin", -"oitava", -"oka", -"okapi", -"okee", -"okenite", -"oket", -"oki", -"okia", -"okonite", -"okra", -"okrug", -"olam", -"olamic", -"old", -"olden", -"older", -"oldish", -"oldland", -"oldness", -"oldster", -"oldwife", -"oleana", -"olease", -"oleate", -"olefin", -"olefine", -"oleic", -"olein", -"olena", -"olenid", -"olent", -"oleo", -"oleose", -"oleous", -"olfact", -"olfacty", -"oliban", -"olid", -"oligist", -"olio", -"olitory", -"oliva", -"olivary", -"olive", -"olived", -"olivet", -"olivil", -"olivile", -"olivine", -"olla", -"ollamh", -"ollapod", -"ollock", -"olm", -"ologist", -"ology", -"olomao", -"olona", -"oloroso", -"olpe", -"oltonde", -"oltunna", -"olycook", -"olykoek", -"om", -"omagra", -"omalgia", -"omao", -"omasum", -"omber", -"omega", -"omegoid", -"omelet", -"omen", -"omened", -"omental", -"omentum", -"omer", -"omicron", -"omina", -"ominous", -"omit", -"omitis", -"omitter", -"omlah", -"omneity", -"omniana", -"omnibus", -"omnific", -"omnify", -"omnist", -"omnium", -"on", -"ona", -"onager", -"onagra", -"onanism", -"onanist", -"onca", -"once", -"oncetta", -"oncia", -"oncin", -"oncome", -"oncosis", -"oncost", -"ondatra", -"ondine", -"ondy", -"one", -"onefold", -"onegite", -"onehow", -"oneiric", -"oneism", -"onement", -"oneness", -"oner", -"onerary", -"onerous", -"onery", -"oneself", -"onetime", -"oneyer", -"onfall", -"onflow", -"ongaro", -"ongoing", -"onicolo", -"onion", -"onionet", -"oniony", -"onium", -"onkos", -"onlay", -"onlepy", -"onliest", -"onlook", -"only", -"onmarch", -"onrush", -"ons", -"onset", -"onshore", -"onside", -"onsight", -"onstand", -"onstead", -"onsweep", -"ontal", -"onto", -"onus", -"onward", -"onwards", -"onycha", -"onychia", -"onychin", -"onym", -"onymal", -"onymity", -"onymize", -"onymous", -"onymy", -"onyx", -"onyxis", -"onza", -"ooblast", -"oocyst", -"oocyte", -"oodles", -"ooecial", -"ooecium", -"oofbird", -"ooftish", -"oofy", -"oogamy", -"oogeny", -"ooglea", -"oogone", -"oograph", -"ooid", -"ooidal", -"oolak", -"oolemma", -"oolite", -"oolitic", -"oolly", -"oologic", -"oology", -"oolong", -"oomancy", -"oometer", -"oometry", -"oons", -"oont", -"oopak", -"oophore", -"oophyte", -"ooplasm", -"ooplast", -"oopod", -"oopodal", -"oorali", -"oord", -"ooscope", -"ooscopy", -"oosperm", -"oospore", -"ootheca", -"ootid", -"ootype", -"ooze", -"oozily", -"oozooid", -"oozy", -"opacate", -"opacify", -"opacite", -"opacity", -"opacous", -"opah", -"opal", -"opaled", -"opaline", -"opalish", -"opalize", -"opaloid", -"opaque", -"ope", -"opelet", -"open", -"opener", -"opening", -"openly", -"opera", -"operae", -"operand", -"operant", -"operate", -"opercle", -"operose", -"ophic", -"ophioid", -"ophite", -"ophitic", -"ophryon", -"opianic", -"opianyl", -"opiate", -"opiatic", -"opiism", -"opinant", -"opine", -"opiner", -"opinion", -"opium", -"opossum", -"oppidan", -"oppose", -"opposed", -"opposer", -"opposit", -"oppress", -"oppugn", -"opsonic", -"opsonin", -"opsy", -"opt", -"optable", -"optably", -"optant", -"optate", -"optic", -"optical", -"opticon", -"optics", -"optimal", -"optime", -"optimum", -"option", -"optive", -"opulent", -"opulus", -"opus", -"oquassa", -"or", -"ora", -"orach", -"oracle", -"orad", -"orage", -"oral", -"oraler", -"oralism", -"oralist", -"orality", -"oralize", -"orally", -"oralogy", -"orang", -"orange", -"oranger", -"orangey", -"orant", -"orarian", -"orarion", -"orarium", -"orary", -"orate", -"oration", -"orator", -"oratory", -"oratrix", -"orb", -"orbed", -"orbic", -"orbical", -"orbicle", -"orbific", -"orbit", -"orbital", -"orbitar", -"orbite", -"orbless", -"orblet", -"orby", -"orc", -"orcanet", -"orcein", -"orchard", -"orchat", -"orchel", -"orchic", -"orchid", -"orchil", -"orcin", -"orcinol", -"ordain", -"ordeal", -"order", -"ordered", -"orderer", -"orderly", -"ordinal", -"ordinar", -"ordinee", -"ordines", -"ordu", -"ordure", -"ore", -"oread", -"orectic", -"orellin", -"oreman", -"orenda", -"oreweed", -"orewood", -"orexis", -"orf", -"orfgild", -"organ", -"organal", -"organdy", -"organer", -"organic", -"organon", -"organry", -"organum", -"orgasm", -"orgeat", -"orgia", -"orgiac", -"orgiacs", -"orgiasm", -"orgiast", -"orgic", -"orgue", -"orgy", -"orgyia", -"oribi", -"oriel", -"oriency", -"orient", -"orifice", -"oriform", -"origan", -"origin", -"orignal", -"orihon", -"orillon", -"oriole", -"orison", -"oristic", -"orle", -"orlean", -"orlet", -"orlo", -"orlop", -"ormer", -"ormolu", -"orna", -"ornate", -"ornery", -"ornis", -"ornoite", -"oroanal", -"orogen", -"orogeny", -"oroide", -"orology", -"oronoco", -"orotund", -"orphan", -"orpheon", -"orpheum", -"orphrey", -"orpine", -"orrery", -"orrhoid", -"orris", -"orsel", -"orselle", -"ort", -"ortalid", -"ortet", -"orthal", -"orthian", -"orthic", -"orthid", -"orthite", -"ortho", -"orthose", -"orthron", -"ortiga", -"ortive", -"ortolan", -"ortygan", -"ory", -"oryssid", -"os", -"osamin", -"osamine", -"osazone", -"oscella", -"oscheal", -"oscin", -"oscine", -"oscnode", -"oscular", -"oscule", -"osculum", -"ose", -"osela", -"oshac", -"oside", -"osier", -"osiered", -"osiery", -"osmate", -"osmatic", -"osmesis", -"osmetic", -"osmic", -"osmin", -"osmina", -"osmious", -"osmium", -"osmose", -"osmosis", -"osmotic", -"osmous", -"osmund", -"osone", -"osophy", -"osprey", -"ossal", -"osse", -"ossein", -"osselet", -"osseous", -"ossicle", -"ossific", -"ossify", -"ossuary", -"osteal", -"ostein", -"ostemia", -"ostent", -"osteoid", -"osteoma", -"ostial", -"ostiary", -"ostiate", -"ostiole", -"ostitis", -"ostium", -"ostmark", -"ostosis", -"ostrich", -"otalgia", -"otalgic", -"otalgy", -"otarian", -"otarine", -"otary", -"otate", -"other", -"othmany", -"otiant", -"otiatry", -"otic", -"otidine", -"otidium", -"otiose", -"otitic", -"otitis", -"otkon", -"otocyst", -"otolite", -"otolith", -"otology", -"otosis", -"ototomy", -"ottar", -"otter", -"otterer", -"otto", -"oturia", -"ouabain", -"ouabaio", -"ouabe", -"ouakari", -"ouch", -"ouenite", -"ouf", -"ough", -"ought", -"oughtnt", -"oukia", -"oulap", -"ounce", -"ounds", -"ouphe", -"ouphish", -"our", -"ourie", -"ouroub", -"ours", -"ourself", -"oust", -"ouster", -"out", -"outact", -"outage", -"outarde", -"outask", -"outawe", -"outback", -"outbake", -"outban", -"outbar", -"outbark", -"outbawl", -"outbeam", -"outbear", -"outbeg", -"outbent", -"outbid", -"outblot", -"outblow", -"outbond", -"outbook", -"outborn", -"outbow", -"outbowl", -"outbox", -"outbrag", -"outbray", -"outbred", -"outbud", -"outbulk", -"outburn", -"outbuy", -"outbuzz", -"outby", -"outcant", -"outcase", -"outcast", -"outcity", -"outcome", -"outcrop", -"outcrow", -"outcry", -"outcull", -"outcure", -"outcut", -"outdare", -"outdate", -"outdo", -"outdoer", -"outdoor", -"outdraw", -"outdure", -"outeat", -"outecho", -"outed", -"outedge", -"outen", -"outer", -"outerly", -"outeye", -"outeyed", -"outface", -"outfall", -"outfame", -"outfast", -"outfawn", -"outfeat", -"outfish", -"outfit", -"outflow", -"outflue", -"outflux", -"outfly", -"outfold", -"outfool", -"outfoot", -"outform", -"outfort", -"outgain", -"outgame", -"outgang", -"outgas", -"outgate", -"outgaze", -"outgive", -"outglad", -"outglow", -"outgnaw", -"outgo", -"outgoer", -"outgone", -"outgrin", -"outgrow", -"outgun", -"outgush", -"outhaul", -"outhear", -"outheel", -"outher", -"outhire", -"outhiss", -"outhit", -"outhold", -"outhowl", -"outhue", -"outhunt", -"outhurl", -"outhut", -"outhymn", -"outing", -"outish", -"outjazz", -"outjest", -"outjet", -"outjinx", -"outjump", -"outjut", -"outkick", -"outkill", -"outking", -"outkiss", -"outknee", -"outlaid", -"outland", -"outlash", -"outlast", -"outlaw", -"outlay", -"outlean", -"outleap", -"outler", -"outlet", -"outlie", -"outlier", -"outlimb", -"outlimn", -"outline", -"outlip", -"outlive", -"outlook", -"outlord", -"outlove", -"outlung", -"outly", -"outman", -"outmate", -"outmode", -"outmost", -"outmove", -"outname", -"outness", -"outnook", -"outoven", -"outpace", -"outpage", -"outpart", -"outpass", -"outpath", -"outpay", -"outpeal", -"outpeep", -"outpeer", -"outpick", -"outpipe", -"outpity", -"outplan", -"outplay", -"outplod", -"outplot", -"outpoll", -"outpomp", -"outpop", -"outport", -"outpost", -"outpour", -"outpray", -"outpry", -"outpull", -"outpurl", -"outpush", -"output", -"outrace", -"outrage", -"outrail", -"outrank", -"outrant", -"outrap", -"outrate", -"outrave", -"outray", -"outre", -"outread", -"outrede", -"outrick", -"outride", -"outrig", -"outring", -"outroar", -"outroll", -"outroot", -"outrove", -"outrow", -"outrun", -"outrush", -"outsail", -"outsay", -"outsea", -"outseam", -"outsee", -"outseek", -"outsell", -"outsert", -"outset", -"outshot", -"outshow", -"outshut", -"outside", -"outsift", -"outsigh", -"outsin", -"outsing", -"outsit", -"outsize", -"outskip", -"outsoar", -"outsole", -"outspan", -"outspin", -"outspit", -"outspue", -"outstay", -"outstep", -"outsuck", -"outsulk", -"outsum", -"outswim", -"outtalk", -"outtask", -"outtear", -"outtell", -"outtire", -"outtoil", -"outtop", -"outtrot", -"outturn", -"outvie", -"outvier", -"outvote", -"outwait", -"outwake", -"outwale", -"outwalk", -"outwall", -"outwar", -"outward", -"outwash", -"outwave", -"outwear", -"outweed", -"outweep", -"outwell", -"outwent", -"outwick", -"outwile", -"outwill", -"outwind", -"outwing", -"outwish", -"outwit", -"outwith", -"outwoe", -"outwood", -"outword", -"outwore", -"outwork", -"outworn", -"outyard", -"outyell", -"outyelp", -"outzany", -"ouzel", -"ova", -"oval", -"ovalish", -"ovalize", -"ovally", -"ovaloid", -"ovant", -"ovarial", -"ovarian", -"ovarin", -"ovarium", -"ovary", -"ovate", -"ovated", -"ovately", -"ovation", -"oven", -"ovenful", -"ovenly", -"ovenman", -"over", -"overact", -"overage", -"overall", -"overapt", -"overarm", -"overawe", -"overawn", -"overbet", -"overbid", -"overbig", -"overbit", -"overbow", -"overbuy", -"overby", -"overcap", -"overcow", -"overcoy", -"overcry", -"overcup", -"overcut", -"overdo", -"overdry", -"overdue", -"overdye", -"overeat", -"overegg", -"overeye", -"overfag", -"overfar", -"overfat", -"overfed", -"overfee", -"overfew", -"overfit", -"overfix", -"overfly", -"overget", -"overgo", -"overgod", -"overgun", -"overhit", -"overhot", -"overink", -"overjob", -"overjoy", -"overlap", -"overlax", -"overlay", -"overleg", -"overlie", -"overlip", -"overlow", -"overly", -"overman", -"overmix", -"overnet", -"overnew", -"overpay", -"overpet", -"overply", -"overpot", -"overrim", -"overrun", -"oversad", -"oversea", -"oversee", -"overset", -"oversew", -"oversot", -"oversow", -"overt", -"overtax", -"overtip", -"overtly", -"overtoe", -"overtop", -"overuse", -"overway", -"overweb", -"overwet", -"overwin", -"ovest", -"ovey", -"ovicell", -"ovicide", -"ovicyst", -"oviduct", -"oviform", -"ovigerm", -"ovile", -"ovine", -"ovinia", -"ovipara", -"ovisac", -"ovism", -"ovist", -"ovistic", -"ovocyte", -"ovoid", -"ovoidal", -"ovolo", -"ovology", -"ovular", -"ovulary", -"ovulate", -"ovule", -"ovulist", -"ovum", -"ow", -"owd", -"owe", -"owelty", -"ower", -"owerby", -"owght", -"owing", -"owk", -"owl", -"owldom", -"owler", -"owlery", -"owlet", -"owlhead", -"owling", -"owlish", -"owlism", -"owllike", -"owly", -"own", -"owner", -"ownhood", -"ownness", -"ownself", -"owrehip", -"owrelay", -"owse", -"owsen", -"owser", -"owtchah", -"ox", -"oxacid", -"oxalan", -"oxalate", -"oxalic", -"oxalite", -"oxalyl", -"oxamate", -"oxamic", -"oxamid", -"oxamide", -"oxan", -"oxanate", -"oxane", -"oxanic", -"oxazine", -"oxazole", -"oxbane", -"oxberry", -"oxbird", -"oxbiter", -"oxblood", -"oxbow", -"oxboy", -"oxbrake", -"oxcart", -"oxcheek", -"oxea", -"oxeate", -"oxen", -"oxeote", -"oxer", -"oxetone", -"oxeye", -"oxfly", -"oxgang", -"oxgoad", -"oxhead", -"oxheal", -"oxheart", -"oxhide", -"oxhoft", -"oxhorn", -"oxhouse", -"oxhuvud", -"oxidant", -"oxidase", -"oxidate", -"oxide", -"oxidic", -"oxidize", -"oximate", -"oxime", -"oxland", -"oxlike", -"oxlip", -"oxman", -"oxonic", -"oxonium", -"oxozone", -"oxphony", -"oxreim", -"oxshoe", -"oxskin", -"oxtail", -"oxter", -"oxwort", -"oxy", -"oxyacid", -"oxygas", -"oxygen", -"oxyl", -"oxymel", -"oxyntic", -"oxyopia", -"oxysalt", -"oxytone", -"oyapock", -"oyer", -"oyster", -"ozena", -"ozonate", -"ozone", -"ozoned", -"ozonic", -"ozonide", -"ozonify", -"ozonize", -"ozonous", -"ozophen", -"ozotype", -"p", -"pa", -"paal", -"paar", -"paauw", -"pabble", -"pablo", -"pabouch", -"pabular", -"pabulum", -"pac", -"paca", -"pacable", -"pacate", -"pacay", -"pacaya", -"pace", -"paced", -"pacer", -"pachak", -"pachisi", -"pacific", -"pacify", -"pack", -"package", -"packer", -"packery", -"packet", -"packly", -"packman", -"packway", -"paco", -"pact", -"paction", -"pad", -"padder", -"padding", -"paddle", -"paddled", -"paddler", -"paddock", -"paddy", -"padella", -"padfoot", -"padge", -"padle", -"padlike", -"padlock", -"padnag", -"padre", -"padtree", -"paean", -"paegel", -"paegle", -"paenula", -"paeon", -"paeonic", -"paga", -"pagan", -"paganic", -"paganly", -"paganry", -"page", -"pageant", -"pagedom", -"pageful", -"pager", -"pagina", -"paginal", -"pagoda", -"pagrus", -"pagurid", -"pagus", -"pah", -"paha", -"pahi", -"pahlavi", -"pahmi", -"paho", -"pahutan", -"paigle", -"paik", -"pail", -"pailful", -"pailou", -"pain", -"pained", -"painful", -"paining", -"paint", -"painted", -"painter", -"painty", -"paip", -"pair", -"paired", -"pairer", -"pais", -"paisa", -"paiwari", -"pajama", -"pajock", -"pakchoi", -"pakeha", -"paktong", -"pal", -"palace", -"palaced", -"paladin", -"palaite", -"palama", -"palame", -"palanka", -"palar", -"palas", -"palatal", -"palate", -"palated", -"palatic", -"palaver", -"palay", -"palazzi", -"palch", -"pale", -"palea", -"paleate", -"paled", -"palely", -"paleola", -"paler", -"palet", -"paletot", -"palette", -"paletz", -"palfrey", -"palgat", -"pali", -"palikar", -"palila", -"palinal", -"paling", -"palisfy", -"palish", -"palkee", -"pall", -"palla", -"pallae", -"pallah", -"pallall", -"palled", -"pallet", -"palli", -"pallial", -"pallid", -"pallion", -"pallium", -"pallone", -"pallor", -"pally", -"palm", -"palma", -"palmad", -"palmar", -"palmary", -"palmate", -"palmed", -"palmer", -"palmery", -"palmful", -"palmist", -"palmite", -"palmito", -"palmo", -"palmula", -"palmus", -"palmy", -"palmyra", -"palolo", -"palp", -"palpal", -"palpate", -"palped", -"palpi", -"palpon", -"palpus", -"palsied", -"palster", -"palsy", -"palt", -"palter", -"paltry", -"paludal", -"paludic", -"palule", -"palulus", -"palus", -"paly", -"pam", -"pament", -"pamment", -"pampas", -"pampean", -"pamper", -"pampero", -"pampre", -"pan", -"panace", -"panacea", -"panache", -"panada", -"panade", -"panama", -"panaris", -"panary", -"panax", -"pancake", -"pand", -"panda", -"pandal", -"pandan", -"pandect", -"pandemy", -"pander", -"pandita", -"pandle", -"pandora", -"pandour", -"pandrop", -"pandura", -"pandy", -"pane", -"paned", -"paneity", -"panel", -"panela", -"paneler", -"panfil", -"panfish", -"panful", -"pang", -"pangamy", -"pangane", -"pangen", -"pangene", -"pangful", -"pangi", -"panhead", -"panic", -"panical", -"panicky", -"panicle", -"panisc", -"panisca", -"panisic", -"pank", -"pankin", -"panman", -"panmixy", -"panmug", -"pannade", -"pannage", -"pannam", -"panne", -"pannel", -"panner", -"pannery", -"pannier", -"panning", -"pannose", -"pannum", -"pannus", -"panocha", -"panoche", -"panoply", -"panoram", -"panse", -"panside", -"pansied", -"pansy", -"pant", -"pantas", -"panter", -"panther", -"pantie", -"panties", -"pantile", -"panting", -"pantle", -"pantler", -"panto", -"pantod", -"panton", -"pantoon", -"pantoum", -"pantry", -"pants", -"pantun", -"panty", -"panung", -"panurgy", -"panyar", -"paolo", -"paon", -"pap", -"papa", -"papable", -"papabot", -"papacy", -"papain", -"papal", -"papally", -"papalty", -"papane", -"papaw", -"papaya", -"papboat", -"pape", -"paper", -"papered", -"paperer", -"papern", -"papery", -"papess", -"papey", -"papilla", -"papion", -"papish", -"papism", -"papist", -"papize", -"papless", -"papmeat", -"papoose", -"pappi", -"pappose", -"pappox", -"pappus", -"pappy", -"papreg", -"paprica", -"paprika", -"papula", -"papular", -"papule", -"papyr", -"papyral", -"papyri", -"papyrin", -"papyrus", -"paquet", -"par", -"para", -"parable", -"paracme", -"parade", -"parader", -"parado", -"parados", -"paradox", -"parafle", -"parage", -"paragon", -"parah", -"paraiba", -"parale", -"param", -"paramo", -"parang", -"parao", -"parapet", -"paraph", -"parapod", -"pararek", -"parasol", -"paraspy", -"parate", -"paraxon", -"parbake", -"parboil", -"parcel", -"parch", -"parcher", -"parchy", -"parcook", -"pard", -"pardao", -"parded", -"pardesi", -"pardine", -"pardner", -"pardo", -"pardon", -"pare", -"parel", -"parella", -"paren", -"parent", -"parer", -"paresis", -"paretic", -"parfait", -"pargana", -"parge", -"parget", -"pargo", -"pari", -"pariah", -"parial", -"parian", -"paries", -"parify", -"parilla", -"parine", -"paring", -"parish", -"parisis", -"parison", -"parity", -"park", -"parka", -"parkee", -"parker", -"parkin", -"parking", -"parkish", -"parkway", -"parky", -"parlay", -"parle", -"parley", -"parling", -"parlish", -"parlor", -"parlous", -"parly", -"parma", -"parmak", -"parnas", -"parnel", -"paroch", -"parode", -"parodic", -"parodos", -"parody", -"paroecy", -"parol", -"parole", -"parolee", -"paroli", -"paronym", -"parotic", -"parotid", -"parotis", -"parous", -"parpal", -"parquet", -"parr", -"parrel", -"parrier", -"parrock", -"parrot", -"parroty", -"parry", -"parse", -"parsec", -"parser", -"parsley", -"parsnip", -"parson", -"parsony", -"part", -"partake", -"partan", -"parted", -"parter", -"partial", -"partile", -"partite", -"partlet", -"partly", -"partner", -"parto", -"partook", -"parture", -"party", -"parulis", -"parure", -"paruria", -"parvenu", -"parvis", -"parvule", -"pasan", -"pasang", -"paschal", -"pascual", -"pash", -"pasha", -"pashm", -"pasi", -"pasmo", -"pasquil", -"pasquin", -"pass", -"passade", -"passado", -"passage", -"passant", -"passe", -"passee", -"passen", -"passer", -"passewa", -"passing", -"passion", -"passir", -"passive", -"passkey", -"passman", -"passo", -"passout", -"passus", -"passway", -"past", -"paste", -"pasted", -"pastel", -"paster", -"pastern", -"pasteur", -"pastil", -"pastile", -"pastime", -"pasting", -"pastor", -"pastose", -"pastry", -"pasture", -"pasty", -"pasul", -"pat", -"pata", -"pataca", -"patacao", -"pataco", -"patagon", -"pataka", -"patamar", -"patao", -"patapat", -"pataque", -"patas", -"patball", -"patch", -"patcher", -"patchy", -"pate", -"patefy", -"patel", -"patella", -"paten", -"patency", -"patener", -"patent", -"pater", -"patera", -"patesi", -"path", -"pathed", -"pathema", -"pathic", -"pathlet", -"pathos", -"pathway", -"pathy", -"patible", -"patient", -"patina", -"patine", -"patined", -"patio", -"patly", -"patness", -"pato", -"patois", -"patola", -"patonce", -"patria", -"patrial", -"patrice", -"patrico", -"patrin", -"patriot", -"patrist", -"patrix", -"patrol", -"patron", -"patroon", -"patta", -"patte", -"pattee", -"patten", -"patter", -"pattern", -"pattu", -"patty", -"patu", -"patwari", -"paty", -"pau", -"paucify", -"paucity", -"paughty", -"paukpan", -"paular", -"paulie", -"paulin", -"paunch", -"paunchy", -"paup", -"pauper", -"pausal", -"pause", -"pauser", -"paussid", -"paut", -"pauxi", -"pavage", -"pavan", -"pavane", -"pave", -"paver", -"pavid", -"pavier", -"paving", -"pavior", -"paviour", -"pavis", -"paviser", -"pavisor", -"pavy", -"paw", -"pawdite", -"pawer", -"pawing", -"pawk", -"pawkery", -"pawkily", -"pawkrie", -"pawky", -"pawl", -"pawn", -"pawnage", -"pawnee", -"pawner", -"pawnie", -"pawnor", -"pawpaw", -"pax", -"paxilla", -"paxiuba", -"paxwax", -"pay", -"payable", -"payably", -"payday", -"payed", -"payee", -"payeny", -"payer", -"paying", -"payment", -"paynim", -"payoff", -"payong", -"payor", -"payroll", -"pea", -"peace", -"peach", -"peachen", -"peacher", -"peachy", -"peacoat", -"peacock", -"peacod", -"peafowl", -"peag", -"peage", -"peahen", -"peai", -"peaiism", -"peak", -"peaked", -"peaker", -"peakily", -"peaking", -"peakish", -"peaky", -"peal", -"pealike", -"pean", -"peanut", -"pear", -"pearl", -"pearled", -"pearler", -"pearlet", -"pearlin", -"pearly", -"peart", -"pearten", -"peartly", -"peasant", -"peasen", -"peason", -"peasy", -"peat", -"peatery", -"peatman", -"peaty", -"peavey", -"peavy", -"peba", -"pebble", -"pebbled", -"pebbly", -"pebrine", -"pecan", -"peccant", -"peccary", -"peccavi", -"pech", -"pecht", -"pecite", -"peck", -"pecked", -"pecker", -"pecket", -"peckful", -"peckish", -"peckle", -"peckled", -"peckly", -"pecky", -"pectase", -"pectate", -"pecten", -"pectic", -"pectin", -"pectize", -"pectora", -"pectose", -"pectous", -"pectus", -"ped", -"peda", -"pedage", -"pedagog", -"pedal", -"pedaler", -"pedant", -"pedary", -"pedate", -"pedated", -"pedder", -"peddle", -"peddler", -"pedee", -"pedes", -"pedesis", -"pedicab", -"pedicel", -"pedicle", -"pedion", -"pedlar", -"pedlary", -"pedocal", -"pedrail", -"pedrero", -"pedro", -"pedule", -"pedum", -"pee", -"peed", -"peek", -"peel", -"peele", -"peeled", -"peeler", -"peeling", -"peelman", -"peen", -"peenge", -"peeoy", -"peep", -"peeper", -"peepeye", -"peepy", -"peer", -"peerage", -"peerdom", -"peeress", -"peerie", -"peerly", -"peery", -"peesash", -"peeve", -"peeved", -"peever", -"peevish", -"peewee", -"peg", -"pega", -"pegall", -"pegasid", -"pegbox", -"pegged", -"pegger", -"pegging", -"peggle", -"peggy", -"pegless", -"peglet", -"peglike", -"pegman", -"pegwood", -"peho", -"peine", -"peisage", -"peise", -"peiser", -"peixere", -"pekan", -"pekin", -"pekoe", -"peladic", -"pelage", -"pelagic", -"pelamyd", -"pelanos", -"pelean", -"pelecan", -"pelf", -"pelican", -"pelick", -"pelike", -"peliom", -"pelioma", -"pelisse", -"pelite", -"pelitic", -"pell", -"pellage", -"pellar", -"pellard", -"pellas", -"pellate", -"peller", -"pellet", -"pellety", -"pellile", -"pellock", -"pelmet", -"pelon", -"peloria", -"peloric", -"pelorus", -"pelota", -"peloton", -"pelt", -"pelta", -"peltast", -"peltate", -"pelter", -"pelting", -"peltry", -"pelu", -"peludo", -"pelves", -"pelvic", -"pelvis", -"pembina", -"pemican", -"pen", -"penal", -"penally", -"penalty", -"penance", -"penang", -"penates", -"penbard", -"pence", -"pencel", -"pencil", -"pend", -"penda", -"pendant", -"pendent", -"pending", -"pendle", -"pendom", -"pendule", -"penfold", -"penful", -"pengo", -"penguin", -"penhead", -"penial", -"penide", -"penile", -"penis", -"penk", -"penlike", -"penman", -"penna", -"pennae", -"pennage", -"pennant", -"pennate", -"penner", -"pennet", -"penni", -"pennia", -"pennied", -"pennill", -"penning", -"pennon", -"penny", -"penrack", -"penship", -"pensile", -"pension", -"pensive", -"penster", -"pensum", -"pensy", -"pent", -"penta", -"pentace", -"pentad", -"pentail", -"pentane", -"pentene", -"pentine", -"pentit", -"pentite", -"pentode", -"pentoic", -"pentol", -"pentose", -"pentrit", -"pentyl", -"pentyne", -"penuchi", -"penult", -"penury", -"peon", -"peonage", -"peonism", -"peony", -"people", -"peopler", -"peoplet", -"peotomy", -"pep", -"pepful", -"pepino", -"peplos", -"peplum", -"peplus", -"pepo", -"pepper", -"peppery", -"peppily", -"peppin", -"peppy", -"pepsin", -"pepsis", -"peptic", -"peptide", -"peptize", -"peptone", -"per", -"peracid", -"peract", -"perbend", -"percale", -"percent", -"percept", -"perch", -"percha", -"percher", -"percid", -"percoct", -"percoid", -"percur", -"percuss", -"perdu", -"perdure", -"pereion", -"pereira", -"peres", -"perfect", -"perfidy", -"perform", -"perfume", -"perfumy", -"perfuse", -"pergola", -"perhaps", -"peri", -"periapt", -"peridot", -"perigee", -"perigon", -"peril", -"perine", -"period", -"periost", -"perique", -"perish", -"perit", -"perite", -"periwig", -"perjink", -"perjure", -"perjury", -"perk", -"perkily", -"perkin", -"perking", -"perkish", -"perky", -"perle", -"perlid", -"perlite", -"perloir", -"perm", -"permit", -"permute", -"pern", -"pernine", -"pernor", -"pernyi", -"peroba", -"peropod", -"peropus", -"peroral", -"perosis", -"perotic", -"peroxy", -"peroxyl", -"perpend", -"perpera", -"perplex", -"perrier", -"perron", -"perry", -"persalt", -"perse", -"persico", -"persis", -"persist", -"person", -"persona", -"pert", -"pertain", -"perten", -"pertish", -"pertly", -"perturb", -"pertuse", -"perty", -"peruke", -"perula", -"perule", -"perusal", -"peruse", -"peruser", -"pervade", -"pervert", -"pes", -"pesa", -"pesade", -"pesage", -"peseta", -"peshkar", -"peshwa", -"peskily", -"pesky", -"peso", -"pess", -"pessary", -"pest", -"peste", -"pester", -"pestful", -"pestify", -"pestle", -"pet", -"petal", -"petaled", -"petalon", -"petaly", -"petard", -"petary", -"petasos", -"petasus", -"petcock", -"pete", -"peteca", -"peteman", -"peter", -"petful", -"petiole", -"petit", -"petite", -"petitor", -"petkin", -"petling", -"peto", -"petrary", -"petre", -"petrean", -"petrel", -"petrie", -"petrify", -"petrol", -"petrosa", -"petrous", -"petted", -"petter", -"pettily", -"pettish", -"pettle", -"petty", -"petune", -"petwood", -"petzite", -"peuhl", -"pew", -"pewage", -"pewdom", -"pewee", -"pewful", -"pewing", -"pewit", -"pewless", -"pewmate", -"pewter", -"pewtery", -"pewy", -"peyote", -"peyotl", -"peyton", -"peytrel", -"pfennig", -"pfui", -"pfund", -"phacoid", -"phaeism", -"phaeton", -"phage", -"phalanx", -"phalera", -"phallic", -"phallin", -"phallus", -"phanic", -"phano", -"phantom", -"phare", -"pharmic", -"pharos", -"pharynx", -"phase", -"phaseal", -"phasemy", -"phases", -"phasic", -"phasis", -"phasm", -"phasma", -"phasmid", -"pheal", -"phellem", -"phemic", -"phenate", -"phene", -"phenene", -"phenic", -"phenin", -"phenol", -"phenyl", -"pheon", -"phew", -"phi", -"phial", -"phiale", -"philter", -"philtra", -"phit", -"phiz", -"phizes", -"phizog", -"phlegm", -"phlegma", -"phlegmy", -"phloem", -"phloxin", -"pho", -"phobiac", -"phobic", -"phobism", -"phobist", -"phoby", -"phoca", -"phocal", -"phocid", -"phocine", -"phocoid", -"phoebe", -"phoenix", -"phoh", -"pholad", -"pholcid", -"pholido", -"phon", -"phonal", -"phonate", -"phone", -"phoneme", -"phonic", -"phonics", -"phonism", -"phono", -"phony", -"phoo", -"phoresy", -"phoria", -"phorid", -"phorone", -"phos", -"phose", -"phosis", -"phospho", -"phossy", -"phot", -"photal", -"photic", -"photics", -"photism", -"photo", -"photoma", -"photon", -"phragma", -"phrasal", -"phrase", -"phraser", -"phrasy", -"phrator", -"phratry", -"phrenic", -"phrynid", -"phrynin", -"phthor", -"phu", -"phugoid", -"phulwa", -"phut", -"phycite", -"phyla", -"phyle", -"phylic", -"phyllin", -"phylon", -"phylum", -"phyma", -"phymata", -"physic", -"physics", -"phytase", -"phytic", -"phytin", -"phytoid", -"phytol", -"phytoma", -"phytome", -"phyton", -"phytyl", -"pi", -"pia", -"piaba", -"piacaba", -"piacle", -"piaffe", -"piaffer", -"pial", -"pialyn", -"pian", -"pianic", -"pianino", -"pianism", -"pianist", -"piannet", -"piano", -"pianola", -"piaster", -"piastre", -"piation", -"piazine", -"piazza", -"pibcorn", -"pibroch", -"pic", -"pica", -"picador", -"pical", -"picamar", -"picara", -"picarel", -"picaro", -"picary", -"piccolo", -"pice", -"picene", -"piceous", -"pichi", -"picine", -"pick", -"pickage", -"pickax", -"picked", -"pickee", -"pickeer", -"picker", -"pickery", -"picket", -"pickle", -"pickler", -"pickman", -"pickmaw", -"pickup", -"picky", -"picnic", -"pico", -"picoid", -"picot", -"picotah", -"picotee", -"picra", -"picrate", -"picric", -"picrite", -"picrol", -"picryl", -"pict", -"picture", -"pictury", -"picuda", -"picudo", -"picul", -"piculet", -"pidan", -"piddle", -"piddler", -"piddock", -"pidgin", -"pie", -"piebald", -"piece", -"piecen", -"piecer", -"piecing", -"pied", -"piedly", -"pieless", -"pielet", -"pielum", -"piemag", -"pieman", -"pien", -"piend", -"piepan", -"pier", -"pierage", -"pierce", -"pierced", -"piercel", -"piercer", -"pierid", -"pierine", -"pierrot", -"pieshop", -"piet", -"pietas", -"pietic", -"pietism", -"pietist", -"pietose", -"piety", -"piewife", -"piewipe", -"piezo", -"piff", -"piffle", -"piffler", -"pifine", -"pig", -"pigdan", -"pigdom", -"pigeon", -"pigface", -"pigfish", -"pigfoot", -"pigful", -"piggery", -"piggin", -"pigging", -"piggish", -"piggle", -"piggy", -"pighead", -"pigherd", -"pightle", -"pigless", -"piglet", -"pigling", -"pigly", -"pigman", -"pigment", -"pignon", -"pignus", -"pignut", -"pigpen", -"pigroot", -"pigskin", -"pigsney", -"pigsty", -"pigtail", -"pigwash", -"pigweed", -"pigyard", -"piitis", -"pik", -"pika", -"pike", -"piked", -"pikel", -"pikelet", -"pikeman", -"piker", -"pikey", -"piki", -"piking", -"pikle", -"piky", -"pilage", -"pilapil", -"pilar", -"pilary", -"pilau", -"pilaued", -"pilch", -"pilcher", -"pilcorn", -"pilcrow", -"pile", -"pileata", -"pileate", -"piled", -"pileous", -"piler", -"piles", -"pileus", -"pilfer", -"pilger", -"pilgrim", -"pili", -"pilifer", -"piligan", -"pilikai", -"pilin", -"piline", -"piling", -"pilkins", -"pill", -"pillage", -"pillar", -"pillary", -"pillas", -"pillbox", -"pilled", -"pillet", -"pilleus", -"pillion", -"pillory", -"pillow", -"pillowy", -"pilm", -"pilmy", -"pilon", -"pilori", -"pilose", -"pilosis", -"pilot", -"pilotee", -"pilotry", -"pilous", -"pilpul", -"piltock", -"pilula", -"pilular", -"pilule", -"pilum", -"pilus", -"pily", -"pimaric", -"pimelic", -"pimento", -"pimlico", -"pimola", -"pimp", -"pimpery", -"pimping", -"pimpish", -"pimple", -"pimpled", -"pimplo", -"pimploe", -"pimply", -"pin", -"pina", -"pinaces", -"pinacle", -"pinacol", -"pinang", -"pinax", -"pinball", -"pinbone", -"pinbush", -"pincase", -"pincer", -"pincers", -"pinch", -"pinche", -"pinched", -"pinchem", -"pincher", -"pind", -"pinda", -"pinder", -"pindy", -"pine", -"pineal", -"pined", -"pinene", -"piner", -"pinery", -"pinesap", -"pinetum", -"piney", -"pinfall", -"pinfish", -"pinfold", -"ping", -"pingle", -"pingler", -"pingue", -"pinguid", -"pinguin", -"pinhead", -"pinhold", -"pinhole", -"pinhook", -"pinic", -"pining", -"pinion", -"pinite", -"pinitol", -"pinjane", -"pinjra", -"pink", -"pinked", -"pinkeen", -"pinken", -"pinker", -"pinkeye", -"pinkie", -"pinkify", -"pinkily", -"pinking", -"pinkish", -"pinkly", -"pinky", -"pinless", -"pinlock", -"pinna", -"pinnace", -"pinnae", -"pinnal", -"pinnate", -"pinned", -"pinnel", -"pinner", -"pinnet", -"pinning", -"pinnock", -"pinnula", -"pinnule", -"pinny", -"pino", -"pinole", -"pinolia", -"pinolin", -"pinon", -"pinonic", -"pinrail", -"pinsons", -"pint", -"pinta", -"pintado", -"pintail", -"pintano", -"pinte", -"pintle", -"pinto", -"pintura", -"pinulus", -"pinweed", -"pinwing", -"pinwork", -"pinworm", -"piny", -"pinyl", -"pinyon", -"pioneer", -"pioted", -"piotine", -"piotty", -"pioury", -"pious", -"piously", -"pip", -"pipa", -"pipage", -"pipal", -"pipe", -"pipeage", -"piped", -"pipeful", -"pipeman", -"piper", -"piperic", -"piperly", -"piperno", -"pipery", -"pipet", -"pipette", -"pipi", -"piping", -"pipiri", -"pipit", -"pipkin", -"pipless", -"pipped", -"pipper", -"pippin", -"pippy", -"piprine", -"piproid", -"pipy", -"piquant", -"pique", -"piquet", -"piquia", -"piqure", -"pir", -"piracy", -"piragua", -"piranha", -"pirate", -"piraty", -"pirl", -"pirn", -"pirner", -"pirnie", -"pirny", -"pirogue", -"pirol", -"pirr", -"pirrmaw", -"pisaca", -"pisang", -"pisay", -"piscary", -"piscian", -"piscina", -"piscine", -"pisco", -"pise", -"pish", -"pishaug", -"pishu", -"pisk", -"pisky", -"pismire", -"piso", -"piss", -"pissant", -"pist", -"pistic", -"pistil", -"pistle", -"pistol", -"pistole", -"piston", -"pistrix", -"pit", -"pita", -"pitanga", -"pitapat", -"pitarah", -"pitau", -"pitaya", -"pitch", -"pitcher", -"pitchi", -"pitchy", -"piteous", -"pitfall", -"pith", -"pithful", -"pithily", -"pithole", -"pithos", -"pithy", -"pitier", -"pitiful", -"pitless", -"pitlike", -"pitman", -"pitmark", -"pitmirk", -"pitpan", -"pitpit", -"pitside", -"pitted", -"pitter", -"pittine", -"pitting", -"pittite", -"pittoid", -"pituite", -"pituri", -"pitwood", -"pitwork", -"pity", -"pitying", -"piuri", -"pivalic", -"pivot", -"pivotal", -"pivoter", -"pix", -"pixie", -"pixy", -"pize", -"pizza", -"pizzle", -"placard", -"placate", -"place", -"placebo", -"placer", -"placet", -"placid", -"plack", -"placket", -"placode", -"placoid", -"placula", -"plaga", -"plagal", -"plagate", -"plage", -"plagium", -"plagose", -"plague", -"plagued", -"plaguer", -"plaguy", -"plaice", -"plaid", -"plaided", -"plaidie", -"plaidy", -"plain", -"plainer", -"plainly", -"plaint", -"plait", -"plaited", -"plaiter", -"plak", -"plakat", -"plan", -"planaea", -"planar", -"planate", -"planch", -"plandok", -"plane", -"planer", -"planet", -"planeta", -"planful", -"plang", -"plangor", -"planish", -"planity", -"plank", -"planker", -"planky", -"planner", -"plant", -"planta", -"plantad", -"plantal", -"plantar", -"planter", -"planula", -"planury", -"planxty", -"plap", -"plaque", -"plash", -"plasher", -"plashet", -"plashy", -"plasm", -"plasma", -"plasmic", -"plasome", -"plass", -"plasson", -"plaster", -"plastic", -"plastid", -"plastin", -"plat", -"platan", -"platane", -"platano", -"platch", -"plate", -"platea", -"plateau", -"plated", -"platen", -"plater", -"platery", -"platic", -"platina", -"plating", -"platode", -"platoid", -"platoon", -"platted", -"platten", -"platter", -"platty", -"platy", -"plaud", -"plaudit", -"play", -"playa", -"playbox", -"playboy", -"playday", -"player", -"playful", -"playlet", -"playman", -"playock", -"playpen", -"plaza", -"plea", -"pleach", -"plead", -"pleader", -"please", -"pleaser", -"pleat", -"pleater", -"pleb", -"plebe", -"plebify", -"plebs", -"pleck", -"plectre", -"pled", -"pledge", -"pledgee", -"pledger", -"pledget", -"pledgor", -"pleion", -"plenary", -"plenipo", -"plenish", -"plenism", -"plenist", -"plenty", -"plenum", -"pleny", -"pleon", -"pleonal", -"pleonic", -"pleopod", -"pleroma", -"plerome", -"plessor", -"pleura", -"pleural", -"pleuric", -"pleuron", -"pleurum", -"plew", -"plex", -"plexal", -"plexor", -"plexure", -"plexus", -"pliable", -"pliably", -"pliancy", -"pliant", -"plica", -"plical", -"plicate", -"plied", -"plier", -"plies", -"pliers", -"plight", -"plim", -"plinth", -"pliskie", -"plisky", -"ploat", -"ploce", -"plock", -"plod", -"plodder", -"plodge", -"plomb", -"plook", -"plop", -"plosion", -"plosive", -"plot", -"plote", -"plotful", -"plotted", -"plotter", -"plotty", -"plough", -"plouk", -"plouked", -"plouky", -"plounce", -"plout", -"plouter", -"plover", -"plovery", -"plow", -"plowboy", -"plower", -"plowing", -"plowman", -"ploy", -"pluck", -"plucked", -"plucker", -"plucky", -"plud", -"pluff", -"pluffer", -"pluffy", -"plug", -"plugged", -"plugger", -"pluggy", -"plugman", -"plum", -"pluma", -"plumach", -"plumade", -"plumage", -"plumate", -"plumb", -"plumber", -"plumbet", -"plumbic", -"plumbog", -"plumbum", -"plumcot", -"plume", -"plumed", -"plumer", -"plumery", -"plumet", -"plumier", -"plumify", -"plumist", -"plumlet", -"plummer", -"plummet", -"plummy", -"plumose", -"plumous", -"plump", -"plumpen", -"plumper", -"plumply", -"plumps", -"plumpy", -"plumula", -"plumule", -"plumy", -"plunder", -"plunge", -"plunger", -"plunk", -"plup", -"plural", -"pluries", -"plurify", -"plus", -"plush", -"plushed", -"plushy", -"pluteal", -"plutean", -"pluteus", -"pluvial", -"pluvian", -"pluvine", -"ply", -"plyer", -"plying", -"plywood", -"pneuma", -"po", -"poach", -"poacher", -"poachy", -"poalike", -"pob", -"pobby", -"pobs", -"pochade", -"pochard", -"pochay", -"poche", -"pock", -"pocket", -"pockety", -"pockily", -"pocky", -"poco", -"pocosin", -"pod", -"podagra", -"podal", -"podalic", -"podatus", -"podded", -"podder", -"poddish", -"poddle", -"poddy", -"podeon", -"podesta", -"podex", -"podge", -"podger", -"podgily", -"podgy", -"podial", -"podical", -"podices", -"podite", -"poditic", -"poditti", -"podium", -"podler", -"podley", -"podlike", -"podogyn", -"podsol", -"poduran", -"podurid", -"podware", -"podzol", -"poe", -"poem", -"poemet", -"poemlet", -"poesie", -"poesis", -"poesy", -"poet", -"poetdom", -"poetess", -"poetic", -"poetics", -"poetito", -"poetize", -"poetly", -"poetry", -"pogge", -"poggy", -"pogonip", -"pogrom", -"pogy", -"poh", -"poha", -"pohna", -"poi", -"poietic", -"poignet", -"poil", -"poilu", -"poind", -"poinder", -"point", -"pointed", -"pointel", -"pointer", -"pointy", -"poise", -"poised", -"poiser", -"poison", -"poitrel", -"pokable", -"poke", -"poked", -"pokeful", -"pokeout", -"poker", -"pokey", -"pokily", -"poking", -"pokomoo", -"pokunt", -"poky", -"pol", -"polacca", -"polack", -"polacre", -"polar", -"polaric", -"polarly", -"polaxis", -"poldavy", -"polder", -"pole", -"polearm", -"poleax", -"poleaxe", -"polecat", -"poleman", -"polemic", -"polenta", -"poler", -"poley", -"poliad", -"police", -"policed", -"policy", -"poligar", -"polio", -"polis", -"polish", -"polite", -"politic", -"polity", -"polk", -"polka", -"poll", -"pollack", -"polladz", -"pollage", -"pollam", -"pollan", -"pollard", -"polled", -"pollen", -"pollent", -"poller", -"pollex", -"polling", -"pollock", -"polloi", -"pollute", -"pollux", -"polo", -"poloist", -"polony", -"polos", -"polska", -"polt", -"poltina", -"poly", -"polyact", -"polyad", -"polygam", -"polygon", -"polygyn", -"polymer", -"polyose", -"polyp", -"polyped", -"polypi", -"polypod", -"polypus", -"pom", -"pomace", -"pomade", -"pomane", -"pomate", -"pomato", -"pomatum", -"pombe", -"pombo", -"pome", -"pomelo", -"pomey", -"pomfret", -"pomme", -"pommee", -"pommel", -"pommet", -"pommey", -"pommy", -"pomonal", -"pomonic", -"pomp", -"pompa", -"pompal", -"pompano", -"pompey", -"pomphus", -"pompier", -"pompion", -"pompist", -"pompon", -"pompous", -"pomster", -"pon", -"ponce", -"ponceau", -"poncho", -"pond", -"pondage", -"ponder", -"pondful", -"pondlet", -"pondman", -"pondok", -"pondus", -"pondy", -"pone", -"ponent", -"ponerid", -"poney", -"pong", -"ponga", -"pongee", -"poniard", -"ponica", -"ponier", -"ponja", -"pont", -"pontage", -"pontal", -"pontee", -"pontes", -"pontic", -"pontiff", -"pontify", -"pontil", -"pontile", -"pontin", -"pontine", -"pontist", -"ponto", -"ponton", -"pontoon", -"pony", -"ponzite", -"pooa", -"pooch", -"pooder", -"poodle", -"poof", -"poogye", -"pooh", -"pook", -"pooka", -"pookaun", -"pookoo", -"pool", -"pooler", -"pooli", -"pooly", -"poon", -"poonac", -"poonga", -"poop", -"pooped", -"poor", -"poorish", -"poorly", -"poot", -"pop", -"popadam", -"popal", -"popcorn", -"popdock", -"pope", -"popedom", -"popeism", -"popeler", -"popely", -"popery", -"popess", -"popeye", -"popeyed", -"popgun", -"popify", -"popinac", -"popish", -"popjoy", -"poplar", -"poplin", -"popover", -"poppa", -"poppean", -"poppel", -"popper", -"poppet", -"poppied", -"poppin", -"popple", -"popply", -"poppy", -"popshop", -"popular", -"populin", -"popweed", -"poral", -"porcate", -"porch", -"porched", -"porcine", -"pore", -"pored", -"porer", -"porge", -"porger", -"porgy", -"poring", -"porism", -"porite", -"pork", -"porker", -"porkery", -"porket", -"porkish", -"porkman", -"porkpie", -"porky", -"porogam", -"poroma", -"poros", -"porose", -"porosis", -"porotic", -"porous", -"porr", -"porrect", -"porret", -"porrigo", -"porry", -"port", -"porta", -"portage", -"portail", -"portal", -"portass", -"ported", -"portend", -"portent", -"porter", -"portia", -"portico", -"portify", -"portio", -"portion", -"portlet", -"portly", -"portman", -"porto", -"portray", -"portway", -"porty", -"porule", -"porus", -"pory", -"posca", -"pose", -"poser", -"poseur", -"posey", -"posh", -"posing", -"posit", -"positor", -"positum", -"posnet", -"posole", -"poss", -"posse", -"possess", -"posset", -"possum", -"post", -"postage", -"postal", -"postbag", -"postbox", -"postboy", -"posted", -"posteen", -"poster", -"postern", -"postfix", -"postic", -"postil", -"posting", -"postman", -"posture", -"postwar", -"posy", -"pot", -"potable", -"potamic", -"potash", -"potass", -"potassa", -"potate", -"potato", -"potator", -"potbank", -"potboil", -"potboy", -"potch", -"potcher", -"potdar", -"pote", -"poteen", -"potence", -"potency", -"potent", -"poter", -"poteye", -"potful", -"potgirl", -"potgun", -"pothead", -"potheen", -"pother", -"potherb", -"pothery", -"pothole", -"pothook", -"pothunt", -"potifer", -"potion", -"potleg", -"potlid", -"potlike", -"potluck", -"potman", -"potong", -"potoo", -"potoroo", -"potpie", -"potrack", -"pott", -"pottage", -"pottagy", -"pottah", -"potted", -"potter", -"pottery", -"potting", -"pottle", -"pottled", -"potto", -"potty", -"potware", -"potwork", -"potwort", -"pouce", -"poucer", -"poucey", -"pouch", -"pouched", -"pouchy", -"pouf", -"poulard", -"poulp", -"poulpe", -"poult", -"poulter", -"poultry", -"pounamu", -"pounce", -"pounced", -"pouncer", -"pouncet", -"pound", -"poundal", -"pounder", -"pour", -"pourer", -"pourie", -"pouring", -"pouser", -"pout", -"pouter", -"poutful", -"pouting", -"pouty", -"poverty", -"pow", -"powder", -"powdery", -"powdike", -"powdry", -"power", -"powered", -"powitch", -"pownie", -"powwow", -"pox", -"poxy", -"poy", -"poyou", -"praam", -"prabble", -"prabhu", -"practic", -"prad", -"praecox", -"praetor", -"prairie", -"praise", -"praiser", -"prajna", -"praline", -"pram", -"prana", -"prance", -"prancer", -"prancy", -"prank", -"pranked", -"pranker", -"prankle", -"pranky", -"prase", -"prasine", -"prasoid", -"prastha", -"prat", -"pratal", -"prate", -"prater", -"pratey", -"prating", -"prattle", -"prattly", -"prau", -"pravity", -"prawn", -"prawner", -"prawny", -"praxis", -"pray", -"praya", -"prayer", -"prayful", -"praying", -"preach", -"preachy", -"preacid", -"preact", -"preaged", -"preally", -"preanal", -"prearm", -"preaver", -"prebake", -"prebend", -"prebid", -"prebill", -"preboil", -"preborn", -"preburn", -"precant", -"precary", -"precast", -"precava", -"precede", -"precent", -"precept", -"preces", -"precess", -"precipe", -"precis", -"precise", -"precite", -"precoil", -"precook", -"precool", -"precopy", -"precox", -"precure", -"precut", -"precyst", -"predamn", -"predark", -"predata", -"predate", -"predawn", -"preday", -"predefy", -"predeny", -"predial", -"predict", -"prediet", -"predine", -"predoom", -"predraw", -"predry", -"predusk", -"preen", -"preener", -"preeze", -"prefab", -"preface", -"prefect", -"prefer", -"prefine", -"prefix", -"prefool", -"preform", -"pregain", -"pregust", -"prehaps", -"preheal", -"preheat", -"prehend", -"preidea", -"preknit", -"preknow", -"prelacy", -"prelate", -"prelect", -"prelim", -"preloan", -"preloss", -"prelude", -"premake", -"premate", -"premial", -"premier", -"premise", -"premiss", -"premium", -"premix", -"premold", -"premove", -"prename", -"prender", -"prendre", -"preomit", -"preopen", -"preoral", -"prep", -"prepare", -"prepave", -"prepay", -"prepink", -"preplan", -"preplot", -"prepose", -"prepuce", -"prepupa", -"prerent", -"prerich", -"prerupt", -"presage", -"presay", -"preseal", -"presee", -"presell", -"present", -"preses", -"preset", -"preship", -"preshow", -"preside", -"presift", -"presign", -"prespur", -"press", -"pressel", -"presser", -"pressor", -"prest", -"prester", -"presto", -"presume", -"pretan", -"pretell", -"pretend", -"pretest", -"pretext", -"pretire", -"pretone", -"pretry", -"pretty", -"pretzel", -"prevail", -"prevene", -"prevent", -"preverb", -"preveto", -"previde", -"preview", -"previse", -"prevoid", -"prevote", -"prevue", -"prewar", -"prewarn", -"prewash", -"prewhip", -"prewire", -"prewrap", -"prexy", -"prey", -"preyer", -"preyful", -"prezone", -"price", -"priced", -"pricer", -"prich", -"prick", -"pricked", -"pricker", -"pricket", -"prickle", -"prickly", -"pricks", -"pricky", -"pride", -"pridian", -"priding", -"pridy", -"pried", -"prier", -"priest", -"prig", -"prigdom", -"prigger", -"prigman", -"prill", -"prim", -"prima", -"primacy", -"primage", -"primal", -"primar", -"primary", -"primate", -"prime", -"primely", -"primer", -"primero", -"primine", -"priming", -"primly", -"primost", -"primp", -"primsie", -"primula", -"primus", -"primy", -"prince", -"princox", -"prine", -"pringle", -"prink", -"prinker", -"prinkle", -"prinky", -"print", -"printed", -"printer", -"prion", -"prionid", -"prior", -"prioral", -"priorly", -"priory", -"prisage", -"prisal", -"priscan", -"prism", -"prismal", -"prismed", -"prismy", -"prison", -"priss", -"prissy", -"pritch", -"prithee", -"prius", -"privacy", -"privant", -"private", -"privet", -"privily", -"privity", -"privy", -"prize", -"prizer", -"prizery", -"pro", -"proa", -"proal", -"proarmy", -"prob", -"probabl", -"probal", -"probang", -"probant", -"probate", -"probe", -"probeer", -"prober", -"probity", -"problem", -"procarp", -"proceed", -"process", -"proctal", -"proctor", -"procure", -"prod", -"prodder", -"proddle", -"prodigy", -"produce", -"product", -"proem", -"proetid", -"prof", -"profane", -"profert", -"profess", -"proffer", -"profile", -"profit", -"profuse", -"prog", -"progeny", -"progger", -"progne", -"program", -"project", -"proke", -"proker", -"prolan", -"prolate", -"proleg", -"prolify", -"proline", -"prolix", -"prolong", -"prolyl", -"promic", -"promise", -"promote", -"prompt", -"pronaos", -"pronate", -"pronavy", -"prone", -"pronely", -"proneur", -"prong", -"pronged", -"pronger", -"pronic", -"pronoun", -"pronpl", -"pronto", -"pronuba", -"proo", -"proof", -"proofer", -"proofy", -"prop", -"propago", -"propale", -"propane", -"propend", -"propene", -"proper", -"prophet", -"propine", -"proplex", -"propone", -"propons", -"propose", -"propoxy", -"propper", -"props", -"propupa", -"propyl", -"propyne", -"prorata", -"prorate", -"prore", -"prorean", -"prorsad", -"prorsal", -"prosaic", -"prosar", -"prose", -"prosect", -"proser", -"prosify", -"prosily", -"prosing", -"prosish", -"prosist", -"proso", -"prosode", -"prosody", -"prosoma", -"prosper", -"pross", -"prossy", -"prosy", -"protax", -"prote", -"protea", -"protead", -"protean", -"protect", -"protege", -"proteic", -"protein", -"protend", -"protest", -"protext", -"prothyl", -"protide", -"protist", -"protium", -"proto", -"protoma", -"protome", -"proton", -"protone", -"protore", -"protyl", -"protyle", -"protype", -"proudly", -"provand", -"provant", -"prove", -"provect", -"proved", -"proven", -"prover", -"proverb", -"provide", -"provine", -"proving", -"proviso", -"provoke", -"provost", -"prow", -"prowar", -"prowed", -"prowess", -"prowl", -"prowler", -"proxeny", -"proximo", -"proxy", -"proxysm", -"prozone", -"prude", -"prudely", -"prudent", -"prudery", -"prudish", -"prudist", -"prudity", -"pruh", -"prunase", -"prune", -"prunell", -"pruner", -"pruning", -"prunt", -"prunted", -"prurigo", -"prussic", -"prut", -"prutah", -"pry", -"pryer", -"prying", -"pryler", -"pryse", -"prytany", -"psalis", -"psalm", -"psalmic", -"psalmy", -"psaloid", -"psalter", -"psaltes", -"pschent", -"pseudo", -"psha", -"pshaw", -"psi", -"psiloi", -"psoadic", -"psoas", -"psoatic", -"psocid", -"psocine", -"psoitis", -"psora", -"psoric", -"psoroid", -"psorous", -"pst", -"psych", -"psychal", -"psyche", -"psychic", -"psychid", -"psychon", -"psykter", -"psylla", -"psyllid", -"ptarmic", -"ptereal", -"pteric", -"pterion", -"pteroid", -"pteroma", -"pteryla", -"ptinid", -"ptinoid", -"ptisan", -"ptomain", -"ptosis", -"ptotic", -"ptyalin", -"ptyxis", -"pu", -"pua", -"puan", -"pub", -"pubal", -"pubble", -"puberal", -"puberty", -"pubes", -"pubian", -"pubic", -"pubis", -"public", -"publish", -"puccoon", -"puce", -"pucelle", -"puchero", -"puck", -"pucka", -"pucker", -"puckery", -"puckish", -"puckle", -"puckrel", -"pud", -"puddee", -"pudder", -"pudding", -"puddle", -"puddled", -"puddler", -"puddly", -"puddock", -"puddy", -"pudency", -"pudenda", -"pudent", -"pudge", -"pudgily", -"pudgy", -"pudiano", -"pudic", -"pudical", -"pudsey", -"pudsy", -"pudu", -"pueblo", -"puerer", -"puerile", -"puerman", -"puff", -"puffed", -"puffer", -"puffery", -"puffily", -"puffin", -"puffing", -"pufflet", -"puffwig", -"puffy", -"pug", -"pugged", -"pugger", -"puggi", -"pugging", -"puggish", -"puggle", -"puggree", -"puggy", -"pugh", -"pugil", -"pugman", -"pugmill", -"puisne", -"puist", -"puistie", -"puja", -"puka", -"pukatea", -"puke", -"pukeko", -"puker", -"pukish", -"pukras", -"puku", -"puky", -"pul", -"pulahan", -"pulasan", -"pule", -"pulegol", -"puler", -"puli", -"pulicat", -"pulicid", -"puling", -"pulish", -"pulk", -"pulka", -"pull", -"pulldoo", -"pullen", -"puller", -"pullery", -"pullet", -"pulley", -"pulli", -"pullus", -"pulp", -"pulpal", -"pulper", -"pulpify", -"pulpily", -"pulpit", -"pulpous", -"pulpy", -"pulque", -"pulsant", -"pulsate", -"pulse", -"pulsion", -"pulsive", -"pulton", -"pulu", -"pulvic", -"pulvil", -"pulvino", -"pulwar", -"puly", -"puma", -"pumice", -"pumiced", -"pumicer", -"pummel", -"pummice", -"pump", -"pumpage", -"pumper", -"pumpkin", -"pumple", -"pumpman", -"pun", -"puna", -"punaise", -"punalua", -"punatoo", -"punch", -"puncher", -"punchy", -"punct", -"punctal", -"punctum", -"pundit", -"pundita", -"pundum", -"puneca", -"pung", -"punga", -"pungar", -"pungent", -"punger", -"pungey", -"pungi", -"pungle", -"pungled", -"punicin", -"punily", -"punish", -"punjum", -"punk", -"punkah", -"punkie", -"punky", -"punless", -"punlet", -"punnage", -"punner", -"punnet", -"punnic", -"punster", -"punt", -"punta", -"puntal", -"puntel", -"punter", -"punti", -"puntil", -"puntist", -"punto", -"puntout", -"punty", -"puny", -"punyish", -"punyism", -"pup", -"pupa", -"pupal", -"pupate", -"pupelo", -"pupil", -"pupilar", -"pupiled", -"pupoid", -"puppet", -"puppify", -"puppily", -"puppy", -"pupulo", -"pupunha", -"pur", -"purana", -"puranic", -"puraque", -"purdah", -"purdy", -"pure", -"pured", -"puree", -"purely", -"purer", -"purfle", -"purfled", -"purfler", -"purfly", -"purga", -"purge", -"purger", -"purgery", -"purging", -"purify", -"purine", -"puriri", -"purism", -"purist", -"purity", -"purl", -"purler", -"purlieu", -"purlin", -"purlman", -"purloin", -"purpart", -"purple", -"purply", -"purport", -"purpose", -"purpura", -"purpure", -"purr", -"purre", -"purree", -"purreic", -"purrel", -"purrer", -"purring", -"purrone", -"purry", -"purse", -"pursed", -"purser", -"pursily", -"purslet", -"pursley", -"pursual", -"pursue", -"pursuer", -"pursuit", -"pursy", -"purusha", -"purvey", -"purview", -"purvoe", -"pus", -"push", -"pusher", -"pushful", -"pushing", -"pushpin", -"puss", -"pusscat", -"pussley", -"pussy", -"pustule", -"put", -"putage", -"putamen", -"putback", -"putchen", -"putcher", -"puteal", -"putelee", -"puther", -"puthery", -"putid", -"putidly", -"putlog", -"putois", -"putrefy", -"putrid", -"putt", -"puttee", -"putter", -"puttier", -"puttock", -"putty", -"puture", -"puxy", -"puzzle", -"puzzled", -"puzzler", -"pya", -"pyal", -"pyche", -"pycnia", -"pycnial", -"pycnid", -"pycnite", -"pycnium", -"pyelic", -"pyemia", -"pyemic", -"pygal", -"pygarg", -"pygidid", -"pygmoid", -"pygmy", -"pygofer", -"pygopod", -"pyic", -"pyin", -"pyjama", -"pyke", -"pyknic", -"pyla", -"pylar", -"pylic", -"pylon", -"pyloric", -"pylorus", -"pyocele", -"pyocyst", -"pyocyte", -"pyoid", -"pyosis", -"pyr", -"pyral", -"pyralid", -"pyralis", -"pyramid", -"pyran", -"pyranyl", -"pyre", -"pyrena", -"pyrene", -"pyrenic", -"pyrenin", -"pyretic", -"pyrex", -"pyrexia", -"pyrexic", -"pyrgom", -"pyridic", -"pyridyl", -"pyrite", -"pyrites", -"pyritic", -"pyro", -"pyrogen", -"pyroid", -"pyrone", -"pyrope", -"pyropen", -"pyropus", -"pyrosis", -"pyrotic", -"pyrrhic", -"pyrrol", -"pyrrole", -"pyrroyl", -"pyrryl", -"pyruvic", -"pyruvil", -"pyruvyl", -"python", -"pyuria", -"pyvuril", -"pyx", -"pyxides", -"pyxie", -"pyxis", -"q", -"qasida", -"qere", -"qeri", -"qintar", -"qoph", -"qua", -"quab", -"quabird", -"quachil", -"quack", -"quackle", -"quacky", -"quad", -"quadded", -"quaddle", -"quadra", -"quadral", -"quadrat", -"quadric", -"quadrum", -"quaedam", -"quaff", -"quaffer", -"quag", -"quagga", -"quaggle", -"quaggy", -"quahog", -"quail", -"quaily", -"quaint", -"quake", -"quaker", -"quaking", -"quaky", -"quale", -"qualify", -"quality", -"qualm", -"qualmy", -"quan", -"quandy", -"quannet", -"quant", -"quanta", -"quantic", -"quantum", -"quar", -"quare", -"quark", -"quarl", -"quarle", -"quarred", -"quarrel", -"quarry", -"quart", -"quartan", -"quarter", -"quartet", -"quartic", -"quarto", -"quartz", -"quartzy", -"quash", -"quashey", -"quashy", -"quasi", -"quasky", -"quassin", -"quat", -"quata", -"quatch", -"quatern", -"quaters", -"quatral", -"quatre", -"quatrin", -"quattie", -"quatuor", -"quauk", -"quave", -"quaver", -"quavery", -"quaw", -"quawk", -"quay", -"quayage", -"quayful", -"quayman", -"qubba", -"queach", -"queachy", -"queak", -"queal", -"quean", -"queasom", -"queasy", -"quedful", -"queechy", -"queen", -"queenly", -"queer", -"queerer", -"queerly", -"queery", -"queest", -"queet", -"queeve", -"quegh", -"quei", -"quelch", -"quell", -"queller", -"quemado", -"queme", -"quemely", -"quench", -"quercic", -"quercin", -"querent", -"querier", -"querist", -"querken", -"querl", -"quern", -"quernal", -"query", -"quest", -"quester", -"questor", -"quet", -"quetch", -"quetzal", -"queue", -"quey", -"quiapo", -"quib", -"quibble", -"quiblet", -"quica", -"quick", -"quicken", -"quickie", -"quickly", -"quid", -"quidder", -"quiddit", -"quiddle", -"quiesce", -"quiet", -"quieten", -"quieter", -"quietly", -"quietus", -"quiff", -"quila", -"quiles", -"quilkin", -"quill", -"quillai", -"quilled", -"quiller", -"quillet", -"quilly", -"quilt", -"quilted", -"quilter", -"quin", -"quina", -"quinary", -"quinate", -"quince", -"quinch", -"quinia", -"quinic", -"quinin", -"quinina", -"quinine", -"quinism", -"quinite", -"quinize", -"quink", -"quinnat", -"quinnet", -"quinoa", -"quinoid", -"quinol", -"quinone", -"quinova", -"quinoyl", -"quinse", -"quinsy", -"quint", -"quintad", -"quintal", -"quintan", -"quinte", -"quintet", -"quintic", -"quintin", -"quinto", -"quinton", -"quintus", -"quinyl", -"quinze", -"quip", -"quipful", -"quipo", -"quipper", -"quippy", -"quipu", -"quira", -"quire", -"quirk", -"quirky", -"quirl", -"quirt", -"quis", -"quisby", -"quiscos", -"quisle", -"quit", -"quitch", -"quite", -"quits", -"quitted", -"quitter", -"quittor", -"quiver", -"quivery", -"quiz", -"quizzee", -"quizzer", -"quizzy", -"quo", -"quod", -"quoin", -"quoined", -"quoit", -"quoiter", -"quoits", -"quondam", -"quoniam", -"quop", -"quorum", -"quot", -"quota", -"quote", -"quotee", -"quoter", -"quoth", -"quotha", -"quotity", -"quotum", -"r", -"ra", -"raad", -"raash", -"rab", -"raband", -"rabanna", -"rabat", -"rabatte", -"rabbet", -"rabbi", -"rabbin", -"rabbit", -"rabbity", -"rabble", -"rabbler", -"rabboni", -"rabic", -"rabid", -"rabidly", -"rabies", -"rabific", -"rabinet", -"rabitic", -"raccoon", -"raccroc", -"race", -"raceme", -"racemed", -"racemic", -"racer", -"raceway", -"rach", -"rache", -"rachial", -"rachis", -"racial", -"racily", -"racing", -"racism", -"racist", -"rack", -"rackan", -"racker", -"racket", -"rackett", -"rackety", -"rackful", -"racking", -"rackle", -"rackway", -"racloir", -"racon", -"racoon", -"racy", -"rad", -"rada", -"radar", -"raddle", -"radial", -"radiale", -"radian", -"radiant", -"radiate", -"radical", -"radicel", -"radices", -"radicle", -"radii", -"radio", -"radiode", -"radish", -"radium", -"radius", -"radix", -"radman", -"radome", -"radon", -"radula", -"raff", -"raffe", -"raffee", -"raffery", -"raffia", -"raffing", -"raffish", -"raffle", -"raffler", -"raft", -"raftage", -"rafter", -"raftman", -"rafty", -"rag", -"raga", -"rage", -"rageful", -"rageous", -"rager", -"ragfish", -"ragged", -"raggedy", -"raggee", -"ragger", -"raggery", -"raggety", -"raggil", -"raggily", -"ragging", -"raggle", -"raggled", -"raggy", -"raging", -"raglan", -"raglet", -"raglin", -"ragman", -"ragout", -"ragshag", -"ragtag", -"ragtime", -"ragule", -"raguly", -"ragweed", -"ragwort", -"rah", -"rahdar", -"raia", -"raid", -"raider", -"rail", -"railage", -"railer", -"railing", -"railly", -"railman", -"railway", -"raiment", -"rain", -"rainbow", -"rainer", -"rainful", -"rainily", -"rainy", -"raioid", -"rais", -"raise", -"raised", -"raiser", -"raisin", -"raising", -"raisiny", -"raj", -"raja", -"rajah", -"rakan", -"rake", -"rakeage", -"rakeful", -"raker", -"rakery", -"rakh", -"raki", -"rakily", -"raking", -"rakish", -"rakit", -"raku", -"rallier", -"ralline", -"rally", -"ralph", -"ram", -"ramada", -"ramage", -"ramal", -"ramanas", -"ramass", -"ramate", -"rambeh", -"ramble", -"rambler", -"rambong", -"rame", -"rameal", -"ramed", -"ramekin", -"rament", -"rameous", -"ramet", -"ramex", -"ramhead", -"ramhood", -"rami", -"ramie", -"ramify", -"ramlike", -"ramline", -"rammack", -"rammel", -"rammer", -"rammish", -"rammy", -"ramose", -"ramous", -"ramp", -"rampage", -"rampant", -"rampart", -"ramped", -"ramper", -"rampick", -"rampike", -"ramping", -"rampion", -"rampire", -"rampler", -"ramplor", -"ramrace", -"ramrod", -"ramsch", -"ramson", -"ramstam", -"ramtil", -"ramular", -"ramule", -"ramulus", -"ramus", -"ran", -"rana", -"ranal", -"rance", -"rancel", -"rancer", -"ranch", -"ranche", -"rancher", -"rancho", -"rancid", -"rancor", -"rand", -"randan", -"randem", -"rander", -"randing", -"randir", -"randle", -"random", -"randy", -"rane", -"rang", -"range", -"ranged", -"ranger", -"rangey", -"ranging", -"rangle", -"rangler", -"rangy", -"rani", -"ranid", -"ranine", -"rank", -"ranked", -"ranker", -"rankish", -"rankle", -"rankly", -"rann", -"rannel", -"ranny", -"ransack", -"ransel", -"ransom", -"rant", -"rantan", -"ranter", -"ranting", -"rantock", -"ranty", -"ranula", -"ranular", -"rap", -"rape", -"rapeful", -"raper", -"raphany", -"raphe", -"raphide", -"raphis", -"rapic", -"rapid", -"rapidly", -"rapier", -"rapillo", -"rapine", -"rapiner", -"raping", -"rapinic", -"rapist", -"raploch", -"rappage", -"rappe", -"rappel", -"rapper", -"rapping", -"rappist", -"rapport", -"rapt", -"raptly", -"raptor", -"raptril", -"rapture", -"raptury", -"raptus", -"rare", -"rarebit", -"rarefy", -"rarely", -"rarish", -"rarity", -"ras", -"rasa", -"rasant", -"rascal", -"rasceta", -"rase", -"rasen", -"raser", -"rasgado", -"rash", -"rasher", -"rashful", -"rashing", -"rashly", -"rasion", -"rasp", -"rasped", -"rasper", -"rasping", -"raspish", -"raspite", -"raspy", -"rasse", -"rassle", -"raster", -"rastik", -"rastle", -"rasure", -"rat", -"rata", -"ratable", -"ratably", -"ratafee", -"ratafia", -"ratal", -"ratbite", -"ratch", -"ratchel", -"ratcher", -"ratchet", -"rate", -"rated", -"ratel", -"rater", -"ratfish", -"rath", -"rathe", -"rathed", -"rathely", -"rather", -"rathest", -"rathite", -"rathole", -"ratify", -"ratine", -"rating", -"ratio", -"ration", -"ratite", -"ratlike", -"ratline", -"ratoon", -"rattage", -"rattail", -"rattan", -"ratteen", -"ratten", -"ratter", -"rattery", -"ratti", -"rattish", -"rattle", -"rattled", -"rattler", -"rattles", -"rattly", -"ratton", -"rattrap", -"ratty", -"ratwa", -"ratwood", -"raucid", -"raucity", -"raucous", -"raught", -"rauk", -"raukle", -"rauli", -"raun", -"raunge", -"raupo", -"rauque", -"ravage", -"ravager", -"rave", -"ravel", -"raveler", -"ravelin", -"ravelly", -"raven", -"ravener", -"ravenry", -"ravens", -"raver", -"ravin", -"ravine", -"ravined", -"raviney", -"raving", -"ravioli", -"ravish", -"ravison", -"raw", -"rawhead", -"rawhide", -"rawish", -"rawness", -"rax", -"ray", -"raya", -"rayage", -"rayed", -"rayful", -"rayless", -"raylet", -"rayon", -"raze", -"razee", -"razer", -"razoo", -"razor", -"razz", -"razzia", -"razzly", -"re", -"rea", -"reaal", -"reabuse", -"reach", -"reacher", -"reachy", -"react", -"reactor", -"read", -"readapt", -"readd", -"reader", -"readily", -"reading", -"readmit", -"readopt", -"readorn", -"ready", -"reagent", -"reagin", -"reagree", -"reak", -"real", -"realarm", -"reales", -"realest", -"realgar", -"realign", -"realism", -"realist", -"reality", -"realive", -"realize", -"reallot", -"reallow", -"really", -"realm", -"realter", -"realtor", -"realty", -"ream", -"reamage", -"reamass", -"reamend", -"reamer", -"reamuse", -"reamy", -"reannex", -"reannoy", -"reanvil", -"reap", -"reaper", -"reapply", -"rear", -"rearer", -"reargue", -"rearise", -"rearm", -"rearray", -"reask", -"reason", -"reassay", -"reasty", -"reasy", -"reatus", -"reaudit", -"reavail", -"reave", -"reaver", -"reavoid", -"reavow", -"reawait", -"reawake", -"reaward", -"reaware", -"reb", -"rebab", -"reback", -"rebag", -"rebait", -"rebake", -"rebale", -"reban", -"rebar", -"rebase", -"rebasis", -"rebate", -"rebater", -"rebathe", -"rebato", -"rebawl", -"rebear", -"rebeat", -"rebec", -"rebeck", -"rebed", -"rebeg", -"rebeget", -"rebegin", -"rebel", -"rebelly", -"rebend", -"rebeset", -"rebia", -"rebias", -"rebid", -"rebill", -"rebind", -"rebirth", -"rebite", -"reblade", -"reblame", -"reblast", -"reblend", -"rebless", -"reblock", -"rebloom", -"reblot", -"reblow", -"reblue", -"rebluff", -"reboant", -"reboard", -"reboast", -"rebob", -"reboil", -"reboise", -"rebold", -"rebolt", -"rebone", -"rebook", -"rebop", -"rebore", -"reborn", -"rebound", -"rebox", -"rebrace", -"rebraid", -"rebrand", -"rebreed", -"rebrew", -"rebribe", -"rebrick", -"rebring", -"rebrown", -"rebrush", -"rebud", -"rebuff", -"rebuild", -"rebuilt", -"rebuke", -"rebuker", -"rebulk", -"rebunch", -"rebuoy", -"reburn", -"reburst", -"rebury", -"rebus", -"rebush", -"rebusy", -"rebut", -"rebute", -"rebuy", -"recable", -"recage", -"recalk", -"recall", -"recant", -"recap", -"recarry", -"recart", -"recarve", -"recase", -"recash", -"recast", -"recatch", -"recce", -"recco", -"reccy", -"recede", -"receder", -"receipt", -"receive", -"recency", -"recense", -"recent", -"recept", -"recess", -"rechafe", -"rechain", -"rechal", -"rechant", -"rechaos", -"rechar", -"rechase", -"rechaw", -"recheat", -"recheck", -"recheer", -"rechew", -"rechip", -"rechuck", -"rechurn", -"recipe", -"recital", -"recite", -"reciter", -"reck", -"reckla", -"reckon", -"reclaim", -"reclama", -"reclang", -"reclasp", -"reclass", -"reclean", -"reclear", -"reclimb", -"recline", -"reclose", -"recluse", -"recoach", -"recoal", -"recoast", -"recoat", -"recock", -"recoct", -"recode", -"recoil", -"recoin", -"recoke", -"recolor", -"recomb", -"recon", -"recook", -"recool", -"recopy", -"record", -"recork", -"recount", -"recoup", -"recover", -"recramp", -"recrank", -"recrate", -"recrew", -"recroon", -"recrop", -"recross", -"recrowd", -"recrown", -"recruit", -"recrush", -"rect", -"recta", -"rectal", -"recti", -"rectify", -"rection", -"recto", -"rector", -"rectory", -"rectrix", -"rectum", -"rectus", -"recur", -"recure", -"recurl", -"recurse", -"recurve", -"recuse", -"recut", -"recycle", -"red", -"redact", -"redan", -"redare", -"redarn", -"redart", -"redate", -"redaub", -"redawn", -"redback", -"redbait", -"redbill", -"redbird", -"redbone", -"redbuck", -"redbud", -"redcap", -"redcoat", -"redd", -"redden", -"redder", -"redding", -"reddish", -"reddock", -"reddy", -"rede", -"redeal", -"redebit", -"redeck", -"redeed", -"redeem", -"redefer", -"redefy", -"redeify", -"redelay", -"redeny", -"redeye", -"redfin", -"redfish", -"redfoot", -"redhead", -"redhoop", -"redia", -"redient", -"redig", -"redip", -"redive", -"redleg", -"redlegs", -"redly", -"redness", -"redo", -"redock", -"redoom", -"redoubt", -"redound", -"redowa", -"redox", -"redpoll", -"redraft", -"redrag", -"redrape", -"redraw", -"redream", -"redress", -"redrill", -"redrive", -"redroot", -"redry", -"redsear", -"redskin", -"redtab", -"redtail", -"redtop", -"redub", -"reduce", -"reduced", -"reducer", -"reduct", -"redue", -"redux", -"redward", -"redware", -"redweed", -"redwing", -"redwood", -"redye", -"ree", -"reechy", -"reed", -"reeded", -"reeden", -"reeder", -"reedily", -"reeding", -"reedish", -"reedman", -"reedy", -"reef", -"reefer", -"reefing", -"reefy", -"reek", -"reeker", -"reeky", -"reel", -"reeled", -"reeler", -"reem", -"reeming", -"reemish", -"reen", -"reenge", -"reeper", -"reese", -"reeshle", -"reesk", -"reesle", -"reest", -"reester", -"reestle", -"reesty", -"reet", -"reetam", -"reetle", -"reeve", -"ref", -"reface", -"refall", -"refan", -"refavor", -"refect", -"refeed", -"refeel", -"refeign", -"refel", -"refence", -"refer", -"referee", -"refetch", -"refight", -"refill", -"refilm", -"refind", -"refine", -"refined", -"refiner", -"refire", -"refit", -"refix", -"reflag", -"reflame", -"reflash", -"reflate", -"reflect", -"reflee", -"reflex", -"refling", -"refloat", -"reflog", -"reflood", -"refloor", -"reflow", -"reflush", -"reflux", -"refly", -"refocus", -"refold", -"refont", -"refool", -"refoot", -"reforce", -"reford", -"reforge", -"reform", -"refound", -"refract", -"refrain", -"reframe", -"refresh", -"refront", -"reft", -"refuel", -"refuge", -"refugee", -"refulge", -"refund", -"refurl", -"refusal", -"refuse", -"refuser", -"refutal", -"refute", -"refuter", -"reg", -"regain", -"regal", -"regale", -"regaler", -"regalia", -"regally", -"regard", -"regatta", -"regauge", -"regency", -"regent", -"reges", -"reget", -"regia", -"regift", -"regild", -"regill", -"regime", -"regimen", -"regin", -"reginal", -"region", -"regive", -"reglair", -"reglaze", -"regle", -"reglet", -"regloss", -"reglove", -"reglow", -"reglue", -"regma", -"regnal", -"regnant", -"regorge", -"regrade", -"regraft", -"regrant", -"regrasp", -"regrass", -"regrate", -"regrede", -"regreen", -"regreet", -"regress", -"regret", -"regrind", -"regrip", -"regroup", -"regrow", -"reguard", -"reguide", -"regula", -"regular", -"reguli", -"regulus", -"regur", -"regurge", -"regush", -"reh", -"rehair", -"rehale", -"rehang", -"reharm", -"rehash", -"rehaul", -"rehead", -"reheal", -"reheap", -"rehear", -"reheat", -"rehedge", -"reheel", -"rehoe", -"rehoist", -"rehonor", -"rehood", -"rehook", -"rehoop", -"rehouse", -"rehung", -"reif", -"reify", -"reign", -"reim", -"reimage", -"reimpel", -"reimply", -"rein", -"reina", -"reincur", -"reindue", -"reinfer", -"reins", -"reinter", -"reis", -"reissue", -"reit", -"reitbok", -"reiter", -"reiver", -"rejail", -"reject", -"rejerk", -"rejoice", -"rejoin", -"rejolt", -"rejudge", -"rekick", -"rekill", -"reking", -"rekiss", -"reknit", -"reknow", -"rel", -"relabel", -"relace", -"relade", -"reladen", -"relais", -"relamp", -"reland", -"relap", -"relapse", -"relast", -"relata", -"relatch", -"relate", -"related", -"relater", -"relator", -"relatum", -"relax", -"relaxed", -"relaxer", -"relay", -"relbun", -"relead", -"releap", -"relearn", -"release", -"relend", -"relent", -"relet", -"relevel", -"relevy", -"reliant", -"relic", -"relick", -"relict", -"relief", -"relier", -"relieve", -"relievo", -"relift", -"relight", -"relime", -"relimit", -"reline", -"reliner", -"relink", -"relish", -"relishy", -"relist", -"relive", -"reload", -"reloan", -"relock", -"relodge", -"relook", -"relose", -"relost", -"relot", -"relove", -"relower", -"reluct", -"relume", -"rely", -"remade", -"remail", -"remain", -"remains", -"remake", -"remaker", -"reman", -"remand", -"remanet", -"remap", -"remarch", -"remark", -"remarry", -"remask", -"remass", -"remast", -"rematch", -"remble", -"remeant", -"remede", -"remedy", -"remeet", -"remelt", -"remend", -"remerge", -"remetal", -"remex", -"remica", -"remicle", -"remiges", -"remill", -"remimic", -"remind", -"remint", -"remiped", -"remise", -"remiss", -"remit", -"remix", -"remnant", -"remock", -"remodel", -"remold", -"remop", -"remora", -"remord", -"remorse", -"remote", -"remould", -"remount", -"removal", -"remove", -"removed", -"remover", -"renable", -"renably", -"renail", -"renal", -"rename", -"rend", -"render", -"reneg", -"renege", -"reneger", -"renegue", -"renerve", -"renes", -"renet", -"renew", -"renewal", -"renewer", -"renin", -"renish", -"renk", -"renky", -"renne", -"rennet", -"rennin", -"renown", -"rent", -"rentage", -"rental", -"rented", -"rentee", -"renter", -"renvoi", -"renvoy", -"reoccur", -"reoffer", -"reoil", -"reomit", -"reopen", -"reorder", -"reown", -"rep", -"repace", -"repack", -"repage", -"repaint", -"repair", -"repale", -"repand", -"repanel", -"repaper", -"repark", -"repass", -"repast", -"repaste", -"repatch", -"repave", -"repawn", -"repay", -"repayal", -"repeal", -"repeat", -"repeg", -"repel", -"repen", -"repent", -"repew", -"rephase", -"repic", -"repick", -"repiece", -"repile", -"repin", -"repine", -"repiner", -"repipe", -"repique", -"repitch", -"repkie", -"replace", -"replait", -"replan", -"replane", -"replant", -"replate", -"replay", -"replead", -"repleat", -"replete", -"replevy", -"replica", -"replier", -"replod", -"replot", -"replow", -"replum", -"replume", -"reply", -"repoint", -"repoll", -"repolon", -"repone", -"repope", -"report", -"reposal", -"repose", -"reposed", -"reposer", -"reposit", -"repost", -"repot", -"repound", -"repour", -"repp", -"repped", -"repray", -"repress", -"reprice", -"reprime", -"reprint", -"reprise", -"reproof", -"reprove", -"reprune", -"reps", -"reptant", -"reptile", -"repuff", -"repugn", -"repulse", -"repump", -"repurge", -"repute", -"reputed", -"requeen", -"request", -"requiem", -"requin", -"require", -"requit", -"requite", -"requiz", -"requote", -"rerack", -"rerail", -"reraise", -"rerake", -"rerank", -"rerate", -"reread", -"reredos", -"reree", -"rereel", -"rereeve", -"rereign", -"rerent", -"rerig", -"rering", -"rerise", -"rerival", -"rerivet", -"rerob", -"rerobe", -"reroll", -"reroof", -"reroot", -"rerope", -"reroute", -"rerow", -"rerub", -"rerun", -"resaca", -"resack", -"resail", -"resale", -"resalt", -"resaw", -"resawer", -"resay", -"rescan", -"rescind", -"rescore", -"rescrub", -"rescue", -"rescuer", -"reseal", -"reseam", -"reseat", -"resect", -"reseda", -"resee", -"reseed", -"reseek", -"reseise", -"reseize", -"reself", -"resell", -"resend", -"resene", -"resent", -"reserve", -"reset", -"resever", -"resew", -"resex", -"resh", -"reshake", -"reshape", -"reshare", -"reshave", -"reshear", -"reshift", -"reshine", -"reship", -"reshoe", -"reshoot", -"reshun", -"reshunt", -"reshut", -"reside", -"resider", -"residua", -"residue", -"resift", -"resigh", -"resign", -"resile", -"resin", -"resina", -"resiner", -"resing", -"resinic", -"resink", -"resinol", -"resiny", -"resist", -"resize", -"resizer", -"reskin", -"reslash", -"reslate", -"reslay", -"reslide", -"reslot", -"resmell", -"resmelt", -"resmile", -"resnap", -"resnub", -"resoak", -"resoap", -"resoil", -"resole", -"resolve", -"resorb", -"resort", -"resound", -"resow", -"resp", -"respace", -"respade", -"respan", -"respeak", -"respect", -"respell", -"respin", -"respire", -"respite", -"resplit", -"respoke", -"respond", -"respot", -"respray", -"respue", -"ressala", -"ressaut", -"rest", -"restack", -"restaff", -"restain", -"restake", -"restamp", -"restant", -"restart", -"restate", -"restaur", -"resteal", -"resteel", -"resteep", -"restem", -"restep", -"rester", -"restes", -"restful", -"restiad", -"restiff", -"resting", -"restir", -"restis", -"restive", -"restock", -"restore", -"restow", -"restrap", -"restrip", -"restudy", -"restuff", -"resty", -"restyle", -"resuck", -"resue", -"resuing", -"resuit", -"result", -"resume", -"resumer", -"resun", -"resup", -"resurge", -"reswage", -"resward", -"reswarm", -"reswear", -"resweat", -"resweep", -"reswell", -"reswill", -"reswim", -"ret", -"retable", -"retack", -"retag", -"retail", -"retain", -"retake", -"retaker", -"retalk", -"retama", -"retame", -"retan", -"retape", -"retard", -"retare", -"retaste", -"retax", -"retch", -"reteach", -"retell", -"retem", -"retempt", -"retene", -"retent", -"retest", -"rethank", -"rethaw", -"rethe", -"rethink", -"rethrow", -"retia", -"retial", -"retiary", -"reticle", -"retie", -"retier", -"retile", -"retill", -"retime", -"retin", -"retina", -"retinal", -"retinol", -"retinue", -"retip", -"retiral", -"retire", -"retired", -"retirer", -"retoast", -"retold", -"retomb", -"retook", -"retool", -"retooth", -"retort", -"retoss", -"retotal", -"retouch", -"retour", -"retrace", -"retrack", -"retract", -"retrad", -"retrade", -"retrain", -"retral", -"retramp", -"retread", -"retreat", -"retree", -"retrial", -"retrim", -"retrip", -"retrot", -"retrude", -"retrue", -"retrust", -"retry", -"retted", -"retter", -"rettery", -"retting", -"rettory", -"retube", -"retuck", -"retune", -"returf", -"return", -"retuse", -"retwine", -"retwist", -"retying", -"retype", -"retzian", -"reune", -"reunify", -"reunion", -"reunite", -"reurge", -"reuse", -"reutter", -"rev", -"revalue", -"revamp", -"revary", -"reve", -"reveal", -"reveil", -"revel", -"reveler", -"revelly", -"revelry", -"revend", -"revenge", -"revent", -"revenue", -"rever", -"reverb", -"revere", -"revered", -"reverer", -"reverie", -"revers", -"reverse", -"reversi", -"reverso", -"revert", -"revery", -"revest", -"revet", -"revete", -"revie", -"review", -"revile", -"reviler", -"revisal", -"revise", -"revisee", -"reviser", -"revisit", -"revisor", -"revival", -"revive", -"reviver", -"revivor", -"revoice", -"revoke", -"revoker", -"revolt", -"revolve", -"revomit", -"revote", -"revue", -"revuist", -"rewade", -"rewager", -"rewake", -"rewaken", -"rewall", -"reward", -"rewarm", -"rewarn", -"rewash", -"rewater", -"rewave", -"rewax", -"rewayle", -"rewear", -"reweave", -"rewed", -"reweigh", -"reweld", -"rewend", -"rewet", -"rewhelp", -"rewhirl", -"rewiden", -"rewin", -"rewind", -"rewire", -"rewish", -"rewood", -"reword", -"rework", -"rewound", -"rewove", -"rewoven", -"rewrap", -"rewrite", -"rex", -"rexen", -"reyield", -"reyoke", -"reyouth", -"rhabdom", -"rhabdos", -"rhabdus", -"rhagite", -"rhagon", -"rhagose", -"rhamn", -"rhamnal", -"rhason", -"rhatany", -"rhe", -"rhea", -"rhebok", -"rheeboc", -"rheebok", -"rheen", -"rheic", -"rhein", -"rheinic", -"rhema", -"rheme", -"rhenium", -"rheotan", -"rhesian", -"rhesus", -"rhetor", -"rheum", -"rheumed", -"rheumic", -"rheumy", -"rhexis", -"rhinal", -"rhine", -"rhinion", -"rhino", -"rhizine", -"rhizoid", -"rhizoma", -"rhizome", -"rhizote", -"rho", -"rhodic", -"rhoding", -"rhodite", -"rhodium", -"rhomb", -"rhombic", -"rhombos", -"rhombus", -"rhubarb", -"rhumb", -"rhumba", -"rhyme", -"rhymer", -"rhymery", -"rhymic", -"rhymist", -"rhymy", -"rhyptic", -"rhythm", -"rhyton", -"ria", -"rial", -"riancy", -"riant", -"riantly", -"riata", -"rib", -"ribald", -"riband", -"ribat", -"ribband", -"ribbed", -"ribber", -"ribbet", -"ribbing", -"ribble", -"ribbon", -"ribbony", -"ribby", -"ribe", -"ribless", -"riblet", -"riblike", -"ribonic", -"ribose", -"ribskin", -"ribwork", -"ribwort", -"rice", -"ricer", -"ricey", -"rich", -"richdom", -"richen", -"riches", -"richly", -"richt", -"ricin", -"ricine", -"ricinic", -"ricinus", -"rick", -"ricker", -"rickets", -"rickety", -"rickey", -"rickle", -"ricksha", -"ricrac", -"rictal", -"rictus", -"rid", -"ridable", -"ridably", -"riddam", -"riddel", -"ridden", -"ridder", -"ridding", -"riddle", -"riddler", -"ride", -"rideau", -"riden", -"rident", -"rider", -"ridered", -"ridge", -"ridged", -"ridgel", -"ridger", -"ridgil", -"ridging", -"ridgy", -"riding", -"ridotto", -"rie", -"riem", -"riempie", -"rier", -"rife", -"rifely", -"riff", -"riffle", -"riffler", -"rifle", -"rifler", -"riflery", -"rifling", -"rift", -"rifter", -"rifty", -"rig", -"rigbane", -"riggald", -"rigger", -"rigging", -"riggish", -"riggite", -"riggot", -"right", -"righten", -"righter", -"rightle", -"rightly", -"righto", -"righty", -"rigid", -"rigidly", -"rigling", -"rignum", -"rigol", -"rigor", -"rigsby", -"rikisha", -"rikk", -"riksha", -"rikshaw", -"rilawa", -"rile", -"riley", -"rill", -"rillet", -"rillett", -"rillock", -"rilly", -"rim", -"rima", -"rimal", -"rimate", -"rimbase", -"rime", -"rimer", -"rimfire", -"rimland", -"rimless", -"rimmed", -"rimmer", -"rimose", -"rimous", -"rimpi", -"rimple", -"rimrock", -"rimu", -"rimula", -"rimy", -"rinceau", -"rinch", -"rincon", -"rind", -"rinded", -"rindle", -"rindy", -"rine", -"ring", -"ringe", -"ringed", -"ringent", -"ringer", -"ringeye", -"ringing", -"ringite", -"ringle", -"ringlet", -"ringman", -"ringtaw", -"ringy", -"rink", -"rinka", -"rinker", -"rinkite", -"rinner", -"rinse", -"rinser", -"rinsing", -"rio", -"riot", -"rioter", -"rioting", -"riotist", -"riotous", -"riotry", -"rip", -"ripa", -"ripal", -"ripcord", -"ripe", -"ripely", -"ripen", -"ripener", -"riper", -"ripgut", -"ripieno", -"ripier", -"ripost", -"riposte", -"ripper", -"rippet", -"rippier", -"ripping", -"rippit", -"ripple", -"rippler", -"ripplet", -"ripply", -"rippon", -"riprap", -"ripsack", -"ripsaw", -"ripup", -"risala", -"risberm", -"rise", -"risen", -"riser", -"rishi", -"risible", -"risibly", -"rising", -"risk", -"risker", -"riskful", -"riskily", -"riskish", -"risky", -"risp", -"risper", -"risque", -"risquee", -"rissel", -"risser", -"rissle", -"rissoid", -"rist", -"ristori", -"rit", -"rita", -"rite", -"ritling", -"ritual", -"ritzy", -"riva", -"rivage", -"rival", -"rivalry", -"rive", -"rivel", -"rivell", -"riven", -"river", -"rivered", -"riverly", -"rivery", -"rivet", -"riveter", -"riving", -"rivose", -"rivulet", -"rix", -"rixy", -"riyal", -"rizzar", -"rizzle", -"rizzom", -"roach", -"road", -"roadbed", -"roaded", -"roader", -"roading", -"roadite", -"roadman", -"roadway", -"roam", -"roamage", -"roamer", -"roaming", -"roan", -"roanoke", -"roar", -"roarer", -"roaring", -"roast", -"roaster", -"rob", -"robalo", -"roband", -"robber", -"robbery", -"robbin", -"robbing", -"robe", -"rober", -"roberd", -"robin", -"robinet", -"robing", -"robinin", -"roble", -"robomb", -"robot", -"robotry", -"robur", -"robust", -"roc", -"rocher", -"rochet", -"rock", -"rockaby", -"rocker", -"rockery", -"rocket", -"rockety", -"rocking", -"rockish", -"rocklay", -"rocklet", -"rockman", -"rocky", -"rococo", -"rocta", -"rod", -"rodd", -"roddin", -"rodding", -"rode", -"rodent", -"rodeo", -"rodge", -"rodham", -"roding", -"rodless", -"rodlet", -"rodlike", -"rodman", -"rodney", -"rodsman", -"rodster", -"rodwood", -"roe", -"roebuck", -"roed", -"roelike", -"roer", -"roey", -"rog", -"rogan", -"roger", -"roggle", -"rogue", -"roguery", -"roguing", -"roguish", -"rohan", -"rohob", -"rohun", -"rohuna", -"roi", -"roid", -"roil", -"roily", -"roister", -"roit", -"roka", -"roke", -"rokeage", -"rokee", -"rokelay", -"roker", -"rokey", -"roky", -"role", -"roleo", -"roll", -"rolled", -"roller", -"rolley", -"rollick", -"rolling", -"rollix", -"rollmop", -"rollock", -"rollway", -"roloway", -"romaika", -"romaine", -"romal", -"romance", -"romancy", -"romanza", -"romaunt", -"rombos", -"romeite", -"romero", -"rommack", -"romp", -"romper", -"romping", -"rompish", -"rompu", -"rompy", -"roncet", -"ronco", -"rond", -"ronde", -"rondeau", -"rondel", -"rondino", -"rondle", -"rondo", -"rondure", -"rone", -"rongeur", -"ronquil", -"rontgen", -"ronyon", -"rood", -"roodle", -"roof", -"roofage", -"roofer", -"roofing", -"rooflet", -"roofman", -"roofy", -"rooibok", -"rooinek", -"rook", -"rooker", -"rookery", -"rookie", -"rookish", -"rooklet", -"rooky", -"rool", -"room", -"roomage", -"roomed", -"roomer", -"roomful", -"roomie", -"roomily", -"roomlet", -"roomth", -"roomthy", -"roomy", -"roon", -"roosa", -"roost", -"roosted", -"rooster", -"root", -"rootage", -"rootcap", -"rooted", -"rooter", -"rootery", -"rootle", -"rootlet", -"rooty", -"roove", -"ropable", -"rope", -"ropeman", -"roper", -"ropery", -"ropes", -"ropeway", -"ropily", -"roping", -"ropish", -"ropp", -"ropy", -"roque", -"roquer", -"roquet", -"roquist", -"roral", -"roric", -"rorqual", -"rorty", -"rory", -"rosal", -"rosario", -"rosary", -"rosated", -"roscid", -"rose", -"roseal", -"roseate", -"rosebay", -"rosebud", -"rosed", -"roseine", -"rosel", -"roselet", -"rosella", -"roselle", -"roseola", -"roseous", -"rosery", -"roset", -"rosetan", -"rosette", -"rosetty", -"rosetum", -"rosety", -"rosied", -"rosier", -"rosilla", -"rosillo", -"rosily", -"rosin", -"rosiny", -"rosland", -"rosoli", -"rosolic", -"rosolio", -"ross", -"rosser", -"rossite", -"rostel", -"roster", -"rostra", -"rostral", -"rostrum", -"rosular", -"rosy", -"rot", -"rota", -"rotal", -"rotaman", -"rotan", -"rotang", -"rotary", -"rotate", -"rotated", -"rotator", -"rotch", -"rote", -"rotella", -"roter", -"rotge", -"rotgut", -"rother", -"rotifer", -"roto", -"rotor", -"rottan", -"rotten", -"rotter", -"rotting", -"rottle", -"rottock", -"rottolo", -"rotula", -"rotulad", -"rotular", -"rotulet", -"rotulus", -"rotund", -"rotunda", -"rotundo", -"roub", -"roucou", -"roud", -"roue", -"rouelle", -"rouge", -"rougeau", -"rougeot", -"rough", -"roughen", -"rougher", -"roughet", -"roughie", -"roughly", -"roughy", -"rougy", -"rouille", -"rouky", -"roulade", -"rouleau", -"roun", -"rounce", -"rouncy", -"round", -"rounded", -"roundel", -"rounder", -"roundly", -"roundup", -"roundy", -"roup", -"rouper", -"roupet", -"roupily", -"roupit", -"roupy", -"rouse", -"rouser", -"rousing", -"roust", -"rouster", -"rout", -"route", -"router", -"routh", -"routhie", -"routhy", -"routine", -"routing", -"routous", -"rove", -"rover", -"rovet", -"rovetto", -"roving", -"row", -"rowable", -"rowan", -"rowboat", -"rowdily", -"rowdy", -"rowed", -"rowel", -"rowen", -"rower", -"rowet", -"rowing", -"rowlet", -"rowlock", -"rowport", -"rowty", -"rowy", -"rox", -"roxy", -"royal", -"royale", -"royalet", -"royally", -"royalty", -"royet", -"royt", -"rozum", -"ruach", -"ruana", -"rub", -"rubasse", -"rubato", -"rubbed", -"rubber", -"rubbers", -"rubbery", -"rubbing", -"rubbish", -"rubble", -"rubbler", -"rubbly", -"rubdown", -"rubelet", -"rubella", -"rubelle", -"rubeola", -"rubiate", -"rubican", -"rubidic", -"rubied", -"rubific", -"rubify", -"rubine", -"rubious", -"ruble", -"rublis", -"rubor", -"rubric", -"rubrica", -"rubrify", -"ruby", -"ruche", -"ruching", -"ruck", -"rucker", -"ruckle", -"rucksey", -"ruckus", -"rucky", -"ruction", -"rud", -"rudas", -"rudd", -"rudder", -"ruddied", -"ruddily", -"ruddle", -"ruddock", -"ruddy", -"rude", -"rudely", -"ruderal", -"rudesby", -"rudge", -"rudish", -"rudity", -"rue", -"rueful", -"ruelike", -"ruelle", -"ruen", -"ruer", -"ruesome", -"ruewort", -"ruff", -"ruffed", -"ruffer", -"ruffian", -"ruffin", -"ruffle", -"ruffled", -"ruffler", -"ruffly", -"rufous", -"rufter", -"rufus", -"rug", -"ruga", -"rugate", -"rugged", -"rugging", -"ruggle", -"ruggy", -"ruglike", -"rugosa", -"rugose", -"rugous", -"ruin", -"ruinate", -"ruined", -"ruiner", -"ruing", -"ruinous", -"rukh", -"rulable", -"rule", -"ruledom", -"ruler", -"ruling", -"rull", -"ruller", -"rullion", -"rum", -"rumal", -"rumble", -"rumbler", -"rumbly", -"rumbo", -"rumen", -"ruminal", -"rumkin", -"rumless", -"rumly", -"rummage", -"rummagy", -"rummer", -"rummily", -"rummish", -"rummy", -"rumness", -"rumney", -"rumor", -"rumorer", -"rump", -"rumpad", -"rumpade", -"rumple", -"rumply", -"rumpus", -"rumshop", -"run", -"runaway", -"runback", -"runby", -"runch", -"rundale", -"rundle", -"rundlet", -"rune", -"runed", -"runer", -"runfish", -"rung", -"runic", -"runite", -"runkle", -"runkly", -"runless", -"runlet", -"runman", -"runnel", -"runner", -"runnet", -"running", -"runny", -"runoff", -"runout", -"runover", -"runrig", -"runt", -"runted", -"runtee", -"runtish", -"runty", -"runway", -"rupa", -"rupee", -"rupia", -"rupiah", -"rupial", -"rupie", -"rupitic", -"ruptile", -"ruption", -"ruptive", -"rupture", -"rural", -"rurally", -"rurban", -"ruru", -"ruse", -"rush", -"rushed", -"rushen", -"rusher", -"rushing", -"rushlit", -"rushy", -"rusine", -"rusk", -"ruskin", -"rusky", -"rusma", -"rusot", -"ruspone", -"russel", -"russet", -"russety", -"russia", -"russud", -"rust", -"rustful", -"rustic", -"rustily", -"rustle", -"rustler", -"rustly", -"rustre", -"rustred", -"rusty", -"ruswut", -"rut", -"rutate", -"rutch", -"ruth", -"ruther", -"ruthful", -"rutic", -"rutile", -"rutin", -"ruttee", -"rutter", -"ruttish", -"rutty", -"rutyl", -"ruvid", -"rux", -"ryal", -"ryania", -"rybat", -"ryder", -"rye", -"ryen", -"ryme", -"rynd", -"rynt", -"ryot", -"ryotwar", -"rype", -"rypeck", -"s", -"sa", -"saa", -"sab", -"sabalo", -"sabanut", -"sabbat", -"sabbath", -"sabe", -"sabeca", -"sabella", -"saber", -"sabered", -"sabicu", -"sabina", -"sabine", -"sabino", -"sable", -"sably", -"sabora", -"sabot", -"saboted", -"sabra", -"sabulum", -"saburra", -"sabutan", -"sabzi", -"sac", -"sacaton", -"sacatra", -"saccade", -"saccate", -"saccos", -"saccule", -"saccus", -"sachem", -"sachet", -"sack", -"sackage", -"sackbag", -"sackbut", -"sacked", -"sacken", -"sacker", -"sackful", -"sacking", -"sackman", -"saclike", -"saco", -"sacope", -"sacque", -"sacra", -"sacrad", -"sacral", -"sacred", -"sacring", -"sacrist", -"sacro", -"sacrum", -"sad", -"sadden", -"saddik", -"saddish", -"saddle", -"saddled", -"saddler", -"sade", -"sadh", -"sadhe", -"sadhu", -"sadic", -"sadiron", -"sadism", -"sadist", -"sadly", -"sadness", -"sado", -"sadr", -"saecula", -"saeter", -"saeume", -"safari", -"safe", -"safely", -"safen", -"safener", -"safety", -"saffian", -"safflor", -"safflow", -"saffron", -"safrole", -"saft", -"sag", -"saga", -"sagaie", -"sagaman", -"sagathy", -"sage", -"sagely", -"sagene", -"sagger", -"sagging", -"saggon", -"saggy", -"saging", -"sagitta", -"sagless", -"sago", -"sagoin", -"saguaro", -"sagum", -"saguran", -"sagwire", -"sagy", -"sah", -"sahh", -"sahib", -"sahme", -"sahukar", -"sai", -"saic", -"said", -"saiga", -"sail", -"sailage", -"sailed", -"sailer", -"sailing", -"sailor", -"saily", -"saim", -"saimiri", -"saimy", -"sain", -"saint", -"sainted", -"saintly", -"saip", -"sair", -"sairly", -"sairve", -"sairy", -"saithe", -"saj", -"sajou", -"sake", -"sakeber", -"sakeen", -"saker", -"sakeret", -"saki", -"sakieh", -"sakulya", -"sal", -"salaam", -"salable", -"salably", -"salacot", -"salad", -"salago", -"salal", -"salamo", -"salar", -"salary", -"salat", -"salay", -"sale", -"salele", -"salema", -"salep", -"salfern", -"salic", -"salicin", -"salicyl", -"salient", -"salify", -"saligot", -"salina", -"saline", -"salite", -"salited", -"saliva", -"salival", -"salix", -"salle", -"sallee", -"sallet", -"sallier", -"salloo", -"sallow", -"sallowy", -"sally", -"salma", -"salmiac", -"salmine", -"salmis", -"salmon", -"salol", -"salomon", -"salon", -"saloon", -"saloop", -"salp", -"salpa", -"salpian", -"salpinx", -"salpoid", -"salse", -"salsify", -"salt", -"salta", -"saltant", -"saltary", -"saltate", -"saltcat", -"salted", -"saltee", -"salten", -"salter", -"saltern", -"saltery", -"saltfat", -"saltier", -"saltine", -"salting", -"saltish", -"saltly", -"saltman", -"saltpan", -"saltus", -"salty", -"saluki", -"salung", -"salute", -"saluter", -"salvage", -"salve", -"salver", -"salviol", -"salvo", -"salvor", -"salvy", -"sam", -"samadh", -"samadhi", -"samaj", -"saman", -"samara", -"samaria", -"samarra", -"samba", -"sambal", -"sambar", -"sambo", -"sambuk", -"sambuke", -"same", -"samekh", -"samel", -"samely", -"samen", -"samh", -"samhita", -"samiel", -"samiri", -"samisen", -"samite", -"samkara", -"samlet", -"sammel", -"sammer", -"sammier", -"sammy", -"samovar", -"samp", -"sampan", -"sampi", -"sample", -"sampler", -"samsara", -"samshu", -"samson", -"samurai", -"san", -"sanable", -"sanai", -"sancho", -"sanct", -"sancta", -"sanctum", -"sand", -"sandak", -"sandal", -"sandan", -"sandbag", -"sandbin", -"sandbox", -"sandboy", -"sandbur", -"sanded", -"sander", -"sanders", -"sandhi", -"sanding", -"sandix", -"sandman", -"sandust", -"sandy", -"sane", -"sanely", -"sang", -"sanga", -"sangar", -"sangei", -"sanger", -"sangha", -"sangley", -"sangrel", -"sangsue", -"sanicle", -"sanies", -"sanify", -"sanious", -"sanity", -"sanjak", -"sank", -"sankha", -"sannup", -"sans", -"sansei", -"sansi", -"sant", -"santal", -"santene", -"santimi", -"santims", -"santir", -"santon", -"sao", -"sap", -"sapa", -"sapajou", -"sapan", -"sapbush", -"sapek", -"sapful", -"saphead", -"saphena", -"saphie", -"sapid", -"sapient", -"sapin", -"sapinda", -"saple", -"sapless", -"sapling", -"sapo", -"saponin", -"sapor", -"sapota", -"sapote", -"sappare", -"sapper", -"sapphic", -"sapping", -"sapples", -"sappy", -"saprine", -"sapsago", -"sapsuck", -"sapwood", -"sapwort", -"sar", -"saraad", -"saraf", -"sarangi", -"sarcasm", -"sarcast", -"sarcine", -"sarcle", -"sarcler", -"sarcode", -"sarcoid", -"sarcoma", -"sarcous", -"sard", -"sardel", -"sardine", -"sardius", -"sare", -"sargo", -"sargus", -"sari", -"sarif", -"sarigue", -"sarinda", -"sarip", -"sark", -"sarkar", -"sarkful", -"sarkine", -"sarking", -"sarkit", -"sarlak", -"sarlyk", -"sarment", -"sarna", -"sarod", -"saron", -"sarong", -"saronic", -"saros", -"sarpler", -"sarpo", -"sarra", -"sarraf", -"sarsa", -"sarsen", -"sart", -"sartage", -"sartain", -"sartor", -"sarus", -"sarwan", -"sasa", -"sasan", -"sasani", -"sash", -"sashay", -"sashery", -"sashing", -"sasin", -"sasine", -"sassaby", -"sassy", -"sat", -"satable", -"satan", -"satang", -"satanic", -"satara", -"satchel", -"sate", -"sateen", -"satiate", -"satient", -"satiety", -"satin", -"satine", -"satined", -"satiny", -"satire", -"satiric", -"satisfy", -"satlijk", -"satrap", -"satrapy", -"satron", -"sattle", -"sattva", -"satura", -"satyr", -"satyric", -"sauce", -"saucer", -"saucily", -"saucy", -"sauf", -"sauger", -"saugh", -"saughen", -"sauld", -"saulie", -"sault", -"saulter", -"saum", -"saumon", -"saumont", -"sauna", -"saunter", -"sauqui", -"saur", -"saurel", -"saurian", -"saury", -"sausage", -"saut", -"saute", -"sauteur", -"sauty", -"sauve", -"savable", -"savacu", -"savage", -"savanna", -"savant", -"savarin", -"save", -"saved", -"saveloy", -"saver", -"savin", -"saving", -"savior", -"savola", -"savor", -"savored", -"savorer", -"savory", -"savour", -"savoy", -"savoyed", -"savssat", -"savvy", -"saw", -"sawah", -"sawali", -"sawarra", -"sawback", -"sawbill", -"sawbuck", -"sawbwa", -"sawder", -"sawdust", -"sawed", -"sawer", -"sawfish", -"sawfly", -"sawing", -"sawish", -"sawlike", -"sawman", -"sawmill", -"sawmon", -"sawmont", -"sawn", -"sawney", -"sawt", -"sawway", -"sawwort", -"sawyer", -"sax", -"saxhorn", -"saxten", -"saxtie", -"saxtuba", -"say", -"saya", -"sayable", -"sayer", -"sayette", -"sayid", -"saying", -"sazen", -"sblood", -"scab", -"scabbed", -"scabble", -"scabby", -"scabid", -"scabies", -"scabish", -"scabrid", -"scad", -"scaddle", -"scads", -"scaff", -"scaffer", -"scaffie", -"scaffle", -"scaglia", -"scala", -"scalage", -"scalar", -"scalare", -"scald", -"scalded", -"scalder", -"scaldic", -"scaldy", -"scale", -"scaled", -"scalena", -"scalene", -"scaler", -"scales", -"scaling", -"scall", -"scalled", -"scallom", -"scallop", -"scalma", -"scaloni", -"scalp", -"scalpel", -"scalper", -"scalt", -"scaly", -"scam", -"scamble", -"scamell", -"scamler", -"scamles", -"scamp", -"scamper", -"scan", -"scandal", -"scandia", -"scandic", -"scanmag", -"scanner", -"scant", -"scantle", -"scantly", -"scanty", -"scap", -"scape", -"scapel", -"scapha", -"scapoid", -"scapose", -"scapple", -"scapula", -"scapus", -"scar", -"scarab", -"scarce", -"scarcen", -"scare", -"scarer", -"scarf", -"scarfed", -"scarfer", -"scarfy", -"scarid", -"scarify", -"scarily", -"scarlet", -"scarman", -"scarn", -"scaroid", -"scarp", -"scarred", -"scarrer", -"scarry", -"scart", -"scarth", -"scarus", -"scarved", -"scary", -"scase", -"scasely", -"scat", -"scatch", -"scathe", -"scatter", -"scatty", -"scatula", -"scaul", -"scaum", -"scaup", -"scauper", -"scaur", -"scaurie", -"scaut", -"scavage", -"scavel", -"scaw", -"scawd", -"scawl", -"scazon", -"sceat", -"scena", -"scenary", -"scend", -"scene", -"scenery", -"scenic", -"scenist", -"scenite", -"scent", -"scented", -"scenter", -"scepsis", -"scepter", -"sceptic", -"sceptry", -"scerne", -"schanz", -"schappe", -"scharf", -"schelly", -"schema", -"scheme", -"schemer", -"schemy", -"schene", -"schepel", -"schepen", -"scherm", -"scherzi", -"scherzo", -"schesis", -"schism", -"schisma", -"schist", -"schloop", -"schmelz", -"scho", -"schola", -"scholae", -"scholar", -"scholia", -"schone", -"school", -"schoon", -"schorl", -"schorly", -"schout", -"schtoff", -"schuh", -"schuhe", -"schuit", -"schule", -"schuss", -"schute", -"schwa", -"schwarz", -"sciapod", -"sciarid", -"sciatic", -"scibile", -"science", -"scient", -"scincid", -"scind", -"sciniph", -"scintle", -"scion", -"scious", -"scirrhi", -"scissel", -"scissor", -"sciurid", -"sclaff", -"sclate", -"sclater", -"sclaw", -"scler", -"sclera", -"scleral", -"sclere", -"scliff", -"sclim", -"sclimb", -"scoad", -"scob", -"scobby", -"scobs", -"scoff", -"scoffer", -"scog", -"scoggan", -"scogger", -"scoggin", -"scoke", -"scolb", -"scold", -"scolder", -"scolex", -"scolia", -"scoliid", -"scolion", -"scolite", -"scollop", -"scolog", -"sconce", -"sconcer", -"scone", -"scoon", -"scoop", -"scooped", -"scooper", -"scoot", -"scooter", -"scopa", -"scopate", -"scope", -"scopet", -"scopic", -"scopine", -"scopola", -"scops", -"scopula", -"scorch", -"score", -"scored", -"scorer", -"scoria", -"scoriac", -"scoriae", -"scorify", -"scoring", -"scorn", -"scorned", -"scorner", -"scorny", -"scorper", -"scorse", -"scot", -"scotale", -"scotch", -"scote", -"scoter", -"scotia", -"scotino", -"scotoma", -"scotomy", -"scouch", -"scouk", -"scoup", -"scour", -"scoured", -"scourer", -"scourge", -"scoury", -"scouse", -"scout", -"scouter", -"scouth", -"scove", -"scovel", -"scovy", -"scow", -"scowder", -"scowl", -"scowler", -"scowman", -"scrab", -"scrabe", -"scrae", -"scrag", -"scraggy", -"scraily", -"scram", -"scran", -"scranch", -"scrank", -"scranky", -"scranny", -"scrap", -"scrape", -"scraped", -"scraper", -"scrapie", -"scrappy", -"scrapy", -"scrat", -"scratch", -"scrath", -"scrauch", -"scraw", -"scrawk", -"scrawl", -"scrawly", -"scrawm", -"scrawny", -"scray", -"scraze", -"screak", -"screaky", -"scream", -"screamy", -"scree", -"screech", -"screed", -"screek", -"screel", -"screen", -"screeny", -"screet", -"screeve", -"screich", -"screigh", -"screve", -"screver", -"screw", -"screwed", -"screwer", -"screwy", -"scribal", -"scribe", -"scriber", -"scride", -"scrieve", -"scrike", -"scrim", -"scrime", -"scrimer", -"scrimp", -"scrimpy", -"scrin", -"scrinch", -"scrine", -"scringe", -"scrip", -"scripee", -"script", -"scritch", -"scrive", -"scriven", -"scriver", -"scrob", -"scrobe", -"scrobis", -"scrod", -"scroff", -"scrog", -"scroggy", -"scrolar", -"scroll", -"scrolly", -"scroo", -"scrooch", -"scrooge", -"scroop", -"scrota", -"scrotal", -"scrotum", -"scrouge", -"scrout", -"scrow", -"scroyle", -"scrub", -"scrubby", -"scruf", -"scruff", -"scruffy", -"scruft", -"scrum", -"scrump", -"scrunch", -"scrunge", -"scrunt", -"scruple", -"scrush", -"scruto", -"scruze", -"scry", -"scryer", -"scud", -"scudder", -"scuddle", -"scuddy", -"scudi", -"scudler", -"scudo", -"scuff", -"scuffed", -"scuffer", -"scuffle", -"scuffly", -"scuffy", -"scuft", -"scufter", -"scug", -"sculch", -"scull", -"sculler", -"scullog", -"sculp", -"sculper", -"sculpin", -"sculpt", -"sculsh", -"scum", -"scumber", -"scumble", -"scummed", -"scummer", -"scummy", -"scun", -"scunder", -"scunner", -"scup", -"scupful", -"scupper", -"scuppet", -"scur", -"scurdy", -"scurf", -"scurfer", -"scurfy", -"scurry", -"scurvy", -"scuse", -"scut", -"scuta", -"scutage", -"scutal", -"scutate", -"scutch", -"scute", -"scutel", -"scutter", -"scuttle", -"scutty", -"scutula", -"scutum", -"scybala", -"scye", -"scypha", -"scyphae", -"scyphi", -"scyphoi", -"scyphus", -"scyt", -"scytale", -"scythe", -"sdeath", -"se", -"sea", -"seadog", -"seafare", -"seafolk", -"seafowl", -"seagirt", -"seagoer", -"seah", -"seak", -"seal", -"sealant", -"sealch", -"sealed", -"sealer", -"sealery", -"sealess", -"sealet", -"sealike", -"sealine", -"sealing", -"seam", -"seaman", -"seamark", -"seamed", -"seamer", -"seaming", -"seamlet", -"seamost", -"seamrog", -"seamy", -"seance", -"seaport", -"sear", -"searce", -"searcer", -"search", -"seared", -"searer", -"searing", -"seary", -"seasick", -"seaside", -"season", -"seat", -"seatang", -"seated", -"seater", -"seathe", -"seating", -"seatron", -"seave", -"seavy", -"seawant", -"seaward", -"seaware", -"seaway", -"seaweed", -"seawife", -"seaworn", -"seax", -"sebacic", -"sebait", -"sebate", -"sebific", -"sebilla", -"sebkha", -"sebum", -"sebundy", -"sec", -"secable", -"secalin", -"secancy", -"secant", -"secede", -"seceder", -"secern", -"secesh", -"sech", -"seck", -"seclude", -"secluse", -"secohm", -"second", -"seconde", -"secos", -"secpar", -"secque", -"secre", -"secrecy", -"secret", -"secreta", -"secrete", -"secreto", -"sect", -"sectary", -"sectile", -"section", -"sectism", -"sectist", -"sective", -"sector", -"secular", -"secund", -"secure", -"securer", -"sedan", -"sedate", -"sedent", -"sedge", -"sedged", -"sedging", -"sedgy", -"sedile", -"sedilia", -"seduce", -"seducee", -"seducer", -"seduct", -"sedum", -"see", -"seeable", -"seech", -"seed", -"seedage", -"seedbed", -"seedbox", -"seeded", -"seeder", -"seedful", -"seedily", -"seedkin", -"seedlet", -"seedlip", -"seedman", -"seedy", -"seege", -"seeing", -"seek", -"seeker", -"seeking", -"seel", -"seelful", -"seely", -"seem", -"seemer", -"seeming", -"seemly", -"seen", -"seenie", -"seep", -"seepage", -"seeped", -"seepy", -"seer", -"seeress", -"seerpaw", -"seesaw", -"seesee", -"seethe", -"seg", -"seggar", -"seggard", -"segged", -"seggrom", -"segment", -"sego", -"segol", -"seiche", -"seidel", -"seine", -"seiner", -"seise", -"seism", -"seismal", -"seismic", -"seit", -"seity", -"seize", -"seizer", -"seizin", -"seizing", -"seizor", -"seizure", -"sejant", -"sejoin", -"sejunct", -"sekos", -"selah", -"selamin", -"seldom", -"seldor", -"sele", -"select", -"selenic", -"self", -"selfdom", -"selfful", -"selfish", -"selfism", -"selfist", -"selfly", -"selion", -"sell", -"sella", -"sellar", -"sellate", -"seller", -"sellie", -"selling", -"sellout", -"selly", -"selsyn", -"selt", -"selva", -"selvage", -"semarum", -"sematic", -"semball", -"semble", -"seme", -"semeed", -"semeia", -"semeion", -"semen", -"semence", -"semese", -"semi", -"semiape", -"semiarc", -"semibay", -"semic", -"semicup", -"semidry", -"semiegg", -"semifib", -"semifit", -"semify", -"semigod", -"semihot", -"seminal", -"seminar", -"semiorb", -"semiped", -"semipro", -"semiraw", -"semis", -"semita", -"semitae", -"semital", -"semiurn", -"semmet", -"semmit", -"semola", -"semsem", -"sen", -"senaite", -"senam", -"senary", -"senate", -"senator", -"sence", -"sencion", -"send", -"sendal", -"sendee", -"sender", -"sending", -"senega", -"senegin", -"senesce", -"senile", -"senior", -"senna", -"sennet", -"sennit", -"sennite", -"sensa", -"sensal", -"sensate", -"sense", -"sensed", -"sensify", -"sensile", -"sension", -"sensism", -"sensist", -"sensive", -"sensize", -"senso", -"sensor", -"sensory", -"sensual", -"sensum", -"sensyne", -"sent", -"sentry", -"sepad", -"sepal", -"sepaled", -"sephen", -"sepia", -"sepian", -"sepiary", -"sepic", -"sepioid", -"sepion", -"sepiost", -"sepium", -"sepone", -"sepoy", -"seppuku", -"seps", -"sepsine", -"sepsis", -"sept", -"septa", -"septal", -"septan", -"septane", -"septate", -"septave", -"septet", -"septic", -"septier", -"septile", -"septime", -"septoic", -"septole", -"septum", -"septuor", -"sequa", -"sequel", -"sequela", -"sequent", -"sequest", -"sequin", -"ser", -"sera", -"serab", -"seragli", -"serai", -"serail", -"seral", -"serang", -"serape", -"seraph", -"serau", -"seraw", -"sercial", -"serdab", -"sere", -"sereh", -"serene", -"serf", -"serfage", -"serfdom", -"serfish", -"serfism", -"serge", -"serger", -"serging", -"serial", -"seriary", -"seriate", -"sericea", -"sericin", -"seriema", -"series", -"serif", -"serific", -"serin", -"serine", -"seringa", -"serio", -"serious", -"serment", -"sermo", -"sermon", -"sero", -"serolin", -"seron", -"seroon", -"seroot", -"seropus", -"serosa", -"serous", -"serow", -"serpent", -"serphid", -"serpigo", -"serpula", -"serra", -"serrage", -"serran", -"serrana", -"serrano", -"serrate", -"serried", -"serry", -"sert", -"serta", -"sertule", -"sertum", -"serum", -"serumal", -"serut", -"servage", -"serval", -"servant", -"serve", -"server", -"servery", -"servet", -"service", -"servile", -"serving", -"servist", -"servo", -"sesame", -"sesma", -"sesqui", -"sess", -"sessile", -"session", -"sestet", -"sesti", -"sestiad", -"sestina", -"sestine", -"sestole", -"sestuor", -"set", -"seta", -"setae", -"setal", -"setback", -"setbolt", -"setdown", -"setfast", -"seth", -"sethead", -"setier", -"setline", -"setness", -"setoff", -"seton", -"setose", -"setous", -"setout", -"setover", -"setsman", -"sett", -"settee", -"setter", -"setting", -"settle", -"settled", -"settler", -"settlor", -"setula", -"setule", -"setup", -"setwall", -"setwise", -"setwork", -"seugh", -"seven", -"sevener", -"seventh", -"seventy", -"sever", -"several", -"severe", -"severer", -"severy", -"sew", -"sewable", -"sewage", -"sewan", -"sewed", -"sewen", -"sewer", -"sewered", -"sewery", -"sewing", -"sewless", -"sewn", -"sex", -"sexed", -"sexern", -"sexfid", -"sexfoil", -"sexhood", -"sexifid", -"sexiped", -"sexless", -"sexlike", -"sexly", -"sext", -"sextain", -"sextan", -"sextans", -"sextant", -"sextar", -"sextary", -"sextern", -"sextet", -"sextic", -"sextile", -"sexto", -"sextole", -"sexton", -"sextry", -"sextula", -"sexual", -"sexuale", -"sexuous", -"sexy", -"sey", -"sfoot", -"sh", -"sha", -"shab", -"shabash", -"shabbed", -"shabble", -"shabby", -"shachle", -"shachly", -"shack", -"shackle", -"shackly", -"shacky", -"shad", -"shade", -"shaded", -"shader", -"shadily", -"shadine", -"shading", -"shadkan", -"shadoof", -"shadow", -"shadowy", -"shady", -"shaffle", -"shaft", -"shafted", -"shafter", -"shafty", -"shag", -"shagbag", -"shagged", -"shaggy", -"shaglet", -"shagrag", -"shah", -"shahdom", -"shahi", -"shahin", -"shaikh", -"shaitan", -"shake", -"shaken", -"shaker", -"shakers", -"shakha", -"shakily", -"shaking", -"shako", -"shakti", -"shaku", -"shaky", -"shale", -"shall", -"shallal", -"shallon", -"shallop", -"shallot", -"shallow", -"shallu", -"shalom", -"shalt", -"shalwar", -"shaly", -"sham", -"shama", -"shamal", -"shamalo", -"shaman", -"shamba", -"shamble", -"shame", -"shamed", -"shamer", -"shamir", -"shammed", -"shammer", -"shammy", -"shampoo", -"shan", -"shandry", -"shandy", -"shangan", -"shank", -"shanked", -"shanker", -"shanna", -"shanny", -"shansa", -"shant", -"shanty", -"shap", -"shape", -"shaped", -"shapely", -"shapen", -"shaper", -"shaping", -"shaps", -"shapy", -"shard", -"sharded", -"shardy", -"share", -"sharer", -"shargar", -"shark", -"sharky", -"sharn", -"sharny", -"sharp", -"sharpen", -"sharper", -"sharpie", -"sharply", -"sharps", -"sharpy", -"sharrag", -"sharry", -"shaster", -"shastra", -"shastri", -"shat", -"shatan", -"shatter", -"shaugh", -"shaul", -"shaup", -"shauri", -"shauwe", -"shave", -"shaved", -"shavee", -"shaven", -"shaver", -"shavery", -"shaving", -"shaw", -"shawl", -"shawled", -"shawm", -"shawny", -"shawy", -"shay", -"she", -"shea", -"sheaf", -"sheafy", -"sheal", -"shear", -"sheard", -"shearer", -"shears", -"sheat", -"sheath", -"sheathe", -"sheathy", -"sheave", -"sheaved", -"shebang", -"shebeen", -"shed", -"shedded", -"shedder", -"sheder", -"shedman", -"shee", -"sheely", -"sheen", -"sheenly", -"sheeny", -"sheep", -"sheepy", -"sheer", -"sheered", -"sheerly", -"sheet", -"sheeted", -"sheeter", -"sheety", -"sheik", -"sheikly", -"shekel", -"shela", -"sheld", -"shelder", -"shelf", -"shelfy", -"shell", -"shellac", -"shelled", -"sheller", -"shellum", -"shelly", -"shelta", -"shelter", -"shelty", -"shelve", -"shelver", -"shelvy", -"shend", -"sheng", -"sheolic", -"sheppey", -"sher", -"sherbet", -"sheriat", -"sherif", -"sherifa", -"sheriff", -"sherifi", -"sherify", -"sherry", -"sheth", -"sheugh", -"sheva", -"shevel", -"shevri", -"shewa", -"shewel", -"sheyle", -"shi", -"shibah", -"shibar", -"shice", -"shicer", -"shicker", -"shide", -"shied", -"shiel", -"shield", -"shier", -"shies", -"shiest", -"shift", -"shifter", -"shifty", -"shigram", -"shih", -"shikar", -"shikara", -"shikari", -"shikimi", -"shikken", -"shiko", -"shikra", -"shilf", -"shilfa", -"shill", -"shilla", -"shillet", -"shilloo", -"shilpit", -"shim", -"shimal", -"shimmer", -"shimmy", -"shimose", -"shimper", -"shin", -"shindig", -"shindle", -"shindy", -"shine", -"shiner", -"shingle", -"shingly", -"shinily", -"shining", -"shinner", -"shinny", -"shinty", -"shiny", -"shinza", -"ship", -"shipboy", -"shipful", -"shiplap", -"shiplet", -"shipman", -"shipped", -"shipper", -"shippo", -"shippon", -"shippy", -"shipway", -"shire", -"shirk", -"shirker", -"shirky", -"shirl", -"shirpit", -"shirr", -"shirt", -"shirty", -"shish", -"shisham", -"shisn", -"shita", -"shither", -"shittah", -"shittim", -"shiv", -"shive", -"shiver", -"shivery", -"shivey", -"shivoo", -"shivy", -"sho", -"shoad", -"shoader", -"shoal", -"shoaler", -"shoaly", -"shoat", -"shock", -"shocker", -"shod", -"shodden", -"shoddy", -"shode", -"shoder", -"shoe", -"shoeboy", -"shoeing", -"shoeman", -"shoer", -"shoful", -"shog", -"shogaol", -"shoggie", -"shoggle", -"shoggly", -"shogi", -"shogun", -"shohet", -"shoji", -"shola", -"shole", -"shone", -"shoneen", -"shoo", -"shood", -"shoofa", -"shoofly", -"shooi", -"shook", -"shool", -"shooler", -"shoop", -"shoor", -"shoot", -"shootee", -"shooter", -"shop", -"shopboy", -"shopful", -"shophar", -"shoplet", -"shopman", -"shoppe", -"shopper", -"shoppy", -"shoq", -"shor", -"shoran", -"shore", -"shored", -"shorer", -"shoring", -"shorn", -"short", -"shorten", -"shorter", -"shortly", -"shorts", -"shot", -"shote", -"shotgun", -"shotman", -"shott", -"shotted", -"shotten", -"shotter", -"shotty", -"shou", -"should", -"shout", -"shouter", -"shoval", -"shove", -"shovel", -"shover", -"show", -"showdom", -"shower", -"showery", -"showily", -"showing", -"showish", -"showman", -"shown", -"showup", -"showy", -"shoya", -"shrab", -"shradh", -"shraf", -"shrag", -"shram", -"shrank", -"shrap", -"shrave", -"shravey", -"shred", -"shreddy", -"shree", -"shreeve", -"shrend", -"shrew", -"shrewd", -"shrewdy", -"shrewly", -"shriek", -"shrieky", -"shrift", -"shrike", -"shrill", -"shrilly", -"shrimp", -"shrimpi", -"shrimpy", -"shrinal", -"shrine", -"shrink", -"shrinky", -"shrip", -"shrite", -"shrive", -"shrivel", -"shriven", -"shriver", -"shroff", -"shrog", -"shroud", -"shroudy", -"shrove", -"shrover", -"shrub", -"shrubby", -"shruff", -"shrug", -"shrunk", -"shrups", -"shuba", -"shuck", -"shucker", -"shucks", -"shudder", -"shuff", -"shuffle", -"shug", -"shul", -"shuler", -"shumac", -"shun", -"shune", -"shunner", -"shunt", -"shunter", -"shure", -"shurf", -"shush", -"shusher", -"shut", -"shutoff", -"shutout", -"shutten", -"shutter", -"shuttle", -"shy", -"shyer", -"shyish", -"shyly", -"shyness", -"shyster", -"si", -"siak", -"sial", -"sialic", -"sialid", -"sialoid", -"siamang", -"sib", -"sibbed", -"sibbens", -"sibber", -"sibby", -"sibilus", -"sibling", -"sibness", -"sibrede", -"sibship", -"sibyl", -"sibylic", -"sibylla", -"sic", -"sicca", -"siccant", -"siccate", -"siccity", -"sice", -"sick", -"sickbed", -"sicken", -"sicker", -"sickish", -"sickle", -"sickled", -"sickler", -"sickly", -"sicsac", -"sicula", -"sicular", -"sidder", -"siddur", -"side", -"sideage", -"sidearm", -"sidecar", -"sided", -"sider", -"sideral", -"siderin", -"sides", -"sideway", -"sidhe", -"sidi", -"siding", -"sidle", -"sidler", -"sidling", -"sidth", -"sidy", -"sie", -"siege", -"sieger", -"sienna", -"sier", -"siering", -"sierra", -"sierran", -"siesta", -"sieve", -"siever", -"sievy", -"sifac", -"sifaka", -"sife", -"siffle", -"sifflet", -"sifflot", -"sift", -"siftage", -"sifted", -"sifter", -"sifting", -"sig", -"sigger", -"sigh", -"sigher", -"sighful", -"sighing", -"sight", -"sighted", -"sighten", -"sighter", -"sightly", -"sighty", -"sigil", -"sigla", -"siglos", -"sigma", -"sigmate", -"sigmoid", -"sign", -"signal", -"signary", -"signate", -"signee", -"signer", -"signet", -"signify", -"signior", -"signist", -"signman", -"signory", -"signum", -"sika", -"sikar", -"sikatch", -"sike", -"sikerly", -"siket", -"sikhara", -"sikhra", -"sil", -"silage", -"silane", -"sile", -"silen", -"silence", -"silency", -"sileni", -"silenic", -"silent", -"silenus", -"silesia", -"silex", -"silica", -"silicam", -"silicic", -"silicle", -"silico", -"silicon", -"silicyl", -"siliqua", -"silique", -"silk", -"silked", -"silken", -"silker", -"silkie", -"silkily", -"silkman", -"silky", -"sill", -"sillar", -"siller", -"sillily", -"sillock", -"sillon", -"silly", -"silo", -"siloist", -"silphid", -"silt", -"siltage", -"silting", -"silty", -"silurid", -"silva", -"silvan", -"silver", -"silvern", -"silvery", -"silvics", -"silyl", -"sima", -"simal", -"simar", -"simball", -"simbil", -"simblin", -"simblot", -"sime", -"simiad", -"simial", -"simian", -"similar", -"simile", -"similor", -"simioid", -"simious", -"simity", -"simkin", -"simlin", -"simling", -"simmer", -"simmon", -"simnel", -"simony", -"simool", -"simoom", -"simoon", -"simous", -"simp", -"simpai", -"simper", -"simple", -"simpler", -"simplex", -"simply", -"simsim", -"simson", -"simular", -"simuler", -"sin", -"sina", -"sinaite", -"sinal", -"sinamay", -"sinapic", -"sinapis", -"sinawa", -"since", -"sincere", -"sind", -"sinder", -"sindle", -"sindoc", -"sindon", -"sindry", -"sine", -"sinew", -"sinewed", -"sinewy", -"sinful", -"sing", -"singe", -"singed", -"singer", -"singey", -"singh", -"singing", -"single", -"singled", -"singler", -"singles", -"singlet", -"singly", -"singult", -"sinh", -"sink", -"sinkage", -"sinker", -"sinking", -"sinky", -"sinless", -"sinlike", -"sinnen", -"sinner", -"sinnet", -"sinopia", -"sinople", -"sinsion", -"sinsyne", -"sinter", -"sintoc", -"sinuate", -"sinuose", -"sinuous", -"sinus", -"sinusal", -"sinward", -"siol", -"sion", -"sip", -"sipage", -"sipe", -"siper", -"siphoid", -"siphon", -"sipid", -"siping", -"sipling", -"sipper", -"sippet", -"sippio", -"sir", -"sircar", -"sirdar", -"sire", -"siren", -"sirene", -"sirenic", -"sireny", -"siress", -"sirgang", -"sirian", -"siricid", -"sirih", -"siris", -"sirkeer", -"sirki", -"sirky", -"sirloin", -"siroc", -"sirocco", -"sirpea", -"sirple", -"sirpoon", -"sirrah", -"sirree", -"sirship", -"sirup", -"siruped", -"siruper", -"sirupy", -"sis", -"sisal", -"sise", -"sisel", -"sish", -"sisham", -"sisi", -"siskin", -"siss", -"sissify", -"sissoo", -"sissy", -"sist", -"sister", -"sistern", -"sistle", -"sistrum", -"sit", -"sitao", -"sitar", -"sitch", -"site", -"sitfast", -"sith", -"sithe", -"sithens", -"sitient", -"sitio", -"sittee", -"sitten", -"sitter", -"sittine", -"sitting", -"situal", -"situate", -"situla", -"situlae", -"situs", -"siva", -"siver", -"sivvens", -"siwash", -"six", -"sixain", -"sixer", -"sixfoil", -"sixfold", -"sixsome", -"sixte", -"sixteen", -"sixth", -"sixthet", -"sixthly", -"sixty", -"sizable", -"sizably", -"sizal", -"sizar", -"size", -"sized", -"sizeman", -"sizer", -"sizes", -"sizing", -"sizy", -"sizygia", -"sizz", -"sizzard", -"sizzing", -"sizzle", -"sjambok", -"skaddle", -"skaff", -"skaffie", -"skag", -"skair", -"skal", -"skance", -"skart", -"skasely", -"skat", -"skate", -"skater", -"skatiku", -"skating", -"skatist", -"skatole", -"skaw", -"skean", -"skedge", -"skee", -"skeed", -"skeeg", -"skeel", -"skeely", -"skeen", -"skeer", -"skeered", -"skeery", -"skeet", -"skeeter", -"skeezix", -"skeg", -"skegger", -"skeif", -"skeigh", -"skeily", -"skein", -"skeiner", -"skeipp", -"skel", -"skelder", -"skelf", -"skelic", -"skell", -"skellat", -"skeller", -"skellum", -"skelly", -"skelp", -"skelper", -"skelpin", -"skelter", -"skemmel", -"skemp", -"sken", -"skene", -"skeo", -"skeough", -"skep", -"skepful", -"skeptic", -"sker", -"skere", -"skerret", -"skerry", -"sketch", -"sketchy", -"skete", -"skevish", -"skew", -"skewed", -"skewer", -"skewl", -"skewly", -"skewy", -"skey", -"ski", -"skiapod", -"skibby", -"skice", -"skid", -"skidded", -"skidder", -"skiddoo", -"skiddy", -"skidpan", -"skidway", -"skied", -"skieppe", -"skier", -"skies", -"skiff", -"skift", -"skiing", -"skijore", -"skil", -"skilder", -"skill", -"skilled", -"skillet", -"skilly", -"skilpot", -"skilts", -"skim", -"skime", -"skimmed", -"skimmer", -"skimp", -"skimpy", -"skin", -"skinch", -"skinful", -"skink", -"skinker", -"skinkle", -"skinned", -"skinner", -"skinny", -"skip", -"skipman", -"skippel", -"skipper", -"skippet", -"skipple", -"skippy", -"skirl", -"skirp", -"skirr", -"skirreh", -"skirret", -"skirt", -"skirted", -"skirter", -"skirty", -"skit", -"skite", -"skiter", -"skither", -"skitter", -"skittle", -"skitty", -"skiv", -"skive", -"skiver", -"skiving", -"sklate", -"sklater", -"sklent", -"skoal", -"skoo", -"skookum", -"skoptsy", -"skout", -"skraigh", -"skrike", -"skrupul", -"skua", -"skulk", -"skulker", -"skull", -"skulled", -"skully", -"skulp", -"skun", -"skunk", -"skunky", -"skuse", -"sky", -"skybal", -"skyey", -"skyful", -"skyish", -"skylark", -"skyless", -"skylike", -"skylook", -"skyman", -"skyphoi", -"skyphos", -"skyre", -"skysail", -"skyugle", -"skyward", -"skyway", -"sla", -"slab", -"slabbed", -"slabber", -"slabby", -"slabman", -"slack", -"slacked", -"slacken", -"slacker", -"slackly", -"slad", -"sladang", -"slade", -"slae", -"slag", -"slagger", -"slaggy", -"slagman", -"slain", -"slainte", -"slait", -"slake", -"slaker", -"slaking", -"slaky", -"slam", -"slamp", -"slander", -"slane", -"slang", -"slangy", -"slank", -"slant", -"slantly", -"slap", -"slape", -"slapper", -"slare", -"slart", -"slarth", -"slash", -"slashed", -"slasher", -"slashy", -"slat", -"slatch", -"slate", -"slater", -"slath", -"slather", -"slatify", -"slating", -"slatish", -"slatted", -"slatter", -"slaty", -"slaum", -"slave", -"slaved", -"slaver", -"slavery", -"slavey", -"slaving", -"slavish", -"slaw", -"slay", -"slayer", -"slaying", -"sleathy", -"sleave", -"sleaved", -"sleazy", -"sleck", -"sled", -"sledded", -"sledder", -"sledful", -"sledge", -"sledger", -"slee", -"sleech", -"sleechy", -"sleek", -"sleeken", -"sleeker", -"sleekit", -"sleekly", -"sleeky", -"sleep", -"sleeper", -"sleepry", -"sleepy", -"sleer", -"sleet", -"sleety", -"sleeve", -"sleeved", -"sleever", -"sleigh", -"sleight", -"slender", -"slent", -"slepez", -"slept", -"slete", -"sleuth", -"slew", -"slewed", -"slewer", -"slewing", -"sley", -"sleyer", -"slice", -"sliced", -"slicer", -"slich", -"slicht", -"slicing", -"slick", -"slicken", -"slicker", -"slickly", -"slid", -"slidage", -"slidden", -"slidder", -"slide", -"slided", -"slider", -"sliding", -"slifter", -"slight", -"slighty", -"slim", -"slime", -"slimer", -"slimily", -"slimish", -"slimly", -"slimpsy", -"slimsy", -"slimy", -"sline", -"sling", -"slinge", -"slinger", -"slink", -"slinker", -"slinky", -"slip", -"slipe", -"slipman", -"slipped", -"slipper", -"slippy", -"slipway", -"slirt", -"slish", -"slit", -"slitch", -"slite", -"slither", -"slithy", -"slitted", -"slitter", -"slitty", -"slive", -"sliver", -"slivery", -"sliving", -"sloan", -"slob", -"slobber", -"slobby", -"slock", -"slocken", -"slod", -"slodder", -"slodge", -"slodger", -"sloe", -"slog", -"slogan", -"slogger", -"sloka", -"sloke", -"slon", -"slone", -"slonk", -"sloo", -"sloom", -"sloomy", -"sloop", -"sloosh", -"slop", -"slope", -"sloped", -"slopely", -"sloper", -"sloping", -"slopped", -"sloppy", -"slops", -"slopy", -"slorp", -"slosh", -"slosher", -"sloshy", -"slot", -"slote", -"sloted", -"sloth", -"slotted", -"slotter", -"slouch", -"slouchy", -"slough", -"sloughy", -"slour", -"sloush", -"sloven", -"slow", -"slowish", -"slowly", -"slowrie", -"slows", -"sloyd", -"slub", -"slubber", -"slubby", -"slud", -"sludder", -"sludge", -"sludged", -"sludger", -"sludgy", -"slue", -"sluer", -"slug", -"slugged", -"slugger", -"sluggy", -"sluice", -"sluicer", -"sluicy", -"sluig", -"sluit", -"slum", -"slumber", -"slumdom", -"slumgum", -"slummer", -"slummy", -"slump", -"slumpy", -"slung", -"slunge", -"slunk", -"slunken", -"slur", -"slurbow", -"slurp", -"slurry", -"slush", -"slusher", -"slushy", -"slut", -"slutch", -"slutchy", -"sluther", -"slutter", -"slutty", -"sly", -"slyish", -"slyly", -"slyness", -"slype", -"sma", -"smack", -"smackee", -"smacker", -"smaik", -"small", -"smallen", -"smaller", -"smalls", -"smally", -"smalm", -"smalt", -"smalter", -"smalts", -"smaragd", -"smarm", -"smarmy", -"smart", -"smarten", -"smartly", -"smarty", -"smash", -"smasher", -"smashup", -"smatter", -"smaze", -"smear", -"smeared", -"smearer", -"smeary", -"smectic", -"smectis", -"smeddum", -"smee", -"smeech", -"smeek", -"smeeky", -"smeer", -"smeeth", -"smegma", -"smell", -"smelled", -"smeller", -"smelly", -"smelt", -"smelter", -"smeth", -"smethe", -"smeuse", -"smew", -"smich", -"smicker", -"smicket", -"smiddie", -"smiddum", -"smidge", -"smidgen", -"smilax", -"smile", -"smiler", -"smilet", -"smiling", -"smily", -"smirch", -"smirchy", -"smiris", -"smirk", -"smirker", -"smirkle", -"smirkly", -"smirky", -"smirtle", -"smit", -"smitch", -"smite", -"smiter", -"smith", -"smitham", -"smither", -"smithy", -"smiting", -"smitten", -"smock", -"smocker", -"smog", -"smoke", -"smoked", -"smoker", -"smokery", -"smokily", -"smoking", -"smokish", -"smoky", -"smolder", -"smolt", -"smooch", -"smoochy", -"smoodge", -"smook", -"smoot", -"smooth", -"smopple", -"smore", -"smote", -"smother", -"smotter", -"smouch", -"smous", -"smouse", -"smouser", -"smout", -"smriti", -"smudge", -"smudged", -"smudger", -"smudgy", -"smug", -"smuggle", -"smugism", -"smugly", -"smuisty", -"smur", -"smurr", -"smurry", -"smuse", -"smush", -"smut", -"smutch", -"smutchy", -"smutted", -"smutter", -"smutty", -"smyth", -"smytrie", -"snab", -"snabbie", -"snabble", -"snack", -"snackle", -"snaff", -"snaffle", -"snafu", -"snag", -"snagged", -"snagger", -"snaggy", -"snagrel", -"snail", -"snails", -"snaily", -"snaith", -"snake", -"snaker", -"snakery", -"snakily", -"snaking", -"snakish", -"snaky", -"snap", -"snapbag", -"snape", -"snaper", -"snapped", -"snapper", -"snapps", -"snappy", -"snaps", -"snapy", -"snare", -"snarer", -"snark", -"snarl", -"snarler", -"snarly", -"snary", -"snaste", -"snatch", -"snatchy", -"snath", -"snathe", -"snavel", -"snavvle", -"snaw", -"snead", -"sneak", -"sneaker", -"sneaky", -"sneap", -"sneath", -"sneathe", -"sneb", -"sneck", -"snecker", -"snecket", -"sned", -"snee", -"sneer", -"sneerer", -"sneery", -"sneesh", -"sneest", -"sneesty", -"sneeze", -"sneezer", -"sneezy", -"snell", -"snelly", -"snerp", -"snew", -"snib", -"snibble", -"snibel", -"snicher", -"snick", -"snicker", -"snicket", -"snickey", -"snickle", -"sniddle", -"snide", -"sniff", -"sniffer", -"sniffle", -"sniffly", -"sniffy", -"snift", -"snifter", -"snifty", -"snig", -"snigger", -"sniggle", -"snip", -"snipe", -"sniper", -"sniping", -"snipish", -"snipper", -"snippet", -"snippy", -"snipy", -"snirl", -"snirt", -"snirtle", -"snitch", -"snite", -"snithe", -"snithy", -"snittle", -"snivel", -"snively", -"snivy", -"snob", -"snobber", -"snobby", -"snobdom", -"snocher", -"snock", -"snocker", -"snod", -"snodly", -"snoek", -"snog", -"snoga", -"snoke", -"snood", -"snooded", -"snook", -"snooker", -"snoop", -"snooper", -"snoopy", -"snoose", -"snoot", -"snooty", -"snoove", -"snooze", -"snoozer", -"snoozle", -"snoozy", -"snop", -"snore", -"snorer", -"snoring", -"snork", -"snorkel", -"snorker", -"snort", -"snorter", -"snortle", -"snorty", -"snot", -"snotter", -"snotty", -"snouch", -"snout", -"snouted", -"snouter", -"snouty", -"snow", -"snowcap", -"snowie", -"snowily", -"snowish", -"snowk", -"snowl", -"snowy", -"snozzle", -"snub", -"snubbed", -"snubbee", -"snubber", -"snubby", -"snuck", -"snudge", -"snuff", -"snuffer", -"snuffle", -"snuffly", -"snuffy", -"snug", -"snugger", -"snuggle", -"snugify", -"snugly", -"snum", -"snup", -"snupper", -"snur", -"snurl", -"snurly", -"snurp", -"snurt", -"snuzzle", -"sny", -"snying", -"so", -"soak", -"soakage", -"soaked", -"soaken", -"soaker", -"soaking", -"soakman", -"soaky", -"soally", -"soam", -"soap", -"soapbox", -"soaper", -"soapery", -"soapily", -"soapsud", -"soapy", -"soar", -"soarer", -"soaring", -"soary", -"sob", -"sobber", -"sobbing", -"sobby", -"sobeit", -"sober", -"soberer", -"soberly", -"sobful", -"soboles", -"soc", -"socage", -"socager", -"soccer", -"soce", -"socht", -"social", -"society", -"socii", -"socius", -"sock", -"socker", -"socket", -"sockeye", -"socky", -"socle", -"socman", -"soco", -"sod", -"soda", -"sodaic", -"sodded", -"sodden", -"sodding", -"soddite", -"soddy", -"sodic", -"sodio", -"sodium", -"sodless", -"sodoku", -"sodomic", -"sodomy", -"sodwork", -"sody", -"soe", -"soekoe", -"soever", -"sofa", -"sofane", -"sofar", -"soffit", -"soft", -"softa", -"soften", -"softish", -"softly", -"softner", -"softy", -"sog", -"soger", -"soget", -"soggily", -"sogging", -"soggy", -"soh", -"soho", -"soil", -"soilage", -"soiled", -"soiling", -"soilure", -"soily", -"soiree", -"soja", -"sojourn", -"sok", -"soka", -"soke", -"sokeman", -"soken", -"sol", -"sola", -"solace", -"solacer", -"solan", -"solanal", -"solanum", -"solar", -"solate", -"solatia", -"solay", -"sold", -"soldado", -"soldan", -"solder", -"soldi", -"soldier", -"soldo", -"sole", -"solea", -"soleas", -"soleil", -"solely", -"solemn", -"solen", -"solent", -"soler", -"soles", -"soleus", -"soleyn", -"soli", -"solicit", -"solid", -"solidi", -"solidly", -"solidum", -"solidus", -"solio", -"soliped", -"solist", -"sollar", -"solo", -"solod", -"solodi", -"soloist", -"solon", -"soloth", -"soluble", -"solubly", -"solum", -"solute", -"solvate", -"solve", -"solvend", -"solvent", -"solver", -"soma", -"somal", -"somata", -"somatic", -"somber", -"sombre", -"some", -"someday", -"somehow", -"someone", -"somers", -"someway", -"somewhy", -"somital", -"somite", -"somitic", -"somma", -"somnial", -"somnify", -"somnus", -"sompay", -"sompne", -"sompner", -"son", -"sonable", -"sonance", -"sonancy", -"sonant", -"sonar", -"sonata", -"sond", -"sondeli", -"soneri", -"song", -"songful", -"songish", -"songle", -"songlet", -"songman", -"songy", -"sonhood", -"sonic", -"soniou", -"sonk", -"sonless", -"sonlike", -"sonly", -"sonnet", -"sonny", -"sonoric", -"sons", -"sonship", -"sonsy", -"sontag", -"soodle", -"soodly", -"sook", -"sooky", -"sool", -"sooloos", -"soon", -"sooner", -"soonish", -"soonly", -"soorawn", -"soord", -"soorkee", -"soot", -"sooter", -"sooth", -"soothe", -"soother", -"sootily", -"sooty", -"sop", -"sope", -"soph", -"sophia", -"sophic", -"sophism", -"sophy", -"sopite", -"sopor", -"sopper", -"sopping", -"soppy", -"soprani", -"soprano", -"sora", -"sorage", -"soral", -"sorb", -"sorbate", -"sorbent", -"sorbic", -"sorbile", -"sorbin", -"sorbite", -"sorbose", -"sorbus", -"sorcer", -"sorcery", -"sorchin", -"sorda", -"sordes", -"sordid", -"sordine", -"sordino", -"sordor", -"sore", -"soredia", -"soree", -"sorehon", -"sorely", -"sorema", -"sorgho", -"sorghum", -"sorgo", -"sori", -"soricid", -"sorite", -"sorites", -"sorn", -"sornare", -"sornari", -"sorner", -"sorning", -"soroban", -"sororal", -"sorose", -"sorosis", -"sorra", -"sorrel", -"sorrily", -"sorroa", -"sorrow", -"sorrowy", -"sorry", -"sort", -"sortal", -"sorted", -"sorter", -"sortie", -"sortly", -"sorty", -"sorus", -"sorva", -"sory", -"sosh", -"soshed", -"soso", -"sosoish", -"soss", -"sossle", -"sot", -"sotie", -"sotnia", -"sotnik", -"sotol", -"sots", -"sottage", -"sotted", -"sotter", -"sottish", -"sou", -"souari", -"soubise", -"soucar", -"souchet", -"souchy", -"soud", -"souffle", -"sough", -"sougher", -"sought", -"soul", -"soulack", -"souled", -"soulful", -"soulish", -"souly", -"soum", -"sound", -"sounder", -"soundly", -"soup", -"soupcon", -"souper", -"souple", -"soupy", -"sour", -"source", -"soured", -"souren", -"sourer", -"souring", -"sourish", -"sourly", -"sourock", -"soursop", -"sourtop", -"soury", -"souse", -"souser", -"souslik", -"soutane", -"souter", -"south", -"souther", -"sov", -"soviet", -"sovite", -"sovkhoz", -"sovran", -"sow", -"sowable", -"sowan", -"sowans", -"sowar", -"sowarry", -"sowback", -"sowbane", -"sowel", -"sowens", -"sower", -"sowfoot", -"sowing", -"sowins", -"sowl", -"sowle", -"sowlike", -"sowlth", -"sown", -"sowse", -"sowt", -"sowte", -"soy", -"soya", -"soybean", -"sozin", -"sozolic", -"sozzle", -"sozzly", -"spa", -"space", -"spaced", -"spacer", -"spacing", -"spack", -"spacy", -"spad", -"spade", -"spaded", -"spader", -"spadger", -"spading", -"spadix", -"spadone", -"spae", -"spaedom", -"spaeman", -"spaer", -"spahi", -"spaid", -"spaik", -"spairge", -"spak", -"spald", -"spalder", -"spale", -"spall", -"spaller", -"spalt", -"span", -"spancel", -"spandle", -"spandy", -"spane", -"spanemy", -"spang", -"spangle", -"spangly", -"spaniel", -"spaning", -"spank", -"spanker", -"spanky", -"spann", -"spannel", -"spanner", -"spanule", -"spar", -"sparada", -"sparch", -"spare", -"sparely", -"sparer", -"sparge", -"sparger", -"sparid", -"sparing", -"spark", -"sparked", -"sparker", -"sparkle", -"sparkly", -"sparks", -"sparky", -"sparm", -"sparoid", -"sparred", -"sparrer", -"sparrow", -"sparry", -"sparse", -"spart", -"sparth", -"spartle", -"sparver", -"spary", -"spasm", -"spasmed", -"spasmic", -"spastic", -"spat", -"spate", -"spatha", -"spathal", -"spathe", -"spathed", -"spathic", -"spatial", -"spatted", -"spatter", -"spattle", -"spatula", -"spatule", -"spave", -"spaver", -"spavie", -"spavied", -"spaviet", -"spavin", -"spawn", -"spawner", -"spawny", -"spay", -"spayad", -"spayard", -"spaying", -"speak", -"speaker", -"speal", -"spean", -"spear", -"spearer", -"speary", -"spec", -"spece", -"special", -"specie", -"species", -"specify", -"speck", -"specked", -"speckle", -"speckly", -"specks", -"specky", -"specs", -"specter", -"spectra", -"spectry", -"specula", -"specus", -"sped", -"speech", -"speed", -"speeder", -"speedy", -"speel", -"speen", -"speer", -"speiss", -"spelder", -"spelk", -"spell", -"speller", -"spelt", -"spelter", -"speltz", -"spelunk", -"spence", -"spencer", -"spend", -"spender", -"spense", -"spent", -"speos", -"sperate", -"sperity", -"sperket", -"sperm", -"sperma", -"spermic", -"spermy", -"sperone", -"spet", -"spetch", -"spew", -"spewer", -"spewing", -"spewy", -"spex", -"sphacel", -"sphecid", -"spheges", -"sphegid", -"sphene", -"sphenic", -"spheral", -"sphere", -"spheric", -"sphery", -"sphinx", -"spica", -"spical", -"spicant", -"spicate", -"spice", -"spiced", -"spicer", -"spicery", -"spicily", -"spicing", -"spick", -"spicket", -"spickle", -"spicose", -"spicous", -"spicula", -"spicule", -"spicy", -"spider", -"spidery", -"spidger", -"spied", -"spiegel", -"spiel", -"spieler", -"spier", -"spiff", -"spiffed", -"spiffy", -"spig", -"spignet", -"spigot", -"spike", -"spiked", -"spiker", -"spikily", -"spiking", -"spiky", -"spile", -"spiler", -"spiling", -"spilite", -"spill", -"spiller", -"spillet", -"spilly", -"spiloma", -"spilt", -"spilth", -"spilus", -"spin", -"spina", -"spinach", -"spinae", -"spinage", -"spinal", -"spinate", -"spinder", -"spindle", -"spindly", -"spine", -"spined", -"spinel", -"spinet", -"spingel", -"spink", -"spinner", -"spinney", -"spinoid", -"spinose", -"spinous", -"spinule", -"spiny", -"spionid", -"spiral", -"spirale", -"spiran", -"spirant", -"spirate", -"spire", -"spirea", -"spired", -"spireme", -"spiring", -"spirit", -"spirity", -"spirket", -"spiro", -"spiroid", -"spirous", -"spirt", -"spiry", -"spise", -"spit", -"spital", -"spitbox", -"spite", -"spitful", -"spitish", -"spitted", -"spitten", -"spitter", -"spittle", -"spitz", -"spiv", -"spivery", -"splash", -"splashy", -"splat", -"splatch", -"splay", -"splayed", -"splayer", -"spleen", -"spleeny", -"spleet", -"splenic", -"splet", -"splice", -"splicer", -"spline", -"splint", -"splinty", -"split", -"splodge", -"splodgy", -"splore", -"splosh", -"splotch", -"splunge", -"splurge", -"splurgy", -"splurt", -"spoach", -"spode", -"spodium", -"spoffle", -"spoffy", -"spogel", -"spoil", -"spoiled", -"spoiler", -"spoilt", -"spoke", -"spoken", -"spoky", -"spole", -"spolia", -"spolium", -"spondee", -"spondyl", -"spong", -"sponge", -"sponged", -"sponger", -"spongin", -"spongy", -"sponsal", -"sponson", -"sponsor", -"spoof", -"spoofer", -"spook", -"spooky", -"spool", -"spooler", -"spoom", -"spoon", -"spooner", -"spoony", -"spoor", -"spoorer", -"spoot", -"spor", -"sporal", -"spore", -"spored", -"sporid", -"sporoid", -"sporont", -"sporous", -"sporran", -"sport", -"sporter", -"sportly", -"sports", -"sporty", -"sporule", -"sposh", -"sposhy", -"spot", -"spotted", -"spotter", -"spottle", -"spotty", -"spousal", -"spouse", -"spousy", -"spout", -"spouter", -"spouty", -"sprack", -"sprad", -"sprag", -"spraich", -"sprain", -"spraint", -"sprang", -"sprank", -"sprat", -"spratty", -"sprawl", -"sprawly", -"spray", -"sprayer", -"sprayey", -"spread", -"spready", -"spreath", -"spree", -"spreeuw", -"spreng", -"sprent", -"spret", -"sprew", -"sprewl", -"spried", -"sprier", -"spriest", -"sprig", -"spriggy", -"spring", -"springe", -"springy", -"sprink", -"sprint", -"sprit", -"sprite", -"spritty", -"sproat", -"sprod", -"sprogue", -"sproil", -"sprong", -"sprose", -"sprout", -"sprowsy", -"spruce", -"sprue", -"spruer", -"sprug", -"spruit", -"sprung", -"sprunny", -"sprunt", -"spry", -"spryly", -"spud", -"spudder", -"spuddle", -"spuddy", -"spuffle", -"spug", -"spuke", -"spume", -"spumone", -"spumose", -"spumous", -"spumy", -"spun", -"spung", -"spunk", -"spunkie", -"spunky", -"spunny", -"spur", -"spurge", -"spuriae", -"spurl", -"spurlet", -"spurn", -"spurner", -"spurred", -"spurrer", -"spurry", -"spurt", -"spurter", -"spurtle", -"spurway", -"sput", -"sputa", -"sputter", -"sputum", -"spy", -"spyboat", -"spydom", -"spyer", -"spyhole", -"spyism", -"spyship", -"squab", -"squabby", -"squacco", -"squad", -"squaddy", -"squail", -"squalid", -"squall", -"squally", -"squalm", -"squalor", -"squam", -"squama", -"squamae", -"squame", -"square", -"squared", -"squarer", -"squark", -"squary", -"squash", -"squashy", -"squat", -"squatly", -"squatty", -"squaw", -"squawk", -"squawky", -"squdge", -"squdgy", -"squeak", -"squeaky", -"squeal", -"squeald", -"squeam", -"squeamy", -"squeege", -"squeeze", -"squeezy", -"squelch", -"squench", -"squib", -"squid", -"squidge", -"squidgy", -"squiffy", -"squilla", -"squin", -"squinch", -"squinny", -"squinsy", -"squint", -"squinty", -"squire", -"squiret", -"squirk", -"squirm", -"squirmy", -"squirr", -"squirt", -"squirty", -"squish", -"squishy", -"squit", -"squitch", -"squoze", -"squush", -"squushy", -"sraddha", -"sramana", -"sri", -"sruti", -"ssu", -"st", -"staab", -"stab", -"stabber", -"stabile", -"stable", -"stabler", -"stably", -"staboy", -"stacher", -"stachys", -"stack", -"stacker", -"stacte", -"stadda", -"staddle", -"stade", -"stadia", -"stadic", -"stadion", -"stadium", -"staff", -"staffed", -"staffer", -"stag", -"stage", -"staged", -"stager", -"stagery", -"stagese", -"stagger", -"staggie", -"staggy", -"stagily", -"staging", -"stagnum", -"stagy", -"staia", -"staid", -"staidly", -"stain", -"stainer", -"staio", -"stair", -"staired", -"stairy", -"staith", -"staiver", -"stake", -"staker", -"stale", -"stalely", -"staling", -"stalk", -"stalked", -"stalker", -"stalko", -"stalky", -"stall", -"stallar", -"staller", -"stam", -"stambha", -"stamen", -"stamin", -"stamina", -"stammel", -"stammer", -"stamnos", -"stamp", -"stampee", -"stamper", -"stample", -"stance", -"stanch", -"stand", -"standee", -"standel", -"stander", -"stane", -"stang", -"stanine", -"stanjen", -"stank", -"stankie", -"stannel", -"stanner", -"stannic", -"stanno", -"stannum", -"stannyl", -"stanza", -"stanze", -"stap", -"stapes", -"staple", -"stapled", -"stapler", -"star", -"starch", -"starchy", -"stardom", -"stare", -"staree", -"starer", -"starets", -"starful", -"staring", -"stark", -"starken", -"starkly", -"starky", -"starlet", -"starlit", -"starn", -"starnel", -"starnie", -"starost", -"starred", -"starry", -"start", -"starter", -"startle", -"startly", -"startor", -"starty", -"starve", -"starved", -"starver", -"starvy", -"stary", -"stases", -"stash", -"stashie", -"stasis", -"statal", -"statant", -"state", -"stated", -"stately", -"stater", -"static", -"statics", -"station", -"statism", -"statist", -"stative", -"stator", -"statue", -"statued", -"stature", -"status", -"statute", -"stauk", -"staumer", -"staun", -"staunch", -"staup", -"stauter", -"stave", -"staver", -"stavers", -"staving", -"staw", -"stawn", -"staxis", -"stay", -"stayed", -"stayer", -"staynil", -"stays", -"stchi", -"stead", -"steady", -"steak", -"steal", -"stealed", -"stealer", -"stealth", -"stealy", -"steam", -"steamer", -"steamy", -"stean", -"stearic", -"stearin", -"stearyl", -"steatin", -"stech", -"steddle", -"steed", -"steek", -"steel", -"steeler", -"steely", -"steen", -"steenth", -"steep", -"steepen", -"steeper", -"steeple", -"steeply", -"steepy", -"steer", -"steerer", -"steeve", -"steever", -"steg", -"steid", -"steigh", -"stein", -"stekan", -"stela", -"stelae", -"stelai", -"stelar", -"stele", -"stell", -"stella", -"stellar", -"stem", -"stema", -"stemlet", -"stemma", -"stemmed", -"stemmer", -"stemmy", -"stemple", -"stemson", -"sten", -"stenar", -"stench", -"stenchy", -"stencil", -"stend", -"steng", -"stengah", -"stenion", -"steno", -"stenog", -"stent", -"stenter", -"stenton", -"step", -"steppe", -"stepped", -"stepper", -"stepson", -"stept", -"stepway", -"stere", -"stereo", -"steri", -"steric", -"sterics", -"steride", -"sterile", -"sterin", -"sterk", -"sterlet", -"stern", -"sterna", -"sternad", -"sternal", -"sterned", -"sternly", -"sternum", -"stero", -"steroid", -"sterol", -"stert", -"stertor", -"sterve", -"stet", -"stetch", -"stevel", -"steven", -"stevia", -"stew", -"steward", -"stewed", -"stewpan", -"stewpot", -"stewy", -"stey", -"sthenia", -"sthenic", -"stib", -"stibial", -"stibic", -"stibine", -"stibium", -"stich", -"stichic", -"stichid", -"stick", -"sticked", -"sticker", -"stickit", -"stickle", -"stickly", -"sticks", -"stickum", -"sticky", -"stid", -"stiddy", -"stife", -"stiff", -"stiffen", -"stiffly", -"stifle", -"stifler", -"stigma", -"stigmai", -"stigmal", -"stigme", -"stile", -"stilet", -"still", -"stiller", -"stilly", -"stilt", -"stilted", -"stilter", -"stilty", -"stim", -"stime", -"stimuli", -"stimy", -"stine", -"sting", -"stinge", -"stinger", -"stingo", -"stingy", -"stink", -"stinker", -"stint", -"stinted", -"stinter", -"stinty", -"stion", -"stionic", -"stipe", -"stiped", -"stipel", -"stipend", -"stipes", -"stippen", -"stipple", -"stipply", -"stipula", -"stipule", -"stir", -"stirk", -"stirp", -"stirps", -"stirra", -"stirrer", -"stirrup", -"stitch", -"stite", -"stith", -"stithy", -"stive", -"stiver", -"stivy", -"stoa", -"stoach", -"stoat", -"stoater", -"stob", -"stocah", -"stock", -"stocker", -"stocks", -"stocky", -"stod", -"stodge", -"stodger", -"stodgy", -"stoep", -"stof", -"stoff", -"stog", -"stoga", -"stogie", -"stogy", -"stoic", -"stoical", -"stoke", -"stoker", -"stola", -"stolae", -"stole", -"stoled", -"stolen", -"stolid", -"stolist", -"stollen", -"stolon", -"stoma", -"stomach", -"stomata", -"stomate", -"stomium", -"stomp", -"stomper", -"stond", -"stone", -"stoned", -"stonen", -"stoner", -"stong", -"stonied", -"stonify", -"stonily", -"stoning", -"stonish", -"stonker", -"stony", -"stood", -"stooded", -"stooden", -"stoof", -"stooge", -"stook", -"stooker", -"stookie", -"stool", -"stoon", -"stoond", -"stoop", -"stooper", -"stoory", -"stoot", -"stop", -"stopa", -"stope", -"stoper", -"stopgap", -"stoping", -"stopped", -"stopper", -"stoppit", -"stopple", -"storage", -"storax", -"store", -"storeen", -"storer", -"storge", -"storied", -"storier", -"storify", -"stork", -"storken", -"storm", -"stormer", -"stormy", -"story", -"stosh", -"stoss", -"stot", -"stotter", -"stoun", -"stound", -"stoup", -"stour", -"stoury", -"stoush", -"stout", -"stouten", -"stouth", -"stoutly", -"stouty", -"stove", -"stoven", -"stover", -"stow", -"stowage", -"stowce", -"stower", -"stowing", -"stra", -"strack", -"stract", -"strad", -"strade", -"stradl", -"stradld", -"strae", -"strafe", -"strafer", -"strag", -"straik", -"strain", -"straint", -"strait", -"strake", -"straked", -"straky", -"stram", -"stramp", -"strand", -"strang", -"strange", -"strany", -"strap", -"strass", -"strata", -"stratal", -"strath", -"strati", -"stratic", -"stratum", -"stratus", -"strave", -"straw", -"strawen", -"strawer", -"strawy", -"stray", -"strayer", -"stre", -"streak", -"streaky", -"stream", -"streamy", -"streck", -"stree", -"streek", -"streel", -"streen", -"streep", -"street", -"streets", -"streite", -"streke", -"stremma", -"streng", -"strent", -"strenth", -"strepen", -"strepor", -"stress", -"stret", -"stretch", -"strette", -"stretti", -"stretto", -"strew", -"strewer", -"strewn", -"strey", -"streyne", -"stria", -"striae", -"strial", -"striate", -"strich", -"striche", -"strick", -"strict", -"strid", -"stride", -"strider", -"stridor", -"strife", -"strig", -"striga", -"strigae", -"strigal", -"stright", -"strigil", -"strike", -"striker", -"strind", -"string", -"stringy", -"striola", -"strip", -"stripe", -"striped", -"striper", -"stript", -"stripy", -"strit", -"strive", -"strived", -"striven", -"striver", -"strix", -"stroam", -"strobic", -"strode", -"stroil", -"stroke", -"stroker", -"stroky", -"strold", -"stroll", -"strolld", -"strom", -"stroma", -"stromal", -"stromb", -"strome", -"strone", -"strong", -"strook", -"stroot", -"strop", -"strophe", -"stroth", -"stroud", -"stroup", -"strove", -"strow", -"strowd", -"strown", -"stroy", -"stroyer", -"strub", -"struck", -"strudel", -"strue", -"strum", -"struma", -"strumae", -"strung", -"strunt", -"strut", -"struth", -"struv", -"strych", -"stub", -"stubb", -"stubbed", -"stubber", -"stubble", -"stubbly", -"stubboy", -"stubby", -"stuber", -"stuboy", -"stucco", -"stuck", -"stud", -"studder", -"studdie", -"studdle", -"stude", -"student", -"studia", -"studied", -"studier", -"studio", -"studium", -"study", -"stue", -"stuff", -"stuffed", -"stuffer", -"stuffy", -"stug", -"stuggy", -"stuiver", -"stull", -"stuller", -"stulm", -"stum", -"stumble", -"stumbly", -"stumer", -"stummer", -"stummy", -"stump", -"stumper", -"stumpy", -"stun", -"stung", -"stunk", -"stunner", -"stunsle", -"stunt", -"stunted", -"stunter", -"stunty", -"stupa", -"stupe", -"stupefy", -"stupend", -"stupent", -"stupex", -"stupid", -"stupor", -"stupose", -"stupp", -"stuprum", -"sturdy", -"sturine", -"sturk", -"sturt", -"sturtan", -"sturtin", -"stuss", -"stut", -"stutter", -"sty", -"styan", -"styca", -"styful", -"stylar", -"stylate", -"style", -"styler", -"stylet", -"styline", -"styling", -"stylish", -"stylist", -"stylite", -"stylize", -"stylo", -"styloid", -"stylops", -"stylus", -"stymie", -"stypsis", -"styptic", -"styrax", -"styrene", -"styrol", -"styrone", -"styryl", -"stythe", -"styward", -"suable", -"suably", -"suade", -"suaharo", -"suant", -"suantly", -"suasion", -"suasive", -"suasory", -"suave", -"suavely", -"suavify", -"suavity", -"sub", -"subacid", -"subact", -"subage", -"subah", -"subaid", -"subanal", -"subarch", -"subarea", -"subatom", -"subaud", -"subband", -"subbank", -"subbase", -"subbass", -"subbeau", -"subbias", -"subbing", -"subcase", -"subcash", -"subcast", -"subcell", -"subcity", -"subclan", -"subcool", -"subdate", -"subdean", -"subdeb", -"subdial", -"subdie", -"subdual", -"subduce", -"subduct", -"subdue", -"subdued", -"subduer", -"subecho", -"subedit", -"suber", -"suberic", -"suberin", -"subface", -"subfeu", -"subfief", -"subfix", -"subform", -"subfusc", -"subfusk", -"subgape", -"subgens", -"subget", -"subgit", -"subgod", -"subgrin", -"subgyre", -"subhall", -"subhead", -"subherd", -"subhero", -"subicle", -"subidar", -"subidea", -"subitem", -"subjack", -"subject", -"subjee", -"subjoin", -"subking", -"sublate", -"sublet", -"sublid", -"sublime", -"sublong", -"sublot", -"submaid", -"submain", -"subman", -"submind", -"submiss", -"submit", -"subnect", -"subness", -"subnex", -"subnote", -"subnude", -"suboral", -"suborn", -"suboval", -"subpart", -"subpass", -"subpial", -"subpimp", -"subplat", -"subplot", -"subplow", -"subpool", -"subport", -"subrace", -"subrent", -"subroot", -"subrule", -"subsale", -"subsalt", -"subsea", -"subsect", -"subsept", -"subset", -"subside", -"subsidy", -"subsill", -"subsist", -"subsoil", -"subsult", -"subsume", -"subtack", -"subtend", -"subtext", -"subtile", -"subtill", -"subtle", -"subtly", -"subtone", -"subtype", -"subunit", -"suburb", -"subvein", -"subvene", -"subvert", -"subvola", -"subway", -"subwink", -"subzone", -"succade", -"succeed", -"succent", -"success", -"succi", -"succin", -"succise", -"succor", -"succory", -"succous", -"succub", -"succuba", -"succube", -"succula", -"succumb", -"succuss", -"such", -"suck", -"suckage", -"sucken", -"sucker", -"sucking", -"suckle", -"suckler", -"suclat", -"sucrate", -"sucre", -"sucrose", -"suction", -"sucuri", -"sucuriu", -"sud", -"sudamen", -"sudary", -"sudate", -"sudd", -"sudden", -"sudder", -"suddle", -"suddy", -"sudoral", -"sudoric", -"suds", -"sudsman", -"sudsy", -"sue", -"suede", -"suer", -"suet", -"suety", -"suff", -"suffect", -"suffer", -"suffete", -"suffice", -"suffix", -"sufflue", -"suffuse", -"sugamo", -"sugan", -"sugar", -"sugared", -"sugarer", -"sugary", -"sugent", -"suggest", -"sugh", -"sugi", -"suguaro", -"suhuaro", -"suicide", -"suid", -"suidian", -"suiform", -"suimate", -"suine", -"suing", -"suingly", -"suint", -"suist", -"suit", -"suite", -"suiting", -"suitor", -"suity", -"suji", -"sulcal", -"sulcar", -"sulcate", -"sulcus", -"suld", -"sulea", -"sulfa", -"sulfato", -"sulfion", -"sulfury", -"sulk", -"sulka", -"sulker", -"sulkily", -"sulky", -"sull", -"sulla", -"sullage", -"sullen", -"sullow", -"sully", -"sulpha", -"sulpho", -"sulphur", -"sultam", -"sultan", -"sultana", -"sultane", -"sultone", -"sultry", -"sulung", -"sum", -"sumac", -"sumatra", -"sumbul", -"sumless", -"summage", -"summand", -"summar", -"summary", -"summate", -"summed", -"summer", -"summery", -"summist", -"summit", -"summity", -"summon", -"summons", -"summula", -"summut", -"sumner", -"sump", -"sumpage", -"sumper", -"sumph", -"sumphy", -"sumpit", -"sumple", -"sumpman", -"sumpter", -"sun", -"sunbeam", -"sunbird", -"sunbow", -"sunburn", -"suncup", -"sundae", -"sundang", -"sundari", -"sundek", -"sunder", -"sundew", -"sundial", -"sundik", -"sundog", -"sundown", -"sundra", -"sundri", -"sundry", -"sune", -"sunfall", -"sunfast", -"sunfish", -"sung", -"sungha", -"sunglo", -"sunglow", -"sunk", -"sunken", -"sunket", -"sunlamp", -"sunland", -"sunless", -"sunlet", -"sunlike", -"sunlit", -"sunn", -"sunnily", -"sunnud", -"sunny", -"sunray", -"sunrise", -"sunroom", -"sunset", -"sunsmit", -"sunspot", -"sunt", -"sunup", -"sunward", -"sunway", -"sunways", -"sunweed", -"sunwise", -"sunyie", -"sup", -"supa", -"supari", -"supawn", -"supe", -"super", -"superb", -"supine", -"supper", -"supping", -"supple", -"supply", -"support", -"suppose", -"suppost", -"supreme", -"sur", -"sura", -"surah", -"surahi", -"sural", -"suranal", -"surat", -"surbase", -"surbate", -"surbed", -"surcoat", -"surcrue", -"surculi", -"surd", -"surdent", -"surdity", -"sure", -"surely", -"sures", -"surette", -"surety", -"surf", -"surface", -"surfacy", -"surfeit", -"surfer", -"surfle", -"surfman", -"surfuse", -"surfy", -"surge", -"surgent", -"surgeon", -"surgery", -"surging", -"surgy", -"suriga", -"surlily", -"surly", -"surma", -"surmark", -"surmise", -"surname", -"surnap", -"surnay", -"surpass", -"surplus", -"surra", -"surrey", -"surtax", -"surtout", -"survey", -"survive", -"suscept", -"susi", -"suslik", -"suspect", -"suspend", -"suspire", -"sustain", -"susu", -"susurr", -"suther", -"sutile", -"sutler", -"sutlery", -"sutor", -"sutra", -"suttee", -"sutten", -"suttin", -"suttle", -"sutural", -"suture", -"suum", -"suwarro", -"suwe", -"suz", -"svelte", -"swa", -"swab", -"swabber", -"swabble", -"swack", -"swacken", -"swad", -"swaddle", -"swaddy", -"swag", -"swage", -"swager", -"swagger", -"swaggie", -"swaggy", -"swagman", -"swain", -"swaird", -"swale", -"swaler", -"swaling", -"swallet", -"swallo", -"swallow", -"swam", -"swami", -"swamp", -"swamper", -"swampy", -"swan", -"swang", -"swangy", -"swank", -"swanker", -"swanky", -"swanner", -"swanny", -"swap", -"swape", -"swapper", -"swaraj", -"swarbie", -"sward", -"swardy", -"sware", -"swarf", -"swarfer", -"swarm", -"swarmer", -"swarmy", -"swarry", -"swart", -"swarth", -"swarthy", -"swartly", -"swarty", -"swarve", -"swash", -"swasher", -"swashy", -"swat", -"swatch", -"swath", -"swathe", -"swather", -"swathy", -"swatter", -"swattle", -"swaver", -"sway", -"swayed", -"swayer", -"swayful", -"swaying", -"sweal", -"swear", -"swearer", -"sweat", -"sweated", -"sweater", -"sweath", -"sweaty", -"swedge", -"sweeny", -"sweep", -"sweeper", -"sweepy", -"sweer", -"sweered", -"sweet", -"sweeten", -"sweetie", -"sweetly", -"sweety", -"swego", -"swell", -"swelled", -"sweller", -"swelly", -"swelp", -"swelt", -"swelter", -"swelth", -"sweltry", -"swelty", -"swep", -"swept", -"swerd", -"swerve", -"swerver", -"swick", -"swidge", -"swift", -"swiften", -"swifter", -"swifty", -"swig", -"swigger", -"swiggle", -"swile", -"swill", -"swiller", -"swim", -"swimmer", -"swimmy", -"swimy", -"swindle", -"swine", -"swinely", -"swinery", -"swiney", -"swing", -"swinge", -"swinger", -"swingle", -"swingy", -"swinish", -"swink", -"swinney", -"swipe", -"swiper", -"swipes", -"swiple", -"swipper", -"swipy", -"swird", -"swire", -"swirl", -"swirly", -"swish", -"swisher", -"swishy", -"swiss", -"switch", -"switchy", -"swith", -"swithe", -"swithen", -"swither", -"swivel", -"swivet", -"swiz", -"swizzle", -"swob", -"swollen", -"swom", -"swonken", -"swoon", -"swooned", -"swoony", -"swoop", -"swooper", -"swoosh", -"sword", -"swore", -"sworn", -"swosh", -"swot", -"swotter", -"swounds", -"swow", -"swum", -"swung", -"swungen", -"swure", -"syagush", -"sybotic", -"syce", -"sycee", -"sycock", -"sycoma", -"syconid", -"syconus", -"sycosis", -"sye", -"syenite", -"sylid", -"syllab", -"syllabe", -"syllabi", -"sylloge", -"sylph", -"sylphic", -"sylphid", -"sylphy", -"sylva", -"sylvae", -"sylvage", -"sylvan", -"sylvate", -"sylvic", -"sylvine", -"sylvite", -"symbion", -"symbiot", -"symbol", -"sympode", -"symptom", -"synacme", -"synacmy", -"synange", -"synapse", -"synapte", -"synaxar", -"synaxis", -"sync", -"syncarp", -"synch", -"synchro", -"syncope", -"syndic", -"syndoc", -"syne", -"synema", -"synergy", -"synesis", -"syngamy", -"synod", -"synodal", -"synoecy", -"synonym", -"synopsy", -"synovia", -"syntan", -"syntax", -"synthol", -"syntomy", -"syntone", -"syntony", -"syntype", -"synusia", -"sypher", -"syre", -"syringa", -"syringe", -"syrinx", -"syrma", -"syrphid", -"syrt", -"syrtic", -"syrup", -"syruped", -"syruper", -"syrupy", -"syssel", -"system", -"systole", -"systyle", -"syzygy", -"t", -"ta", -"taa", -"taar", -"tab", -"tabacin", -"tabacum", -"tabanid", -"tabard", -"tabaret", -"tabaxir", -"tabber", -"tabby", -"tabefy", -"tabella", -"taberna", -"tabes", -"tabet", -"tabetic", -"tabic", -"tabid", -"tabidly", -"tabific", -"tabinet", -"tabla", -"table", -"tableau", -"tabled", -"tabler", -"tables", -"tablet", -"tabling", -"tabloid", -"tabog", -"taboo", -"taboot", -"tabor", -"taborer", -"taboret", -"taborin", -"tabour", -"tabret", -"tabu", -"tabula", -"tabular", -"tabule", -"tabut", -"taccada", -"tach", -"tache", -"tachiol", -"tacit", -"tacitly", -"tack", -"tacker", -"tacket", -"tackety", -"tackey", -"tacking", -"tackle", -"tackled", -"tackler", -"tacky", -"tacnode", -"tacso", -"tact", -"tactful", -"tactic", -"tactics", -"tactile", -"taction", -"tactite", -"tactive", -"tactor", -"tactual", -"tactus", -"tad", -"tade", -"tadpole", -"tae", -"tael", -"taen", -"taenia", -"taenial", -"taenian", -"taenite", -"taennin", -"taffeta", -"taffety", -"taffle", -"taffy", -"tafia", -"taft", -"tafwiz", -"tag", -"tagetol", -"tagged", -"tagger", -"taggle", -"taggy", -"taglet", -"taglike", -"taglock", -"tagrag", -"tagsore", -"tagtail", -"tagua", -"taguan", -"tagwerk", -"taha", -"taheen", -"tahil", -"tahin", -"tahr", -"tahsil", -"tahua", -"tai", -"taiaha", -"taich", -"taiga", -"taigle", -"taihoa", -"tail", -"tailage", -"tailed", -"tailer", -"tailet", -"tailge", -"tailing", -"taille", -"taillie", -"tailor", -"tailory", -"tailpin", -"taily", -"tailzee", -"tailzie", -"taimen", -"tain", -"taint", -"taintor", -"taipan", -"taipo", -"tairge", -"tairger", -"tairn", -"taisch", -"taise", -"taissle", -"tait", -"taiver", -"taivers", -"taivert", -"taj", -"takable", -"takar", -"take", -"takeful", -"taken", -"taker", -"takin", -"taking", -"takings", -"takosis", -"takt", -"taky", -"takyr", -"tal", -"tala", -"talabon", -"talahib", -"talaje", -"talak", -"talao", -"talar", -"talari", -"talaria", -"talaric", -"talayot", -"talbot", -"talc", -"talcer", -"talcky", -"talcoid", -"talcose", -"talcous", -"talcum", -"tald", -"tale", -"taled", -"taleful", -"talent", -"taler", -"tales", -"tali", -"taliage", -"taliera", -"talion", -"talipat", -"taliped", -"talipes", -"talipot", -"talis", -"talisay", -"talite", -"talitol", -"talk", -"talker", -"talkful", -"talkie", -"talking", -"talky", -"tall", -"tallage", -"tallboy", -"taller", -"tallero", -"talles", -"tallet", -"talliar", -"tallier", -"tallis", -"tallish", -"tallit", -"tallith", -"talloel", -"tallote", -"tallow", -"tallowy", -"tally", -"tallyho", -"talma", -"talon", -"taloned", -"talonic", -"talonid", -"talose", -"talpid", -"talpify", -"talpine", -"talpoid", -"talthib", -"taluk", -"taluka", -"talus", -"taluto", -"talwar", -"talwood", -"tam", -"tamable", -"tamably", -"tamale", -"tamandu", -"tamanu", -"tamara", -"tamarao", -"tamarin", -"tamas", -"tamasha", -"tambac", -"tamber", -"tambo", -"tamboo", -"tambor", -"tambour", -"tame", -"tamein", -"tamely", -"tamer", -"tamis", -"tamise", -"tamlung", -"tammie", -"tammock", -"tammy", -"tamp", -"tampala", -"tampan", -"tampang", -"tamper", -"tampin", -"tamping", -"tampion", -"tampon", -"tampoon", -"tan", -"tana", -"tanach", -"tanager", -"tanaist", -"tanak", -"tanan", -"tanbark", -"tanbur", -"tancel", -"tandan", -"tandem", -"tandle", -"tandour", -"tane", -"tang", -"tanga", -"tanged", -"tangelo", -"tangent", -"tanger", -"tangham", -"tanghan", -"tanghin", -"tangi", -"tangie", -"tangka", -"tanglad", -"tangle", -"tangler", -"tangly", -"tango", -"tangram", -"tangs", -"tangue", -"tangum", -"tangun", -"tangy", -"tanh", -"tanha", -"tania", -"tanica", -"tanier", -"tanist", -"tanjib", -"tanjong", -"tank", -"tanka", -"tankage", -"tankah", -"tankard", -"tanked", -"tanker", -"tankert", -"tankful", -"tankle", -"tankman", -"tanling", -"tannage", -"tannaic", -"tannaim", -"tannase", -"tannate", -"tanned", -"tanner", -"tannery", -"tannic", -"tannide", -"tannin", -"tanning", -"tannoid", -"tannyl", -"tanoa", -"tanquam", -"tanquen", -"tanrec", -"tansy", -"tantara", -"tanti", -"tantivy", -"tantle", -"tantra", -"tantric", -"tantrik", -"tantrum", -"tantum", -"tanwood", -"tanyard", -"tanzeb", -"tanzib", -"tanzy", -"tao", -"taotai", -"taoyin", -"tap", -"tapa", -"tapalo", -"tapas", -"tapasvi", -"tape", -"tapeman", -"tapen", -"taper", -"tapered", -"taperer", -"taperly", -"tapet", -"tapetal", -"tapete", -"tapeti", -"tapetum", -"taphole", -"tapia", -"tapioca", -"tapir", -"tapis", -"tapism", -"tapist", -"taplash", -"taplet", -"tapmost", -"tapnet", -"tapoa", -"tapoun", -"tappa", -"tappall", -"tappaul", -"tappen", -"tapper", -"tappet", -"tapping", -"tappoon", -"taproom", -"taproot", -"taps", -"tapster", -"tapu", -"tapul", -"taqua", -"tar", -"tara", -"taraf", -"tarage", -"tarairi", -"tarand", -"taraph", -"tarapin", -"tarata", -"taratah", -"tarau", -"tarbet", -"tarboy", -"tarbush", -"tardily", -"tardive", -"tardle", -"tardy", -"tare", -"tarea", -"tarefa", -"tarente", -"tarfa", -"targe", -"targer", -"target", -"tarhood", -"tari", -"tarie", -"tariff", -"tarin", -"tariric", -"tarish", -"tarkhan", -"tarlike", -"tarmac", -"tarman", -"tarn", -"tarnal", -"tarnish", -"taro", -"taroc", -"tarocco", -"tarok", -"tarot", -"tarp", -"tarpan", -"tarpon", -"tarpot", -"tarpum", -"tarr", -"tarrack", -"tarras", -"tarrass", -"tarred", -"tarrer", -"tarri", -"tarrie", -"tarrier", -"tarrify", -"tarrily", -"tarrish", -"tarrock", -"tarrow", -"tarry", -"tars", -"tarsal", -"tarsale", -"tarse", -"tarsi", -"tarsia", -"tarsier", -"tarsome", -"tarsus", -"tart", -"tartago", -"tartan", -"tartana", -"tartane", -"tartar", -"tarten", -"tartish", -"tartle", -"tartlet", -"tartly", -"tartro", -"tartryl", -"tarve", -"tarweed", -"tarwood", -"taryard", -"tasajo", -"tascal", -"tasco", -"tash", -"tashie", -"tashlik", -"tashrif", -"task", -"taskage", -"tasker", -"taskit", -"taslet", -"tass", -"tassago", -"tassah", -"tassal", -"tassard", -"tasse", -"tassel", -"tassely", -"tasser", -"tasset", -"tassie", -"tassoo", -"taste", -"tasted", -"tasten", -"taster", -"tastily", -"tasting", -"tasty", -"tasu", -"tat", -"tataupa", -"tatbeb", -"tatchy", -"tate", -"tater", -"tath", -"tatie", -"tatinek", -"tatler", -"tatou", -"tatouay", -"tatsman", -"tatta", -"tatter", -"tattery", -"tatther", -"tattied", -"tatting", -"tattle", -"tattler", -"tattoo", -"tattva", -"tatty", -"tatu", -"tau", -"taught", -"taula", -"taum", -"taun", -"taunt", -"taunter", -"taupe", -"taupo", -"taupou", -"taur", -"taurean", -"taurian", -"tauric", -"taurine", -"taurite", -"tauryl", -"taut", -"tautaug", -"tauted", -"tauten", -"tautit", -"tautly", -"tautog", -"tav", -"tave", -"tavell", -"taver", -"tavern", -"tavers", -"tavert", -"tavola", -"taw", -"tawa", -"tawdry", -"tawer", -"tawery", -"tawie", -"tawite", -"tawkee", -"tawkin", -"tawn", -"tawney", -"tawnily", -"tawnle", -"tawny", -"tawpi", -"tawpie", -"taws", -"tawse", -"tawtie", -"tax", -"taxable", -"taxably", -"taxator", -"taxed", -"taxeme", -"taxemic", -"taxer", -"taxi", -"taxibus", -"taxicab", -"taximan", -"taxine", -"taxing", -"taxis", -"taxite", -"taxitic", -"taxless", -"taxman", -"taxon", -"taxor", -"taxpaid", -"taxwax", -"taxy", -"tay", -"tayer", -"tayir", -"tayra", -"taysaam", -"tazia", -"tch", -"tchai", -"tcharik", -"tchast", -"tche", -"tchick", -"tchu", -"tck", -"te", -"tea", -"teabox", -"teaboy", -"teacake", -"teacart", -"teach", -"teache", -"teacher", -"teachy", -"teacup", -"tead", -"teadish", -"teaer", -"teaey", -"teagle", -"teaish", -"teaism", -"teak", -"teal", -"tealery", -"tealess", -"team", -"teaman", -"teameo", -"teamer", -"teaming", -"teamman", -"tean", -"teanal", -"teap", -"teapot", -"teapoy", -"tear", -"tearage", -"tearcat", -"tearer", -"tearful", -"tearing", -"tearlet", -"tearoom", -"tearpit", -"teart", -"teary", -"tease", -"teasel", -"teaser", -"teashop", -"teasing", -"teasler", -"teasy", -"teat", -"teated", -"teathe", -"teather", -"teatime", -"teatman", -"teaty", -"teave", -"teaware", -"teaze", -"teazer", -"tebbet", -"tec", -"teca", -"tecali", -"tech", -"techily", -"technic", -"techous", -"techy", -"teck", -"tecomin", -"tecon", -"tectal", -"tectum", -"tecum", -"tecuma", -"ted", -"tedder", -"tedge", -"tedious", -"tedium", -"tee", -"teedle", -"teel", -"teem", -"teemer", -"teemful", -"teeming", -"teems", -"teen", -"teenage", -"teenet", -"teens", -"teensy", -"teenty", -"teeny", -"teer", -"teerer", -"teest", -"teet", -"teetan", -"teeter", -"teeth", -"teethe", -"teethy", -"teeting", -"teety", -"teevee", -"teff", -"teg", -"tegmen", -"tegmina", -"tegua", -"tegula", -"tegular", -"tegumen", -"tehseel", -"tehsil", -"teicher", -"teil", -"teind", -"teinder", -"teioid", -"tejon", -"teju", -"tekiah", -"tekke", -"tekken", -"tektite", -"tekya", -"telamon", -"telang", -"telar", -"telary", -"tele", -"teledu", -"telega", -"teleost", -"teleran", -"telergy", -"telesia", -"telesis", -"teleuto", -"televox", -"telfer", -"telford", -"teli", -"telial", -"telic", -"telical", -"telium", -"tell", -"tellach", -"tellee", -"teller", -"telling", -"tellt", -"telome", -"telomic", -"telpath", -"telpher", -"telson", -"telt", -"telurgy", -"telyn", -"temacha", -"teman", -"tembe", -"temblor", -"temenos", -"temiak", -"temin", -"temp", -"temper", -"tempera", -"tempery", -"tempest", -"tempi", -"templar", -"temple", -"templed", -"templet", -"tempo", -"tempora", -"tempre", -"tempt", -"tempter", -"temse", -"temser", -"ten", -"tenable", -"tenably", -"tenace", -"tenai", -"tenancy", -"tenant", -"tench", -"tend", -"tendant", -"tendent", -"tender", -"tending", -"tendon", -"tendour", -"tendril", -"tendron", -"tenebra", -"tenent", -"teneral", -"tenet", -"tenfold", -"teng", -"tengere", -"tengu", -"tenible", -"tenio", -"tenline", -"tenne", -"tenner", -"tennis", -"tennisy", -"tenon", -"tenoner", -"tenor", -"tenpin", -"tenrec", -"tense", -"tensely", -"tensify", -"tensile", -"tension", -"tensity", -"tensive", -"tenson", -"tensor", -"tent", -"tentage", -"tented", -"tenter", -"tentful", -"tenth", -"tenthly", -"tentigo", -"tention", -"tentlet", -"tenture", -"tenty", -"tenuate", -"tenues", -"tenuis", -"tenuity", -"tenuous", -"tenure", -"teopan", -"tepache", -"tepal", -"tepee", -"tepefy", -"tepid", -"tepidly", -"tepor", -"tequila", -"tera", -"terap", -"teras", -"terbia", -"terbic", -"terbium", -"tercel", -"tercer", -"tercet", -"tercia", -"tercine", -"tercio", -"terebic", -"terebra", -"teredo", -"terek", -"terete", -"tereu", -"terfez", -"tergal", -"tergant", -"tergite", -"tergum", -"term", -"terma", -"termage", -"termen", -"termer", -"termin", -"termine", -"termini", -"termino", -"termite", -"termly", -"termon", -"termor", -"tern", -"terna", -"ternal", -"ternar", -"ternary", -"ternate", -"terne", -"ternery", -"ternion", -"ternize", -"ternlet", -"terp", -"terpane", -"terpene", -"terpin", -"terpine", -"terrace", -"terrage", -"terrain", -"terral", -"terrane", -"terrar", -"terrene", -"terret", -"terrier", -"terrify", -"terrine", -"terron", -"terror", -"terry", -"terse", -"tersely", -"tersion", -"tertia", -"tertial", -"tertian", -"tertius", -"terton", -"tervee", -"terzina", -"terzo", -"tesack", -"teskere", -"tessara", -"tessel", -"tessera", -"test", -"testa", -"testacy", -"testar", -"testata", -"testate", -"teste", -"tested", -"testee", -"tester", -"testes", -"testify", -"testily", -"testing", -"testis", -"teston", -"testone", -"testoon", -"testor", -"testril", -"testudo", -"testy", -"tetanic", -"tetanus", -"tetany", -"tetard", -"tetch", -"tetchy", -"tete", -"tetel", -"teth", -"tether", -"tethery", -"tetra", -"tetract", -"tetrad", -"tetrane", -"tetrazo", -"tetric", -"tetrode", -"tetrole", -"tetrose", -"tetryl", -"tetter", -"tettery", -"tettix", -"teucrin", -"teufit", -"teuk", -"teviss", -"tew", -"tewel", -"tewer", -"tewit", -"tewly", -"tewsome", -"text", -"textile", -"textlet", -"textman", -"textual", -"texture", -"tez", -"tezkere", -"th", -"tha", -"thack", -"thacker", -"thakur", -"thalami", -"thaler", -"thalli", -"thallic", -"thallus", -"thameng", -"than", -"thana", -"thanage", -"thanan", -"thane", -"thank", -"thankee", -"thanker", -"thanks", -"thapes", -"thapsia", -"thar", -"tharf", -"tharm", -"that", -"thatch", -"thatchy", -"thatn", -"thats", -"thaught", -"thave", -"thaw", -"thawer", -"thawn", -"thawy", -"the", -"theah", -"theasum", -"theat", -"theater", -"theatry", -"theave", -"theb", -"theca", -"thecae", -"thecal", -"thecate", -"thecia", -"thecium", -"thecla", -"theclan", -"thecoid", -"thee", -"theek", -"theeker", -"theelin", -"theelol", -"theer", -"theet", -"theezan", -"theft", -"thegn", -"thegnly", -"theine", -"their", -"theirn", -"theirs", -"theism", -"theist", -"thelium", -"them", -"thema", -"themata", -"theme", -"themer", -"themis", -"themsel", -"then", -"thenal", -"thenar", -"thence", -"theody", -"theorbo", -"theorem", -"theoria", -"theoric", -"theorum", -"theory", -"theow", -"therapy", -"there", -"thereas", -"thereat", -"thereby", -"therein", -"thereof", -"thereon", -"theres", -"therese", -"thereto", -"thereup", -"theriac", -"therial", -"therm", -"thermae", -"thermal", -"thermic", -"thermit", -"thermo", -"thermos", -"theroid", -"these", -"theses", -"thesial", -"thesis", -"theta", -"thetch", -"thetic", -"thetics", -"thetin", -"thetine", -"theurgy", -"thew", -"thewed", -"thewy", -"they", -"theyll", -"theyre", -"thiamin", -"thiasi", -"thiasoi", -"thiasos", -"thiasus", -"thick", -"thicken", -"thicket", -"thickly", -"thief", -"thienyl", -"thieve", -"thiever", -"thig", -"thigger", -"thigh", -"thighed", -"thight", -"thilk", -"thill", -"thiller", -"thilly", -"thimber", -"thimble", -"thin", -"thine", -"thing", -"thingal", -"thingly", -"thingum", -"thingy", -"think", -"thinker", -"thinly", -"thinner", -"thio", -"thiol", -"thiolic", -"thionic", -"thionyl", -"thir", -"third", -"thirdly", -"thirl", -"thirst", -"thirsty", -"thirt", -"thirty", -"this", -"thishow", -"thisn", -"thissen", -"thistle", -"thistly", -"thither", -"thiuram", -"thivel", -"thixle", -"tho", -"thob", -"thocht", -"thof", -"thoft", -"thoke", -"thokish", -"thole", -"tholi", -"tholoi", -"tholos", -"tholus", -"thon", -"thonder", -"thone", -"thong", -"thonged", -"thongy", -"thoo", -"thooid", -"thoom", -"thoral", -"thorax", -"thore", -"thoria", -"thoric", -"thorina", -"thorite", -"thorium", -"thorn", -"thorned", -"thornen", -"thorny", -"thoro", -"thoron", -"thorp", -"thort", -"thorter", -"those", -"thou", -"though", -"thought", -"thouse", -"thow", -"thowel", -"thowt", -"thrack", -"thraep", -"thrail", -"thrain", -"thrall", -"thram", -"thrang", -"thrap", -"thrash", -"thrast", -"thrave", -"thraver", -"thraw", -"thrawn", -"thread", -"thready", -"threap", -"threat", -"three", -"threne", -"threnos", -"threose", -"thresh", -"threw", -"thrice", -"thrift", -"thrifty", -"thrill", -"thrilly", -"thrimp", -"thring", -"thrip", -"thripel", -"thrips", -"thrive", -"thriven", -"thriver", -"thro", -"throat", -"throaty", -"throb", -"throck", -"throddy", -"throe", -"thronal", -"throne", -"throng", -"throu", -"throuch", -"through", -"throve", -"throw", -"thrower", -"thrown", -"thrum", -"thrummy", -"thrush", -"thrushy", -"thrust", -"thrutch", -"thruv", -"thrymsa", -"thud", -"thug", -"thugdom", -"thuggee", -"thujene", -"thujin", -"thujone", -"thujyl", -"thulia", -"thulir", -"thulite", -"thulium", -"thulr", -"thuluth", -"thumb", -"thumbed", -"thumber", -"thumble", -"thumby", -"thump", -"thumper", -"thunder", -"thung", -"thunge", -"thuoc", -"thurify", -"thurl", -"thurm", -"thurmus", -"thurse", -"thurt", -"thus", -"thusly", -"thutter", -"thwack", -"thwaite", -"thwart", -"thwite", -"thy", -"thyine", -"thymate", -"thyme", -"thymele", -"thymene", -"thymic", -"thymine", -"thymol", -"thymoma", -"thymus", -"thymy", -"thymyl", -"thynnid", -"thyroid", -"thyrse", -"thyrsus", -"thysel", -"thyself", -"thysen", -"ti", -"tiang", -"tiao", -"tiar", -"tiara", -"tib", -"tibby", -"tibet", -"tibey", -"tibia", -"tibiad", -"tibiae", -"tibial", -"tibiale", -"tiburon", -"tic", -"tical", -"ticca", -"tice", -"ticer", -"tick", -"ticked", -"ticken", -"ticker", -"ticket", -"tickey", -"tickie", -"ticking", -"tickle", -"tickled", -"tickler", -"tickly", -"tickney", -"ticky", -"ticul", -"tid", -"tidal", -"tidally", -"tidbit", -"tiddle", -"tiddler", -"tiddley", -"tiddy", -"tide", -"tided", -"tideful", -"tidely", -"tideway", -"tidily", -"tiding", -"tidings", -"tidley", -"tidy", -"tidyism", -"tie", -"tieback", -"tied", -"tien", -"tiepin", -"tier", -"tierce", -"tierced", -"tiered", -"tierer", -"tietick", -"tiewig", -"tiff", -"tiffany", -"tiffie", -"tiffin", -"tiffish", -"tiffle", -"tiffy", -"tift", -"tifter", -"tig", -"tige", -"tigella", -"tigelle", -"tiger", -"tigerly", -"tigery", -"tigger", -"tight", -"tighten", -"tightly", -"tights", -"tiglic", -"tignum", -"tigress", -"tigrine", -"tigroid", -"tigtag", -"tikka", -"tikker", -"tiklin", -"tikor", -"tikur", -"til", -"tilaite", -"tilaka", -"tilbury", -"tilde", -"tile", -"tiled", -"tiler", -"tilery", -"tilikum", -"tiling", -"till", -"tillage", -"tiller", -"tilley", -"tillite", -"tillot", -"tilly", -"tilmus", -"tilpah", -"tilt", -"tilter", -"tilth", -"tilting", -"tiltup", -"tilty", -"tilyer", -"timable", -"timar", -"timarau", -"timawa", -"timbal", -"timbale", -"timbang", -"timbe", -"timber", -"timbern", -"timbery", -"timbo", -"timbre", -"timbrel", -"time", -"timed", -"timeful", -"timely", -"timeous", -"timer", -"times", -"timid", -"timidly", -"timing", -"timish", -"timist", -"timon", -"timor", -"timothy", -"timpani", -"timpano", -"tin", -"tinamou", -"tincal", -"tinchel", -"tinclad", -"tinct", -"tind", -"tindal", -"tindalo", -"tinder", -"tindery", -"tine", -"tinea", -"tineal", -"tinean", -"tined", -"tineid", -"tineine", -"tineman", -"tineoid", -"tinety", -"tinful", -"ting", -"tinge", -"tinged", -"tinger", -"tingi", -"tingid", -"tingle", -"tingler", -"tingly", -"tinguy", -"tinhorn", -"tinily", -"tining", -"tink", -"tinker", -"tinkle", -"tinkler", -"tinkly", -"tinlet", -"tinlike", -"tinman", -"tinned", -"tinner", -"tinnery", -"tinnet", -"tinnily", -"tinning", -"tinnock", -"tinny", -"tinosa", -"tinsel", -"tinsman", -"tint", -"tinta", -"tintage", -"tinted", -"tinter", -"tintie", -"tinting", -"tintist", -"tinty", -"tintype", -"tinwald", -"tinware", -"tinwork", -"tiny", -"tip", -"tipburn", -"tipcart", -"tipcat", -"tipe", -"tipful", -"tiphead", -"tipiti", -"tiple", -"tipless", -"tiplet", -"tipman", -"tipmost", -"tiponi", -"tipped", -"tippee", -"tipper", -"tippet", -"tipping", -"tipple", -"tippler", -"tipply", -"tippy", -"tipsify", -"tipsily", -"tipster", -"tipsy", -"tiptail", -"tiptilt", -"tiptoe", -"tiptop", -"tipulid", -"tipup", -"tirade", -"tiralee", -"tire", -"tired", -"tiredly", -"tiredom", -"tireman", -"tirer", -"tiriba", -"tiring", -"tirl", -"tirma", -"tirr", -"tirret", -"tirrlie", -"tirve", -"tirwit", -"tisane", -"tisar", -"tissual", -"tissue", -"tissued", -"tissuey", -"tiswin", -"tit", -"titania", -"titanic", -"titano", -"titanyl", -"titar", -"titbit", -"tite", -"titer", -"titfish", -"tithal", -"tithe", -"tither", -"tithing", -"titi", -"titian", -"titien", -"titlark", -"title", -"titled", -"titler", -"titlike", -"titling", -"titlist", -"titmal", -"titman", -"titoki", -"titrate", -"titre", -"titter", -"tittery", -"tittie", -"tittle", -"tittler", -"tittup", -"tittupy", -"titty", -"titular", -"titule", -"titulus", -"tiver", -"tivoli", -"tivy", -"tiza", -"tizeur", -"tizzy", -"tji", -"tjosite", -"tlaco", -"tmema", -"tmesis", -"to", -"toa", -"toad", -"toadeat", -"toader", -"toadery", -"toadess", -"toadier", -"toadish", -"toadlet", -"toady", -"toast", -"toastee", -"toaster", -"toasty", -"toat", -"toatoa", -"tobacco", -"tobe", -"tobine", -"tobira", -"toby", -"tobyman", -"toccata", -"tocher", -"tock", -"toco", -"tocome", -"tocsin", -"tocusso", -"tod", -"today", -"todder", -"toddick", -"toddite", -"toddle", -"toddler", -"toddy", -"tode", -"tody", -"toe", -"toecap", -"toed", -"toeless", -"toelike", -"toenail", -"toetoe", -"toff", -"toffee", -"toffing", -"toffish", -"toffy", -"toft", -"tofter", -"toftman", -"tofu", -"tog", -"toga", -"togaed", -"togata", -"togate", -"togated", -"toggel", -"toggery", -"toggle", -"toggler", -"togless", -"togs", -"togt", -"togue", -"toher", -"toheroa", -"toho", -"tohunga", -"toi", -"toil", -"toiled", -"toiler", -"toilet", -"toilful", -"toiling", -"toise", -"toit", -"toitish", -"toity", -"tokay", -"toke", -"token", -"tokened", -"toko", -"tokopat", -"tol", -"tolan", -"tolane", -"told", -"toldo", -"tole", -"tolite", -"toll", -"tollage", -"toller", -"tollery", -"tolling", -"tollman", -"tolly", -"tolsey", -"tolt", -"tolter", -"tolu", -"toluate", -"toluene", -"toluic", -"toluide", -"toluido", -"toluol", -"toluyl", -"tolyl", -"toman", -"tomato", -"tomb", -"tombac", -"tombal", -"tombe", -"tombic", -"tomblet", -"tombola", -"tombolo", -"tomboy", -"tomcat", -"tomcod", -"tome", -"tomeful", -"tomelet", -"toment", -"tomfool", -"tomial", -"tomin", -"tomish", -"tomium", -"tomjohn", -"tomkin", -"tommy", -"tomnoup", -"tomorn", -"tomosis", -"tompon", -"tomtate", -"tomtit", -"ton", -"tonal", -"tonally", -"tonant", -"tondino", -"tone", -"toned", -"toneme", -"toner", -"tonetic", -"tong", -"tonga", -"tonger", -"tongman", -"tongs", -"tongue", -"tongued", -"tonguer", -"tonguey", -"tonic", -"tonify", -"tonight", -"tonish", -"tonite", -"tonjon", -"tonk", -"tonkin", -"tonlet", -"tonnage", -"tonneau", -"tonner", -"tonnish", -"tonous", -"tonsil", -"tonsor", -"tonsure", -"tontine", -"tonus", -"tony", -"too", -"toodle", -"took", -"tooken", -"tool", -"toolbox", -"tooler", -"tooling", -"toolman", -"toom", -"toomly", -"toon", -"toop", -"toorie", -"toorock", -"tooroo", -"toosh", -"toot", -"tooter", -"tooth", -"toothed", -"toother", -"toothy", -"tootle", -"tootler", -"tootsy", -"toozle", -"toozoo", -"top", -"toparch", -"topass", -"topaz", -"topazy", -"topcap", -"topcast", -"topcoat", -"tope", -"topee", -"topeng", -"topepo", -"toper", -"topfull", -"toph", -"tophus", -"topi", -"topia", -"topiary", -"topic", -"topical", -"topknot", -"topless", -"toplike", -"topline", -"topman", -"topmast", -"topmost", -"topo", -"toponym", -"topped", -"topper", -"topping", -"topple", -"toppler", -"topply", -"toppy", -"toprail", -"toprope", -"tops", -"topsail", -"topside", -"topsl", -"topsman", -"topsoil", -"toptail", -"topwise", -"toque", -"tor", -"tora", -"torah", -"toral", -"toran", -"torc", -"torcel", -"torch", -"torcher", -"torchon", -"tore", -"tored", -"torero", -"torfel", -"torgoch", -"toric", -"torii", -"torma", -"tormen", -"torment", -"tormina", -"torn", -"tornade", -"tornado", -"tornal", -"tornese", -"torney", -"tornote", -"tornus", -"toro", -"toroid", -"torose", -"torous", -"torpedo", -"torpent", -"torpid", -"torpify", -"torpor", -"torque", -"torqued", -"torques", -"torrefy", -"torrent", -"torrid", -"torsade", -"torse", -"torsel", -"torsile", -"torsion", -"torsive", -"torsk", -"torso", -"tort", -"torta", -"torteau", -"tortile", -"tortive", -"tortula", -"torture", -"toru", -"torula", -"torulin", -"torulus", -"torus", -"torve", -"torvid", -"torvity", -"torvous", -"tory", -"tosh", -"tosher", -"toshery", -"toshly", -"toshy", -"tosily", -"toss", -"tosser", -"tossily", -"tossing", -"tosspot", -"tossup", -"tossy", -"tost", -"toston", -"tosy", -"tot", -"total", -"totally", -"totara", -"totchka", -"tote", -"totem", -"totemic", -"totemy", -"toter", -"tother", -"totient", -"toto", -"totora", -"totquot", -"totter", -"tottery", -"totting", -"tottle", -"totty", -"totuava", -"totum", -"toty", -"totyman", -"tou", -"toucan", -"touch", -"touched", -"toucher", -"touchy", -"toug", -"tough", -"toughen", -"toughly", -"tought", -"tould", -"toumnah", -"toup", -"toupee", -"toupeed", -"toupet", -"tour", -"touraco", -"tourer", -"touring", -"tourism", -"tourist", -"tourize", -"tourn", -"tournay", -"tournee", -"tourney", -"tourte", -"tousche", -"touse", -"touser", -"tousle", -"tously", -"tousy", -"tout", -"touter", -"tovar", -"tow", -"towable", -"towage", -"towai", -"towan", -"toward", -"towards", -"towboat", -"towcock", -"towd", -"towel", -"towelry", -"tower", -"towered", -"towery", -"towght", -"towhead", -"towhee", -"towing", -"towkay", -"towlike", -"towline", -"towmast", -"town", -"towned", -"townee", -"towner", -"townet", -"townful", -"townify", -"townish", -"townist", -"townlet", -"townly", -"townman", -"towny", -"towpath", -"towrope", -"towser", -"towy", -"tox", -"toxa", -"toxamin", -"toxcatl", -"toxemia", -"toxemic", -"toxic", -"toxical", -"toxicum", -"toxifer", -"toxin", -"toxity", -"toxoid", -"toxon", -"toxone", -"toxosis", -"toxotae", -"toy", -"toydom", -"toyer", -"toyful", -"toying", -"toyish", -"toyland", -"toyless", -"toylike", -"toyman", -"toyon", -"toyshop", -"toysome", -"toytown", -"toywort", -"toze", -"tozee", -"tozer", -"tra", -"trabal", -"trabant", -"trabea", -"trabeae", -"trabuch", -"trace", -"tracer", -"tracery", -"trachea", -"trachle", -"tracing", -"track", -"tracked", -"tracker", -"tract", -"tractor", -"tradal", -"trade", -"trader", -"trading", -"tradite", -"traduce", -"trady", -"traffic", -"trag", -"tragal", -"tragedy", -"tragi", -"tragic", -"tragus", -"trah", -"traheen", -"traik", -"trail", -"trailer", -"traily", -"train", -"trained", -"trainee", -"trainer", -"trainy", -"traipse", -"trait", -"traitor", -"traject", -"trajet", -"tralira", -"tram", -"trama", -"tramal", -"tramcar", -"trame", -"tramful", -"tramman", -"trammel", -"trammer", -"trammon", -"tramp", -"tramper", -"trample", -"trampot", -"tramway", -"trance", -"tranced", -"traneen", -"trank", -"tranka", -"tranker", -"trankum", -"tranky", -"transit", -"transom", -"trant", -"tranter", -"trap", -"trapes", -"trapeze", -"trapped", -"trapper", -"trappy", -"traps", -"trash", -"traship", -"trashy", -"trass", -"trasy", -"trauma", -"travail", -"travale", -"trave", -"travel", -"travis", -"travois", -"travoy", -"trawl", -"trawler", -"tray", -"trayful", -"treacle", -"treacly", -"tread", -"treader", -"treadle", -"treason", -"treat", -"treatee", -"treater", -"treator", -"treaty", -"treble", -"trebly", -"treddle", -"tree", -"treed", -"treeful", -"treeify", -"treelet", -"treeman", -"treen", -"treetop", -"treey", -"tref", -"trefle", -"trefoil", -"tregerg", -"tregohm", -"trehala", -"trek", -"trekker", -"trellis", -"tremble", -"trembly", -"tremie", -"tremolo", -"tremor", -"trenail", -"trench", -"trend", -"trendle", -"trental", -"trepan", -"trepang", -"trepid", -"tress", -"tressed", -"tresson", -"tressy", -"trest", -"trestle", -"tret", -"trevet", -"trews", -"trey", -"tri", -"triable", -"triace", -"triacid", -"triact", -"triad", -"triadic", -"triaene", -"triage", -"trial", -"triamid", -"triarch", -"triarii", -"triatic", -"triaxon", -"triazin", -"triazo", -"tribade", -"tribady", -"tribal", -"tribase", -"tribble", -"tribe", -"triblet", -"tribrac", -"tribual", -"tribuna", -"tribune", -"tribute", -"trica", -"tricae", -"tricar", -"trice", -"triceps", -"trichi", -"trichia", -"trichy", -"trick", -"tricker", -"trickle", -"trickly", -"tricksy", -"tricky", -"triclad", -"tricorn", -"tricot", -"trident", -"triduan", -"triduum", -"tried", -"triedly", -"triene", -"triens", -"trier", -"trifa", -"trifid", -"trifle", -"trifler", -"triflet", -"trifoil", -"trifold", -"trifoly", -"triform", -"trig", -"trigamy", -"trigger", -"triglid", -"triglot", -"trigly", -"trigon", -"trigone", -"trigram", -"trigyn", -"trikaya", -"trike", -"triker", -"triketo", -"trikir", -"trilabe", -"trilby", -"trilit", -"trilite", -"trilith", -"trill", -"trillet", -"trilli", -"trillo", -"trilobe", -"trilogy", -"trim", -"trimer", -"trimly", -"trimmer", -"trin", -"trinal", -"trinary", -"trindle", -"trine", -"trinely", -"tringle", -"trinity", -"trink", -"trinket", -"trinkle", -"trinode", -"trinol", -"trintle", -"trio", -"triobol", -"triode", -"triodia", -"triole", -"triolet", -"trionym", -"trior", -"triose", -"trip", -"tripal", -"tripara", -"tripart", -"tripe", -"tripel", -"tripery", -"triple", -"triplet", -"triplex", -"triplum", -"triply", -"tripod", -"tripody", -"tripoli", -"tripos", -"tripper", -"trippet", -"tripple", -"tripsis", -"tripy", -"trireme", -"trisalt", -"trisazo", -"trisect", -"triseme", -"trishna", -"trismic", -"trismus", -"trisome", -"trisomy", -"trist", -"trisul", -"trisula", -"tritaph", -"trite", -"tritely", -"tritish", -"tritium", -"tritolo", -"triton", -"tritone", -"tritor", -"trityl", -"triumph", -"triunal", -"triune", -"triurid", -"trivant", -"trivet", -"trivia", -"trivial", -"trivium", -"trivvet", -"trizoic", -"trizone", -"troat", -"troca", -"trocar", -"trochal", -"troche", -"trochee", -"trochi", -"trochid", -"trochus", -"trock", -"troco", -"trod", -"trodden", -"trode", -"troft", -"trog", -"trogger", -"troggin", -"trogon", -"trogs", -"trogue", -"troika", -"troke", -"troker", -"troll", -"troller", -"trolley", -"trollol", -"trollop", -"trolly", -"tromba", -"trombe", -"trommel", -"tromp", -"trompe", -"trompil", -"tromple", -"tron", -"trona", -"tronage", -"tronc", -"trone", -"troner", -"troolie", -"troop", -"trooper", -"troot", -"tropal", -"tropary", -"tropate", -"trope", -"tropeic", -"troper", -"trophal", -"trophi", -"trophic", -"trophy", -"tropic", -"tropine", -"tropism", -"tropist", -"tropoyl", -"tropyl", -"trot", -"troth", -"trotlet", -"trotol", -"trotter", -"trottie", -"trotty", -"trotyl", -"trouble", -"troubly", -"trough", -"troughy", -"trounce", -"troupe", -"trouper", -"trouse", -"trouser", -"trout", -"trouter", -"trouty", -"trove", -"trover", -"trow", -"trowel", -"trowing", -"trowman", -"trowth", -"troy", -"truancy", -"truant", -"trub", -"trubu", -"truce", -"trucial", -"truck", -"trucker", -"truckle", -"trucks", -"truddo", -"trudge", -"trudgen", -"trudger", -"true", -"truer", -"truff", -"truffle", -"trug", -"truish", -"truism", -"trull", -"truller", -"trullo", -"truly", -"trummel", -"trump", -"trumper", -"trumpet", -"trumph", -"trumpie", -"trun", -"truncal", -"trunch", -"trundle", -"trunk", -"trunked", -"trunnel", -"trush", -"trusion", -"truss", -"trussed", -"trusser", -"trust", -"trustee", -"trusten", -"truster", -"trustle", -"trusty", -"truth", -"truthy", -"truvat", -"try", -"trygon", -"trying", -"tryma", -"tryout", -"tryp", -"trypa", -"trypan", -"trypsin", -"tryptic", -"trysail", -"tryst", -"tryster", -"tryt", -"tsadik", -"tsamba", -"tsantsa", -"tsar", -"tsardom", -"tsarina", -"tsatlee", -"tsere", -"tsetse", -"tsia", -"tsine", -"tst", -"tsuba", -"tsubo", -"tsun", -"tsunami", -"tsungtu", -"tu", -"tua", -"tuan", -"tuarn", -"tuart", -"tuatara", -"tuatera", -"tuath", -"tub", -"tuba", -"tubae", -"tubage", -"tubal", -"tubar", -"tubate", -"tubba", -"tubbal", -"tubbeck", -"tubber", -"tubbie", -"tubbing", -"tubbish", -"tubboe", -"tubby", -"tube", -"tubeful", -"tubelet", -"tubeman", -"tuber", -"tuberin", -"tubfish", -"tubful", -"tubicen", -"tubifer", -"tubig", -"tubik", -"tubing", -"tublet", -"tublike", -"tubman", -"tubular", -"tubule", -"tubulet", -"tubuli", -"tubulus", -"tuchit", -"tuchun", -"tuck", -"tucker", -"tucket", -"tucking", -"tuckner", -"tucktoo", -"tucky", -"tucum", -"tucuma", -"tucuman", -"tudel", -"tue", -"tueiron", -"tufa", -"tufan", -"tuff", -"tuffet", -"tuffing", -"tuft", -"tufted", -"tufter", -"tuftily", -"tufting", -"tuftlet", -"tufty", -"tug", -"tugboat", -"tugger", -"tuggery", -"tugging", -"tughra", -"tugless", -"tuglike", -"tugman", -"tugrik", -"tugui", -"tui", -"tuik", -"tuille", -"tuilyie", -"tuism", -"tuition", -"tuitive", -"tuke", -"tukra", -"tula", -"tulare", -"tulasi", -"tulchan", -"tulchin", -"tule", -"tuliac", -"tulip", -"tulipy", -"tulisan", -"tulle", -"tulsi", -"tulwar", -"tum", -"tumasha", -"tumbak", -"tumble", -"tumbled", -"tumbler", -"tumbly", -"tumbrel", -"tume", -"tumefy", -"tumid", -"tumidly", -"tummals", -"tummel", -"tummer", -"tummock", -"tummy", -"tumor", -"tumored", -"tump", -"tumtum", -"tumular", -"tumuli", -"tumult", -"tumulus", -"tun", -"tuna", -"tunable", -"tunably", -"tunca", -"tund", -"tunder", -"tundish", -"tundra", -"tundun", -"tune", -"tuned", -"tuneful", -"tuner", -"tunful", -"tung", -"tungate", -"tungo", -"tunhoof", -"tunic", -"tunicin", -"tunicle", -"tuning", -"tunish", -"tunist", -"tunk", -"tunket", -"tunlike", -"tunmoot", -"tunna", -"tunnel", -"tunner", -"tunnery", -"tunnor", -"tunny", -"tuno", -"tunu", -"tuny", -"tup", -"tupara", -"tupek", -"tupelo", -"tupik", -"tupman", -"tupuna", -"tuque", -"tur", -"turacin", -"turb", -"turban", -"turbary", -"turbeh", -"turbid", -"turbine", -"turbit", -"turbith", -"turbo", -"turbot", -"turco", -"turd", -"turdine", -"turdoid", -"tureen", -"turf", -"turfage", -"turfdom", -"turfed", -"turfen", -"turfing", -"turfite", -"turfman", -"turfy", -"turgent", -"turgid", -"turgite", -"turgoid", -"turgor", -"turgy", -"turio", -"turion", -"turjite", -"turk", -"turken", -"turkey", -"turkis", -"turkle", -"turm", -"turma", -"turment", -"turmit", -"turmoil", -"turn", -"turncap", -"turndun", -"turned", -"turnel", -"turner", -"turnery", -"turney", -"turning", -"turnip", -"turnipy", -"turnix", -"turnkey", -"turnoff", -"turnout", -"turnpin", -"turnrow", -"turns", -"turnup", -"turp", -"turpeth", -"turpid", -"turps", -"turr", -"turret", -"turse", -"tursio", -"turtle", -"turtler", -"turtlet", -"turtosa", -"tururi", -"turus", -"turwar", -"tusche", -"tush", -"tushed", -"tusher", -"tushery", -"tusk", -"tuskar", -"tusked", -"tusker", -"tuskish", -"tusky", -"tussah", -"tussal", -"tusser", -"tussis", -"tussive", -"tussle", -"tussock", -"tussore", -"tussur", -"tut", -"tutania", -"tutball", -"tute", -"tutee", -"tutela", -"tutelar", -"tutenag", -"tuth", -"tutin", -"tutly", -"tutman", -"tutor", -"tutorer", -"tutorly", -"tutory", -"tutoyer", -"tutress", -"tutrice", -"tutrix", -"tuts", -"tutsan", -"tutster", -"tutti", -"tutty", -"tutu", -"tutulus", -"tutwork", -"tuwi", -"tux", -"tuxedo", -"tuyere", -"tuza", -"tuzzle", -"twa", -"twaddle", -"twaddly", -"twaddy", -"twae", -"twagger", -"twain", -"twaite", -"twal", -"twale", -"twalt", -"twang", -"twanger", -"twangle", -"twangy", -"twank", -"twanker", -"twankle", -"twanky", -"twant", -"twarly", -"twas", -"twasome", -"twat", -"twattle", -"tway", -"twazzy", -"tweag", -"tweak", -"tweaker", -"tweaky", -"twee", -"tweed", -"tweeded", -"tweedle", -"tweedy", -"tweeg", -"tweel", -"tween", -"tweeny", -"tweesh", -"tweesht", -"tweest", -"tweet", -"tweeter", -"tweeze", -"tweezer", -"tweil", -"twelfth", -"twelve", -"twenty", -"twere", -"twerp", -"twibil", -"twice", -"twicer", -"twicet", -"twick", -"twiddle", -"twiddly", -"twifoil", -"twifold", -"twig", -"twigful", -"twigged", -"twiggen", -"twigger", -"twiggy", -"twiglet", -"twilit", -"twill", -"twilled", -"twiller", -"twilly", -"twilt", -"twin", -"twindle", -"twine", -"twiner", -"twinge", -"twingle", -"twinism", -"twink", -"twinkle", -"twinkly", -"twinly", -"twinned", -"twinner", -"twinter", -"twiny", -"twire", -"twirk", -"twirl", -"twirler", -"twirly", -"twiscar", -"twisel", -"twist", -"twisted", -"twister", -"twistle", -"twisty", -"twit", -"twitch", -"twitchy", -"twite", -"twitten", -"twitter", -"twitty", -"twixt", -"twizzle", -"two", -"twofold", -"twoling", -"twoness", -"twosome", -"tychism", -"tychite", -"tycoon", -"tyddyn", -"tydie", -"tye", -"tyee", -"tyg", -"tying", -"tyke", -"tyken", -"tykhana", -"tyking", -"tylarus", -"tylion", -"tyloma", -"tylopod", -"tylose", -"tylosis", -"tylote", -"tylotic", -"tylotus", -"tylus", -"tymp", -"tympan", -"tympana", -"tympani", -"tympany", -"tynd", -"typal", -"type", -"typer", -"typeset", -"typhia", -"typhic", -"typhlon", -"typhoid", -"typhoon", -"typhose", -"typhous", -"typhus", -"typic", -"typica", -"typical", -"typicon", -"typicum", -"typify", -"typist", -"typo", -"typobar", -"typonym", -"typp", -"typy", -"tyranny", -"tyrant", -"tyre", -"tyro", -"tyroma", -"tyrone", -"tyronic", -"tyrosyl", -"tyste", -"tyt", -"tzolkin", -"tzontle", -"u", -"uang", -"uayeb", -"uberant", -"uberous", -"uberty", -"ubi", -"ubiety", -"ubiquit", -"ubussu", -"uckia", -"udal", -"udaler", -"udaller", -"udalman", -"udasi", -"udder", -"uddered", -"udell", -"udo", -"ug", -"ugh", -"uglify", -"uglily", -"ugly", -"ugsome", -"uhlan", -"uhllo", -"uhtsong", -"uily", -"uinal", -"uintjie", -"uitspan", -"uji", -"ukase", -"uke", -"ukiyoye", -"ukulele", -"ula", -"ulcer", -"ulcered", -"ulcery", -"ule", -"ulema", -"uletic", -"ulex", -"ulexine", -"ulexite", -"ulitis", -"ull", -"ulla", -"ullage", -"ullaged", -"uller", -"ulling", -"ulluco", -"ulmic", -"ulmin", -"ulminic", -"ulmo", -"ulmous", -"ulna", -"ulnad", -"ulnae", -"ulnar", -"ulnare", -"ulnaria", -"uloid", -"uloncus", -"ulster", -"ultima", -"ultimo", -"ultimum", -"ultra", -"ulu", -"ulua", -"uluhi", -"ululant", -"ululate", -"ululu", -"um", -"umbel", -"umbeled", -"umbella", -"umber", -"umbilic", -"umble", -"umbo", -"umbonal", -"umbone", -"umbones", -"umbonic", -"umbra", -"umbrae", -"umbrage", -"umbral", -"umbrel", -"umbril", -"umbrine", -"umbrose", -"umbrous", -"ume", -"umiak", -"umiri", -"umlaut", -"ump", -"umph", -"umpire", -"umpirer", -"umpteen", -"umpty", -"umu", -"un", -"unable", -"unably", -"unact", -"unacted", -"unacute", -"unadapt", -"unadd", -"unadded", -"unadopt", -"unadorn", -"unadult", -"unafire", -"unaflow", -"unaged", -"unagile", -"unaging", -"unaided", -"unaimed", -"unaired", -"unakin", -"unakite", -"unal", -"unalarm", -"unalert", -"unalike", -"unalist", -"unalive", -"unallow", -"unalone", -"unaloud", -"unamend", -"unamiss", -"unamo", -"unample", -"unamply", -"unangry", -"unannex", -"unapart", -"unapt", -"unaptly", -"unarch", -"unark", -"unarm", -"unarmed", -"unarray", -"unarted", -"unary", -"unasked", -"unau", -"unavian", -"unawake", -"unaware", -"unaway", -"unawed", -"unawful", -"unawned", -"unaxled", -"unbag", -"unbain", -"unbait", -"unbaked", -"unbale", -"unbank", -"unbar", -"unbarb", -"unbare", -"unbark", -"unbase", -"unbased", -"unbaste", -"unbated", -"unbay", -"unbe", -"unbear", -"unbeard", -"unbeast", -"unbed", -"unbefit", -"unbeget", -"unbegot", -"unbegun", -"unbeing", -"unbell", -"unbelt", -"unbench", -"unbend", -"unbent", -"unberth", -"unbeset", -"unbesot", -"unbet", -"unbias", -"unbid", -"unbind", -"unbit", -"unbitt", -"unblade", -"unbled", -"unblent", -"unbless", -"unblest", -"unblind", -"unbliss", -"unblock", -"unbloom", -"unblown", -"unblued", -"unblush", -"unboat", -"unbody", -"unbog", -"unboggy", -"unbokel", -"unbold", -"unbolt", -"unbone", -"unboned", -"unbonny", -"unboot", -"unbored", -"unborn", -"unborne", -"unbosom", -"unbound", -"unbow", -"unbowed", -"unbowel", -"unbox", -"unboxed", -"unboy", -"unbrace", -"unbraid", -"unbran", -"unbrand", -"unbrave", -"unbraze", -"unbred", -"unbrent", -"unbrick", -"unbrief", -"unbroad", -"unbroke", -"unbrown", -"unbrute", -"unbud", -"unbuild", -"unbuilt", -"unbulky", -"unbung", -"unburly", -"unburn", -"unburnt", -"unburst", -"unbury", -"unbush", -"unbusk", -"unbusy", -"unbuxom", -"unca", -"uncage", -"uncaged", -"uncake", -"uncalk", -"uncall", -"uncalm", -"uncaned", -"uncanny", -"uncap", -"uncart", -"uncase", -"uncased", -"uncask", -"uncast", -"uncaste", -"uncate", -"uncave", -"unceded", -"unchain", -"unchair", -"uncharm", -"unchary", -"uncheat", -"uncheck", -"unchid", -"unchild", -"unchurn", -"unci", -"uncia", -"uncial", -"uncinal", -"uncinch", -"uncinct", -"uncini", -"uncinus", -"uncite", -"uncited", -"uncity", -"uncivic", -"uncivil", -"unclad", -"unclamp", -"unclasp", -"unclay", -"uncle", -"unclead", -"unclean", -"unclear", -"uncleft", -"unclew", -"unclick", -"unclify", -"unclimb", -"uncling", -"unclip", -"uncloak", -"unclog", -"unclose", -"uncloud", -"unclout", -"unclub", -"unco", -"uncoach", -"uncoat", -"uncock", -"uncoded", -"uncoif", -"uncoil", -"uncoin", -"uncoked", -"uncolt", -"uncoly", -"uncome", -"uncomfy", -"uncomic", -"uncoop", -"uncope", -"uncord", -"uncore", -"uncored", -"uncork", -"uncost", -"uncouch", -"uncous", -"uncouth", -"uncover", -"uncowed", -"uncowl", -"uncoy", -"uncram", -"uncramp", -"uncream", -"uncrest", -"uncrib", -"uncried", -"uncrime", -"uncrisp", -"uncrook", -"uncropt", -"uncross", -"uncrown", -"uncrude", -"uncruel", -"unction", -"uncubic", -"uncular", -"uncurb", -"uncurd", -"uncured", -"uncurl", -"uncurse", -"uncurst", -"uncus", -"uncut", -"uncuth", -"undaily", -"undam", -"undamn", -"undared", -"undark", -"undate", -"undated", -"undaub", -"undazed", -"unde", -"undead", -"undeaf", -"undealt", -"undean", -"undear", -"undeck", -"undecyl", -"undeep", -"undeft", -"undeify", -"undelve", -"unden", -"under", -"underdo", -"underer", -"undergo", -"underly", -"undern", -"undevil", -"undewed", -"undewy", -"undid", -"undies", -"undig", -"undight", -"undiked", -"undim", -"undine", -"undined", -"undirk", -"undo", -"undock", -"undoer", -"undog", -"undoing", -"undomed", -"undon", -"undone", -"undoped", -"undose", -"undosed", -"undowny", -"undrab", -"undrag", -"undrape", -"undraw", -"undrawn", -"undress", -"undried", -"undrunk", -"undry", -"undub", -"unducal", -"undue", -"undug", -"unduke", -"undular", -"undull", -"unduly", -"unduped", -"undust", -"unduty", -"undwelt", -"undy", -"undye", -"undyed", -"undying", -"uneager", -"unearly", -"unearth", -"unease", -"uneasy", -"uneaten", -"uneath", -"unebbed", -"unedge", -"unedged", -"unelect", -"unempt", -"unempty", -"unended", -"unepic", -"unequal", -"unerect", -"unethic", -"uneven", -"unevil", -"unexact", -"uneye", -"uneyed", -"unface", -"unfaced", -"unfact", -"unfaded", -"unfain", -"unfaint", -"unfair", -"unfaith", -"unfaked", -"unfalse", -"unfamed", -"unfancy", -"unfar", -"unfast", -"unfeary", -"unfed", -"unfeed", -"unfele", -"unfelon", -"unfelt", -"unfence", -"unfeted", -"unfeued", -"unfew", -"unfiber", -"unfiend", -"unfiery", -"unfight", -"unfile", -"unfiled", -"unfill", -"unfilm", -"unfine", -"unfined", -"unfired", -"unfirm", -"unfit", -"unfitly", -"unfitty", -"unfix", -"unfixed", -"unflag", -"unflaky", -"unflank", -"unflat", -"unflead", -"unflesh", -"unflock", -"unfloor", -"unflown", -"unfluid", -"unflush", -"unfoggy", -"unfold", -"unfond", -"unfool", -"unfork", -"unform", -"unfoul", -"unfound", -"unfoxy", -"unfrail", -"unframe", -"unfrank", -"unfree", -"unfreed", -"unfret", -"unfried", -"unfrill", -"unfrizz", -"unfrock", -"unfrost", -"unfroze", -"unfull", -"unfully", -"unfumed", -"unfunny", -"unfur", -"unfurl", -"unfused", -"unfussy", -"ungag", -"ungaged", -"ungain", -"ungaite", -"ungaro", -"ungaudy", -"ungear", -"ungelt", -"unget", -"ungiant", -"ungiddy", -"ungild", -"ungill", -"ungilt", -"ungird", -"ungirt", -"ungirth", -"ungive", -"ungiven", -"ungka", -"unglad", -"unglaze", -"unglee", -"unglobe", -"ungloom", -"unglory", -"ungloss", -"unglove", -"unglue", -"unglued", -"ungnaw", -"ungnawn", -"ungod", -"ungodly", -"ungold", -"ungone", -"ungood", -"ungored", -"ungorge", -"ungot", -"ungouty", -"ungown", -"ungrace", -"ungraft", -"ungrain", -"ungrand", -"ungrasp", -"ungrave", -"ungreat", -"ungreen", -"ungrip", -"ungripe", -"ungross", -"ungrow", -"ungrown", -"ungruff", -"ungual", -"unguard", -"ungueal", -"unguent", -"ungues", -"unguis", -"ungula", -"ungulae", -"ungular", -"unguled", -"ungull", -"ungulp", -"ungum", -"unguyed", -"ungyve", -"ungyved", -"unhabit", -"unhad", -"unhaft", -"unhair", -"unhairy", -"unhand", -"unhandy", -"unhang", -"unhap", -"unhappy", -"unhard", -"unhardy", -"unharsh", -"unhasp", -"unhaste", -"unhasty", -"unhat", -"unhate", -"unhated", -"unhaunt", -"unhave", -"unhayed", -"unhazed", -"unhead", -"unheady", -"unheal", -"unheard", -"unheart", -"unheavy", -"unhedge", -"unheed", -"unheedy", -"unheld", -"unhele", -"unheler", -"unhelm", -"unherd", -"unhero", -"unhewed", -"unhewn", -"unhex", -"unhid", -"unhide", -"unhigh", -"unhinge", -"unhired", -"unhit", -"unhitch", -"unhive", -"unhoard", -"unhoary", -"unhoed", -"unhoist", -"unhold", -"unholy", -"unhome", -"unhoned", -"unhood", -"unhook", -"unhoop", -"unhoped", -"unhorny", -"unhorse", -"unhose", -"unhosed", -"unhot", -"unhouse", -"unhull", -"unhuman", -"unhumid", -"unhung", -"unhurt", -"unhusk", -"uniat", -"uniate", -"uniaxal", -"unible", -"unice", -"uniced", -"unicell", -"unicism", -"unicist", -"unicity", -"unicorn", -"unicum", -"unideal", -"unidle", -"unidly", -"unie", -"uniface", -"unific", -"unified", -"unifier", -"uniflow", -"uniform", -"unify", -"unilobe", -"unimped", -"uninked", -"uninn", -"unio", -"unioid", -"union", -"unioned", -"unionic", -"unionid", -"unioval", -"unipara", -"uniped", -"unipod", -"unique", -"unireme", -"unisoil", -"unison", -"unit", -"unitage", -"unital", -"unitary", -"unite", -"united", -"uniter", -"uniting", -"unition", -"unitism", -"unitive", -"unitize", -"unitude", -"unity", -"univied", -"unjaded", -"unjam", -"unjewel", -"unjoin", -"unjoint", -"unjolly", -"unjoyed", -"unjudge", -"unjuicy", -"unjust", -"unkamed", -"unked", -"unkempt", -"unken", -"unkept", -"unket", -"unkey", -"unkeyed", -"unkid", -"unkill", -"unkin", -"unkind", -"unking", -"unkink", -"unkirk", -"unkiss", -"unkist", -"unknave", -"unknew", -"unknit", -"unknot", -"unknow", -"unknown", -"unlace", -"unlaced", -"unlade", -"unladen", -"unlaid", -"unlame", -"unlamed", -"unland", -"unlap", -"unlarge", -"unlash", -"unlatch", -"unlath", -"unlaugh", -"unlaved", -"unlaw", -"unlawed", -"unlawly", -"unlay", -"unlead", -"unleaf", -"unleaky", -"unleal", -"unlean", -"unlearn", -"unleash", -"unleave", -"unled", -"unleft", -"unlegal", -"unlent", -"unless", -"unlet", -"unlevel", -"unlid", -"unlie", -"unlight", -"unlike", -"unliked", -"unliken", -"unlimb", -"unlime", -"unlimed", -"unlimp", -"unline", -"unlined", -"unlink", -"unlist", -"unlisty", -"unlit", -"unlive", -"unload", -"unloath", -"unlobed", -"unlocal", -"unlock", -"unlodge", -"unlofty", -"unlogic", -"unlook", -"unloop", -"unloose", -"unlord", -"unlost", -"unlousy", -"unlove", -"unloved", -"unlowly", -"unloyal", -"unlucid", -"unluck", -"unlucky", -"unlunar", -"unlured", -"unlust", -"unlusty", -"unlute", -"unluted", -"unlying", -"unmad", -"unmade", -"unmagic", -"unmaid", -"unmail", -"unmake", -"unmaker", -"unman", -"unmaned", -"unmanly", -"unmarch", -"unmarry", -"unmask", -"unmast", -"unmate", -"unmated", -"unmaze", -"unmeant", -"unmeek", -"unmeet", -"unmerge", -"unmerry", -"unmesh", -"unmet", -"unmeted", -"unmew", -"unmewed", -"unmind", -"unmined", -"unmired", -"unmiry", -"unmist", -"unmiter", -"unmix", -"unmixed", -"unmodel", -"unmoist", -"unmold", -"unmoldy", -"unmoor", -"unmoral", -"unmount", -"unmoved", -"unmowed", -"unmown", -"unmuddy", -"unmuted", -"unnail", -"unnaked", -"unname", -"unnamed", -"unneat", -"unneedy", -"unnegro", -"unnerve", -"unnest", -"unneth", -"unnethe", -"unnew", -"unnewly", -"unnice", -"unnigh", -"unnoble", -"unnobly", -"unnose", -"unnosed", -"unnoted", -"unnovel", -"unoared", -"unobese", -"unode", -"unoften", -"unogled", -"unoil", -"unoiled", -"unoily", -"unold", -"unoped", -"unopen", -"unorbed", -"unorder", -"unorn", -"unornly", -"unovert", -"unowed", -"unowing", -"unown", -"unowned", -"unpaced", -"unpack", -"unpagan", -"unpaged", -"unpaid", -"unpaint", -"unpale", -"unpaled", -"unpanel", -"unpapal", -"unpaper", -"unparch", -"unpared", -"unpark", -"unparty", -"unpass", -"unpaste", -"unpave", -"unpaved", -"unpawed", -"unpawn", -"unpeace", -"unpeel", -"unpeg", -"unpen", -"unpenal", -"unpent", -"unperch", -"unpetal", -"unpick", -"unpiece", -"unpiety", -"unpile", -"unpiled", -"unpin", -"unpious", -"unpiped", -"unplace", -"unplaid", -"unplain", -"unplait", -"unplan", -"unplank", -"unplant", -"unplat", -"unpleat", -"unplied", -"unplow", -"unplug", -"unplumb", -"unplume", -"unplump", -"unpoise", -"unpoled", -"unpope", -"unposed", -"unpot", -"unpower", -"unpray", -"unprim", -"unprime", -"unprint", -"unprop", -"unproud", -"unpure", -"unpurse", -"unput", -"unqueen", -"unquick", -"unquiet", -"unquit", -"unquote", -"unraced", -"unrack", -"unrainy", -"unrake", -"unraked", -"unram", -"unrank", -"unraped", -"unrare", -"unrash", -"unrated", -"unravel", -"unray", -"unrayed", -"unrazed", -"unread", -"unready", -"unreal", -"unreave", -"unrebel", -"unred", -"unreel", -"unreeve", -"unregal", -"unrein", -"unrent", -"unrest", -"unresty", -"unrhyme", -"unrich", -"unricht", -"unrid", -"unride", -"unrife", -"unrig", -"unright", -"unrigid", -"unrind", -"unring", -"unrip", -"unripe", -"unriped", -"unrisen", -"unrisky", -"unrived", -"unriven", -"unrivet", -"unroast", -"unrobe", -"unrobed", -"unroll", -"unroof", -"unroomy", -"unroost", -"unroot", -"unrope", -"unroped", -"unrosed", -"unroted", -"unrough", -"unround", -"unrove", -"unroved", -"unrow", -"unrowed", -"unroyal", -"unrule", -"unruled", -"unruly", -"unrun", -"unrung", -"unrural", -"unrust", -"unruth", -"unsack", -"unsad", -"unsafe", -"unsage", -"unsaid", -"unsaint", -"unsalt", -"unsane", -"unsappy", -"unsash", -"unsated", -"unsatin", -"unsaved", -"unsawed", -"unsawn", -"unsay", -"unscale", -"unscaly", -"unscarb", -"unscent", -"unscrew", -"unseal", -"unseam", -"unseat", -"unsee", -"unseen", -"unself", -"unsense", -"unsent", -"unset", -"unsew", -"unsewed", -"unsewn", -"unsex", -"unsexed", -"unshade", -"unshady", -"unshape", -"unsharp", -"unshawl", -"unsheaf", -"unshed", -"unsheet", -"unshell", -"unship", -"unshod", -"unshoe", -"unshoed", -"unshop", -"unshore", -"unshorn", -"unshort", -"unshot", -"unshown", -"unshowy", -"unshrew", -"unshut", -"unshy", -"unshyly", -"unsick", -"unsided", -"unsiege", -"unsight", -"unsilly", -"unsin", -"unsinew", -"unsing", -"unsized", -"unskin", -"unslack", -"unslain", -"unslate", -"unslave", -"unsleek", -"unslept", -"unsling", -"unslip", -"unslit", -"unslot", -"unslow", -"unslung", -"unsly", -"unsmart", -"unsmoky", -"unsmote", -"unsnaky", -"unsnap", -"unsnare", -"unsnarl", -"unsneck", -"unsnib", -"unsnow", -"unsober", -"unsoft", -"unsoggy", -"unsoil", -"unsolar", -"unsold", -"unsole", -"unsoled", -"unsolid", -"unsome", -"unson", -"unsonsy", -"unsooty", -"unsore", -"unsorry", -"unsort", -"unsoul", -"unsound", -"unsour", -"unsowed", -"unsown", -"unspan", -"unspar", -"unspeak", -"unsped", -"unspeed", -"unspell", -"unspelt", -"unspent", -"unspicy", -"unspied", -"unspike", -"unspin", -"unspit", -"unsplit", -"unspoil", -"unspot", -"unspun", -"unstack", -"unstagy", -"unstaid", -"unstain", -"unstar", -"unstate", -"unsteck", -"unsteel", -"unsteep", -"unstep", -"unstern", -"unstick", -"unstill", -"unsting", -"unstock", -"unstoic", -"unstone", -"unstony", -"unstop", -"unstore", -"unstout", -"unstow", -"unstrap", -"unstrip", -"unstuck", -"unstuff", -"unstung", -"unsty", -"unsued", -"unsuit", -"unsulky", -"unsun", -"unsung", -"unsunk", -"unsunny", -"unsure", -"unswear", -"unsweat", -"unsweet", -"unswell", -"unswept", -"unswing", -"unsworn", -"unswung", -"untack", -"untaint", -"untaken", -"untall", -"untame", -"untamed", -"untap", -"untaped", -"untar", -"untaste", -"untasty", -"untaut", -"untawed", -"untax", -"untaxed", -"unteach", -"unteam", -"unteem", -"untell", -"untense", -"untent", -"untenty", -"untewed", -"unthank", -"unthaw", -"unthick", -"unthink", -"unthorn", -"unthrid", -"unthrob", -"untidal", -"untidy", -"untie", -"untied", -"untight", -"until", -"untile", -"untiled", -"untill", -"untilt", -"untimed", -"untin", -"untinct", -"untine", -"untipt", -"untire", -"untired", -"unto", -"untold", -"untomb", -"untone", -"untoned", -"untooth", -"untop", -"untorn", -"untouch", -"untough", -"untown", -"untrace", -"untrain", -"untread", -"untreed", -"untress", -"untried", -"untrig", -"untrill", -"untrim", -"untripe", -"untrite", -"untrod", -"untruck", -"untrue", -"untruly", -"untruss", -"untrust", -"untruth", -"untuck", -"untumid", -"untune", -"untuned", -"unturf", -"unturn", -"untwine", -"untwirl", -"untwist", -"untying", -"untz", -"unugly", -"unultra", -"unupset", -"unurban", -"unurged", -"unurn", -"unurned", -"unuse", -"unused", -"unusual", -"unvain", -"unvalid", -"unvalue", -"unveil", -"unvenom", -"unvest", -"unvexed", -"unvicar", -"unvisor", -"unvital", -"unvivid", -"unvocal", -"unvoice", -"unvote", -"unvoted", -"unvowed", -"unwaded", -"unwaged", -"unwaked", -"unwall", -"unwan", -"unware", -"unwarm", -"unwarn", -"unwarp", -"unwary", -"unwater", -"unwaved", -"unwax", -"unwaxed", -"unwayed", -"unweal", -"unweary", -"unweave", -"unweb", -"unwed", -"unwedge", -"unweel", -"unweft", -"unweld", -"unwell", -"unwept", -"unwet", -"unwheel", -"unwhig", -"unwhip", -"unwhite", -"unwield", -"unwifed", -"unwig", -"unwild", -"unwill", -"unwily", -"unwind", -"unwindy", -"unwiped", -"unwire", -"unwired", -"unwise", -"unwish", -"unwist", -"unwitch", -"unwitty", -"unwive", -"unwived", -"unwoful", -"unwoman", -"unwomb", -"unwon", -"unwooed", -"unwoof", -"unwooly", -"unwordy", -"unwork", -"unworld", -"unwormy", -"unworn", -"unworth", -"unwound", -"unwoven", -"unwrap", -"unwrit", -"unwrite", -"unwrung", -"unyoke", -"unyoked", -"unyoung", -"unze", -"unzen", -"unzone", -"unzoned", -"up", -"upaisle", -"upalley", -"upalong", -"uparch", -"uparise", -"uparm", -"uparna", -"upas", -"upattic", -"upbank", -"upbar", -"upbay", -"upbear", -"upbeat", -"upbelch", -"upbelt", -"upbend", -"upbid", -"upbind", -"upblast", -"upblaze", -"upblow", -"upboil", -"upbolt", -"upboost", -"upborne", -"upbotch", -"upbound", -"upbrace", -"upbraid", -"upbray", -"upbreak", -"upbred", -"upbreed", -"upbrim", -"upbring", -"upbrook", -"upbrow", -"upbuild", -"upbuoy", -"upburn", -"upburst", -"upbuy", -"upcall", -"upcanal", -"upcarry", -"upcast", -"upcatch", -"upchoke", -"upchuck", -"upcity", -"upclimb", -"upclose", -"upcoast", -"upcock", -"upcoil", -"upcome", -"upcover", -"upcrane", -"upcrawl", -"upcreek", -"upcreep", -"upcrop", -"upcrowd", -"upcry", -"upcurl", -"upcurve", -"upcut", -"updart", -"update", -"updeck", -"updelve", -"updive", -"updo", -"updome", -"updraft", -"updrag", -"updraw", -"updrink", -"updry", -"upeat", -"upend", -"upeygan", -"upfeed", -"upfield", -"upfill", -"upflame", -"upflare", -"upflash", -"upflee", -"upfling", -"upfloat", -"upflood", -"upflow", -"upflung", -"upfly", -"upfold", -"upframe", -"upfurl", -"upgale", -"upgang", -"upgape", -"upgaze", -"upget", -"upgird", -"upgirt", -"upgive", -"upglean", -"upglide", -"upgo", -"upgorge", -"upgrade", -"upgrave", -"upgrow", -"upgully", -"upgush", -"uphand", -"uphang", -"uphasp", -"upheal", -"upheap", -"upheave", -"upheld", -"uphelm", -"uphelya", -"upher", -"uphill", -"uphoard", -"uphoist", -"uphold", -"uphung", -"uphurl", -"upjerk", -"upjet", -"upkeep", -"upknell", -"upknit", -"upla", -"uplaid", -"uplake", -"upland", -"uplane", -"uplay", -"uplead", -"upleap", -"upleg", -"uplick", -"uplift", -"uplight", -"uplimb", -"upline", -"uplock", -"uplong", -"uplook", -"uploom", -"uploop", -"uplying", -"upmast", -"upmix", -"upmost", -"upmount", -"upmove", -"upness", -"upo", -"upon", -"uppard", -"uppent", -"upper", -"upperch", -"upperer", -"uppers", -"uppile", -"upping", -"uppish", -"uppity", -"upplow", -"uppluck", -"uppoint", -"uppoise", -"uppop", -"uppour", -"uppowoc", -"upprick", -"upprop", -"uppuff", -"uppull", -"uppush", -"upraise", -"upreach", -"uprear", -"uprein", -"uprend", -"uprest", -"uprid", -"upridge", -"upright", -"uprip", -"uprisal", -"uprise", -"uprisen", -"upriser", -"uprist", -"uprive", -"upriver", -"uproad", -"uproar", -"uproom", -"uproot", -"uprose", -"uprouse", -"uproute", -"uprun", -"uprush", -"upscale", -"upscrew", -"upseal", -"upseek", -"upseize", -"upsend", -"upset", -"upsey", -"upshaft", -"upshear", -"upshoot", -"upshore", -"upshot", -"upshove", -"upshut", -"upside", -"upsides", -"upsilon", -"upsit", -"upslant", -"upslip", -"upslope", -"upsmite", -"upsoak", -"upsoar", -"upsolve", -"upspeak", -"upspear", -"upspeed", -"upspew", -"upspin", -"upspire", -"upspout", -"upspurt", -"upstaff", -"upstage", -"upstair", -"upstamp", -"upstand", -"upstare", -"upstart", -"upstate", -"upstay", -"upsteal", -"upsteam", -"upstem", -"upstep", -"upstick", -"upstir", -"upsuck", -"upsun", -"upsup", -"upsurge", -"upswarm", -"upsway", -"upsweep", -"upswell", -"upswing", -"uptable", -"uptake", -"uptaker", -"uptear", -"uptend", -"upthrow", -"uptide", -"uptie", -"uptill", -"uptilt", -"uptorn", -"uptoss", -"uptower", -"uptown", -"uptrace", -"uptrack", -"uptrail", -"uptrain", -"uptree", -"uptrend", -"uptrill", -"uptrunk", -"uptruss", -"uptube", -"uptuck", -"upturn", -"uptwist", -"upupoid", -"upvomit", -"upwaft", -"upwall", -"upward", -"upwards", -"upwarp", -"upwax", -"upway", -"upways", -"upwell", -"upwent", -"upwheel", -"upwhelm", -"upwhir", -"upwhirl", -"upwind", -"upwith", -"upwork", -"upwound", -"upwrap", -"upwring", -"upyard", -"upyoke", -"ur", -"ura", -"urachal", -"urachus", -"uracil", -"uraemic", -"uraeus", -"ural", -"urali", -"uraline", -"uralite", -"uralium", -"uramido", -"uramil", -"uramino", -"uran", -"uranate", -"uranic", -"uraniid", -"uranin", -"uranine", -"uranion", -"uranism", -"uranist", -"uranite", -"uranium", -"uranous", -"uranyl", -"urao", -"urare", -"urari", -"urase", -"urate", -"uratic", -"uratoma", -"urazine", -"urazole", -"urban", -"urbane", -"urbian", -"urbic", -"urbify", -"urceole", -"urceoli", -"urceus", -"urchin", -"urd", -"urde", -"urdee", -"ure", -"urea", -"ureal", -"urease", -"uredema", -"uredine", -"uredo", -"ureic", -"ureid", -"ureide", -"ureido", -"uremia", -"uremic", -"urent", -"uresis", -"uretal", -"ureter", -"urethan", -"urethra", -"uretic", -"urf", -"urge", -"urgence", -"urgency", -"urgent", -"urger", -"urging", -"urheen", -"urial", -"uric", -"urinal", -"urinant", -"urinary", -"urinate", -"urine", -"urinose", -"urinous", -"urite", -"urlar", -"urled", -"urling", -"urluch", -"urman", -"urn", -"urna", -"urnae", -"urnal", -"urnful", -"urning", -"urnism", -"urnlike", -"urocele", -"urocyst", -"urodele", -"urogram", -"urohyal", -"urolith", -"urology", -"uromere", -"uronic", -"uropod", -"urosis", -"urosome", -"urostea", -"urotoxy", -"uroxin", -"ursal", -"ursine", -"ursoid", -"ursolic", -"urson", -"ursone", -"ursuk", -"urtica", -"urtite", -"urubu", -"urucu", -"urucuri", -"uruisg", -"urunday", -"urus", -"urushi", -"urushic", -"urva", -"us", -"usable", -"usage", -"usager", -"usance", -"usar", -"usara", -"usaron", -"usation", -"use", -"used", -"usedly", -"usednt", -"usee", -"useful", -"usehold", -"useless", -"usent", -"user", -"ush", -"ushabti", -"usher", -"usherer", -"usings", -"usitate", -"usnea", -"usneoid", -"usnic", -"usninic", -"usque", -"usself", -"ussels", -"ust", -"uster", -"ustion", -"usual", -"usually", -"usuary", -"usucapt", -"usure", -"usurer", -"usuress", -"usurp", -"usurper", -"usurpor", -"usury", -"usward", -"uswards", -"ut", -"uta", -"utahite", -"utai", -"utas", -"utch", -"utchy", -"utees", -"utensil", -"uteri", -"uterine", -"uterus", -"utick", -"utile", -"utility", -"utilize", -"utinam", -"utmost", -"utopia", -"utopian", -"utopism", -"utopist", -"utricle", -"utricul", -"utrubi", -"utrum", -"utsuk", -"utter", -"utterer", -"utterly", -"utu", -"utum", -"uva", -"uval", -"uvalha", -"uvanite", -"uvate", -"uvea", -"uveal", -"uveitic", -"uveitis", -"uveous", -"uvic", -"uvid", -"uviol", -"uvitic", -"uvito", -"uvrou", -"uvula", -"uvulae", -"uvular", -"uvver", -"uxorial", -"uzan", -"uzara", -"uzarin", -"uzaron", -"v", -"vaagmer", -"vaalite", -"vacancy", -"vacant", -"vacate", -"vacatur", -"vaccary", -"vaccina", -"vaccine", -"vache", -"vacoa", -"vacona", -"vacoua", -"vacouf", -"vacual", -"vacuate", -"vacuefy", -"vacuist", -"vacuity", -"vacuole", -"vacuome", -"vacuous", -"vacuum", -"vacuuma", -"vade", -"vadium", -"vadose", -"vady", -"vag", -"vagal", -"vagary", -"vagas", -"vage", -"vagile", -"vagina", -"vaginal", -"vagitus", -"vagrant", -"vagrate", -"vagrom", -"vague", -"vaguely", -"vaguish", -"vaguity", -"vagus", -"vahine", -"vail", -"vain", -"vainful", -"vainly", -"vair", -"vairagi", -"vaire", -"vairy", -"vaivode", -"vajra", -"vakass", -"vakia", -"vakil", -"valance", -"vale", -"valence", -"valency", -"valent", -"valeral", -"valeric", -"valerin", -"valeryl", -"valet", -"valeta", -"valetry", -"valeur", -"valgoid", -"valgus", -"valhall", -"vali", -"valiant", -"valid", -"validly", -"valine", -"valise", -"vall", -"vallar", -"vallary", -"vallate", -"valley", -"vallis", -"vallum", -"valonia", -"valor", -"valse", -"valsoid", -"valuate", -"value", -"valued", -"valuer", -"valuta", -"valva", -"valval", -"valvate", -"valve", -"valved", -"valvula", -"valvule", -"valyl", -"vamfont", -"vamoose", -"vamp", -"vamped", -"vamper", -"vampire", -"van", -"vanadic", -"vanadyl", -"vane", -"vaned", -"vanfoss", -"vang", -"vangee", -"vangeli", -"vanglo", -"vanilla", -"vanille", -"vanish", -"vanity", -"vanman", -"vanmost", -"vanner", -"vannet", -"vansire", -"vantage", -"vanward", -"vapid", -"vapidly", -"vapor", -"vapored", -"vaporer", -"vapory", -"vara", -"varahan", -"varan", -"varanid", -"vardy", -"vare", -"varec", -"vareuse", -"vari", -"variant", -"variate", -"varical", -"varices", -"varied", -"varier", -"variety", -"variola", -"variole", -"various", -"varisse", -"varix", -"varlet", -"varment", -"varna", -"varnish", -"varsha", -"varsity", -"varus", -"varve", -"varved", -"vary", -"vas", -"vasa", -"vasal", -"vase", -"vaseful", -"vaselet", -"vassal", -"vast", -"vastate", -"vastily", -"vastity", -"vastly", -"vasty", -"vasu", -"vat", -"vatful", -"vatic", -"vatman", -"vatter", -"vau", -"vaudy", -"vault", -"vaulted", -"vaulter", -"vaulty", -"vaunt", -"vaunted", -"vaunter", -"vaunty", -"vauxite", -"vavasor", -"vaward", -"veal", -"vealer", -"vealy", -"vection", -"vectis", -"vector", -"vecture", -"vedana", -"vedette", -"vedika", -"vedro", -"veduis", -"vee", -"veen", -"veep", -"veer", -"veery", -"vegetal", -"vegete", -"vehicle", -"vei", -"veigle", -"veil", -"veiled", -"veiler", -"veiling", -"veily", -"vein", -"veinage", -"veinal", -"veined", -"veiner", -"veinery", -"veining", -"veinlet", -"veinous", -"veinule", -"veiny", -"vejoces", -"vela", -"velal", -"velamen", -"velar", -"velaric", -"velary", -"velate", -"velated", -"veldman", -"veldt", -"velic", -"veliger", -"vell", -"vellala", -"velleda", -"vellon", -"vellum", -"vellumy", -"velo", -"velours", -"velte", -"velum", -"velumen", -"velure", -"velvet", -"velvety", -"venada", -"venal", -"venally", -"venatic", -"venator", -"vencola", -"vend", -"vendace", -"vendee", -"vender", -"vending", -"vendor", -"vendue", -"veneer", -"venene", -"veneral", -"venerer", -"venery", -"venesia", -"venger", -"venial", -"venie", -"venin", -"venison", -"vennel", -"venner", -"venom", -"venomed", -"venomer", -"venomly", -"venomy", -"venosal", -"venose", -"venous", -"vent", -"ventage", -"ventail", -"venter", -"ventil", -"ventose", -"ventrad", -"ventral", -"ventric", -"venture", -"venue", -"venula", -"venular", -"venule", -"venust", -"vera", -"veranda", -"verb", -"verbal", -"verbate", -"verbena", -"verbene", -"verbid", -"verbify", -"verbile", -"verbose", -"verbous", -"verby", -"verchok", -"verd", -"verdant", -"verdea", -"verdet", -"verdict", -"verdin", -"verdoy", -"verdun", -"verdure", -"verek", -"verge", -"vergent", -"verger", -"vergery", -"vergi", -"verglas", -"veri", -"veridic", -"verify", -"verily", -"verine", -"verism", -"verist", -"verite", -"verity", -"vermeil", -"vermian", -"vermin", -"verminy", -"vermis", -"vermix", -"vernal", -"vernant", -"vernier", -"vernile", -"vernin", -"vernine", -"verre", -"verrel", -"verruca", -"verruga", -"versal", -"versant", -"versate", -"verse", -"versed", -"verser", -"verset", -"versify", -"versine", -"version", -"verso", -"versor", -"verst", -"versta", -"versual", -"versus", -"vert", -"vertex", -"vertigo", -"veruled", -"vervain", -"verve", -"vervel", -"vervet", -"very", -"vesania", -"vesanic", -"vesbite", -"vesicae", -"vesical", -"vesicle", -"veskit", -"vespal", -"vesper", -"vespers", -"vespery", -"vespid", -"vespine", -"vespoid", -"vessel", -"vest", -"vestal", -"vestee", -"vester", -"vestige", -"vesting", -"vestlet", -"vestral", -"vestry", -"vesture", -"vet", -"veta", -"vetanda", -"vetch", -"vetchy", -"veteran", -"vetiver", -"veto", -"vetoer", -"vetoism", -"vetoist", -"vetust", -"vetusty", -"veuve", -"vex", -"vexable", -"vexed", -"vexedly", -"vexer", -"vexful", -"vexil", -"vext", -"via", -"viable", -"viaduct", -"viagram", -"viajaca", -"vial", -"vialful", -"viand", -"viander", -"viatic", -"viatica", -"viator", -"vibex", -"vibgyor", -"vibix", -"vibrant", -"vibrate", -"vibrato", -"vibrion", -"vicar", -"vicarly", -"vice", -"viceroy", -"vicety", -"vicilin", -"vicinal", -"vicine", -"vicious", -"vicoite", -"victim", -"victor", -"victory", -"victrix", -"victual", -"vicuna", -"viddui", -"video", -"vidette", -"vidonia", -"vidry", -"viduage", -"vidual", -"viduate", -"viduine", -"viduity", -"viduous", -"vidya", -"vie", -"vielle", -"vier", -"viertel", -"view", -"viewer", -"viewly", -"viewy", -"vifda", -"viga", -"vigia", -"vigil", -"vignin", -"vigonia", -"vigor", -"vihara", -"vihuela", -"vijao", -"viking", -"vila", -"vilayet", -"vile", -"vilely", -"vilify", -"vility", -"vill", -"villa", -"village", -"villain", -"villar", -"villate", -"ville", -"villein", -"villoid", -"villose", -"villous", -"villus", -"vim", -"vimana", -"vimen", -"vimful", -"viminal", -"vina", -"vinage", -"vinal", -"vinasse", -"vinata", -"vincent", -"vindex", -"vine", -"vinea", -"vineal", -"vined", -"vinegar", -"vineity", -"vinelet", -"viner", -"vinery", -"vinic", -"vinny", -"vino", -"vinose", -"vinous", -"vint", -"vinta", -"vintage", -"vintem", -"vintner", -"vintry", -"viny", -"vinyl", -"vinylic", -"viol", -"viola", -"violal", -"violate", -"violent", -"violer", -"violet", -"violety", -"violin", -"violina", -"violine", -"violist", -"violon", -"violone", -"viper", -"viperan", -"viperid", -"vipery", -"viqueen", -"viragin", -"virago", -"viral", -"vire", -"virelay", -"viremia", -"viremic", -"virent", -"vireo", -"virga", -"virgal", -"virgate", -"virgin", -"virgula", -"virgule", -"virial", -"virid", -"virific", -"virify", -"virile", -"virl", -"virole", -"viroled", -"viron", -"virose", -"virosis", -"virous", -"virtu", -"virtual", -"virtue", -"virtued", -"viruela", -"virus", -"vis", -"visa", -"visage", -"visaged", -"visarga", -"viscera", -"viscid", -"viscin", -"viscose", -"viscous", -"viscus", -"vise", -"viseman", -"visible", -"visibly", -"visie", -"visile", -"vision", -"visit", -"visita", -"visite", -"visitee", -"visiter", -"visitor", -"visive", -"visne", -"vison", -"visor", -"vista", -"vistaed", -"vistal", -"visto", -"visual", -"vita", -"vital", -"vitalic", -"vitally", -"vitals", -"vitamer", -"vitamin", -"vitasti", -"vitiate", -"vitium", -"vitrage", -"vitrail", -"vitrain", -"vitraux", -"vitreal", -"vitrean", -"vitreum", -"vitric", -"vitrics", -"vitrify", -"vitrine", -"vitriol", -"vitrite", -"vitrous", -"vitta", -"vittate", -"vitular", -"viuva", -"viva", -"vivary", -"vivax", -"vive", -"vively", -"vivency", -"viver", -"vivers", -"vives", -"vivid", -"vividly", -"vivific", -"vivify", -"vixen", -"vixenly", -"vizard", -"vizier", -"vlei", -"voar", -"vocable", -"vocably", -"vocal", -"vocalic", -"vocally", -"vocate", -"vocular", -"vocule", -"vodka", -"voe", -"voet", -"voeten", -"vog", -"voglite", -"vogue", -"voguey", -"voguish", -"voice", -"voiced", -"voicer", -"voicing", -"void", -"voided", -"voidee", -"voider", -"voiding", -"voidly", -"voile", -"voivode", -"vol", -"volable", -"volage", -"volant", -"volar", -"volata", -"volatic", -"volcan", -"volcano", -"vole", -"volency", -"volent", -"volery", -"volet", -"volley", -"volost", -"volt", -"voltage", -"voltaic", -"voltize", -"voluble", -"volubly", -"volume", -"volumed", -"volupt", -"volupty", -"voluta", -"volute", -"voluted", -"volutin", -"volva", -"volvate", -"volvent", -"vomer", -"vomica", -"vomit", -"vomiter", -"vomito", -"vomitus", -"voodoo", -"vorago", -"vorant", -"vorhand", -"vorpal", -"vortex", -"vota", -"votable", -"votal", -"votally", -"votary", -"vote", -"voteen", -"voter", -"voting", -"votive", -"votress", -"vouch", -"vouchee", -"voucher", -"vouge", -"vow", -"vowed", -"vowel", -"vowely", -"vower", -"vowess", -"vowless", -"voyage", -"voyager", -"voyance", -"voyeur", -"vraic", -"vrbaite", -"vriddhi", -"vrother", -"vug", -"vuggy", -"vulgar", -"vulgare", -"vulgate", -"vulgus", -"vuln", -"vulnose", -"vulpic", -"vulpine", -"vulture", -"vulturn", -"vulva", -"vulval", -"vulvar", -"vulvate", -"vum", -"vying", -"vyingly", -"w", -"wa", -"waag", -"waapa", -"waar", -"wab", -"wabber", -"wabble", -"wabbly", -"wabby", -"wabe", -"wabeno", -"wabster", -"wacago", -"wace", -"wachna", -"wack", -"wacke", -"wacken", -"wacker", -"wacky", -"wad", -"waddent", -"wadder", -"wadding", -"waddler", -"waddly", -"waddy", -"wade", -"wader", -"wadi", -"wading", -"wadlike", -"wadmal", -"wadmeal", -"wadna", -"wadset", -"wae", -"waeg", -"waer", -"waesome", -"waesuck", -"wafer", -"waferer", -"wafery", -"waff", -"waffle", -"waffly", -"waft", -"waftage", -"wafter", -"wafture", -"wafty", -"wag", -"wagaun", -"wage", -"waged", -"wagedom", -"wager", -"wagerer", -"wages", -"waggel", -"wagger", -"waggery", -"waggie", -"waggish", -"waggle", -"waggly", -"waggy", -"waglike", -"wagling", -"wagon", -"wagoner", -"wagonry", -"wagsome", -"wagtail", -"wagwag", -"wagwit", -"wah", -"wahahe", -"wahine", -"wahoo", -"waiata", -"waif", -"waik", -"waikly", -"wail", -"wailer", -"wailful", -"waily", -"wain", -"wainage", -"wainer", -"wainful", -"wainman", -"waipiro", -"wairch", -"waird", -"wairepo", -"wairsh", -"waise", -"waist", -"waisted", -"waister", -"wait", -"waiter", -"waiting", -"waive", -"waiver", -"waivery", -"waivod", -"waiwode", -"wajang", -"waka", -"wakan", -"wake", -"wakeel", -"wakeful", -"waken", -"wakener", -"waker", -"wakes", -"wakf", -"wakif", -"wakiki", -"waking", -"wakiup", -"wakken", -"wakon", -"wakonda", -"waky", -"walahee", -"wale", -"waled", -"waler", -"wali", -"waling", -"walk", -"walker", -"walking", -"walkist", -"walkout", -"walkway", -"wall", -"wallaba", -"wallaby", -"wallah", -"walled", -"waller", -"wallet", -"walleye", -"wallful", -"walling", -"wallise", -"wallman", -"walloon", -"wallop", -"wallow", -"wally", -"walnut", -"walrus", -"walsh", -"walt", -"walter", -"walth", -"waltz", -"waltzer", -"wamara", -"wambais", -"wamble", -"wambly", -"wame", -"wamefou", -"wamel", -"wamp", -"wampee", -"wample", -"wampum", -"wampus", -"wamus", -"wan", -"wand", -"wander", -"wandery", -"wandle", -"wandoo", -"wandy", -"wane", -"waned", -"wang", -"wanga", -"wangala", -"wangan", -"wanghee", -"wangle", -"wangler", -"wanhope", -"wanhorn", -"wanigan", -"waning", -"wankle", -"wankly", -"wanle", -"wanly", -"wanner", -"wanness", -"wannish", -"wanny", -"wanrufe", -"want", -"wantage", -"wanter", -"wantful", -"wanting", -"wanton", -"wantwit", -"wanty", -"wany", -"wap", -"wapacut", -"wapatoo", -"wapiti", -"wapp", -"wapper", -"wapping", -"war", -"warabi", -"waratah", -"warble", -"warbled", -"warbler", -"warblet", -"warbly", -"warch", -"ward", -"wardage", -"warday", -"warded", -"warden", -"warder", -"warding", -"wardite", -"wardman", -"ware", -"warehou", -"wareman", -"warf", -"warfare", -"warful", -"warily", -"warish", -"warison", -"wark", -"warl", -"warless", -"warlike", -"warlock", -"warluck", -"warly", -"warm", -"warman", -"warmed", -"warmer", -"warmful", -"warming", -"warmish", -"warmly", -"warmth", -"warmus", -"warn", -"warnel", -"warner", -"warning", -"warnish", -"warnoth", -"warnt", -"warp", -"warpage", -"warped", -"warper", -"warping", -"warple", -"warran", -"warrand", -"warrant", -"warree", -"warren", -"warrer", -"warrin", -"warrior", -"warrok", -"warsaw", -"warse", -"warsel", -"warship", -"warsle", -"warsler", -"warst", -"wart", -"warted", -"wartern", -"warth", -"wartime", -"wartlet", -"warty", -"warve", -"warwolf", -"warworn", -"wary", -"was", -"wasabi", -"wase", -"wasel", -"wash", -"washday", -"washed", -"washen", -"washer", -"washery", -"washin", -"washing", -"washman", -"washoff", -"washout", -"washpot", -"washrag", -"washtub", -"washway", -"washy", -"wasnt", -"wasp", -"waspen", -"waspily", -"waspish", -"waspy", -"wassail", -"wassie", -"wast", -"wastage", -"waste", -"wasted", -"wastel", -"waster", -"wasting", -"wastrel", -"wasty", -"wat", -"watap", -"watch", -"watched", -"watcher", -"water", -"watered", -"waterer", -"waterie", -"watery", -"wath", -"watt", -"wattage", -"wattape", -"wattle", -"wattled", -"wattman", -"wauble", -"wauch", -"wauchle", -"waucht", -"wauf", -"waugh", -"waughy", -"wauken", -"waukit", -"waul", -"waumle", -"wauner", -"wauns", -"waup", -"waur", -"wauve", -"wavable", -"wavably", -"wave", -"waved", -"wavelet", -"waver", -"waverer", -"wavery", -"waveson", -"wavey", -"wavicle", -"wavily", -"waving", -"wavy", -"waw", -"wawa", -"wawah", -"wax", -"waxbill", -"waxbird", -"waxbush", -"waxen", -"waxer", -"waxily", -"waxing", -"waxlike", -"waxman", -"waxweed", -"waxwing", -"waxwork", -"waxy", -"way", -"wayaka", -"wayang", -"wayback", -"waybill", -"waybird", -"waybook", -"waybung", -"wayfare", -"waygang", -"waygate", -"waygone", -"waying", -"waylaid", -"waylay", -"wayless", -"wayman", -"waymark", -"waymate", -"waypost", -"ways", -"wayside", -"wayward", -"waywode", -"wayworn", -"waywort", -"we", -"weak", -"weaken", -"weakish", -"weakly", -"weaky", -"weal", -"weald", -"wealth", -"wealthy", -"weam", -"wean", -"weanel", -"weaner", -"weanyer", -"weapon", -"wear", -"wearer", -"wearied", -"wearier", -"wearily", -"wearing", -"wearish", -"weary", -"weasand", -"weasel", -"weaser", -"weason", -"weather", -"weave", -"weaved", -"weaver", -"weaving", -"weazen", -"weazeny", -"web", -"webbed", -"webber", -"webbing", -"webby", -"weber", -"webeye", -"webfoot", -"webless", -"weblike", -"webster", -"webwork", -"webworm", -"wecht", -"wed", -"wedana", -"wedbed", -"wedded", -"wedder", -"wedding", -"wede", -"wedge", -"wedged", -"wedger", -"wedging", -"wedgy", -"wedlock", -"wedset", -"wee", -"weeble", -"weed", -"weeda", -"weedage", -"weeded", -"weeder", -"weedery", -"weedful", -"weedish", -"weedow", -"weedy", -"week", -"weekday", -"weekend", -"weekly", -"weekwam", -"weel", -"weemen", -"ween", -"weeness", -"weening", -"weenong", -"weeny", -"weep", -"weeper", -"weepful", -"weeping", -"weeps", -"weepy", -"weesh", -"weeshy", -"weet", -"weever", -"weevil", -"weevily", -"weewow", -"weeze", -"weft", -"weftage", -"wefted", -"wefty", -"weigh", -"weighed", -"weigher", -"weighin", -"weight", -"weighty", -"weir", -"weird", -"weirdly", -"weiring", -"weism", -"wejack", -"weka", -"wekau", -"wekeen", -"weki", -"welcome", -"weld", -"welder", -"welding", -"weldor", -"welfare", -"welk", -"welkin", -"well", -"wellat", -"welling", -"wellish", -"wellman", -"welly", -"wels", -"welsh", -"welsher", -"welsium", -"welt", -"welted", -"welter", -"welting", -"wem", -"wemless", -"wen", -"wench", -"wencher", -"wend", -"wende", -"wene", -"wennish", -"wenny", -"went", -"wenzel", -"wept", -"wer", -"were", -"werefox", -"werent", -"werf", -"wergil", -"weri", -"wert", -"wervel", -"wese", -"weskit", -"west", -"weste", -"wester", -"western", -"westing", -"westy", -"wet", -"weta", -"wetback", -"wetbird", -"wetched", -"wetchet", -"wether", -"wetly", -"wetness", -"wetted", -"wetter", -"wetting", -"wettish", -"weve", -"wevet", -"wey", -"wha", -"whabby", -"whack", -"whacker", -"whacky", -"whale", -"whaler", -"whalery", -"whaling", -"whalish", -"whally", -"whalm", -"whalp", -"whaly", -"wham", -"whamble", -"whame", -"whammle", -"whamp", -"whampee", -"whample", -"whan", -"whand", -"whang", -"whangam", -"whangee", -"whank", -"whap", -"whappet", -"whapuka", -"whapuku", -"whar", -"whare", -"whareer", -"wharf", -"wharl", -"wharp", -"wharry", -"whart", -"wharve", -"whase", -"whasle", -"what", -"whata", -"whatkin", -"whatna", -"whatnot", -"whats", -"whatso", -"whatten", -"whau", -"whauk", -"whaup", -"whaur", -"whauve", -"wheal", -"whealy", -"wheam", -"wheat", -"wheaten", -"wheaty", -"whedder", -"whee", -"wheedle", -"wheel", -"wheeled", -"wheeler", -"wheely", -"wheem", -"wheen", -"wheenge", -"wheep", -"wheeple", -"wheer", -"wheesht", -"wheetle", -"wheeze", -"wheezer", -"wheezle", -"wheezy", -"wheft", -"whein", -"whekau", -"wheki", -"whelk", -"whelked", -"whelker", -"whelky", -"whelm", -"whelp", -"whelve", -"whemmel", -"when", -"whenas", -"whence", -"wheneer", -"whenso", -"where", -"whereas", -"whereat", -"whereby", -"whereer", -"wherein", -"whereof", -"whereon", -"whereso", -"whereto", -"whereup", -"wherret", -"wherrit", -"wherry", -"whet", -"whether", -"whetile", -"whetter", -"whew", -"whewer", -"whewl", -"whewt", -"whey", -"wheyey", -"wheyish", -"whiba", -"which", -"whick", -"whicken", -"whicker", -"whid", -"whidah", -"whidder", -"whiff", -"whiffer", -"whiffet", -"whiffle", -"whiffy", -"whift", -"whig", -"while", -"whileen", -"whilere", -"whiles", -"whilie", -"whilk", -"whill", -"whilly", -"whilock", -"whilom", -"whils", -"whilst", -"whilter", -"whim", -"whimble", -"whimmy", -"whimper", -"whimsey", -"whimsic", -"whin", -"whincow", -"whindle", -"whine", -"whiner", -"whing", -"whinge", -"whinger", -"whinnel", -"whinner", -"whinny", -"whiny", -"whip", -"whipcat", -"whipman", -"whippa", -"whipped", -"whipper", -"whippet", -"whippy", -"whipsaw", -"whipt", -"whir", -"whirken", -"whirl", -"whirled", -"whirler", -"whirley", -"whirly", -"whirret", -"whirrey", -"whirroo", -"whirry", -"whirtle", -"whish", -"whisk", -"whisker", -"whiskey", -"whisky", -"whisp", -"whisper", -"whissle", -"whist", -"whister", -"whistle", -"whistly", -"whit", -"white", -"whited", -"whitely", -"whiten", -"whites", -"whither", -"whiting", -"whitish", -"whitlow", -"whits", -"whittaw", -"whitten", -"whitter", -"whittle", -"whity", -"whiz", -"whizgig", -"whizzer", -"whizzle", -"who", -"whoa", -"whoever", -"whole", -"wholly", -"whom", -"whomble", -"whomso", -"whone", -"whoo", -"whoof", -"whoop", -"whoopee", -"whooper", -"whoops", -"whoosh", -"whop", -"whopper", -"whorage", -"whore", -"whorish", -"whorl", -"whorled", -"whorly", -"whort", -"whortle", -"whose", -"whosen", -"whud", -"whuff", -"whuffle", -"whulk", -"whulter", -"whummle", -"whun", -"whup", -"whush", -"whuskie", -"whussle", -"whute", -"whuther", -"whutter", -"whuz", -"why", -"whyever", -"whyfor", -"whyness", -"whyo", -"wi", -"wice", -"wicht", -"wichtje", -"wick", -"wicked", -"wicken", -"wicker", -"wicket", -"wicking", -"wickiup", -"wickup", -"wicky", -"wicopy", -"wid", -"widbin", -"widder", -"widdle", -"widdy", -"wide", -"widegab", -"widely", -"widen", -"widener", -"widgeon", -"widish", -"widow", -"widowed", -"widower", -"widowly", -"widowy", -"width", -"widu", -"wield", -"wielder", -"wieldy", -"wiener", -"wienie", -"wife", -"wifedom", -"wifeism", -"wifekin", -"wifelet", -"wifely", -"wifie", -"wifish", -"wifock", -"wig", -"wigan", -"wigdom", -"wigful", -"wigged", -"wiggen", -"wigger", -"wiggery", -"wigging", -"wiggish", -"wiggism", -"wiggle", -"wiggler", -"wiggly", -"wiggy", -"wight", -"wightly", -"wigless", -"wiglet", -"wiglike", -"wigtail", -"wigwag", -"wigwam", -"wiikite", -"wild", -"wildcat", -"wilded", -"wilder", -"wilding", -"wildish", -"wildly", -"wile", -"wileful", -"wilga", -"wilgers", -"wilily", -"wilk", -"wilkin", -"will", -"willawa", -"willed", -"willer", -"willet", -"willey", -"willful", -"willie", -"willier", -"willies", -"willing", -"willock", -"willow", -"willowy", -"willy", -"willyer", -"wilsome", -"wilt", -"wilter", -"wily", -"wim", -"wimble", -"wimbrel", -"wime", -"wimick", -"wimple", -"win", -"wince", -"wincer", -"wincey", -"winch", -"wincher", -"wincing", -"wind", -"windage", -"windbag", -"winddog", -"winded", -"winder", -"windigo", -"windily", -"winding", -"windle", -"windles", -"windlin", -"windock", -"windore", -"window", -"windowy", -"windrow", -"windup", -"windway", -"windy", -"wine", -"wined", -"winemay", -"winepot", -"winer", -"winery", -"winesop", -"winevat", -"winful", -"wing", -"wingcut", -"winged", -"winger", -"wingle", -"winglet", -"wingman", -"wingy", -"winish", -"wink", -"winkel", -"winker", -"winking", -"winkle", -"winklet", -"winly", -"winna", -"winnard", -"winnel", -"winner", -"winning", -"winnle", -"winnow", -"winrace", -"winrow", -"winsome", -"wint", -"winter", -"wintle", -"wintry", -"winy", -"winze", -"wipe", -"wiper", -"wippen", -"wips", -"wir", -"wirable", -"wirble", -"wird", -"wire", -"wirebar", -"wired", -"wireman", -"wirer", -"wireway", -"wirily", -"wiring", -"wirl", -"wirling", -"wirr", -"wirra", -"wirrah", -"wiry", -"wis", -"wisdom", -"wise", -"wisely", -"wiseman", -"wisen", -"wisent", -"wiser", -"wish", -"wisha", -"wished", -"wisher", -"wishful", -"wishing", -"wishly", -"wishmay", -"wisht", -"wisket", -"wisp", -"wispish", -"wispy", -"wiss", -"wisse", -"wissel", -"wist", -"wiste", -"wistful", -"wistit", -"wistiti", -"wit", -"witan", -"witch", -"witched", -"witchen", -"witchet", -"witchy", -"wite", -"witess", -"witful", -"with", -"withal", -"withe", -"withen", -"wither", -"withers", -"withery", -"within", -"without", -"withy", -"witjar", -"witless", -"witlet", -"witling", -"witloof", -"producer", -"witney", -"witship", -"wittal", -"witted", -"witter", -"wittily", -"witting", -"wittol", -"witty", -"witwall", -"wive", -"wiver", -"wivern", -"wiz", -"wizard", -"wizen", -"wizened", -"wizier", -"wizzen", -"wloka", -"wo", -"woad", -"woader", -"woadman", -"woady", -"woak", -"woald", -"woan", -"wob", -"wobble", -"wobbler", -"wobbly", -"wobster", -"wod", -"woddie", -"wode", -"wodge", -"wodgy", -"woe", -"woeful", -"woesome", -"woevine", -"woeworn", -"woffler", -"woft", -"wog", -"wogiet", -"woibe", -"wokas", -"woke", -"wokowi", -"wold", -"woldy", -"wolf", -"wolfdom", -"wolfen", -"wolfer", -"wolfish", -"wolfkin", -"wolfram", -"wollop", -"wolter", -"wolve", -"wolver", -"woman", -"womanly", -"womb", -"wombat", -"wombed", -"womble", -"womby", -"womera", -"won", -"wonder", -"wone", -"wonegan", -"wong", -"wonga", -"wongen", -"wongshy", -"wongsky", -"woning", -"wonky", -"wonna", -"wonned", -"wonner", -"wonning", -"wonnot", -"wont", -"wonted", -"wonting", -"woo", -"wooable", -"wood", -"woodbin", -"woodcut", -"wooded", -"wooden", -"woodeny", -"woodine", -"wooding", -"woodish", -"woodlet", -"woodly", -"woodman", -"woodrow", -"woodsy", -"woodwax", -"woody", -"wooer", -"woof", -"woofed", -"woofell", -"woofer", -"woofy", -"woohoo", -"wooing", -"wool", -"woold", -"woolder", -"wooled", -"woolen", -"wooler", -"woolert", -"woolly", -"woolman", -"woolsey", -"woom", -"woomer", -"woon", -"woons", -"woorali", -"woorari", -"woosh", -"wootz", -"woozle", -"woozy", -"wop", -"woppish", -"wops", -"worble", -"word", -"wordage", -"worded", -"worder", -"wordily", -"wording", -"wordish", -"wordle", -"wordman", -"wordy", -"wore", -"work", -"workbag", -"workbox", -"workday", -"worked", -"worker", -"working", -"workman", -"workout", -"workpan", -"works", -"worky", -"world", -"worlded", -"worldly", -"worldy", -"worm", -"wormed", -"wormer", -"wormil", -"worming", -"wormy", -"worn", -"wornil", -"worral", -"worried", -"worrier", -"worrit", -"worry", -"worse", -"worsen", -"worser", -"worset", -"worship", -"worst", -"worsted", -"wort", -"worth", -"worthy", -"wosbird", -"wot", -"wote", -"wots", -"wottest", -"wotteth", -"woubit", -"wouch", -"wouf", -"wough", -"would", -"wouldnt", -"wouldst", -"wound", -"wounded", -"wounder", -"wounds", -"woundy", -"wourali", -"wourari", -"wournil", -"wove", -"woven", -"wow", -"wowser", -"wowsery", -"wowt", -"woy", -"wrack", -"wracker", -"wraggle", -"wraith", -"wraithe", -"wraithy", -"wraitly", -"wramp", -"wran", -"wrang", -"wrangle", -"wranny", -"wrap", -"wrapped", -"wrapper", -"wrasse", -"wrastle", -"wrath", -"wrathy", -"wraw", -"wrawl", -"wrawler", -"wraxle", -"wreak", -"wreat", -"wreath", -"wreathe", -"wreathy", -"wreck", -"wrecker", -"wrecky", -"wren", -"wrench", -"wrenlet", -"wrest", -"wrester", -"wrestle", -"wretch", -"wricht", -"wrick", -"wride", -"wried", -"wrier", -"wriest", -"wrig", -"wriggle", -"wriggly", -"wright", -"wring", -"wringer", -"wrinkle", -"wrinkly", -"wrist", -"wristed", -"wrister", -"writ", -"write", -"writee", -"writer", -"writh", -"writhe", -"writhed", -"writhen", -"writher", -"writhy", -"writing", -"written", -"writter", -"wrive", -"wro", -"wrocht", -"wroke", -"wroken", -"wrong", -"wronged", -"wronger", -"wrongly", -"wrossle", -"wrote", -"wroth", -"wrothly", -"wrothy", -"wrought", -"wrox", -"wrung", -"wry", -"wrybill", -"wryly", -"wryneck", -"wryness", -"wrytail", -"wud", -"wuddie", -"wudge", -"wudu", -"wugg", -"wulk", -"wull", -"wullcat", -"wulliwa", -"wumble", -"wumman", -"wummel", -"wun", -"wungee", -"wunna", -"wunner", -"wunsome", -"wup", -"wur", -"wurley", -"wurmal", -"wurrus", -"wurset", -"wurzel", -"wush", -"wusp", -"wuss", -"wusser", -"wust", -"wut", -"wuther", -"wuzu", -"wuzzer", -"wuzzle", -"wuzzy", -"wy", -"wyde", -"wye", -"wyke", -"wyle", -"wymote", -"wyn", -"wynd", -"wyne", -"wynn", -"wype", -"wyson", -"wyss", -"wyve", -"wyver", -"x", -"xanthic", -"xanthin", -"xanthyl", -"xarque", -"xebec", -"xenia", -"xenial", -"xenian", -"xenium", -"xenon", -"xenyl", -"xerafin", -"xerarch", -"xerasia", -"xeric", -"xeriff", -"xerogel", -"xeroma", -"xeronic", -"xerosis", -"xerotes", -"xerotic", -"xi", -"xiphias", -"xiphiid", -"xiphoid", -"xoana", -"xoanon", -"xurel", -"xyla", -"xylan", -"xylate", -"xylem", -"xylene", -"xylenol", -"xylenyl", -"xyletic", -"xylic", -"xylidic", -"xylinid", -"xylite", -"xylitol", -"xylogen", -"xyloid", -"xylol", -"xyloma", -"xylon", -"xylonic", -"xylose", -"xyloyl", -"xylyl", -"xylylic", -"xyphoid", -"xyrid", -"xyst", -"xyster", -"xysti", -"xystos", -"xystum", -"xystus", -"y", -"ya", -"yaba", -"yabber", -"yabbi", -"yabble", -"yabby", -"yabu", -"yacal", -"yacca", -"yachan", -"yacht", -"yachter", -"yachty", -"yad", -"yade", -"yaff", -"yaffle", -"yagger", -"yagi", -"yagua", -"yaguaza", -"yah", -"yahan", -"yahoo", -"yair", -"yaird", -"yaje", -"yajeine", -"yak", -"yakalo", -"yakamik", -"yakin", -"yakka", -"yakman", -"yalb", -"yale", -"yali", -"yalla", -"yallaer", -"yallow", -"yam", -"yamamai", -"yamanai", -"yamen", -"yamilke", -"yammer", -"yamp", -"yampa", -"yamph", -"yamshik", -"yan", -"yander", -"yang", -"yangtao", -"yank", -"yanking", -"yanky", -"yaoort", -"yaourti", -"yap", -"yapa", -"yaply", -"yapness", -"yapok", -"yapp", -"yapped", -"yapper", -"yapping", -"yappish", -"yappy", -"yapster", -"yar", -"yarak", -"yaray", -"yarb", -"yard", -"yardage", -"yardang", -"yardarm", -"yarder", -"yardful", -"yarding", -"yardman", -"yare", -"yareta", -"yark", -"yarke", -"yarl", -"yarly", -"yarm", -"yarn", -"yarnen", -"yarner", -"yarpha", -"yarr", -"yarran", -"yarrow", -"yarth", -"yarthen", -"yarwhip", -"yas", -"yashiro", -"yashmak", -"yat", -"yate", -"yati", -"yatter", -"yaud", -"yauld", -"yaupon", -"yautia", -"yava", -"yaw", -"yawl", -"yawler", -"yawn", -"yawner", -"yawney", -"yawnful", -"yawnily", -"yawning", -"yawnups", -"yawny", -"yawp", -"yawper", -"yawroot", -"yaws", -"yawweed", -"yawy", -"yaxche", -"yaya", -"ycie", -"yday", -"ye", -"yea", -"yeah", -"yealing", -"yean", -"year", -"yeara", -"yeard", -"yearday", -"yearful", -"yearly", -"yearn", -"yearock", -"yearth", -"yeast", -"yeasty", -"yeat", -"yeather", -"yed", -"yede", -"yee", -"yeel", -"yees", -"yegg", -"yeggman", -"yeguita", -"yeld", -"yeldrin", -"yelk", -"yell", -"yeller", -"yelling", -"yelloch", -"yellow", -"yellows", -"yellowy", -"yelm", -"yelmer", -"yelp", -"yelper", -"yelt", -"yen", -"yender", -"yeni", -"yenite", -"yeo", -"yeoman", -"yep", -"yer", -"yerb", -"yerba", -"yercum", -"yerd", -"yere", -"yerga", -"yerk", -"yern", -"yerth", -"yes", -"yese", -"yeso", -"yesso", -"yest", -"yester", -"yestern", -"yesty", -"yet", -"yeta", -"yetapa", -"yeth", -"yether", -"yetlin", -"yeuk", -"yeuky", -"yeven", -"yew", -"yex", -"yez", -"yezzy", -"ygapo", -"yield", -"yielden", -"yielder", -"yieldy", -"yigh", -"yill", -"yilt", -"yin", -"yince", -"yinst", -"yip", -"yird", -"yirk", -"yirm", -"yirn", -"yirr", -"yirth", -"yis", -"yite", -"ym", -"yn", -"ynambu", -"yo", -"yobi", -"yocco", -"yochel", -"yock", -"yockel", -"yodel", -"yodeler", -"yodh", -"yoe", -"yoga", -"yogh", -"yoghurt", -"yogi", -"yogin", -"yogism", -"yogist", -"yogoite", -"yohimbe", -"yohimbi", -"yoi", -"yoick", -"yoicks", -"yojan", -"yojana", -"yok", -"yoke", -"yokeage", -"yokel", -"yokelry", -"yoker", -"yoking", -"yoky", -"yolden", -"yolk", -"yolked", -"yolky", -"yom", -"yomer", -"yon", -"yond", -"yonder", -"yonner", -"yonside", -"yont", -"yook", -"yoop", -"yor", -"yore", -"york", -"yorker", -"yot", -"yote", -"you", -"youd", -"youden", -"youdith", -"youff", -"youl", -"young", -"younger", -"youngly", -"youngun", -"younker", -"youp", -"your", -"yourn", -"yours", -"yoursel", -"youse", -"youth", -"youthen", -"youthy", -"youve", -"youward", -"youze", -"yoven", -"yow", -"yowie", -"yowl", -"yowler", -"yowley", -"yowt", -"yox", -"yoy", -"yperite", -"yr", -"yttria", -"yttric", -"yttrium", -"yuan", -"yuca", -"yucca", -"yuck", -"yuckel", -"yucker", -"yuckle", -"yucky", -"yuft", -"yugada", -"yuh", -"yukkel", -"yulan", -"yule", -"yummy", -"yungan", -"yurt", -"yurta", -"yus", -"yusdrum", -"yutu", -"yuzlik", -"yuzluk", -"z", -"za", -"zabeta", -"zabra", -"zabti", -"zabtie", -"zac", -"zacate", -"zacaton", -"zachun", -"zad", -"zadruga", -"zaffar", -"zaffer", -"zafree", -"zag", -"zagged", -"zain", -"zak", -"zakkeu", -"zaman", -"zamang", -"zamarra", -"zamarro", -"zambo", -"zamorin", -"zamouse", -"zander", -"zanella", -"zant", -"zante", -"zany", -"zanyish", -"zanyism", -"zanze", -"zapas", -"zaphara", -"zapota", -"zaptiah", -"zaptieh", -"zapupe", -"zaqqum", -"zar", -"zareba", -"zarf", -"zarnich", -"zarp", -"zat", -"zati", -"zattare", -"zax", -"zayat", -"zayin", -"zeal", -"zealful", -"zealot", -"zealous", -"zebra", -"zebraic", -"zebrass", -"zebrine", -"zebroid", -"zebrula", -"zebrule", -"zebu", -"zebub", -"zeburro", -"zechin", -"zed", -"zedoary", -"zee", -"zeed", -"zehner", -"zein", -"zeism", -"zeist", -"zel", -"zelator", -"zemeism", -"zemi", -"zemmi", -"zemni", -"zemstvo", -"zenana", -"zendik", -"zenick", -"zenith", -"zenu", -"zeolite", -"zephyr", -"zephyry", -"zequin", -"zer", -"zerda", -"zero", -"zeroize", -"zest", -"zestful", -"zesty", -"zeta", -"zetetic", -"zeugma", -"ziamet", -"ziara", -"ziarat", -"zibet", -"zibetum", -"ziega", -"zieger", -"ziffs", -"zig", -"ziganka", -"zigzag", -"zihar", -"zikurat", -"zillah", -"zimarra", -"zimb", -"zimbi", -"zimme", -"zimmi", -"zimmis", -"zimocca", -"zinc", -"zincate", -"zincic", -"zincide", -"zincify", -"zincing", -"zincite", -"zincize", -"zincke", -"zincky", -"zinco", -"zincous", -"zincum", -"zing", -"zingel", -"zink", -"zinsang", -"zip", -"ziphian", -"zipper", -"zipping", -"zippy", -"zira", -"zirai", -"zircite", -"zircon", -"zither", -"zizz", -"zloty", -"zo", -"zoa", -"zoacum", -"zoaria", -"zoarial", -"zoarium", -"zobo", -"zocco", -"zoccolo", -"zodiac", -"zoea", -"zoeal", -"zoeform", -"zoetic", -"zogan", -"zogo", -"zoic", -"zoid", -"zoisite", -"zoism", -"zoist", -"zoistic", -"zokor", -"zoll", -"zolle", -"zombi", -"zombie", -"zonal", -"zonally", -"zonar", -"zonary", -"zonate", -"zonated", -"zone", -"zoned", -"zonelet", -"zonic", -"zoning", -"zonite", -"zonitid", -"zonoid", -"zonular", -"zonule", -"zonulet", -"zonure", -"zonurid", -"zoo", -"zoocarp", -"zoocyst", -"zooecia", -"zoogamy", -"zoogene", -"zoogeny", -"zoogony", -"zooid", -"zooidal", -"zooks", -"zoolite", -"zoolith", -"zoology", -"zoom", -"zoon", -"zoonal", -"zoonic", -"zoonist", -"zoonite", -"zoonomy", -"zoons", -"zoonule", -"zoopery", -"zoopsia", -"zoosis", -"zootaxy", -"zooter", -"zootic", -"zootomy", -"zootype", -"zoozoo", -"zorgite", -"zoril", -"zorilla", -"zorillo", -"zorro", -"zoster", -"zounds", -"zowie", -"zudda", -"zuisin", -"zumatic", -"zunyite", -"zuza", -"zwitter", -"zyga", -"zygal", -"zygion", -"zygite", -"zygoma", -"zygon", -"zygose", -"zygosis", -"zygote", -"zygotic", -"zygous", -"zymase", -"zyme", -"zymic", -"zymin", -"zymite", -"zymogen", -"zymoid", -"zymome", -"zymomin", -"zymosis", -"zymotic", -"zymurgy", -"zythem", -"zythum" }; - - -const uint32_t word_list_size = sizeof(word_list)/sizeof(word_list[0]); - -void hide_unused_warning() { - (void)word_list_size; - (void)word_list; -} - -} } // eosio::words diff --git a/libraries/wabt b/libraries/wabt index 2f5382661f7..bf353aa719c 160000 --- a/libraries/wabt +++ b/libraries/wabt @@ -1 +1 @@ -Subproject commit 2f5382661f7bf77cf7a70dcf0543a44fd5025910 +Subproject commit bf353aa719c88b7152ee09e7f877a507cb7df27b diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9d4a6ab93b3..0b42bdf41b0 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(producer_plugin) add_subdirectory(producer_api_plugin) add_subdirectory(history_plugin) add_subdirectory(history_api_plugin) +add_subdirectory(state_history_plugin) add_subdirectory(wallet_plugin) add_subdirectory(wallet_api_plugin) diff --git a/plugins/bnet_plugin/bnet_plugin.cpp b/plugins/bnet_plugin/bnet_plugin.cpp index 4052fce2b30..392df4b31eb 100644 --- a/plugins/bnet_plugin/bnet_plugin.cpp +++ b/plugins/bnet_plugin/bnet_plugin.cpp @@ -306,7 +306,7 @@ namespace eosio { int next_session_id()const { - static int session_count = 0; + static std::atomic session_count(0); return ++session_count; } @@ -788,7 +788,7 @@ namespace eosio { /// if something changed, the next block doesn't link to the last /// block we sent, local chain must have switched forks - if( nextblock->previous != _last_sent_block_id ) { + if( nextblock->previous != _last_sent_block_id && _last_sent_block_id != block_id_type() ) { if( !is_known_by_peer( nextblock->previous ) ) { _last_sent_block_id = _local_lib_id; _last_sent_block_num = _local_lib; @@ -1041,26 +1041,7 @@ namespace eosio { return false; } - void on( const packed_transaction_ptr& p ) { - peer_ilog(this, "received packed_transaction_ptr"); - if (!p) { - peer_elog(this, "bad packed_transaction_ptr : null pointer"); - EOS_THROW(transaction_exception, "bad transaction"); - } - if( app().get_plugin().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) - return; - - // ilog( "recv trx ${n}", ("n", id) ); - if( p->expiration() < fc::time_point::now() ) return; - - // get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state - const auto& id = p->get_uncached_id(); - - if( mark_transaction_known_by_peer( id ) ) - return; - - app().get_channel().publish(p); - } + void on( const packed_transaction_ptr& p ); void on_write( boost::system::error_code ec, std::size_t bytes_transferred ) { boost::ignore_unused(bytes_transferred); @@ -1402,8 +1383,10 @@ namespace eosio { if( app().get_plugin().chain().get_read_mode() == chain::db_read_mode::READ_ONLY ) { - my->_request_trx = false; - ilog( "setting bnet-no-trx to true since in read-only mode" ); + if (my->_request_trx) { + my->_request_trx = false; + ilog( "forced bnet-no-trx to true since in read-only mode" ); + } } const auto address = boost::asio::ip::make_address( my->_bnet_endpoint_address ); @@ -1557,4 +1540,24 @@ namespace eosio { } + void session::on( const packed_transaction_ptr& p ) { + peer_ilog(this, "received packed_transaction_ptr"); + if (!p) { + peer_elog(this, "bad packed_transaction_ptr : null pointer"); + EOS_THROW(transaction_exception, "bad transaction"); + } + if( !_net_plugin->_request_trx ) + return; + + // ilog( "recv trx ${n}", ("n", id) ); + if( p->expiration() < fc::time_point::now() ) return; + + // get id via get_uncached_id() as packed_transaction.id() mutates internal transaction state + const auto& id = p->get_uncached_id(); + + if( mark_transaction_known_by_peer( id ) ) + return; + + app().get_channel().publish(p); + } } /// namespace eosio diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 2603a87178b..ad67318528b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -18,10 +18,6 @@ #include -#include -#include -#include - #include #include #include @@ -222,6 +218,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") ("reversible-blocks-db-size-mb", bpo::value()->default_value(config::default_reversible_cache_size / (1024 * 1024)), "Maximum size (in MiB) of the reversible blocks database") ("reversible-blocks-db-guard-size-mb", bpo::value()->default_value(config::default_reversible_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the reverseible blocks database drops below this size (in MiB).") + ("chain-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), + "Number of worker threads in controller thread pool") ("contracts-console", bpo::bool_switch()->default_value(false), "print contract's output to console") ("actor-whitelist", boost::program_options::value>()->composing()->multitoken(), @@ -236,6 +234,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip "Action (in the form code::action) added to action blacklist (may specify multiple times)") ("key-blacklist", boost::program_options::value>()->composing()->multitoken(), "Public key added to blacklist of keys that should not be included in authorities (may specify multiple times)") + ("sender-bypass-whiteblacklist", boost::program_options::value>()->composing()->multitoken(), + "Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times)") ("read-mode", boost::program_options::value()->default_value(eosio::chain::db_read_mode::SPECULATIVE), "Database read mode (\"speculative\", \"head\", or \"read-only\").\n"// or \"irreversible\").\n" "In \"speculative\" mode database contains changes done up to the head block plus changes made by transactions not yet included to the blockchain.\n" @@ -343,6 +343,7 @@ void chain_plugin::plugin_initialize(const variables_map& options) { my->chain_config = controller::config(); + LOAD_VALUE_SET( options, "sender-bypass-whiteblacklist", my->chain_config->sender_bypass_whiteblacklist ); LOAD_VALUE_SET( options, "actor-whitelist", my->chain_config->actor_whitelist ); LOAD_VALUE_SET( options, "actor-blacklist", my->chain_config->actor_blacklist ); LOAD_VALUE_SET( options, "contract-whitelist", my->chain_config->contract_whitelist ); @@ -419,6 +420,12 @@ void chain_plugin::plugin_initialize(const variables_map& options) { if( options.count( "reversible-blocks-db-guard-size-mb" )) my->chain_config->reversible_guard_size = options.at( "reversible-blocks-db-guard-size-mb" ).as() * 1024 * 1024; + if( options.count( "chain-threads" )) { + my->chain_config->thread_pool_size = options.at( "chain-threads" ).as(); + EOS_ASSERT( my->chain_config->thread_pool_size > 0, plugin_config_exception, + "chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) ); + } + if( my->wasm_runtime ) my->chain_config->wasm_runtime = *my->wasm_runtime; @@ -565,12 +572,17 @@ void chain_plugin::plugin_initialize(const variables_map& options) { } } else { - if( options.count( "genesis-json" )) { - EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ), - plugin_config_exception, - "Genesis state can only be set on a fresh blockchain." ); + bfs::path genesis_file; + bool genesis_timestamp_specified = false; + fc::optional existing_genesis; - auto genesis_file = options.at( "genesis-json" ).as(); + if( fc::exists( my->blocks_dir / "blocks.log" ) ) { + my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir ); + existing_genesis = my->chain_config->genesis; + } + + if( options.count( "genesis-json" )) { + genesis_file = options.at( "genesis-json" ).as(); if( genesis_file.is_relative()) { genesis_file = bfs::current_path() / genesis_file; } @@ -581,28 +593,32 @@ void chain_plugin::plugin_initialize(const variables_map& options) { ("genesis", genesis_file.generic_string())); my->chain_config->genesis = fc::json::from_file( genesis_file ).as(); + } - ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string())); + if( options.count( "genesis-timestamp" ) ) { + my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( options.at( "genesis-timestamp" ).as() ); + genesis_timestamp_specified = true; + } - if( options.count( "genesis-timestamp" )) { - my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( - options.at( "genesis-timestamp" ).as()); + if( !existing_genesis ) { + if( !genesis_file.empty() ) { + if( genesis_timestamp_specified ) { + ilog( "Using genesis state provided in '${genesis}' but with adjusted genesis timestamp", + ("genesis", genesis_file.generic_string()) ); + } else { + ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string())); + } + wlog( "Starting up fresh blockchain with provided genesis state." ); + } else if( genesis_timestamp_specified ) { + wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." ); + } else { + wlog( "Starting up fresh blockchain with default genesis state." ); } - - wlog( "Starting up fresh blockchain with provided genesis state." ); - } else if( options.count( "genesis-timestamp" )) { - EOS_ASSERT( !fc::exists( my->blocks_dir / "blocks.log" ), - plugin_config_exception, - "Genesis state can only be set on a fresh blockchain." ); - - my->chain_config->genesis.initial_timestamp = calculate_genesis_timestamp( - options.at( "genesis-timestamp" ).as()); - - wlog( "Starting up fresh blockchain with default genesis state but with adjusted genesis timestamp." ); - } else if( fc::is_regular_file( my->blocks_dir / "blocks.log" )) { - my->chain_config->genesis = block_log::extract_genesis_state( my->blocks_dir ); } else { - wlog( "Starting up fresh blockchain with default genesis state." ); + EOS_ASSERT( my->chain_config->genesis == *existing_genesis, plugin_config_exception, + "Genesis state provided via command line arguments does not match the existing genesis state in blocks.log. " + "It is not necessary to provide genesis state arguments when a blocks.log file already exists." + ); } } @@ -688,13 +704,14 @@ void chain_plugin::plugin_initialize(const variables_map& options) { void chain_plugin::plugin_startup() { try { try { + auto shutdown = [](){ return app().is_quiting(); }; if (my->snapshot_path) { auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary)); auto reader = std::make_shared(infile); - my->chain->startup(reader); + my->chain->startup(shutdown, reader); infile.close(); } else { - my->chain->startup(); + my->chain->startup(shutdown); } } catch (const database_guard_exception& e) { log_guard_exception(e); @@ -734,10 +751,6 @@ void chain_apis::read_write::validate() const { EOS_ASSERT( db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, "Not allowed, node in read-only mode" ); } -chain_apis::read_write chain_plugin::get_read_write_api() { - return chain_apis::read_write(chain(), get_abi_serializer_max_time()); -} - void chain_plugin::accept_block(const signed_block_ptr& block ) { my->incoming_block_sync_method(block); } @@ -992,10 +1005,19 @@ namespace chain_apis { const string read_only::KEYi64 = "i64"; +template +std::string itoh(I n, size_t hlen = sizeof(I)<<1) { + static const char* digits = "0123456789abcdef"; + std::string r(hlen, '0'); + for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4) + r[i] = digits[(n>>j) & 0x0f]; + return r; +} + read_only::get_info_results read_only::get_info(const read_only::get_info_params&) const { const auto& rm = db.get_resource_limits_manager(); return { - eosio::utilities::common::itoh(static_cast(app().version())), + itoh(static_cast(app().version())), db.get_chain_id(), db.fork_db_head_block_num(), db.last_irreversible_block_num(), @@ -1088,6 +1110,19 @@ uint64_t convert_to_type(const string& str, const string& desc) { } } +template<> +double convert_to_type(const string& str, const string& desc) { + double val{}; + try { + val = fc::variant(str).as(); + } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} string '${str}' to key type.", ("desc", desc)("str",str) ) + + EOS_ASSERT( !std::isnan(val), chain::contract_table_query_exception, + "Converted ${desc} string '${str}' to NaN which is not a permitted value for the key type", ("desc", desc)("str",str) ); + + return val; +} + abi_def get_abi( const controller& db, const name& account ) { const auto &d = db.db(); const account_object *code_accnt = d.find(account); @@ -1166,51 +1201,57 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get } read_only::get_table_by_scope_result read_only::get_table_by_scope( const read_only::get_table_by_scope_params& p )const { + read_only::get_table_by_scope_result result; const auto& d = db.db(); + const auto& idx = d.get_index(); - decltype(idx.lower_bound(boost::make_tuple(0, 0, 0))) lower; - decltype(idx.upper_bound(boost::make_tuple(0, 0, 0))) upper; + auto lower_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::lowest(), p.table.value ); + auto upper_bound_lookup_tuple = std::make_tuple( p.code.value, std::numeric_limits::max(), + (p.table.empty() ? std::numeric_limits::max() : p.table.value) ); - if (p.lower_bound.size()) { + if( p.lower_bound.size() ) { uint64_t scope = convert_to_type(p.lower_bound, "lower_bound scope"); - lower = idx.lower_bound( boost::make_tuple(p.code, scope, p.table)); - } else { - lower = idx.lower_bound(boost::make_tuple(p.code, 0, p.table)); + std::get<1>(lower_bound_lookup_tuple) = scope; } - if (p.upper_bound.size()) { + + if( p.upper_bound.size() ) { uint64_t scope = convert_to_type(p.upper_bound, "upper_bound scope"); - upper = idx.lower_bound( boost::make_tuple(p.code, scope, 0)); - } else { - upper = idx.lower_bound(boost::make_tuple((uint64_t)p.code + 1, 0, 0)); + std::get<1>(upper_bound_lookup_tuple) = scope; } - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - unsigned int count = 0; - auto itr = lower; - read_only::get_table_by_scope_result result; - for (; itr != upper; ++itr) { - if (p.table && itr->table != p.table) { - if (fc::time_point::now() > end) { - break; - } - continue; + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) { + if( p.table && itr->table != p.table ) continue; + + result.rows.push_back( {itr->code, itr->scope, itr->table, itr->payer, itr->count} ); + + ++count; } - result.rows.push_back({itr->code, itr->scope, itr->table, itr->payer, itr->count}); - if (++count == p.limit || fc::time_point::now() > end) { - ++itr; - break; + if( itr != end_itr ) { + result.more = string(itr->scope); } + }; + + auto lower = idx.lower_bound( lower_bound_lookup_tuple ); + auto upper = idx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_range( lower, upper ); } - if (itr != upper) { - result.more = (string)itr->scope; - } + return result; } vector read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const { const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - auto table_type = get_table_type( abi, "accounts" ); + (void)get_table_type( abi, "accounts" ); vector results; walk_key_value_table(p.code, p.account, N(accounts), [&](const key_value_object& obj){ @@ -1237,7 +1278,7 @@ fc::variant read_only::get_currency_stats( const read_only::get_currency_stats_p fc::mutable_variant_object results; const abi_def abi = eosio::chain_apis::get_abi( db, p.code ); - auto table_type = get_table_type( abi, "stat" ); + (void)get_table_type( abi, "stat" ); uint64_t scope = ( eosio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 ); @@ -1585,17 +1626,12 @@ read_only::get_code_results read_only::get_code( const get_code_params& params ) EOS_ASSERT( params.code_as_wasm, unsupported_feature, "Returning WAST from get_code is no longer supported" ); if( accnt.code.size() ) { - if (params.code_as_wasm) { - result.wasm = string(accnt.code.begin(), accnt.code.end()); - } else { - result.wast = wasm_to_wast( (const uint8_t*)accnt.code.data(), accnt.code.size(), true ); - } + result.wasm = string(accnt.code.begin(), accnt.code.end()); result.code_hash = fc::sha256::hash( accnt.code.data(), accnt.code.size() ); } abi_def abi; if( abi_serializer::to_abi(accnt.abi, abi) ) { - result.abi = std::move(abi); } @@ -1693,7 +1729,7 @@ read_only::get_account_results read_only::get_account( const get_account_params& auto core_symbol = extract_core_symbol(); - if (params.expected_core_symbol.valid()) + if (params.expected_core_symbol.valid()) core_symbol = *(params.expected_core_symbol); const auto* t_id = d.find(boost::make_tuple( token_code, params.account_name, N(accounts) )); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 0b69a6af89a..832f0b24485 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -55,7 +55,7 @@ struct permission { template struct resolver_factory; -// see specialization for uint64_t in source file +// see specializations for uint64_t and double in source file template Type convert_to_type(const string& str, const string& desc) { try { @@ -66,6 +66,9 @@ Type convert_to_type(const string& str, const string& desc) { template<> uint64_t convert_to_type(const string& str, const string& desc); +template<> +double convert_to_type(const string& str, const string& desc); + class read_only { const controller& db; const fc::microseconds abi_serializer_max_time; @@ -269,6 +272,8 @@ class read_only { string key_type; // type of key specified by index_position string index_position; // 1 - primary (first), 2 - secondary index (in order defined by multi_index), 3 - third index, etc string encode_type{"dec"}; //dec, hex , default=dec + optional reverse; + optional show_payer; // show RAM pyer }; struct get_table_rows_result { @@ -284,6 +289,7 @@ class read_only { string lower_bound; // lower bound of scope, optional string upper_bound; // upper bound of scope, optional uint32_t limit = 10; + optional reverse; }; struct get_table_by_scope_result_row { name code; @@ -398,58 +404,78 @@ class read_only { const uint64_t table_with_index = get_table_index_name(p, primary); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); const auto* index_t_id = d.find(boost::make_tuple(p.code, scope, table_with_index)); - if (t_id != nullptr && index_t_id != nullptr) { - const auto& secidx = d.get_index(); - decltype(index_t_id->id) low_tid(index_t_id->id._id); - decltype(index_t_id->id) next_tid(index_t_id->id._id + 1); - auto lower = secidx.lower_bound(boost::make_tuple(low_tid)); - auto upper = secidx.lower_bound(boost::make_tuple(next_tid)); + if( t_id != nullptr && index_t_id != nullptr ) { + using secondary_key_type = std::result_of_t; + static_assert( std::is_same::value, "Return type of conv does not match type of secondary key for IndexType" ); - if (p.lower_bound.size()) { - if (p.key_type == "name") { + const auto& secidx = d.get_index(); + auto lower_bound_lookup_tuple = std::make_tuple( index_t_id->id._id, + eosio::chain::secondary_key_traits::true_lowest(), + std::numeric_limits::lowest() ); + auto upper_bound_lookup_tuple = std::make_tuple( index_t_id->id._id, + eosio::chain::secondary_key_traits::true_highest(), + std::numeric_limits::max() ); + + if( p.lower_bound.size() ) { + if( p.key_type == "name" ) { name s(p.lower_bound); SecKeyType lv = convert_to_type( s.to_string(), "lower_bound name" ); // avoids compiler error - lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv ))); + std::get<1>(lower_bound_lookup_tuple) = conv( lv ); } else { SecKeyType lv = convert_to_type( p.lower_bound, "lower_bound" ); - lower = secidx.lower_bound( boost::make_tuple( low_tid, conv( lv ))); + std::get<1>(lower_bound_lookup_tuple) = conv( lv ); } } - if (p.upper_bound.size()) { - if (p.key_type == "name") { + + if( p.upper_bound.size() ) { + if( p.key_type == "name" ) { name s(p.upper_bound); SecKeyType uv = convert_to_type( s.to_string(), "upper_bound name" ); - upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv ))); + std::get<1>(upper_bound_lookup_tuple) = conv( uv ); } else { SecKeyType uv = convert_to_type( p.upper_bound, "upper_bound" ); - upper = secidx.lower_bound( boost::make_tuple( low_tid, conv( uv ))); + std::get<1>(upper_bound_lookup_tuple) = conv( uv ); } } - vector data; - - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - - unsigned int count = 0; - auto itr = lower; - for (; itr != upper; ++itr) { - - const auto* itr2 = d.find(boost::make_tuple(t_id->id, itr->primary_key)); - if (itr2 == nullptr) continue; - copy_inline_row(*itr2, data); - - if (p.json) { - result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) ); - } else { - result.rows.emplace_back(fc::variant(data)); + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_row_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + vector data; + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) { + const auto* itr2 = d.find( boost::make_tuple(t_id->id, itr->primary_key) ); + if( itr2 == nullptr ) continue; + copy_inline_row(*itr2, data); + + fc::variant data_var; + if( p.json ) { + data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ); + } else { + data_var = fc::variant( data ); + } + + if( p.show_payer && *p.show_payer ) { + result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) ); + } else { + result.rows.emplace_back( std::move(data_var) ); + } + + ++count; } - - if (++count == p.limit || fc::time_point::now() > end) { - break; + if( itr != end_itr ) { + result.more = true; } - } - if (itr != upper) { - result.more = true; + }; + + auto lower = secidx.lower_bound( lower_bound_lookup_tuple ); + auto upper = secidx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_row_range( lower, upper ); } } return result; @@ -465,53 +491,65 @@ class read_only { abi_serializer abis; abis.set_abi(abi, abi_serializer_max_time); const auto* t_id = d.find(boost::make_tuple(p.code, scope, p.table)); - if (t_id != nullptr) { + if( t_id != nullptr ) { const auto& idx = d.get_index(); - decltype(t_id->id) next_tid(t_id->id._id + 1); - auto lower = idx.lower_bound(boost::make_tuple(t_id->id)); - auto upper = idx.lower_bound(boost::make_tuple(next_tid)); + auto lower_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::lowest() ); + auto upper_bound_lookup_tuple = std::make_tuple( t_id->id, std::numeric_limits::max() ); - if (p.lower_bound.size()) { - if (p.key_type == "name") { + if( p.lower_bound.size() ) { + if( p.key_type == "name" ) { name s(p.lower_bound); - lower = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); + std::get<1>(lower_bound_lookup_tuple) = s.value; } else { auto lv = convert_to_type( p.lower_bound, "lower_bound" ); - lower = idx.lower_bound( boost::make_tuple( t_id->id, lv )); + std::get<1>(lower_bound_lookup_tuple) = lv; } } - if (p.upper_bound.size()) { - if (p.key_type == "name") { + + if( p.upper_bound.size() ) { + if( p.key_type == "name" ) { name s(p.upper_bound); - upper = idx.lower_bound( boost::make_tuple( t_id->id, s.value )); + std::get<1>(upper_bound_lookup_tuple) = s.value; } else { auto uv = convert_to_type( p.upper_bound, "upper_bound" ); - upper = idx.lower_bound( boost::make_tuple( t_id->id, uv )); + std::get<1>(upper_bound_lookup_tuple) = uv; } } - vector data; - - auto end = fc::time_point::now() + fc::microseconds(1000 * 10); /// 10ms max time - - unsigned int count = 0; - auto itr = lower; - for (; itr != upper; ++itr) { - copy_inline_row(*itr, data); - - if (p.json) { - result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ) ); - } else { - result.rows.emplace_back(fc::variant(data)); + if( upper_bound_lookup_tuple < lower_bound_lookup_tuple ) + return result; + + auto walk_table_row_range = [&]( auto itr, auto end_itr ) { + auto cur_time = fc::time_point::now(); + auto end_time = cur_time + fc::microseconds(1000 * 10); /// 10ms max time + vector data; + for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++count, ++itr, cur_time = fc::time_point::now() ) { + copy_inline_row(*itr, data); + + fc::variant data_var; + if( p.json ) { + data_var = abis.binary_to_variant( abis.get_table_type(p.table), data, abi_serializer_max_time, shorten_abi_errors ); + } else { + data_var = fc::variant( data ); + } + + if( p.show_payer && *p.show_payer ) { + result.rows.emplace_back( fc::mutable_variant_object("data", std::move(data_var))("payer", itr->payer) ); + } else { + result.rows.emplace_back( std::move(data_var) ); + } } - - if (++count == p.limit || fc::time_point::now() > end) { - ++itr; - break; + if( itr != end_itr ) { + result.more = true; } - } - if (itr != upper) { - result.more = true; + }; + + auto lower = idx.lower_bound( lower_bound_lookup_tuple ); + auto upper = idx.upper_bound( upper_bound_lookup_tuple ); + if( p.reverse && *p.reverse ) { + walk_table_row_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) ); + } else { + walk_table_row_range( lower, upper ); } } return result; @@ -622,7 +660,7 @@ class chain_plugin : public plugin { void plugin_shutdown(); chain_apis::read_only get_read_only_api() const { return chain_apis::read_only(chain(), get_abi_serializer_max_time()); } - chain_apis::read_write get_read_write_api(); + chain_apis::read_write get_read_write_api() { return chain_apis::read_write(chain(), get_abi_serializer_max_time()); } void accept_block( const chain::signed_block_ptr& block ); void accept_transaction(const chain::packed_transaction& trx, chain::plugin_interface::next_function next); @@ -672,10 +710,10 @@ FC_REFLECT(eosio::chain_apis::read_only::get_block_header_state_params, (block_n FC_REFLECT( eosio::chain_apis::read_write::push_transaction_results, (transaction_id)(processed) ) -FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type) ) +FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_params, (json)(code)(scope)(table)(table_key)(lower_bound)(upper_bound)(limit)(key_type)(index_position)(encode_type)(reverse)(show_payer) ) FC_REFLECT( eosio::chain_apis::read_only::get_table_rows_result, (rows)(more) ); -FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit) ) +FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_params, (code)(table)(lower_bound)(upper_bound)(limit)(reverse) ) FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result_row, (code)(scope)(table)(payer)(count)); FC_REFLECT( eosio::chain_apis::read_only::get_table_by_scope_result, (rows)(more) ); diff --git a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp index 55cbf8eb861..39374e692cd 100644 --- a/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp +++ b/plugins/faucet_testnet_plugin/faucet_testnet_plugin.cpp @@ -4,7 +4,6 @@ */ #include #include -#include #include #include diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 8283c5c9320..23b0c0ddb62 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -1553,9 +1552,10 @@ namespace eosio { req.req_blocks.mode = catch_up; for (auto cc : my_impl->connections) { if (cc->fork_head == id || - cc->fork_head_num > num) + cc->fork_head_num > num) { req.req_blocks.mode = none; - break; + break; + } } if( req.req_blocks.mode == catch_up ) { c->fork_head = id; @@ -2500,7 +2500,7 @@ namespace eosio { request_message req; bool send_req = false; if (msg.known_trx.mode != none) { - fc_dlog(logger,"this is a ${m} notice with ${n} blocks", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending)); + fc_dlog(logger,"this is a ${m} notice with ${n} transactions", ("m",modes_str(msg.known_trx.mode))("n",msg.known_trx.pending)); } switch (msg.known_trx.mode) { case none: @@ -2534,9 +2534,6 @@ namespace eosio { } switch (msg.known_blocks.mode) { case none : { - if (msg.known_trx.mode != normal) { - return; - } break; } case last_irr_catch_up: diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index d7f9188d5bb..fe161f8d913 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -5,6 +5,6 @@ add_library( producer_plugin ${HEADERS} ) -target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities ) +target_link_libraries( producer_plugin chain_plugin http_client_plugin appbase eosio_chain ) target_include_directories( producer_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" ) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index f2e50e92849..7b967421502 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -23,6 +23,7 @@ class producer_plugin : public appbase::plugin { fc::optional max_irreversible_block_age; fc::optional produce_time_offset_us; fc::optional last_block_time_offset_us; + fc::optional max_scheduled_transaction_time_per_block_ms; fc::optional subjective_cpu_leeway_us; fc::optional incoming_defer_ratio; }; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 2d60e92a006..bc29cd87ea3 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -136,6 +136,7 @@ class producer_plugin_impl : public std::enable_shared_from_thisid())); + auto id = block->id(); - EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds(7)), block_from_the_future, "received a block from the future, ignoring it" ); + fc_dlog(_log, "received incoming block ${id}", ("id", id)); + EOS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds( 7 )), block_from_the_future, + "received a block from the future, ignoring it: ${id}", ("id", id) ); chain::controller& chain = app().get_plugin().chain(); /* de-dupe here... no point in aborting block if we already know the block */ - auto id = block->id(); auto existing = chain.fetch_block_by_id( id ); if( existing ) { return; } + // start processing of block + auto bsf = chain.create_block_state_future( block ); + // abort the pending block chain.abort_block(); @@ -308,7 +313,7 @@ class producer_plugin_impl : public std::enable_shared_from_this().handle_guard_exception(e); return; @@ -391,9 +396,10 @@ class producer_plugin_impl : public std::enable_shared_from_this& weak_this, const block_timestamp_type& current_block_time); }; @@ -522,6 +529,8 @@ void producer_plugin::set_program_options( "offset of non last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") ("last-block-time-offset-us", boost::program_options::value()->default_value(0), "offset of last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") + ("max-scheduled-transaction-time-per-block-ms", boost::program_options::value()->default_value(100), + "Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions in any block before returning to normal transaction processing.") ("incoming-defer-ratio", bpo::value()->default_value(1.0), "ratio between incoming transations and deferred transactions when both are exhausted") ("snapshots-dir", bpo::value()->default_value("snapshots"), @@ -648,6 +657,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_last_block_time_offset_us = options.at("last-block-time-offset-us").as(); + my->_max_scheduled_transaction_time_per_block_ms = options.at("max-scheduled-transaction-time-per-block-ms").as(); + my->_max_transaction_time_ms = options.at("max-transaction-time").as(); my->_max_irreversible_block_age_us = fc::seconds(options.at("max-irreversible-block-age").as()); @@ -799,6 +810,10 @@ void producer_plugin::update_runtime_options(const runtime_options& options) { my->_last_block_time_offset_us = *options.last_block_time_offset_us; } + if (options.max_scheduled_transaction_time_per_block_ms) { + my->_max_scheduled_transaction_time_per_block_ms = *options.max_scheduled_transaction_time_per_block_ms; + } + if (options.incoming_defer_ratio) { my->_incoming_defer_ratio = *options.incoming_defer_ratio; } @@ -820,7 +835,8 @@ producer_plugin::runtime_options producer_plugin::get_runtime_options() const { my->_max_transaction_time_ms, my->_max_irreversible_block_age_us.count() < 0 ? -1 : my->_max_irreversible_block_age_us.count() / 1'000'000, my->_produce_time_offset_us, - my->_last_block_time_offset_us + my->_last_block_time_offset_us, + my->_max_scheduled_transaction_time_per_block_ms }; } @@ -989,6 +1005,11 @@ fc::time_point producer_plugin_impl::calculate_pending_block_time() const { return block_time; } +fc::time_point producer_plugin_impl::calculate_block_deadline( const fc::time_point& block_time ) const { + bool last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); + return block_time + fc::microseconds(last_block ? _last_block_time_offset_us : _produce_time_offset_us); +} + enum class tx_category { PERSISTED, UNEXPIRED_UNPERSISTED, @@ -996,7 +1017,7 @@ enum class tx_category { }; -producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool &last_block) { +producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain::controller& chain = app().get_plugin().chain(); if( chain.get_read_mode() == chain::db_read_mode::READ_ONLY ) @@ -1012,7 +1033,6 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool _pending_block_mode = pending_block_mode::producing; // Not our turn - last_block = ((block_timestamp_type(block_time).slot % config::producer_repetitions) == config::producer_repetitions - 1); const auto& scheduled_producer = hbs->get_scheduled_producer(block_time); auto currrent_watermark_itr = _producer_watermarks.find(scheduled_producer.producer_name); auto signature_provider_itr = _signature_providers.find(scheduled_producer.block_signing_key); @@ -1082,6 +1102,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool const auto& pbs = chain.pending_block_state(); if (pbs) { + const fc::time_point preprocess_deadline = calculate_block_deadline(block_time); if (_pending_block_mode == pending_block_mode::producing && pbs->block_signing_key != scheduled_producer.block_signing_key) { elog("Block Signing Key is not expected value, reverting to speculative mode! [expected: \"${expected}\", actual: \"${actual\"", ("expected", scheduled_producer.block_signing_key)("actual", pbs->block_signing_key)); @@ -1164,7 +1185,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int num_processed = 0; for (const auto& trx: apply_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; + if (preprocess_deadline <= fc::time_point::now()) exhausted = true; if (exhausted) { break; } @@ -1174,9 +1195,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool try { auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && preprocess_deadline < deadline)) { deadline_is_subjective = true; - deadline = block_time; + deadline = preprocess_deadline; } auto trace = chain.push_transaction(trx, deadline); @@ -1229,8 +1250,16 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool int num_failed = 0; int num_processed = 0; + auto scheduled_trx_deadline = preprocess_deadline; + if (_max_scheduled_transaction_time_per_block_ms >= 0) { + scheduled_trx_deadline = std::min( + scheduled_trx_deadline, + fc::time_point::now() + fc::milliseconds(_max_scheduled_transaction_time_per_block_ms) + ); + } + for (const auto& trx : scheduled_trxs) { - if (block_time <= fc::time_point::now()) exhausted = true; + if (scheduled_trx_deadline <= fc::time_point::now()) exhausted = true; if (exhausted) { break; } @@ -1239,6 +1268,8 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool // configurable ratio of incoming txns vs deferred txns while (_incoming_trx_weight >= 1.0 && orig_pending_txn_size && _pending_incoming_transactions.size()) { + if (scheduled_trx_deadline <= fc::time_point::now()) break; + auto e = _pending_incoming_transactions.front(); _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; @@ -1246,7 +1277,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); } - if (block_time <= fc::time_point::now()) { + if (scheduled_trx_deadline <= fc::time_point::now()) { exhausted = true; break; } @@ -1258,9 +1289,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool try { auto deadline = fc::time_point::now() + fc::milliseconds(_max_transaction_time_ms); bool deadline_is_subjective = false; - if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && block_time < deadline)) { + if (_max_transaction_time_ms < 0 || (_pending_block_mode == pending_block_mode::producing && scheduled_trx_deadline < deadline)) { deadline_is_subjective = true; - deadline = block_time; + deadline = scheduled_trx_deadline; } auto trace = chain.push_scheduled_transaction(trx, deadline); @@ -1294,7 +1325,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } } - if (exhausted || block_time <= fc::time_point::now()) { + if (exhausted || preprocess_deadline <= fc::time_point::now()) { return start_block_result::exhausted; } else { // attempt to apply any pending incoming transactions @@ -1307,7 +1338,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); - if (block_time <= fc::time_point::now()) return start_block_result::exhausted; + if (preprocess_deadline <= fc::time_point::now()) return start_block_result::exhausted; } } return start_block_result::succeeded; @@ -1328,8 +1359,7 @@ void producer_plugin_impl::schedule_production_loop() { _timer.cancel(); std::weak_ptr weak_this = shared_from_this(); - bool last_block; - auto result = start_block(last_block); + auto result = start_block(); if (result == start_block_result::failed) { elog("Failed to start a pending block, will try again later"); @@ -1355,11 +1385,12 @@ void producer_plugin_impl::schedule_production_loop() { // we succeeded but block may be exhausted static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); - if (result == start_block_result::succeeded) { + auto deadline = calculate_block_deadline(chain.pending_block_time()); + + if (deadline > fc::time_point::now()) { // ship this block off no later than its deadline EOS_ASSERT( chain.pending_block_state(), missing_pending_block_state, "producing without pending_block_state, start_block succeeded" ); - auto deadline = chain.pending_block_time().time_since_epoch().count() + (last_block ? _last_block_time_offset_us : _produce_time_offset_us); - _timer.expires_at( epoch + boost::posix_time::microseconds( deadline )); + _timer.expires_at( epoch + boost::posix_time::microseconds( deadline.time_since_epoch().count() )); fc_dlog(_log, "Scheduling Block Production on Normal Block #${num} for ${time}", ("num", chain.pending_block_state()->block_num)("time",deadline)); } else { EOS_ASSERT( chain.pending_block_state(), missing_pending_block_state, "producing without pending_block_state" ); diff --git a/plugins/state_history_plugin/.clang-format b/plugins/state_history_plugin/.clang-format new file mode 100644 index 00000000000..42dd5b7832c --- /dev/null +++ b/plugins/state_history_plugin/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: LLVM +IndentWidth: 3 +ColumnLimit: 120 +PointerAlignment: Left +AlwaysBreakTemplateDeclarations: true +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +BreakConstructorInitializers: BeforeComma diff --git a/plugins/state_history_plugin/CMakeLists.txt b/plugins/state_history_plugin/CMakeLists.txt new file mode 100644 index 00000000000..21f0e10a900 --- /dev/null +++ b/plugins/state_history_plugin/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB HEADERS "include/eosio/state_history_plugin/*.hpp") +add_library( state_history_plugin + state_history_plugin.cpp + state_history_plugin_abi.cpp + ${HEADERS} ) + +target_link_libraries( state_history_plugin chain_plugin eosio_chain appbase ) +target_include_directories( state_history_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp new file mode 100644 index 00000000000..a580529c5d5 --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_log.hpp @@ -0,0 +1,279 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace eosio { + +/* + * *.log: + * +---------+----------------+-----------+------------------+-----+---------+----------------+ + * | Entry i | Pos of Entry i | Entry i+1 | Pos of Entry i+1 | ... | Entry z | Pos of Entry z | + * +---------+----------------+-----------+------------------+-----+---------+----------------+ + * + * *.index: + * +-----------+-------------+-----+-----------+ + * | Summary i | Summary i+1 | ... | Summary z | + * +-----------+-------------+-----+-----------+ + * + * each entry: + * uint32_t block_num + * block_id_type block_id + * uint64_t size of payload + * uint8_t version + * payload + * + * each summary: + * uint64_t position of entry in *.log + * + * state payload: + * uint32_t size of deltas + * char[] deltas + */ + +// todo: look into switching this to serialization instead of memcpy +// todo: consider reworking versioning +// todo: consider dropping block_num since it's included in block_id +// todo: currently only checks version on the first record. Need in recover_blocks +struct state_history_log_header { + uint32_t block_num = 0; + chain::block_id_type block_id; + uint64_t payload_size = 0; + uint8_t version = 0; +}; + +struct state_history_summary { + uint64_t pos = 0; +}; + +class state_history_log { + private: + const char* const name = ""; + std::string log_filename; + std::string index_filename; + std::fstream log; + std::fstream index; + uint32_t _begin_block = 0; + uint32_t _end_block = 0; + chain::block_id_type last_block_id; + + public: + state_history_log(const char* const name, std::string log_filename, std::string index_filename) + : name(name) + , log_filename(std::move(log_filename)) + , index_filename(std::move(index_filename)) { + open_log(); + open_index(); + } + + uint32_t begin_block() const { return _begin_block; } + uint32_t end_block() const { return _end_block; } + + template + void write_entry(const state_history_log_header& header, const chain::block_id_type& prev_id, F write_payload) { + EOS_ASSERT(_begin_block == _end_block || header.block_num <= _end_block, chain::plugin_exception, + "missed a block in ${name}.log", ("name", name)); + + if (_begin_block != _end_block && header.block_num > _begin_block) { + if (header.block_num == _end_block) { + EOS_ASSERT(prev_id == last_block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } else { + state_history_log_header prev; + get_entry(header.block_num - 1, prev); + EOS_ASSERT(prev_id == prev.block_id, chain::plugin_exception, "missed a fork change in ${name}.log", + ("name", name)); + } + } + + if (header.block_num < _end_block) + truncate(header.block_num); + log.seekg(0, std::ios_base::end); + uint64_t pos = log.tellg(); + log.write((char*)&header, sizeof(header)); + write_payload(log); + uint64_t end = log.tellg(); + EOS_ASSERT(end == pos + sizeof(header) + header.payload_size, chain::plugin_exception, + "wrote payload with incorrect size to ${name}.log", ("name", name)); + log.write((char*)&pos, sizeof(pos)); + + index.seekg(0, std::ios_base::end); + state_history_summary summary{.pos = pos}; + index.write((char*)&summary, sizeof(summary)); + if (_begin_block == _end_block) + _begin_block = header.block_num; + _end_block = header.block_num + 1; + last_block_id = header.block_id; + } + + // returns stream positioned at payload + std::fstream& get_entry(uint32_t block_num, state_history_log_header& header) { + EOS_ASSERT(block_num >= _begin_block && block_num < _end_block, chain::plugin_exception, + "read non-existing block in ${name}.log", ("name", name)); + log.seekg(get_pos(block_num)); + log.read((char*)&header, sizeof(header)); + return log; + } + + chain::block_id_type get_block_id(uint32_t block_num) { + state_history_log_header header; + get_entry(block_num, header); + return header.block_id; + } + + private: + bool get_last_block(uint64_t size) { + state_history_log_header header; + uint64_t suffix; + log.seekg(size - sizeof(suffix)); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix > size || suffix + sizeof(header) > size) { + elog("corrupt ${name}.log (2)", ("name", name)); + return false; + } + log.seekg(suffix); + log.read((char*)&header, sizeof(header)); + if (suffix + sizeof(header) + header.payload_size + sizeof(suffix) != size) { + elog("corrupt ${name}.log (3)", ("name", name)); + return false; + } + _end_block = header.block_num + 1; + last_block_id = header.block_id; + if (_begin_block >= _end_block) { + elog("corrupt ${name}.log (4)", ("name", name)); + return false; + } + return true; + } + + void recover_blocks(uint64_t size) { + ilog("recover ${name}.log", ("name", name)); + uint64_t pos = 0; + uint32_t num_found = 0; + while (true) { + state_history_log_header header; + if (pos + sizeof(header) > size) + break; + log.seekg(pos); + log.read((char*)&header, sizeof(header)); + uint64_t suffix; + if (header.payload_size > size || pos + sizeof(header) + header.payload_size + sizeof(suffix) > size) + break; + log.seekg(pos + sizeof(header) + header.payload_size); + log.read((char*)&suffix, sizeof(suffix)); + if (suffix != pos) + break; + pos = pos + sizeof(header) + header.payload_size + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + log.flush(); + boost::filesystem::resize_file(log_filename, pos); + log.sync(); + EOS_ASSERT(get_last_block(pos), chain::plugin_exception, "recover ${name}.log failed", ("name", name)); + } + + void open_log() { + log.open(log_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellg(); + if (size >= sizeof(state_history_log_header)) { + state_history_log_header header; + log.seekg(0); + log.read((char*)&header, sizeof(header)); + EOS_ASSERT(header.version == 0 && sizeof(header) + header.payload_size + sizeof(uint64_t) <= size, + chain::plugin_exception, "corrupt ${name}.log (1)", ("name", name)); + _begin_block = header.block_num; + last_block_id = header.block_id; + if (!get_last_block(size)) + recover_blocks(size); + ilog("${name}.log has blocks ${b}-${e}", ("name", name)("b", _begin_block)("e", _end_block - 1)); + } else { + EOS_ASSERT(!size, chain::plugin_exception, "corrupt ${name}.log (5)", ("name", name)); + ilog("${name}.log is empty", ("name", name)); + } + } + + void open_index() { + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app); + index.seekg(0, std::ios_base::end); + if (index.tellg() == (_end_block - _begin_block) * sizeof(state_history_summary)) + return; + ilog("Regenerate ${name}.index", ("name", name)); + index.close(); + index.open(index_filename, std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc); + + log.seekg(0, std::ios_base::end); + uint64_t size = log.tellg(); + uint64_t pos = 0; + uint32_t num_found = 0; + while (pos < size) { + state_history_log_header header; + EOS_ASSERT(pos + sizeof(header) <= size, chain::plugin_exception, "corrupt ${name}.log (6)", ("name", name)); + log.seekg(pos); + log.read((char*)&header, sizeof(header)); + uint64_t suffix_pos = pos + sizeof(header) + header.payload_size; + uint64_t suffix; + EOS_ASSERT(suffix_pos + sizeof(suffix) <= size, chain::plugin_exception, "corrupt ${name}.log (7)", + ("name", name)); + log.seekg(suffix_pos); + log.read((char*)&suffix, sizeof(suffix)); + // ilog("block ${b} at ${pos}-${end} suffix=${suffix} file_size=${fs}", + // ("b", header.block_num)("pos", pos)("end", suffix_pos + sizeof(suffix))("suffix", suffix)("fs", size)); + EOS_ASSERT(suffix == pos, chain::plugin_exception, "corrupt ${name}.log (8)", ("name", name)); + + state_history_summary summary{.pos = pos}; + index.write((char*)&summary, sizeof(summary)); + pos = suffix_pos + sizeof(suffix); + if (!(++num_found % 10000)) { + printf("%10u blocks found, log pos=%12llu\r", (unsigned)num_found, (unsigned long long)pos); + fflush(stdout); + } + } + } + + uint64_t get_pos(uint32_t block_num) { + state_history_summary summary; + index.seekg((block_num - _begin_block) * sizeof(summary)); + index.read((char*)&summary, sizeof(summary)); + return summary.pos; + } + + void truncate(uint32_t block_num) { + log.flush(); + index.flush(); + uint64_t num_removed = 0; + if (block_num <= _begin_block) { + num_removed = _end_block - _begin_block; + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, 0); + boost::filesystem::resize_file(index_filename, 0); + _begin_block = _end_block = 0; + } else { + num_removed = _end_block - block_num; + uint64_t pos = get_pos(block_num); + log.seekg(0); + index.seekg(0); + boost::filesystem::resize_file(log_filename, pos); + boost::filesystem::resize_file(index_filename, (block_num - _begin_block) * sizeof(state_history_summary)); + _end_block = block_num; + } + log.sync(); + index.sync(); + ilog("fork or replay: removed ${n} blocks from ${name}.log", ("n", num_removed)("name", name)); + } +}; // state_history_log + +} // namespace eosio diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp new file mode 100644 index 00000000000..ce532d1c89e --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_plugin.hpp @@ -0,0 +1,101 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once +#include + +#include + +template +struct history_serial_big_vector_wrapper { + T obj; +}; + +namespace fc { +class variant; +} + +namespace eosio { +using chain::bytes; +using std::shared_ptr; + +typedef shared_ptr state_history_ptr; + +struct table_delta { + fc::unsigned_int struct_version = 0; + std::string name{}; + history_serial_big_vector_wrapper>> rows{}; +}; + +struct block_position { + uint32_t block_num = 0; + chain::block_id_type block_id = {}; +}; + +struct get_status_request_v0 {}; + +struct get_status_result_v0 { + block_position head = {}; + block_position last_irreversible = {}; + uint32_t trace_begin_block = 0; + uint32_t trace_end_block = 0; + uint32_t chain_state_begin_block = 0; + uint32_t chain_state_end_block = 0; +}; + +struct get_blocks_request_v0 { + uint32_t start_block_num = 0; + uint32_t end_block_num = 0; + uint32_t max_messages_in_flight = 0; + std::vector have_positions = {}; + bool irreversible_only = false; + bool fetch_block = false; + bool fetch_traces = false; + bool fetch_deltas = false; +}; + +struct get_blocks_ack_request_v0 { + uint32_t num_messages = 0; +}; + +struct get_blocks_result_v0 { + block_position head; + block_position last_irreversible; + fc::optional this_block; + fc::optional prev_block; + fc::optional block; + fc::optional traces; + fc::optional deltas; +}; + +using state_request = fc::static_variant; +using state_result = fc::static_variant; + +class state_history_plugin : public plugin { + public: + APPBASE_PLUGIN_REQUIRES((chain_plugin)) + + state_history_plugin(); + virtual ~state_history_plugin(); + + virtual void set_program_options(options_description& cli, options_description& cfg) override; + + void plugin_initialize(const variables_map& options); + void plugin_startup(); + void plugin_shutdown(); + + private: + state_history_ptr my; +}; + +} // namespace eosio + +// clang-format off +FC_REFLECT(eosio::table_delta, (struct_version)(name)(rows)); +FC_REFLECT(eosio::block_position, (block_num)(block_id)); +FC_REFLECT_EMPTY(eosio::get_status_request_v0); +FC_REFLECT(eosio::get_status_result_v0, (head)(last_irreversible)(trace_begin_block)(trace_end_block)(chain_state_begin_block)(chain_state_end_block)); +FC_REFLECT(eosio::get_blocks_request_v0, (start_block_num)(end_block_num)(max_messages_in_flight)(have_positions)(irreversible_only)(fetch_block)(fetch_traces)(fetch_deltas)); +FC_REFLECT(eosio::get_blocks_ack_request_v0, (num_messages)); +// clang-format on diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp new file mode 100644 index 00000000000..b000ac78803 --- /dev/null +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -0,0 +1,557 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct history_serial_wrapper { + const chainbase::database& db; + const T& obj; +}; + +template +history_serial_wrapper make_history_serial_wrapper(const chainbase::database& db, const T& obj) { + return {db, obj}; +} + +template +struct history_context_wrapper { + const chainbase::database& db; + const P& context; + const T& obj; +}; + +template +history_context_wrapper make_history_context_wrapper(const chainbase::database& db, P& context, const T& obj) { + return {db, context, obj}; +} + +namespace fc { + +template +const T& as_type(const T& x) { + return x; +} + +template +datastream& history_serialize_container(datastream& ds, const chainbase::database& db, const T& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (auto& x : v) + ds << make_history_serial_wrapper(db, x); + return ds; +} + +template +datastream& history_serialize_container(datastream& ds, const chainbase::database& db, + const std::vector>& v) { + fc::raw::pack(ds, unsigned_int(v.size())); + for (auto& x : v) { + EOS_ASSERT(!!x, eosio::chain::plugin_exception, "null inside container"); + ds << make_history_serial_wrapper(db, *x); + } + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_big_vector_wrapper& obj) { + FC_ASSERT(obj.obj.size() <= 1024 * 1024 * 1024); + fc::raw::pack(ds, unsigned_int((uint32_t)obj.obj.size())); + for (auto& x : obj.obj) + fc::raw::pack(ds, x); + return ds; +} + +template +void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { + FC_ASSERT(v.size() <= 1024 * 1024 * 1024); + fc::raw::pack(ds, unsigned_int((uint32_t)v.size())); + if (v.size()) + ds.write(&v.front(), (uint32_t)v.size()); +} + +template +void history_pack_big_bytes(datastream& ds, const fc::optional& v) { + fc::raw::pack(ds, v.valid()); + if (v) + history_pack_big_bytes(ds, *v); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { + return history_serialize_container(ds, obj.db, obj.obj); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper>& obj) { + fc::raw::pack(ds, obj.obj.first); + fc::raw::pack(ds, obj.obj.second); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + fc::raw::pack(ds, as_type(obj.obj.vm_type)); + fc::raw::pack(ds, as_type(obj.obj.vm_version)); + fc::raw::pack(ds, as_type(obj.obj.privileged)); + fc::raw::pack(ds, as_type(obj.obj.last_code_update)); + fc::raw::pack(ds, as_type(obj.obj.code_version)); + fc::raw::pack(ds, as_type(obj.obj.creation_date)); + fc::raw::pack(ds, as_type(obj.obj.code)); + fc::raw::pack(ds, as_type(obj.obj.abi)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.code.value)); + fc::raw::pack(ds, as_type(obj.obj.scope.value)); + fc::raw::pack(ds, as_type(obj.obj.table.value)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.context.code.value)); + fc::raw::pack(ds, as_type(obj.context.scope.value)); + fc::raw::pack(ds, as_type(obj.context.table.value)); + fc::raw::pack(ds, as_type(obj.obj.primary_key)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.value)); + return ds; +} + +template +void serialize_secondary_index_data(datastream& ds, const T& obj) { + fc::raw::pack(ds, obj); +} + +template +void serialize_secondary_index_data(datastream& ds, const float64_t& obj) { + uint64_t i; + memcpy(&i, &obj, sizeof(i)); + fc::raw::pack(ds, i); +} + +template +void serialize_secondary_index_data(datastream& ds, const float128_t& obj) { + __uint128_t i; + memcpy(&i, &obj, sizeof(i)); + fc::raw::pack(ds, i); +} + +template +void serialize_secondary_index_data(datastream& ds, const eosio::chain::key256_t& obj) { + auto rev = [&](__uint128_t x) { + char* ch = reinterpret_cast(&x); + std::reverse(ch, ch + sizeof(x)); + return x; + }; + fc::raw::pack(ds, rev(obj[0])); + fc::raw::pack(ds, rev(obj[1])); +} + +template +datastream& serialize_secondary_index(datastream& ds, const eosio::chain::table_id_object& context, + const T& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(context.code.value)); + fc::raw::pack(ds, as_type(context.scope.value)); + fc::raw::pack(ds, as_type(context.table.value)); + fc::raw::pack(ds, as_type(obj.primary_key)); + fc::raw::pack(ds, as_type(obj.payer.value)); + serialize_secondary_index_data(ds, obj.secondary_key); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& +operator<<(datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& operator<<( + datastream& ds, + const history_context_wrapper& obj) { + return serialize_secondary_index(ds, obj.context, obj.obj); +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.producer_name.value)); + fc::raw::pack(ds, as_type(obj.obj.block_signing_key)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.version)); + history_serialize_container(ds, obj.db, + as_type>(obj.obj.producers)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.max_block_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.target_block_net_usage_pct)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.base_per_transaction_net_usage)); + fc::raw::pack(ds, as_type(obj.obj.net_usage_leeway)); + fc::raw::pack(ds, as_type(obj.obj.context_free_discount_net_usage_num)); + fc::raw::pack(ds, as_type(obj.obj.context_free_discount_net_usage_den)); + fc::raw::pack(ds, as_type(obj.obj.max_block_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.target_block_cpu_usage_pct)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.min_transaction_cpu_usage)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_lifetime)); + fc::raw::pack(ds, as_type(obj.obj.deferred_trx_expiration_window)); + fc::raw::pack(ds, as_type(obj.obj.max_transaction_delay)); + fc::raw::pack(ds, as_type(obj.obj.max_inline_action_size)); + fc::raw::pack(ds, as_type(obj.obj.max_inline_action_depth)); + fc::raw::pack(ds, as_type(obj.obj.max_authority_depth)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type>(obj.obj.proposed_schedule_block_num)); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.proposed_schedule))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.configuration))); + + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.sender.value)); + fc::raw::pack(ds, as_type<__uint128_t>(obj.obj.sender_id)); + fc::raw::pack(ds, as_type(obj.obj.payer.value)); + fc::raw::pack(ds, as_type(obj.obj.trx_id)); + fc::raw::pack(ds, as_type(obj.obj.packed_trx)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.key)); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.actor.value)); + fc::raw::pack(ds, as_type(obj.obj.permission.value)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.permission))); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.wait_sec)); + fc::raw::pack(ds, as_type(obj.obj.weight)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.threshold)); + history_serialize_container(ds, obj.db, obj.obj.keys); + history_serialize_container(ds, obj.db, obj.obj.accounts); + history_serialize_container(ds, obj.db, obj.obj.waits); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + if (obj.obj.parent._id) { + auto& index = obj.db.get_index(); + const auto* parent = index.find(obj.obj.parent); + if (!parent) { + auto& undo = index.stack().back(); + auto it = undo.removed_values.find(obj.obj.parent); + EOS_ASSERT(it != undo.removed_values.end(), eosio::chain::plugin_exception, + "can not find parent of permission_object"); + parent = &it->second; + } + fc::raw::pack(ds, as_type(parent->name.value)); + } else { + fc::raw::pack(ds, as_type(0)); + } + fc::raw::pack(ds, as_type(obj.obj.last_updated)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.auth))); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.code.value)); + fc::raw::pack(ds, as_type(obj.obj.message_type.value)); + fc::raw::pack(ds, as_type(obj.obj.required_permission.value)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + EOS_ASSERT(!obj.obj.pending, eosio::chain::plugin_exception, + "accepted_block sent while resource_limits_object in pending state"); + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, as_type(obj.obj.net_weight)); + fc::raw::pack(ds, as_type(obj.obj.cpu_weight)); + fc::raw::pack(ds, as_type(obj.obj.ram_bytes)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.last_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.value_ex)); + fc::raw::pack(ds, as_type(obj.obj.consumed)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.owner.value)); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.net_usage))); + fc::raw::pack(ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.cpu_usage))); + fc::raw::pack(ds, as_type(obj.obj.ram_usage)); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type( + obj.obj.average_block_net_usage))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type( + obj.obj.average_block_cpu_usage))); + fc::raw::pack(ds, as_type(obj.obj.total_net_weight)); + fc::raw::pack(ds, as_type(obj.obj.total_cpu_weight)); + fc::raw::pack(ds, as_type(obj.obj.total_ram_bytes)); + fc::raw::pack(ds, as_type(obj.obj.virtual_net_limit)); + fc::raw::pack(ds, as_type(obj.obj.virtual_cpu_limit)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.numerator)); + fc::raw::pack(ds, as_type(obj.obj.denominator)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.target)); + fc::raw::pack(ds, as_type(obj.obj.max)); + fc::raw::pack(ds, as_type(obj.obj.periods)); + fc::raw::pack(ds, as_type(obj.obj.max_multiplier)); + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.contract_rate))); + fc::raw::pack( + ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.expand_rate))); + return ds; +} + +template +datastream& +operator<<(datastream& ds, + const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack( + ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.cpu_limit_parameters))); + fc::raw::pack( + ds, make_history_serial_wrapper( + obj.db, as_type(obj.obj.net_limit_parameters))); + fc::raw::pack(ds, as_type(obj.obj.account_cpu_usage_average_window)); + fc::raw::pack(ds, as_type(obj.obj.account_net_usage_average_window)); + return ds; +}; + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.name.value)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.authorization)); + fc::raw::pack(ds, as_type(obj.obj.data)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.receiver.value)); + fc::raw::pack(ds, as_type(obj.obj.act_digest)); + fc::raw::pack(ds, as_type(obj.obj.global_sequence)); + fc::raw::pack(ds, as_type(obj.obj.recv_sequence)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.auth_sequence)); + fc::raw::pack(ds, as_type(obj.obj.code_sequence)); + fc::raw::pack(ds, as_type(obj.obj.abi_sequence)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, as_type(obj.obj.account.value)); + fc::raw::pack(ds, as_type(obj.obj.delta)); + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.receipt))); + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); + fc::raw::pack(ds, as_type(obj.obj.context_free)); + fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); + fc::raw::pack(ds, as_type(obj.obj.console)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.account_ram_deltas)); + + fc::optional e; + if (obj.obj.except) + e = obj.obj.except->to_string(); + fc::raw::pack(ds, as_type>(e)); + + history_serialize_container(ds, obj.db, as_type>(obj.obj.inline_traces)); + return ds; +} + +template +datastream& operator<<(datastream& ds, + const history_context_wrapper& obj) { + fc::raw::pack(ds, fc::unsigned_int(0)); + fc::raw::pack(ds, as_type(obj.obj.id)); + if (obj.obj.receipt) { + if (obj.obj.failed_dtrx_trace && + obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + fc::raw::pack(ds, uint8_t(eosio::chain::transaction_receipt_header::executed)); + else + fc::raw::pack(ds, as_type(obj.obj.receipt->status.value)); + fc::raw::pack(ds, as_type(obj.obj.receipt->cpu_usage_us)); + fc::raw::pack(ds, as_type(obj.obj.receipt->net_usage_words)); + } else { + fc::raw::pack(ds, uint8_t(obj.context)); + fc::raw::pack(ds, uint32_t(0)); + fc::raw::pack(ds, fc::unsigned_int(0)); + } + fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); + fc::raw::pack(ds, as_type(obj.obj.net_usage)); + fc::raw::pack(ds, as_type(obj.obj.scheduled)); + history_serialize_container(ds, obj.db, as_type>(obj.obj.action_traces)); + + fc::optional e; + if (obj.obj.except) + e = obj.obj.except->to_string(); + fc::raw::pack(ds, as_type>(e)); + + fc::raw::pack(ds, bool(obj.obj.failed_dtrx_trace)); + if (obj.obj.failed_dtrx_trace) { + uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; + if (obj.obj.receipt && obj.obj.receipt->status.value == eosio::chain::transaction_receipt_header::soft_fail) + stat = eosio::chain::transaction_receipt_header::soft_fail; + fc::raw::pack(ds, make_history_context_wrapper(obj.db, stat, *obj.obj.failed_dtrx_trace)); + } + + return ds; +} + +template +datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { + uint8_t stat = eosio::chain::transaction_receipt_header::hard_fail; + ds << make_history_context_wrapper(obj.db, stat, obj.obj); + return ds; +} + +template +datastream& operator<<(datastream& ds, const eosio::get_blocks_result_v0& obj) { + fc::raw::pack(ds, obj.head); + fc::raw::pack(ds, obj.last_irreversible); + fc::raw::pack(ds, obj.this_block); + fc::raw::pack(ds, obj.prev_block); + history_pack_big_bytes(ds, obj.block); + history_pack_big_bytes(ds, obj.traces); + history_pack_big_bytes(ds, obj.deltas); + return ds; +} + +} // namespace fc diff --git a/plugins/state_history_plugin/state_history_plugin.cpp b/plugins/state_history_plugin/state_history_plugin.cpp new file mode 100644 index 00000000000..e625af5052a --- /dev/null +++ b/plugins/state_history_plugin/state_history_plugin.cpp @@ -0,0 +1,571 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using tcp = boost::asio::ip::tcp; +namespace ws = boost::beast::websocket; + +extern const char* const state_history_plugin_abi; + +namespace eosio { +using namespace chain; +using boost::signals2::scoped_connection; + +static appbase::abstract_plugin& _state_history_plugin = app().register_plugin(); + +template +auto catch_and_log(F f) { + try { + return f(); + } catch (const fc::exception& e) { + elog("${e}", ("e", e.to_detail_string())); + } catch (const std::exception& e) { + elog("${e}", ("e", e.what())); + } catch (...) { + elog("unknown exception"); + } +} + +namespace bio = boost::iostreams; +static bytes zlib_compress_bytes(bytes in) { + bytes out; + bio::filtering_ostream comp; + comp.push(bio::zlib_compressor(bio::zlib::default_compression)); + comp.push(bio::back_inserter(out)); + bio::write(comp, in.data(), in.size()); + bio::close(comp); + return out; +} + +struct state_history_plugin_impl : std::enable_shared_from_this { + chain_plugin* chain_plug = nullptr; + fc::optional trace_log; + fc::optional chain_state_log; + bool stopping = false; + fc::optional applied_transaction_connection; + fc::optional accepted_block_connection; + string endpoint_address = "0.0.0.0"; + uint16_t endpoint_port = 8080; + std::unique_ptr acceptor; + std::map cached_traces; + transaction_trace_ptr onblock_trace; + + void get_log_entry(state_history_log& log, uint32_t block_num, fc::optional& result) { + if (block_num < log.begin_block() || block_num >= log.end_block()) + return; + state_history_log_header header; + auto& stream = log.get_entry(block_num, header); + uint32_t s; + stream.read((char*)&s, sizeof(s)); + result.emplace(); + result->resize(s); + if (s) + stream.read(result->data(), s); + } + + void get_block(uint32_t block_num, fc::optional& result) { + chain::signed_block_ptr p; + try { + p = chain_plug->chain().fetch_block_by_number(block_num); + } catch (...) { + return; + } + result = fc::raw::pack(*p); + } + + fc::optional get_block_id(uint32_t block_num) { + if (trace_log && block_num >= trace_log->begin_block() && block_num < trace_log->end_block()) + return trace_log->get_block_id(block_num); + if (chain_state_log && block_num >= chain_state_log->begin_block() && block_num < chain_state_log->end_block()) + return chain_state_log->get_block_id(block_num); + try { + auto block = chain_plug->chain().fetch_block_by_number(block_num); + if (block) + return block->id(); + } catch (...) { + } + return {}; + } + + struct session : std::enable_shared_from_this { + std::shared_ptr plugin; + std::unique_ptr> socket_stream; + bool sending = false; + bool sent_abi = false; + std::vector> send_queue; + fc::optional current_request; + bool need_to_send_update = false; + + session(std::shared_ptr plugin) + : plugin(std::move(plugin)) {} + + void start(tcp::socket socket) { + ilog("incoming connection"); + socket_stream = std::make_unique>(std::move(socket)); + socket_stream->binary(true); + socket_stream->next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); + socket_stream->next_layer().set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024)); + socket_stream->next_layer().set_option(boost::asio::socket_base::receive_buffer_size(1024 * 1024)); + socket_stream->async_accept([self = shared_from_this(), this](boost::system::error_code ec) { + callback(ec, "async_accept", [&] { + start_read(); + send(state_history_plugin_abi); + }); + }); + } + + void start_read() { + auto in_buffer = std::make_shared(); + socket_stream->async_read( + *in_buffer, [self = shared_from_this(), this, in_buffer](boost::system::error_code ec, size_t) { + callback(ec, "async_read", [&] { + auto d = boost::asio::buffer_cast(boost::beast::buffers_front(in_buffer->data())); + auto s = boost::asio::buffer_size(in_buffer->data()); + fc::datastream ds(d, s); + state_request req; + fc::raw::unpack(ds, req); + req.visit(*this); + start_read(); + }); + }); + } + + void send(const char* s) { + send_queue.push_back({s, s + strlen(s)}); + send(); + } + + template + void send(T obj) { + send_queue.push_back(fc::raw::pack(state_result{std::move(obj)})); + send(); + } + + void send() { + if (sending) + return; + if (send_queue.empty()) + return send_update(); + sending = true; + socket_stream->binary(sent_abi); + sent_abi = true; + socket_stream->async_write( // + boost::asio::buffer(send_queue[0]), + [self = shared_from_this(), this](boost::system::error_code ec, size_t) { + callback(ec, "async_write", [&] { + send_queue.erase(send_queue.begin()); + sending = false; + send(); + }); + }); + } + + using result_type = void; + void operator()(get_status_request_v0&) { + auto& chain = plugin->chain_plug->chain(); + get_status_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; + if (plugin->trace_log) { + result.trace_begin_block = plugin->trace_log->begin_block(); + result.trace_end_block = plugin->trace_log->end_block(); + } + if (plugin->chain_state_log) { + result.chain_state_begin_block = plugin->chain_state_log->begin_block(); + result.chain_state_end_block = plugin->chain_state_log->end_block(); + } + send(std::move(result)); + } + + void operator()(get_blocks_request_v0& req) { + for (auto& cp : req.have_positions) { + if (req.start_block_num <= cp.block_num) + continue; + auto id = plugin->get_block_id(cp.block_num); + if (!id || *id != cp.block_id) + req.start_block_num = std::min(req.start_block_num, cp.block_num); + } + req.have_positions.clear(); + current_request = req; + send_update(true); + } + + void operator()(get_blocks_ack_request_v0& req) { + if (!current_request) + return; + current_request->max_messages_in_flight += req.num_messages; + send_update(); + } + + void send_update(bool changed = false) { + if (changed) + need_to_send_update = true; + if (!send_queue.empty() || !need_to_send_update || !current_request || + !current_request->max_messages_in_flight) + return; + auto& chain = plugin->chain_plug->chain(); + get_blocks_result_v0 result; + result.head = {chain.head_block_num(), chain.head_block_id()}; + result.last_irreversible = {chain.last_irreversible_block_num(), chain.last_irreversible_block_id()}; + uint32_t current = + current_request->irreversible_only ? result.last_irreversible.block_num : result.head.block_num; + if (current_request->start_block_num <= current && + current_request->start_block_num < current_request->end_block_num) { + auto block_id = plugin->get_block_id(current_request->start_block_num); + if (block_id) { + result.this_block = block_position{current_request->start_block_num, *block_id}; + auto prev_block_id = plugin->get_block_id(current_request->start_block_num - 1); + if (prev_block_id) + result.prev_block = block_position{current_request->start_block_num - 1, *prev_block_id}; + if (current_request->fetch_block) + plugin->get_block(current_request->start_block_num, result.block); + if (current_request->fetch_traces && plugin->trace_log) + plugin->get_log_entry(*plugin->trace_log, current_request->start_block_num, result.traces); + if (current_request->fetch_deltas && plugin->chain_state_log) + plugin->get_log_entry(*plugin->chain_state_log, current_request->start_block_num, result.deltas); + } + ++current_request->start_block_num; + } + send(std::move(result)); + --current_request->max_messages_in_flight; + need_to_send_update = current_request->start_block_num <= current && + current_request->start_block_num < current_request->end_block_num; + } + + template + void catch_and_close(F f) { + try { + f(); + } catch (const fc::exception& e) { + elog("${e}", ("e", e.to_detail_string())); + close(); + } catch (const std::exception& e) { + elog("${e}", ("e", e.what())); + close(); + } catch (...) { + elog("unknown exception"); + close(); + } + } + + template + void callback(boost::system::error_code ec, const char* what, F f) { + if (plugin->stopping) + return; + if (ec) + return on_fail(ec, what); + catch_and_close(f); + } + + void on_fail(boost::system::error_code ec, const char* what) { + try { + elog("${w}: ${m}", ("w", what)("m", ec.message())); + close(); + } catch (...) { + elog("uncaught exception on close"); + } + } + + void close() { + socket_stream->next_layer().close(); + plugin->sessions.erase(this); + } + }; + std::map> sessions; + + void listen() { + boost::system::error_code ec; + + auto address = boost::asio::ip::make_address(endpoint_address); + auto endpoint = tcp::endpoint{address, endpoint_port}; + acceptor = std::make_unique(app().get_io_service()); + + auto check_ec = [&](const char* what) { + if (!ec) + return; + elog("${w}: ${m}", ("w", what)("m", ec.message())); + EOS_ASSERT(false, plugin_exception, "unable to open listen socket"); + }; + + acceptor->open(endpoint.protocol(), ec); + check_ec("open"); + acceptor->set_option(boost::asio::socket_base::reuse_address(true)); + acceptor->bind(endpoint, ec); + check_ec("bind"); + acceptor->listen(boost::asio::socket_base::max_listen_connections, ec); + check_ec("listen"); + do_accept(); + } + + void do_accept() { + auto socket = std::make_shared(app().get_io_service()); + acceptor->async_accept(*socket, [self = shared_from_this(), socket, this](auto ec) { + if (stopping) + return; + if (ec) { + if (ec == boost::system::errc::too_many_files_open) + catch_and_log([&] { do_accept(); }); + return; + } + catch_and_log([&] { + auto s = std::make_shared(self); + sessions[s.get()] = s; + s->start(std::move(*socket)); + }); + catch_and_log([&] { do_accept(); }); + }); + } + + static bool is_onblock(const transaction_trace_ptr& p) { + if (p->action_traces.size() != 1) + return false; + auto& act = p->action_traces[0].act; + if (act.account != eosio::chain::config::system_account_name || act.name != N(onblock) || + act.authorization.size() != 1) + return false; + auto& auth = act.authorization[0]; + return auth.actor == eosio::chain::config::system_account_name && + auth.permission == eosio::chain::config::active_name; + } + + void on_applied_transaction(const transaction_trace_ptr& p) { + if (p->receipt) { + if (is_onblock(p)) + onblock_trace = p; + else if (p->failed_dtrx_trace) + cached_traces[p->failed_dtrx_trace->id] = p; + else + cached_traces[p->id] = p; + } + } + + void on_accepted_block(const block_state_ptr& block_state) { + store_traces(block_state); + store_chain_state(block_state); + for (auto& s : sessions) { + auto& p = s.second; + if (p) { + if (p->current_request && block_state->block_num < p->current_request->start_block_num) + p->current_request->start_block_num = block_state->block_num; + p->send_update(true); + } + } + } + + void store_traces(const block_state_ptr& block_state) { + if (!trace_log) + return; + std::vector traces; + if (onblock_trace) + traces.push_back(onblock_trace); + for (auto& r : block_state->block->transactions) { + transaction_id_type id; + if (r.trx.contains()) + id = r.trx.get(); + else + id = r.trx.get().id(); + auto it = cached_traces.find(id); + EOS_ASSERT(it != cached_traces.end() && it->second->receipt, plugin_exception, + "missing trace for transaction ${id}", ("id", id)); + traces.push_back(it->second); + } + cached_traces.clear(); + onblock_trace.reset(); + + auto& db = chain_plug->chain().db(); + auto traces_bin = zlib_compress_bytes(fc::raw::pack(make_history_serial_wrapper(db, traces))); + EOS_ASSERT(traces_bin.size() == (uint32_t)traces_bin.size(), plugin_exception, "traces is too big"); + + state_history_log_header header{.block_num = block_state->block->block_num(), + .block_id = block_state->block->id(), + .payload_size = sizeof(uint32_t) + traces_bin.size()}; + trace_log->write_entry(header, block_state->block->previous, [&](auto& stream) { + uint32_t s = (uint32_t)traces_bin.size(); + stream.write((char*)&s, sizeof(s)); + if (!traces_bin.empty()) + stream.write(traces_bin.data(), traces_bin.size()); + }); + } + + void store_chain_state(const block_state_ptr& block_state) { + if (!chain_state_log) + return; + bool fresh = chain_state_log->begin_block() == chain_state_log->end_block(); + if (fresh) + ilog("Placing initial state in block ${n}", ("n", block_state->block->block_num())); + + std::vector deltas; + auto& db = chain_plug->chain().db(); + + const auto& table_id_index = db.get_index(); + std::map removed_table_id; + for (auto& rem : table_id_index.stack().back().removed_values) + removed_table_id[rem.first._id] = &rem.second; + + auto get_table_id = [&](uint64_t tid) -> const table_id_object& { + auto obj = table_id_index.find(tid); + if (obj) + return *obj; + auto it = removed_table_id.find(tid); + EOS_ASSERT(it != removed_table_id.end(), chain::plugin_exception, "can not found table id ${tid}", + ("tid", tid)); + return *it->second; + }; + + auto pack_row = [&](auto& row) { return fc::raw::pack(make_history_serial_wrapper(db, row)); }; + auto pack_contract_row = [&](auto& row) { + return fc::raw::pack(make_history_context_wrapper(db, get_table_id(row.t_id._id), row)); + }; + + auto process_table = [&](auto* name, auto& index, auto& pack_row) { + if (fresh) { + if (index.indices().empty()) + return; + deltas.push_back({}); + auto& delta = deltas.back(); + delta.name = name; + for (auto& row : index.indices()) + delta.rows.obj.emplace_back(true, pack_row(row)); + } else { + if (index.stack().empty()) + return; + auto& undo = index.stack().back(); + if (undo.old_values.empty() && undo.new_ids.empty() && undo.removed_values.empty()) + return; + deltas.push_back({}); + auto& delta = deltas.back(); + delta.name = name; + for (auto& old : undo.old_values) { + auto& row = index.get(old.first); + delta.rows.obj.emplace_back(true, pack_row(row)); + } + for (auto& old : undo.removed_values) + delta.rows.obj.emplace_back(false, pack_row(old.second)); + for (auto id : undo.new_ids) { + auto& row = index.get(id); + delta.rows.obj.emplace_back(true, pack_row(row)); + } + } + }; + + process_table("account", db.get_index(), pack_row); + + process_table("contract_table", db.get_index(), pack_row); + process_table("contract_row", db.get_index(), pack_contract_row); + process_table("contract_index64", db.get_index(), pack_contract_row); + process_table("contract_index128", db.get_index(), pack_contract_row); + process_table("contract_index256", db.get_index(), pack_contract_row); + process_table("contract_index_double", db.get_index(), pack_contract_row); + process_table("contract_index_long_double", db.get_index(), pack_contract_row); + + process_table("global_property", db.get_index(), pack_row); + process_table("generated_transaction", db.get_index(), pack_row); + + process_table("permission", db.get_index(), pack_row); + process_table("permission_link", db.get_index(), pack_row); + + process_table("resource_limits", db.get_index(), pack_row); + process_table("resource_usage", db.get_index(), pack_row); + process_table("resource_limits_state", db.get_index(), pack_row); + process_table("resource_limits_config", db.get_index(), pack_row); + + auto deltas_bin = zlib_compress_bytes(fc::raw::pack(deltas)); + EOS_ASSERT(deltas_bin.size() == (uint32_t)deltas_bin.size(), plugin_exception, "deltas is too big"); + state_history_log_header header{.block_num = block_state->block->block_num(), + .block_id = block_state->block->id(), + .payload_size = sizeof(uint32_t) + deltas_bin.size()}; + chain_state_log->write_entry(header, block_state->block->previous, [&](auto& stream) { + uint32_t s = (uint32_t)deltas_bin.size(); + stream.write((char*)&s, sizeof(s)); + if (!deltas_bin.empty()) + stream.write(deltas_bin.data(), deltas_bin.size()); + }); + } // store_chain_state +}; // state_history_plugin_impl + +state_history_plugin::state_history_plugin() + : my(std::make_shared()) {} + +state_history_plugin::~state_history_plugin() {} + +void state_history_plugin::set_program_options(options_description& cli, options_description& cfg) { + auto options = cfg.add_options(); + options("state-history-dir", bpo::value()->default_value("state-history"), + "the location of the state-history directory (absolute path or relative to application data dir)"); + cli.add_options()("delete-state-history", bpo::bool_switch()->default_value(false), "clear state history files"); + options("trace-history", bpo::bool_switch()->default_value(false), "enable trace history"); + options("chain-state-history", bpo::bool_switch()->default_value(false), "enable chain state history"); + options("state-history-endpoint", bpo::value()->default_value("0.0.0.0:8080"), + "the endpoint upon which to listen for incoming connections"); +} + +void state_history_plugin::plugin_initialize(const variables_map& options) { + try { + EOS_ASSERT(options.at("disable-replay-opts").as(), plugin_exception, + "state_history_plugin requires --disable-replay-opts"); + + my->chain_plug = app().find_plugin(); + EOS_ASSERT(my->chain_plug, chain::missing_chain_plugin_exception, ""); + auto& chain = my->chain_plug->chain(); + my->applied_transaction_connection.emplace( + chain.applied_transaction.connect([&](const transaction_trace_ptr& p) { my->on_applied_transaction(p); })); + my->accepted_block_connection.emplace( + chain.accepted_block.connect([&](const block_state_ptr& p) { my->on_accepted_block(p); })); + + auto dir_option = options.at("state-history-dir").as(); + boost::filesystem::path state_history_dir; + if (dir_option.is_relative()) + state_history_dir = app().data_dir() / dir_option; + else + state_history_dir = dir_option; + + auto ip_port = options.at("state-history-endpoint").as(); + auto port = ip_port.substr(ip_port.find(':') + 1, ip_port.size()); + auto host = ip_port.substr(0, ip_port.find(':')); + my->endpoint_address = host; + my->endpoint_port = std::stoi(port); + idump((ip_port)(host)(port)); + + if (options.at("delete-state-history").as()) { + ilog("Deleting state history"); + boost::filesystem::remove_all(state_history_dir); + } + boost::filesystem::create_directories(state_history_dir); + + if (options.at("trace-history").as()) + my->trace_log.emplace("trace_history", (state_history_dir / "trace_history.log").string(), + (state_history_dir / "trace_history.index").string()); + if (options.at("chain-state-history").as()) + my->chain_state_log.emplace("chain_state_history", (state_history_dir / "chain_state_history.log").string(), + (state_history_dir / "chain_state_history.index").string()); + } + FC_LOG_AND_RETHROW() +} // state_history_plugin::plugin_initialize + +void state_history_plugin::plugin_startup() { my->listen(); } + +void state_history_plugin::plugin_shutdown() { + my->applied_transaction_connection.reset(); + my->accepted_block_connection.reset(); + while (!my->sessions.empty()) + my->sessions.begin()->second->close(); + my->stopping = true; +} + +} // namespace eosio diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp new file mode 100644 index 00000000000..bdedcc81cd9 --- /dev/null +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -0,0 +1,475 @@ +extern const char* const state_history_plugin_abi = R"({ + "version": "eosio::abi/1.1", + "structs": [ + { + "name": "get_status_request_v0", "fields": [] + }, + { + "name": "block_position", "fields": [ + { "name": "block_num", "type": "uint32" }, + { "name": "block_id", "type": "checksum256" } + ] + }, + { + "name": "get_status_result_v0", "fields": [ + { "name": "head", "type": "block_position" }, + { "name": "last_irreversible", "type": "block_position" }, + { "name": "trace_begin_block", "type": "uint32" }, + { "name": "trace_end_block", "type": "uint32" }, + { "name": "chain_state_begin_block", "type": "uint32" }, + { "name": "chain_state_end_block", "type": "uint32" } + ] + }, + { + "name": "get_blocks_request_v0", "fields": [ + { "name": "start_block_num", "type": "uint32" }, + { "name": "end_block_num", "type": "uint32" }, + { "name": "max_messages_in_flight", "type": "uint32" }, + { "name": "have_positions", "type": "block_position[]" }, + { "name": "irreversible_only", "type": "bool" }, + { "name": "fetch_block", "type": "bool" }, + { "name": "fetch_traces", "type": "bool" }, + { "name": "fetch_deltas", "type": "bool" } + ] + }, + { + "name": "get_blocks_ack_request_v0", "fields": [ + { "name": "num_messages", "type": "uint32" } + ] + }, + { + "name": "get_blocks_result_v0", "fields": [ + { "name": "head", "type": "block_position" }, + { "name": "last_irreversible", "type": "block_position" }, + { "name": "this_block", "type": "block_position?" }, + { "name": "prev_block", "type": "block_position?" }, + { "name": "block", "type": "bytes?" }, + { "name": "traces", "type": "bytes?" }, + { "name": "deltas", "type": "bytes?" } + ] + }, + { + "name": "row", "fields": [ + { "name": "present", "type": "bool" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "table_delta_v0", "fields": [ + { "name": "name", "type": "string" }, + { "name": "rows", "type": "row[]" } + ] + }, + { + "name": "action", "fields": [ + { "name": "account", "type": "name" }, + { "name": "name", "type": "name" }, + { "name": "authorization", "type": "permission_level[]" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "account_auth_sequence", "fields": [ + { "name": "account", "type": "name" }, + { "name": "sequence", "type": "uint64" } + ] + }, + { + "name": "action_receipt_v0", "fields": [ + { "name": "receiver", "type": "name" }, + { "name": "act_digest", "type": "checksum256" }, + { "name": "global_sequence", "type": "uint64" }, + { "name": "recv_sequence", "type": "uint64" }, + { "name": "auth_sequence", "type": "account_auth_sequence[]" }, + { "name": "code_sequence", "type": "varuint32" }, + { "name": "abi_sequence", "type": "varuint32" } + ] + }, + { + "name": "account_delta", "fields": [ + { "name": "account", "type": "name" }, + { "name": "delta", "type": "int64" } + ] + }, + { + "name": "action_trace_v0", "fields": [ + { "name": "receipt", "type": "action_receipt" }, + { "name": "act", "type": "action" }, + { "name": "context_free", "type": "bool" }, + { "name": "elapsed", "type": "int64" }, + { "name": "console", "type": "string" }, + { "name": "account_ram_deltas", "type": "account_delta[]" }, + { "name": "except", "type": "string?" }, + { "name": "inline_traces", "type": "action_trace[]" } + ] + }, + { + "name": "transaction_trace_v0", "fields": [ + { "name": "id", "type": "checksum256" }, + { "name": "status", "type": "uint8" }, + { "name": "cpu_usage_us", "type": "uint32" }, + { "name": "net_usage_words", "type": "varuint32" }, + { "name": "elapsed", "type": "int64" }, + { "name": "net_usage", "type": "uint64" }, + { "name": "scheduled", "type": "bool" }, + { "name": "action_traces", "type": "action_trace[]" }, + { "name": "except", "type": "string?" }, + { "name": "failed_dtrx_trace", "type": "transaction_trace?" } + ] + }, + { + "name": "packed_transaction", "fields": [ + { "name": "signatures", "type": "signature[]" }, + { "name": "compression", "type": "uint8" }, + { "name": "packed_context_free_data", "type": "bytes" }, + { "name": "packed_trx", "type": "bytes" } + ] + }, + { + "name": "transaction_receipt_header", "fields": [ + { "name": "status", "type": "uint8" }, + { "name": "cpu_usage_us", "type": "uint32" }, + { "name": "net_usage_words", "type": "varuint32" } + ] + }, + { + "name": "transaction_receipt", "base": "transaction_receipt_header", "fields": [ + { "name": "trx", "type": "transaction_variant" } + ] + }, + { + "name": "extension", "fields": [ + { "name": "type", "type": "uint16" }, + { "name": "data", "type": "bytes" } + ] + }, + { + "name": "block_header", "fields": [ + { "name": "timestamp", "type": "block_timestamp_type" }, + { "name": "producer", "type": "name" }, + { "name": "confirmed", "type": "uint16" }, + { "name": "previous", "type": "checksum256" }, + { "name": "transaction_mroot", "type": "checksum256" }, + { "name": "action_mroot", "type": "checksum256" }, + { "name": "schedule_version", "type": "uint32" }, + { "name": "new_producers", "type": "producer_schedule?" }, + { "name": "header_extensions", "type": "extension[]" } + ] + }, + { + "name": "signed_block_header", "base": "block_header", "fields": [ + { "name": "producer_signature", "type": "signature" } + ] + }, + { + "name": "signed_block", "base": "signed_block_header", "fields": [ + { "name": "transactions", "type": "transaction_receipt[]" }, + { "name": "block_extensions", "type": "extension[]" } + ] + }, + { "name": "transaction_header", "fields": [ + { "name": "expiration", "type": "time_point_sec" }, + { "name": "ref_block_num", "type": "uint16" }, + { "name": "ref_block_prefix", "type": "uint32" }, + { "name": "max_net_usage_words", "type": "varuint32" }, + { "name": "max_cpu_usage_ms", "type": "uint8" }, + { "name": "delay_sec", "type": "varuint32" } + ] + }, + { "name": "transaction", "base": "transaction_header", "fields": [ + { "name": "context_free_actions", "type": "action[]" }, + { "name": "actions", "type": "action[]" }, + { "name": "transaction_extensions", "type": "extension[]" } + ] + }, + { + "name": "account_v0", "fields": [ + { "type": "name", "name": "name" }, + { "type": "uint8", "name": "vm_type" }, + { "type": "uint8", "name": "vm_version" }, + { "type": "bool", "name": "privileged" }, + { "type": "time_point", "name": "last_code_update" }, + { "type": "checksum256", "name": "code_version" }, + { "type": "block_timestamp_type", "name": "creation_date" }, + { "type": "bytes", "name": "code" }, + { "type": "bytes", "name": "abi" } + ] + }, + { + "name": "contract_table_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "name", "name": "payer" } + ] + }, + { + "name": "contract_row_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "bytes", "name": "value" } + ] + }, + { + "name": "contract_index64_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "uint64", "name": "secondary_key" } + ] + }, + { + "name": "contract_index128_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "uint128", "name": "secondary_key" } + ] + }, + { + "name": "contract_index256_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "checksum256", "name": "secondary_key" } + ] + }, + { + "name": "contract_index_double_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "float64", "name": "secondary_key" } + ] + }, + { + "name": "contract_index_long_double_v0", "fields": [ + { "type": "name", "name": "code" }, + { "type": "name", "name": "scope" }, + { "type": "name", "name": "table" }, + { "type": "uint64", "name": "primary_key" }, + { "type": "name", "name": "payer" }, + { "type": "float128", "name": "secondary_key" } + ] + }, + { + "name": "producer_key", "fields": [ + { "type": "name", "name": "producer_name" }, + { "type": "public_key", "name": "block_signing_key" } + ] + }, + { + "name": "producer_schedule", "fields": [ + { "type": "uint32", "name": "version" }, + { "type": "producer_key[]", "name": "producers" } + ] + }, + { + "name": "chain_config_v0", "fields": [ + { "type": "uint64", "name": "max_block_net_usage" }, + { "type": "uint32", "name": "target_block_net_usage_pct" }, + { "type": "uint32", "name": "max_transaction_net_usage" }, + { "type": "uint32", "name": "base_per_transaction_net_usage" }, + { "type": "uint32", "name": "net_usage_leeway" }, + { "type": "uint32", "name": "context_free_discount_net_usage_num" }, + { "type": "uint32", "name": "context_free_discount_net_usage_den" }, + { "type": "uint32", "name": "max_block_cpu_usage" }, + { "type": "uint32", "name": "target_block_cpu_usage_pct" }, + { "type": "uint32", "name": "max_transaction_cpu_usage" }, + { "type": "uint32", "name": "min_transaction_cpu_usage" }, + { "type": "uint32", "name": "max_transaction_lifetime" }, + { "type": "uint32", "name": "deferred_trx_expiration_window" }, + { "type": "uint32", "name": "max_transaction_delay" }, + { "type": "uint32", "name": "max_inline_action_size" }, + { "type": "uint16", "name": "max_inline_action_depth" }, + { "type": "uint16", "name": "max_authority_depth" } + ] + }, + { + "name": "global_property_v0", "fields": [ + { "type": "uint32?", "name": "proposed_schedule_block_num" }, + { "type": "producer_schedule", "name": "proposed_schedule" }, + { "type": "chain_config", "name": "configuration" } + ] + }, + { + "name": "generated_transaction_v0", "fields": [ + { "type": "name", "name": "sender" }, + { "type": "uint128", "name": "sender_id" }, + { "type": "name", "name": "payer" }, + { "type": "checksum256", "name": "trx_id" }, + { "type": "bytes", "name": "packed_trx" } + ] + }, + { + "name": "key_weight", "fields": [ + { "type": "public_key", "name": "key" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "permission_level", "fields": [ + { "type": "name", "name": "actor" }, + { "type": "name", "name": "permission" } + ] + }, + { + "name": "permission_level_weight", "fields": [ + { "type": "permission_level", "name": "permission" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "wait_weight", "fields": [ + { "type": "uint32", "name": "wait_sec" }, + { "type": "uint16", "name": "weight" } + ] + }, + { + "name": "authority", "fields": [ + { "type": "uint32", "name": "threshold" }, + { "type": "key_weight[]", "name": "keys" }, + { "type": "permission_level_weight[]", "name": "accounts" }, + { "type": "wait_weight[]", "name": "waits" } + ] + }, + { + "name": "permission_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "name", "name": "name" }, + { "type": "name", "name": "parent" }, + { "type": "time_point", "name": "last_updated" }, + { "type": "authority", "name": "auth" } + ] + }, + { + "name": "permission_link_v0", "fields": [ + { "type": "name", "name": "account" }, + { "type": "name", "name": "code" }, + { "type": "name", "name": "message_type" }, + { "type": "name", "name": "required_permission" } + ] + }, + { + "name": "resource_limits_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "int64", "name": "net_weight" }, + { "type": "int64", "name": "cpu_weight" }, + { "type": "int64", "name": "ram_bytes" } + ] + }, + { + "name": "usage_accumulator_v0", "fields": [ + { "type": "uint32", "name": "last_ordinal" }, + { "type": "uint64", "name": "value_ex" }, + { "type": "uint64", "name": "consumed" } + ] + }, + { + "name": "resource_usage_v0", "fields": [ + { "type": "name", "name": "owner" }, + { "type": "usage_accumulator", "name": "net_usage" }, + { "type": "usage_accumulator", "name": "cpu_usage" }, + { "type": "uint64", "name": "ram_usage" } + ] + }, + { + "name": "resource_limits_state_v0", "fields": [ + { "type": "usage_accumulator", "name": "average_block_net_usage" }, + { "type": "usage_accumulator", "name": "average_block_cpu_usage" }, + { "type": "uint64", "name": "total_net_weight" }, + { "type": "uint64", "name": "total_cpu_weight" }, + { "type": "uint64", "name": "total_ram_bytes" }, + { "type": "uint64", "name": "virtual_net_limit" }, + { "type": "uint64", "name": "virtual_cpu_limit" } + ] + }, + { + "name": "resource_limits_ratio_v0", "fields": [ + { "type": "uint64", "name": "numerator" }, + { "type": "uint64", "name": "denominator" } + ] + }, + { + "name": "elastic_limit_parameters_v0", "fields": [ + { "type": "uint64", "name": "target" }, + { "type": "uint64", "name": "max" }, + { "type": "uint32", "name": "periods" }, + { "type": "uint32", "name": "max_multiplier" }, + { "type": "resource_limits_ratio", "name": "contract_rate" }, + { "type": "resource_limits_ratio", "name": "expand_rate" } + ] + }, + { + "name": "resource_limits_config_v0", "fields": [ + { "type": "elastic_limit_parameters", "name": "cpu_limit_parameters" }, + { "type": "elastic_limit_parameters", "name": "net_limit_parameters" }, + { "type": "uint32", "name": "account_cpu_usage_average_window" }, + { "type": "uint32", "name": "account_net_usage_average_window" } + ] + } + ], + "types": [ + { "new_type_name": "transaction_id", "type": "checksum256" } + ], + "variants": [ + { "name": "request", "types": ["get_status_request_v0", "get_blocks_request_v0", "get_blocks_ack_request_v0"] }, + { "name": "result", "types": ["get_status_result_v0", "get_blocks_result_v0"] }, + + { "name": "action_receipt", "types": ["action_receipt_v0"] }, + { "name": "action_trace", "types": ["action_trace_v0"] }, + { "name": "transaction_trace", "types": ["transaction_trace_v0"] }, + { "name": "transaction_variant", "types": ["transaction_id", "packed_transaction"] }, + + { "name": "table_delta", "types": ["table_delta_v0"] }, + { "name": "account", "types": ["account_v0"] }, + { "name": "contract_table", "types": ["contract_table_v0"] }, + { "name": "contract_row", "types": ["contract_row_v0"] }, + { "name": "contract_index64", "types": ["contract_index64_v0"] }, + { "name": "contract_index128", "types": ["contract_index128_v0"] }, + { "name": "contract_index256", "types": ["contract_index256_v0"] }, + { "name": "contract_index_double", "types": ["contract_index_double_v0"] }, + { "name": "contract_index_long_double", "types": ["contract_index_long_double_v0"] }, + { "name": "chain_config", "types": ["chain_config_v0"] }, + { "name": "global_property", "types": ["global_property_v0"] }, + { "name": "generated_transaction", "types": ["generated_transaction_v0"] }, + { "name": "permission", "types": ["permission_v0"] }, + { "name": "permission_link", "types": ["permission_link_v0"] }, + { "name": "resource_limits", "types": ["resource_limits_v0"] }, + { "name": "usage_accumulator", "types": ["usage_accumulator_v0"] }, + { "name": "resource_usage", "types": ["resource_usage_v0"] }, + { "name": "resource_limits_state", "types": ["resource_limits_state_v0"] }, + { "name": "resource_limits_ratio", "types": ["resource_limits_ratio_v0"] }, + { "name": "elastic_limit_parameters", "types": ["elastic_limit_parameters_v0"] }, + { "name": "resource_limits_config", "types": ["resource_limits_config_v0"] } + ], + "tables": [ + { "name": "account", "type": "account", "key_names": ["name"] }, + { "name": "contract_table", "type": "contract_table", "key_names": ["code", "scope", "table"] }, + { "name": "contract_row", "type": "contract_row", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index64", "type": "contract_index64", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index128", "type": "contract_index128", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index256", "type": "contract_index256", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index_double", "type": "contract_index_double", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "contract_index_long_double", "type": "contract_index_long_double", "key_names": ["code", "scope", "table", "primary_key"] }, + { "name": "global_property", "type": "global_property", "key_names": [] }, + { "name": "generated_transaction", "type": "generated_transaction", "key_names": ["sender", "sender_id"] }, + { "name": "permission", "type": "permission", "key_names": ["owner", "name"] }, + { "name": "permission_link", "type": "permission_link", "key_names": ["account", "code", "message_type"] }, + { "name": "resource_limits", "type": "resource_limits", "key_names": ["owner"] }, + { "name": "resource_usage", "type": "resource_usage", "key_names": ["owner"] }, + { "name": "resource_limits_state", "type": "resource_limits_state", "key_names": [] }, + { "name": "resource_limits_config", "type": "resource_limits_config", "key_names": [] } + ] +})"; diff --git a/plugins/test_control_plugin/CMakeLists.txt b/plugins/test_control_plugin/CMakeLists.txt index aa6b1cff397..7e2a79d6c5c 100644 --- a/plugins/test_control_plugin/CMakeLists.txt +++ b/plugins/test_control_plugin/CMakeLists.txt @@ -4,6 +4,6 @@ add_library( test_control_plugin test_control_plugin.cpp ${HEADERS} ) -target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain eos_utilities ) +target_link_libraries( test_control_plugin producer_plugin chain_plugin http_client_plugin appbase eosio_chain ) target_include_directories( test_control_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 6288e8c347d..6b4753e9919 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/plugins/wallet_plugin/se_wallet.cpp b/plugins/wallet_plugin/se_wallet.cpp index 6e1a4fe0e17..b292495c5cc 100644 --- a/plugins/wallet_plugin/se_wallet.cpp +++ b/plugins/wallet_plugin/se_wallet.cpp @@ -305,6 +305,14 @@ se_wallet::se_wallet() : my(new detail::se_wallet_impl()) { return; } } + if(sscanf(model, "Macmini%u", &major) == 1 && major >= 8) { + my->populate_existing_keys(); + return; + } + if(sscanf(model, "MacBookAir%u", &major) == 1 && major >= 8) { + my->populate_existing_keys(); + return; + } } EOS_THROW(secure_enclave_exception, "Secure Enclave not supported on this hardware"); diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index b3a656c3b10..a40ef3b423c 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -2,5 +2,4 @@ add_subdirectory( nodeos ) add_subdirectory( cleos ) add_subdirectory( keosd ) add_subdirectory( eosio-launcher ) -add_subdirectory( eosio-abigen ) add_subdirectory( eosio-blocklog ) diff --git a/programs/cleos/eosc.pot b/programs/cleos/eosc.pot index 8196aad741d..d0927037809 100644 --- a/programs/cleos/eosc.pot +++ b/programs/cleos/eosc.pot @@ -343,16 +343,16 @@ msgstr "" msgid "set or update blockchain action state" msgstr "" -msgid "Transfer EOS from account to account" +msgid "Transfer tokens from account to account" msgstr "" -msgid "The account sending EOS" +msgid "The account sending tokens" msgstr "" -msgid "The account receiving EOS" +msgid "The account receiving tokens" msgstr "" -msgid "The amount of EOS to send" +msgid "The amount of tokens to send" msgstr "" msgid "The memo for the transfer" diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index 7124357f158..ddcb8c11728 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -35,7 +35,7 @@ Usage: programs/cleos/cleos [OPTIONS] SUBCOMMAND create Create various items, on and off the blockchain get Retrieve various items and information from the blockchain set Set or update blockchain state - transfer Transfer EOS from account to account + transfer Transfer tokens from account to account net Interact with local p2p network connections wallet Interact with local wallet sign Sign a transaction @@ -84,7 +84,6 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey #include #include #include -#include #include #include @@ -129,7 +128,6 @@ Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey using namespace std; using namespace eosio; using namespace eosio::chain; -using namespace eosio::utilities; using namespace eosio::client::help; using namespace eosio::client::http; using namespace eosio::client::localize; @@ -234,6 +232,13 @@ vector get_account_permissions(const vector& pe return accountPermissions; } +vector get_account_permissions(const vector& permissions, const chain::permission_level& default_permission) { + if (permissions.empty()) + return vector{default_permission}; + else + return get_account_permissions(tx_permission); +} + template fc::variant call( const std::string& url, const std::string& path, @@ -509,7 +514,7 @@ void send_transaction( signed_transaction& trx, int32_t extra_kcpu, packed_trans chain::action create_newaccount(const name& creator, const name& newaccount, public_key_type owner, public_key_type active) { return action { - tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {creator,config::active_name}), eosio::chain::newaccount{ .creator = creator, .name = newaccount, @@ -528,7 +533,7 @@ chain::action create_buyram(const name& creator, const name& newaccount, const a ("payer", creator.to_string()) ("receiver", newaccount.to_string()) ("quant", quantity.to_string()); - return create_action(tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {creator,config::active_name}), config::system_account_name, N(buyram), act_payload); } @@ -537,7 +542,7 @@ chain::action create_buyrambytes(const name& creator, const name& newaccount, ui ("payer", creator.to_string()) ("receiver", newaccount.to_string()) ("bytes", numbytes); - return create_action(tx_permission.empty() ? vector{{creator,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {creator,config::active_name}), config::system_account_name, N(buyrambytes), act_payload); } @@ -548,19 +553,18 @@ chain::action create_delegate(const name& from, const name& receiver, const asse ("stake_net_quantity", net.to_string()) ("stake_cpu_quantity", cpu.to_string()) ("transfer", transfer); - return create_action(tx_permission.empty() ? vector{{from,config::active_name}} : get_account_permissions(tx_permission), + return create_action(get_account_permissions(tx_permission, {from,config::active_name}), config::system_account_name, N(delegatebw), act_payload); } -fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, const string& location) { -auto _location=atoi(location.c_str()); - FC_ASSERT(_location>-12&&_location<=12,"time zone setting is not legal"); - _location=_location>=0?_location:24+_location; +fc::variant regproducer_variant(const account_name& producer, const public_key_type& key, const string& url, int16_t location) { + FC_ASSERT(location>-12&&location<=12,"time zone setting is not legal"); + location=location>=0?location:24+location; return fc::mutable_variant_object() ("producer", producer) ("producer_key", key) ("url", url) - ("location", _location) + ("location", location) ; } @@ -570,7 +574,7 @@ chain::action create_open(const string& contract, const name& owner, symbol sym, ("symbol", sym) ("ram_payer", ram_payer); return action { - tx_permission.empty() ? vector{{ram_payer,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {ram_payer,config::active_name}), contract, "open", variant_to_bin( contract, N(open), open_ ) }; } @@ -584,14 +588,14 @@ chain::action create_transfer(const string& contract, const name& sender, const ("memo", memo); return action { - tx_permission.empty() ? vector{{sender,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {sender,config::active_name}), contract, "transfer", variant_to_bin( contract, N(transfer), transfer ) }; } chain::action create_setabi(const name& account, const bytes& abi) { return action { - tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {account,config::active_name}), setabi{ .account = account, .abi = abi @@ -601,7 +605,7 @@ chain::action create_setabi(const name& account, const bytes& abi) { chain::action create_setcode(const name& account, const bytes& code) { return action { - tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + get_account_permissions(tx_permission, {account,config::active_name}), setcode{ .account = account, .vmtype = 0, @@ -612,22 +616,22 @@ chain::action create_setcode(const name& account, const bytes& code) { } chain::action create_updateauth(const name& account, const name& permission, const name& parent, const authority& auth) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), updateauth{account, permission, parent, auth}}; } chain::action create_deleteauth(const name& account, const name& permission) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), deleteauth{account, permission}}; } chain::action create_linkauth(const name& account, const name& code, const name& type, const name& requirement) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), linkauth{account, code, type, requirement}}; } chain::action create_unlinkauth(const name& account, const name& code, const name& type) { - return action { tx_permission.empty() ? vector{{account,config::active_name}} : get_account_permissions(tx_permission), + return action { get_account_permissions(tx_permission, {account,config::active_name}), unlinkauth{account, code, type}}; } @@ -686,58 +690,134 @@ inline asset to_asset( const string& s ) { } struct set_account_permission_subcommand { - string accountStr; - string permissionStr; - string authorityJsonOrFile; - string parentStr; + name account; + name permission; + string authority_json_or_file; + name parent; + bool add_code; + bool remove_code; set_account_permission_subcommand(CLI::App* accountCmd) { auto permissions = accountCmd->add_subcommand("permission", localized("set parameters dealing with account permissions")); - permissions->add_option("account", accountStr, localized("The account to set/delete a permission authority for"))->required(); - permissions->add_option("permission", permissionStr, localized("The permission name to set/delete an authority for"))->required(); - permissions->add_option("authority", authorityJsonOrFile, localized("[delete] NULL, [create/update] public key, JSON string, or filename defining the authority"))->required(); - permissions->add_option("parent", parentStr, localized("[create] The permission name of this parents permission (Defaults to: \"Active\")")); + permissions->add_option("account", account, localized("The account to set/delete a permission authority for"))->required(); + permissions->add_option("permission", permission, localized("The permission name to set/delete an authority for"))->required(); + permissions->add_option("authority", authority_json_or_file, localized("[delete] NULL, [create/update] public key, JSON string or filename defining the authority, [code] contract name")); + permissions->add_option("parent", parent, localized("[create] The permission name of this parents permission, defaults to 'active'")); + permissions->add_flag("--add-code", add_code, localized("[code] add '${code}' permission to specified permission authority", ("code", name(config::eosio_code_name)))); + permissions->add_flag("--remove-code", remove_code, localized("[code] remove '${code}' permission from specified permission authority", ("code", name(config::eosio_code_name)))); add_standard_transaction_options(permissions, "account@active"); permissions->set_callback([this] { - name account = name(accountStr); - name permission = name(permissionStr); - bool is_delete = boost::iequals(authorityJsonOrFile, "null"); + EOSC_ASSERT( !(add_code && remove_code), "ERROR: Either --add-code or --remove-code can be set" ); + EOSC_ASSERT( (add_code ^ remove_code) || !authority_json_or_file.empty(), "ERROR: authority should be specified unless add or remove code permission" ); - if (is_delete) { - send_actions({create_deleteauth(account, permission)}); - } else { - authority auth = parse_json_authority_or_key(authorityJsonOrFile); + authority auth; + + bool need_parent = parent.empty() && (permission != name("owner")); + bool need_auth = add_code || remove_code; + + if ( !need_auth && boost::iequals(authority_json_or_file, "null") ) { + send_actions( { create_deleteauth(account, permission) } ); + return; + } - name parent; - if (parentStr.size() == 0 && permissionStr != "owner") { + if ( need_parent || need_auth ) { + fc::variant json = call(get_account_func, fc::mutable_variant_object("account_name", account.to_string())); + auto res = json.as(); + auto itr = std::find_if(res.permissions.begin(), res.permissions.end(), [&](const auto& perm) { + return perm.perm_name == permission; + }); + + if ( need_parent ) { // see if we can auto-determine the proper parent - const auto account_result = call(get_account_func, fc::mutable_variant_object("account_name", accountStr)); - const auto& existing_permissions = account_result.get_object()["permissions"].get_array(); - auto permissionPredicate = [this](const auto& perm) { - return perm.is_object() && - perm.get_object().contains("perm_name") && - boost::equals(perm.get_object()["perm_name"].get_string(), permissionStr); - }; - - auto itr = boost::find_if(existing_permissions, permissionPredicate); - if (itr != existing_permissions.end()) { - parent = name((*itr).get_object()["parent"].get_string()); + if ( itr != res.permissions.end() ) { + parent = (*itr).parent; } else { // if this is a new permission and there is no parent we default to "active" parent = name(config::active_name); + } + } + if ( need_auth ) { + auto actor = (authority_json_or_file.empty()) ? account : name(authority_json_or_file); + auto code_name = name(config::eosio_code_name); + + if ( itr != res.permissions.end() ) { + // fetch existing authority + auth = std::move((*itr).required_auth); + + auto code_perm = permission_level { actor, code_name }; + auto itr2 = std::lower_bound(auth.accounts.begin(), auth.accounts.end(), code_perm, [&](const auto& perm_level, const auto& value) { + return perm_level.permission < value; // Safe since valid authorities must order the permissions in accounts in ascending order + }); + + if ( add_code ) { + if ( itr2 != auth.accounts.end() && itr2->permission == code_perm ) { + // authority already contains code permission, promote its weight to satisfy threshold + if ( (*itr2).weight < auth.threshold ) { + if ( auth.threshold > std::numeric_limits::max() ) { + std::cerr << "ERROR: Threshold is too high to be satisfied by sole code permission" << std::endl; + return; + } + std::cerr << localized("The weight of '${actor}@${code}' in '${permission}' permission authority will be increased up to threshold", + ("actor", actor)("code", code_name)("permission", permission)) << std::endl; + (*itr2).weight = static_cast(auth.threshold); + } else { + std::cerr << localized("ERROR: The permission '${permission}' already contains '${actor}@${code}'", + ("permission", permission)("actor", actor)("code", code_name)) << std::endl; + return ; + } + } else { + // add code permission to specified authority + if ( auth.threshold > std::numeric_limits::max() ) { + std::cerr << "ERROR: Threshold is too high to be satisfied by sole code permission" << std::endl; + return; + } + auth.accounts.insert( itr2, permission_level_weight { + .permission = { actor, code_name }, + .weight = static_cast(auth.threshold) + }); + } + } else { + if ( itr2 != auth.accounts.end() && itr2->permission == code_perm ) { + // remove code permission, if authority becomes empty by the removal of code permission, delete permission + auth.accounts.erase( itr2 ); + if ( auth.keys.empty() && auth.accounts.empty() && auth.waits.empty() ) { + send_actions( { create_deleteauth(account, permission) } ); + return; + } + } else { + // authority doesn't contain code permission + std::cerr << localized("ERROR: '${actor}@${code}' does not exist in '${permission}' permission authority", + ("actor", actor)("code", code_name)("permission", permission)) << std::endl; + return; + } + } + } else { + if ( add_code ) { + // create new permission including code permission + auth.threshold = 1; + auth.accounts.push_back( permission_level_weight { + .permission = { actor, code_name }, + .weight = 1 + }); + } else { + // specified permission doesn't exist, so failed to remove code permission from it + std::cerr << localized("ERROR: The permission '${permission}' does not exist", ("permission", permission)) << std::endl; + return; + } } - } else { - parent = name(parentStr); } + } - send_actions({create_updateauth(account, permission, parent, auth)}); + if ( !need_auth ) { + auth = parse_json_authority_or_key(authority_json_or_file); } + + send_actions( { create_updateauth(account, permission, parent, auth) } ); }); } - }; struct set_action_permission_subcommand { @@ -864,15 +944,15 @@ struct register_producer_subcommand { string producer_str; string producer_key_str; string url; - string loc; + int16_t loc = 0; register_producer_subcommand(CLI::App* actionRoot) { auto register_producer = actionRoot->add_subcommand("regproducer", localized("Register a new producer")); register_producer->add_option("account", producer_str, localized("The account to register as a producer"))->required(); register_producer->add_option("producer_key", producer_key_str, localized("The producer's public key"))->required(); register_producer->add_option("url", url, localized("url where info about producer can be found"), true); - register_producer->add_option("location", loc, localized("time zone from -11 to 12 "))->required(); - add_standard_transaction_options(register_producer); + register_producer->add_option("location", loc, localized("time zone from -11 to 12"), true)->required(); + add_standard_transaction_options(register_producer, "account@active"); register_producer->set_callback([this] { @@ -882,7 +962,8 @@ struct register_producer_subcommand { } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid producer public key: ${public_key}", ("public_key", producer_key_str)) auto regprod_var = regproducer_variant(producer_str, producer_key, url, loc ); - send_actions({create_action({permission_level{producer_str,config::active_name}}, config::system_account_name, N(regproducer), regprod_var)}); + auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproducer), regprod_var)}); }); } }; @@ -913,20 +994,20 @@ struct create_account_subcommand { if (!simple) { createAccount->add_option("--stake-net", stake_net, - (localized("The amount of EOS delegated for net bandwidth")))->required(); + (localized("The amount of tokens delegated for net bandwidth")))->required(); createAccount->add_option("--stake-cpu", stake_cpu, - (localized("The amount of EOS delegated for CPU bandwidth")))->required(); + (localized("The amount of tokens delegated for CPU bandwidth")))->required(); createAccount->add_option("--buy-ram-kbytes", buy_ram_bytes_in_kbytes, (localized("The amount of RAM bytes to purchase for the new account in kibibytes (KiB)"))); createAccount->add_option("--buy-ram-bytes", buy_ram_bytes, (localized("The amount of RAM bytes to purchase for the new account in bytes"))); createAccount->add_option("--buy-ram", buy_ram_eos, - (localized("The amount of RAM bytes to purchase for the new account in EOS"))); + (localized("The amount of RAM bytes to purchase for the new account in tokens"))); createAccount->add_flag("--transfer", transfer, - (localized("Transfer voting power and right to unstake EOS to receiver"))); + (localized("Transfer voting power and right to unstake tokens to receiver"))); } - add_standard_transaction_options(createAccount); + add_standard_transaction_options(createAccount, "creator@active"); createAccount->set_callback([this] { if( !active_key_str.size() ) @@ -965,13 +1046,14 @@ struct unregister_producer_subcommand { unregister_producer_subcommand(CLI::App* actionRoot) { auto unregister_producer = actionRoot->add_subcommand("unregprod", localized("Unregister an existing producer")); unregister_producer->add_option("account", producer_str, localized("The account to unregister as a producer"))->required(); - add_standard_transaction_options(unregister_producer); + add_standard_transaction_options(unregister_producer, "account@active"); unregister_producer->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("producer", producer_str); - send_actions({create_action({permission_level{producer_str,config::active_name}}, config::system_account_name, N(unregprod), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {producer_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(unregprod), act_payload)}); }); } }; @@ -984,14 +1066,15 @@ struct vote_producer_proxy_subcommand { auto vote_proxy = actionRoot->add_subcommand("proxy", localized("Vote your stake through a proxy")); vote_proxy->add_option("voter", voter_str, localized("The voting account"))->required(); vote_proxy->add_option("proxy", proxy_str, localized("The proxy account"))->required(); - add_standard_transaction_options(vote_proxy); + add_standard_transaction_options(vote_proxy, "voter@active"); vote_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("voter", voter_str) ("proxy", proxy_str) ("producers", std::vector{}); - send_actions({create_action({permission_level{voter_str,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1004,7 +1087,7 @@ struct vote_producers_subcommand { auto vote_producers = actionRoot->add_subcommand("prods", localized("Vote for one or more producers")); vote_producers->add_option("voter", voter_str, localized("The voting account"))->required(); vote_producers->add_option("producers", producer_names, localized("The account(s) to vote for. All options from this position and following will be treated as the producer list."))->required(); - add_standard_transaction_options(vote_producers); + add_standard_transaction_options(vote_producers, "voter@active"); vote_producers->set_callback([this] { @@ -1014,7 +1097,8 @@ struct vote_producers_subcommand { ("voter", voter_str) ("proxy", "") ("producers", producer_names); - send_actions({create_action({permission_level{voter_str,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1027,7 +1111,7 @@ struct approve_producer_subcommand { auto approve_producer = actionRoot->add_subcommand("approve", localized("Add one producer to list of voted producers")); approve_producer->add_option("voter", voter, localized("The voting account"))->required(); approve_producer->add_option("producer", producer_name, localized("The account to vote for"))->required(); - add_standard_transaction_options(approve_producer); + add_standard_transaction_options(approve_producer, "voter@active"); approve_producer->set_callback([this] { auto result = call(get_table_func, fc::mutable_variant_object("json", true) @@ -1036,10 +1120,16 @@ struct approve_producer_subcommand { ("table", "voters") ("table_key", "owner") ("lower_bound", voter.value) + ("upper_bound", voter.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) ); auto res = result.as(); - if ( res.rows.empty() || res.rows[0]["owner"].as_string() != name(voter).to_string() ) { + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + // Although since this subcommand will actually change the voter's vote, it is probably better to just keep this check to protect + // against future potential chain_plugin bugs. + if( res.rows.empty() || res.rows[0].get_object()["owner"].as_string() != name(voter).to_string() ) { std::cerr << "Voter info not found for account " << voter << std::endl; return; } @@ -1060,7 +1150,8 @@ struct approve_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - send_actions({create_action({permission_level{voter,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1073,7 +1164,7 @@ struct unapprove_producer_subcommand { auto approve_producer = actionRoot->add_subcommand("unapprove", localized("Remove one producer from list of voted producers")); approve_producer->add_option("voter", voter, localized("The voting account"))->required(); approve_producer->add_option("producer", producer_name, localized("The account to remove from voted producers"))->required(); - add_standard_transaction_options(approve_producer); + add_standard_transaction_options(approve_producer, "voter@active"); approve_producer->set_callback([this] { auto result = call(get_table_func, fc::mutable_variant_object("json", true) @@ -1082,10 +1173,16 @@ struct unapprove_producer_subcommand { ("table", "voters") ("table_key", "owner") ("lower_bound", voter.value) + ("upper_bound", voter.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to voter.value when cleos no longer needs to support nodeos versions older than 1.5.0 ("limit", 1) ); auto res = result.as(); - if ( res.rows.empty() || res.rows[0]["owner"].as_string() != name(voter).to_string() ) { + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + // Although since this subcommand will actually change the voter's vote, it is probably better to just keep this check to protect + // against future potential chain_plugin bugs. + if( res.rows.empty() || res.rows[0].get_object()["owner"].as_string() != name(voter).to_string() ) { std::cerr << "Voter info not found for account " << voter << std::endl; return; } @@ -1105,7 +1202,8 @@ struct unapprove_producer_subcommand { ("voter", voter) ("proxy", "") ("producers", prods); - send_actions({create_action({permission_level{voter,config::active_name}}, config::system_account_name, N(voteproducer), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {voter,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(voteproducer), act_payload)}); }); } }; @@ -1211,12 +1309,12 @@ struct delegate_bandwidth_subcommand { auto delegate_bandwidth = actionRoot->add_subcommand("delegatebw", localized("Delegate bandwidth")); delegate_bandwidth->add_option("from", from_str, localized("The account to delegate bandwidth from"))->required(); delegate_bandwidth->add_option("receiver", receiver_str, localized("The account to receive the delegated bandwidth"))->required(); - delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of EOS to stake for network bandwidth"))->required(); - delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of EOS to stake for CPU bandwidth"))->required(); - delegate_bandwidth->add_option("--buyram", buy_ram_amount, localized("The amount of EOS to buyram")); + delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of tokens to stake for network bandwidth"))->required(); + delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of tokens to stake for CPU bandwidth"))->required(); + delegate_bandwidth->add_option("--buyram", buy_ram_amount, localized("The amount of tokens to buyram")); delegate_bandwidth->add_option("--buy-ram-bytes", buy_ram_bytes, localized("The amount of RAM to buy in number of bytes")); - delegate_bandwidth->add_flag("--transfer", transfer, localized("Transfer voting power and right to unstake EOS to receiver")); - add_standard_transaction_options(delegate_bandwidth); + delegate_bandwidth->add_flag("--transfer", transfer, localized("Transfer voting power and right to unstake tokens to receiver")); + add_standard_transaction_options(delegate_bandwidth, "from@active"); delegate_bandwidth->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1225,7 +1323,8 @@ struct delegate_bandwidth_subcommand { ("stake_net_quantity", to_asset(stake_net_amount)) ("stake_cpu_quantity", to_asset(stake_cpu_amount)) ("transfer", transfer); - std::vector acts{create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(delegatebw), act_payload)}; + auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + std::vector acts{create_action(accountPermissions, config::system_account_name, N(delegatebw), act_payload)}; EOSC_ASSERT( !(buy_ram_amount.size()) || !buy_ram_bytes, "ERROR: --buyram and --buy-ram-bytes cannot be set at the same time" ); if (buy_ram_amount.size()) { acts.push_back( create_buyram(from_str, receiver_str, to_asset(buy_ram_amount)) ); @@ -1248,9 +1347,9 @@ struct undelegate_bandwidth_subcommand { auto undelegate_bandwidth = actionRoot->add_subcommand("undelegatebw", localized("Undelegate bandwidth")); undelegate_bandwidth->add_option("from", from_str, localized("The account undelegating bandwidth"))->required(); undelegate_bandwidth->add_option("receiver", receiver_str, localized("The account to undelegate bandwidth from"))->required(); - undelegate_bandwidth->add_option("unstake_net_quantity", unstake_net_amount, localized("The amount of EOS to undelegate for network bandwidth"))->required(); - undelegate_bandwidth->add_option("unstake_cpu_quantity", unstake_cpu_amount, localized("The amount of EOS to undelegate for CPU bandwidth"))->required(); - add_standard_transaction_options(undelegate_bandwidth); + undelegate_bandwidth->add_option("unstake_net_quantity", unstake_net_amount, localized("The amount of tokens to undelegate for network bandwidth"))->required(); + undelegate_bandwidth->add_option("unstake_cpu_quantity", unstake_cpu_amount, localized("The amount of tokens to undelegate for CPU bandwidth"))->required(); + add_standard_transaction_options(undelegate_bandwidth, "from@active"); undelegate_bandwidth->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() @@ -1258,7 +1357,8 @@ struct undelegate_bandwidth_subcommand { ("receiver", receiver_str) ("unstake_net_quantity", to_asset(unstake_net_amount)) ("unstake_cpu_quantity", to_asset(unstake_cpu_amount)); - send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(undelegatebw), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {from_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(undelegatebw), act_payload)}); }); } }; @@ -1271,47 +1371,57 @@ struct bidname_subcommand { auto bidname = actionRoot->add_subcommand("bidname", localized("Name bidding")); bidname->add_option("bidder", bidder_str, localized("The bidding account"))->required(); bidname->add_option("newname", newname_str, localized("The bidding name"))->required(); - bidname->add_option("bid", bid_amount, localized("The amount of EOS to bid"))->required(); - add_standard_transaction_options(bidname); + bidname->add_option("bid", bid_amount, localized("The amount of tokens to bid"))->required(); + add_standard_transaction_options(bidname, "bidder@active"); bidname->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("bidder", bidder_str) ("newname", newname_str) ("bid", to_asset(bid_amount)); - send_actions({create_action({permission_level{bidder_str, config::active_name}}, config::system_account_name, N(bidname), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {bidder_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(bidname), act_payload)}); }); } }; struct bidname_info_subcommand { bool print_json = false; - string newname_str; + name newname; bidname_info_subcommand(CLI::App* actionRoot) { auto list_producers = actionRoot->add_subcommand("bidnameinfo", localized("Get bidname info")); list_producers->add_flag("--json,-j", print_json, localized("Output in JSON format")); - list_producers->add_option("newname", newname_str, localized("The bidding name"))->required(); + list_producers->add_option("newname", newname, localized("The bidding name"))->required(); list_producers->set_callback([this] { auto rawResult = call(get_table_func, fc::mutable_variant_object("json", true) ("code", "eosio")("scope", "eosio")("table", "namebids") - ("lower_bound", eosio::chain::string_to_name(newname_str.c_str()))("limit", 1)); + ("lower_bound", newname.value) + ("upper_bound", newname.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to newname.value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1)); + if ( print_json ) { std::cout << fc::json::to_pretty_string(rawResult) << std::endl; return; } auto result = rawResult.as(); - if ( result.rows.empty() ) { + // Condition in if statement below can simply be res.rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + if( result.rows.empty() || result.rows[0].get_object()["newname"].as_string() != newname.to_string() ) { std::cout << "No bidname record found" << std::endl; return; } - for ( auto& row : result.rows ) { - fc::time_point time(fc::microseconds(row["last_bid_time"].as_uint64())); - int64_t bid = row["high_bid"].as_int64(); - std::cout << std::left << std::setw(18) << "bidname:" << std::right << std::setw(24) << row["newname"].as_string() << "\n" - << std::left << std::setw(18) << "highest bidder:" << std::right << std::setw(24) << row["high_bidder"].as_string() << "\n" - << std::left << std::setw(18) << "highest bid:" << std::right << std::setw(24) << (bid > 0 ? bid : -bid) << "\n" - << std::left << std::setw(18) << "last bid time:" << std::right << std::setw(24) << ((std::string)time).c_str() << std::endl; - if (bid < 0) std::cout << "This auction has already closed" << std::endl; + const auto& row = result.rows[0]; + string time = row["last_bid_time"].as_string(); + try { + time = (string)fc::time_point(fc::microseconds(to_uint64(time))); + } catch (fc::parse_error_exception&) { } + int64_t bid = row["high_bid"].as_int64(); + std::cout << std::left << std::setw(18) << "bidname:" << std::right << std::setw(24) << row["newname"].as_string() << "\n" + << std::left << std::setw(18) << "highest bidder:" << std::right << std::setw(24) << row["high_bidder"].as_string() << "\n" + << std::left << std::setw(18) << "highest bid:" << std::right << std::setw(24) << (bid > 0 ? bid : -bid) << "\n" + << std::left << std::setw(18) << "last bid time:" << std::right << std::setw(24) << time << std::endl; + if (bid < 0) std::cout << "This auction has already closed" << std::endl; }); } }; @@ -1364,10 +1474,10 @@ struct buyram_subcommand { auto buyram = actionRoot->add_subcommand("buyram", localized("Buy RAM")); buyram->add_option("payer", from_str, localized("The account paying for RAM"))->required(); buyram->add_option("receiver", receiver_str, localized("The account receiving bought RAM"))->required(); - buyram->add_option("amount", amount, localized("The amount of EOS to pay for RAM, or number of bytes/kibibytes of RAM if --bytes/--kbytes is set"))->required(); + buyram->add_option("amount", amount, localized("The amount of tokens to pay for RAM, or number of bytes/kibibytes of RAM if --bytes/--kbytes is set"))->required(); buyram->add_flag("--kbytes,-k", kbytes, localized("buyram in number of kibibytes (KiB)")); buyram->add_flag("--bytes,-b", bytes, localized("buyram in number of bytes")); - add_standard_transaction_options(buyram); + add_standard_transaction_options(buyram, "payer@active"); buyram->set_callback([this] { EOSC_ASSERT( !kbytes || !bytes, "ERROR: --kbytes and --bytes cannot be set at the same time" ); if (kbytes || bytes) { @@ -1386,15 +1496,16 @@ struct sellram_subcommand { sellram_subcommand(CLI::App* actionRoot) { auto sellram = actionRoot->add_subcommand("sellram", localized("Sell RAM")); - sellram->add_option("account", receiver_str, localized("The account to receive EOS for sold RAM"))->required(); + sellram->add_option("account", receiver_str, localized("The account to receive tokens for sold RAM"))->required(); sellram->add_option("bytes", amount, localized("Number of RAM bytes to sell"))->required(); - add_standard_transaction_options(sellram); + add_standard_transaction_options(sellram, "account@active"); sellram->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("account", receiver_str) ("bytes", amount); - send_actions({create_action({permission_level{receiver_str,config::active_name}}, config::system_account_name, N(sellram), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {receiver_str,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(sellram), act_payload)}); }); } }; @@ -1405,12 +1516,13 @@ struct claimrewards_subcommand { claimrewards_subcommand(CLI::App* actionRoot) { auto claim_rewards = actionRoot->add_subcommand("claimrewards", localized("Claim producer rewards")); claim_rewards->add_option("owner", owner, localized("The account to claim rewards for"))->required(); - add_standard_transaction_options(claim_rewards); + add_standard_transaction_options(claim_rewards, "owner@active"); claim_rewards->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("owner", owner); - send_actions({create_action({permission_level{owner,config::active_name}}, config::system_account_name, N(claimrewards), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {owner,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(claimrewards), act_payload)}); }); } }; @@ -1421,13 +1533,14 @@ struct regproxy_subcommand { regproxy_subcommand(CLI::App* actionRoot) { auto register_proxy = actionRoot->add_subcommand("regproxy", localized("Register an account as a proxy (for voting)")); register_proxy->add_option("proxy", proxy, localized("The proxy account to register"))->required(); - add_standard_transaction_options(register_proxy); + add_standard_transaction_options(register_proxy, "proxy@active"); register_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", true); - send_actions({create_action({permission_level{proxy,config::active_name}}, config::system_account_name, N(regproxy), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } }; @@ -1438,13 +1551,14 @@ struct unregproxy_subcommand { unregproxy_subcommand(CLI::App* actionRoot) { auto unregister_proxy = actionRoot->add_subcommand("unregproxy", localized("Unregister an account as a proxy (for voting)")); unregister_proxy->add_option("proxy", proxy, localized("The proxy account to unregister"))->required(); - add_standard_transaction_options(unregister_proxy); + add_standard_transaction_options(unregister_proxy, "proxy@active"); unregister_proxy->set_callback([this] { fc::variant act_payload = fc::mutable_variant_object() ("proxy", proxy) ("isproxy", false); - send_actions({create_action({permission_level{proxy,config::active_name}}, config::system_account_name, N(regproxy), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, {proxy,config::active_name}); + send_actions({create_action(accountPermissions, config::system_account_name, N(regproxy), act_payload)}); }); } }; @@ -1459,14 +1573,15 @@ struct canceldelay_subcommand { cancel_delay->add_option("canceling_account", canceling_account, localized("Account from authorization on the original delayed transaction"))->required(); cancel_delay->add_option("canceling_permission", canceling_permission, localized("Permission from authorization on the original delayed transaction"))->required(); cancel_delay->add_option("trx_id", trx_id, localized("The transaction id of the original delayed transaction"))->required(); - add_standard_transaction_options(cancel_delay); + add_standard_transaction_options(cancel_delay, "canceling_account@canceling_permission"); cancel_delay->set_callback([this] { - const auto canceling_auth = permission_level{canceling_account, canceling_permission}; + auto canceling_auth = permission_level{canceling_account, canceling_permission}; fc::variant act_payload = fc::mutable_variant_object() ("canceling_auth", canceling_auth) ("trx_id", trx_id); - send_actions({create_action({canceling_auth}, config::system_account_name, N(canceldelay), act_payload)}); + auto accountPermissions = get_account_permissions(tx_permission, canceling_auth); + send_actions({create_action(accountPermissions, config::system_account_name, N(canceldelay), act_payload)}); }); } }; @@ -2021,6 +2136,8 @@ int main( int argc, char** argv ) { bool binary = false; uint32_t limit = 10; string index_position; + bool reverse = false; + bool show_payer = false; auto getTable = get->add_subcommand( "table", localized("Retrieve the contents of a database table"), false); getTable->add_option( "account", code, localized("The account who owns the table") )->required(); getTable->add_option( "scope", scope, localized("The scope within the contract in which the table is found") )->required(); @@ -2038,7 +2155,9 @@ int main( int argc, char** argv ) { "\t\t\t\tSpecial type 'name' indicates an account name.")); getTable->add_option( "--encode-type", encode_type, localized("The encoding type of key_type (i64 , i128 , float64, float128) only support decimal encoding e.g. 'dec'" - "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only\n")); + "i256 - supports both 'dec' and 'hex', ripemd160 and sha256 is 'hex' only")); + getTable->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); + getTable->add_flag("--show-payer", show_payer, localized("show RAM payer")); getTable->set_callback([&] { @@ -2053,6 +2172,8 @@ int main( int argc, char** argv ) { ("key_type",key_type) ("index_position", index_position) ("encode_type", encode_type) + ("reverse", reverse) + ("show_payer", show_payer) ); std::cout << fc::json::to_pretty_string(result) @@ -2065,12 +2186,14 @@ int main( int argc, char** argv ) { getScope->add_option( "-l,--limit", limit, localized("The maximum number of rows to return") ); getScope->add_option( "-L,--lower", lower, localized("lower bound of scope") ); getScope->add_option( "-U,--upper", upper, localized("upper bound of scope") ); + getScope->add_flag("-r,--reverse", reverse, localized("Iterate in reverse order")); getScope->set_callback([&] { auto result = call(get_table_by_scope_func, fc::mutable_variant_object("code",code) ("table",table) ("lower_bound",lower) ("upper_bound",upper) ("limit",limit) + ("reverse", reverse) ); std::cout << fc::json::to_pretty_string(result) << std::endl; @@ -2365,9 +2488,7 @@ int main( int argc, char** argv ) { bytes code_bytes; if(!contract_clear){ std::string wasm; - fc::path cpath(contractPath); - - if( cpath.filename().generic_string() == "." ) cpath = cpath.parent_path(); + fc::path cpath = fc::canonical(fc::path(contractPath)); if( wasmPath.empty() ) wasmPath = (cpath / (cpath.filename().generic_string()+".wasm")).generic_string(); @@ -2376,7 +2497,7 @@ int main( int argc, char** argv ) { std::cerr << localized(("Reading WASM from " + wasmPath + "...").c_str()) << std::endl; fc::read_file_contents(wasmPath, wasm); - EOS_ASSERT( !wasm.empty(), wast_file_not_found, "no wasm file found ${f}", ("f", wasmPath) ); + EOS_ASSERT( !wasm.empty(), wasm_file_not_found, "no wasm file found ${f}", ("f", wasmPath) ); const string binary_wasm_header("\x00\x61\x73\x6d\x01\x00\x00\x00", 8); if(wasm.compare(0, 8, binary_wasm_header)) @@ -2420,8 +2541,7 @@ int main( int argc, char** argv ) { bytes abi_bytes; if(!contract_clear){ - fc::path cpath(contractPath); - if( cpath.filename().generic_string() == "." ) cpath = cpath.parent_path(); + fc::path cpath = fc::canonical(fc::path(contractPath)); if( abiPath.empty() ) { abiPath = (cpath / (cpath.filename().generic_string()+".abi")).generic_string(); @@ -2490,10 +2610,10 @@ int main( int argc, char** argv ) { string amount; string memo; bool pay_ram = false; - auto transfer = app.add_subcommand("transfer", localized("Transfer EOS from account to account"), false); - transfer->add_option("sender", sender, localized("The account sending EOS"))->required(); - transfer->add_option("recipient", recipient, localized("The account receiving EOS"))->required(); - transfer->add_option("amount", amount, localized("The amount of EOS to send"))->required(); + auto transfer = app.add_subcommand("transfer", localized("Transfer tokens from account to account"), false); + transfer->add_option("sender", sender, localized("The account sending tokens"))->required(); + transfer->add_option("recipient", recipient, localized("The account receiving tokens"))->required(); + transfer->add_option("amount", amount, localized("The amount of tokens to send"))->required(); transfer->add_option("memo", memo, localized("The memo for the transfer")); transfer->add_option("--contract,-c", con, localized("The contract which controls the token")); transfer->add_flag("--pay-ram-to-open", pay_ram, localized("Pay ram to open recipient's token balance row")); @@ -2740,7 +2860,7 @@ int main( int argc, char** argv ) { fc::set_console_echo(true); } - auto priv_key = fc::crypto::private_key::regenerate(*utilities::wif_to_key(str_private_key)); + auto priv_key = private_key_type(str_private_key); trx.sign(priv_key, *chain_id); if(push_trx) { @@ -2841,7 +2961,7 @@ int main( int argc, char** argv ) { }; auto propose_action = msig->add_subcommand("propose", localized("Propose action")); - add_standard_transaction_options(propose_action); + add_standard_transaction_options(propose_action, "proposer@active"); propose_action->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_action->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_action->add_option("trx_permissions", transaction_perm, localized("The JSON string or filename defining transaction permissions"))->required(); @@ -2910,9 +3030,9 @@ int main( int argc, char** argv ) { send_actions({chain::action{accountPermissions, "eosio.msig", "propose", variant_to_bin( N(eosio.msig), N(propose), args ) }}); }); - //multisige propose transaction + //multisig propose transaction auto propose_trx = msig->add_subcommand("propose_trx", localized("Propose transaction")); - add_standard_transaction_options(propose_trx); + add_standard_transaction_options(propose_trx, "proposer@active"); propose_trx->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); propose_trx->add_option("requested_permissions", requested_perm, localized("The JSON string or filename defining requested permissions"))->required(); propose_trx->add_option("transaction", trx_to_push, localized("The JSON string or filename defining the transaction to push"))->required(); @@ -2952,80 +3072,258 @@ int main( int argc, char** argv ) { // multisig review + bool show_approvals_in_multisig_review = false; auto review = msig->add_subcommand("review", localized("Review transaction")); review->add_option("proposer", proposer, localized("proposer name (string)"))->required(); review->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); + review->add_flag( "--show-approvals", show_approvals_in_multisig_review, localized("Show the status of the approvals requested within the proposal") ); review->set_callback([&] { - auto result = call(get_table_func, fc::mutable_variant_object("json", true) - ("code", "eosio.msig") - ("scope", proposer) - ("table", "proposal") - ("table_key", "") - ("lower_bound", eosio::chain::string_to_name(proposal_name.c_str())) - ("upper_bound", "") - ("limit", 1) - ); + const auto result1 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "proposal") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); //std::cout << fc::json::to_pretty_string(result) << std::endl; - fc::variants rows = result.get_object()["rows"].get_array(); - if (rows.empty()) { + const auto& rows1 = result1.get_object()["rows"].get_array(); + // Condition in if statement below can simply be rows.empty() when cleos no longer needs to support nodeos versions older than 1.5.0 + if( rows1.empty() || rows1[0].get_object()["proposal_name"] != proposal_name ) { std::cerr << "Proposal not found" << std::endl; return; } - fc::mutable_variant_object obj = rows[0].get_object(); - if (obj["proposal_name"] != proposal_name) { - std::cerr << "Proposal not found" << std::endl; - return; + + const auto& proposal_object = rows1[0].get_object(); + + enum class approval_status { + unapproved, + approved, + invalidated + }; + + std::map> all_approvals; + std::map>> provided_approvers; + + bool new_multisig = true; + if( show_approvals_in_multisig_review ) { + fc::variants rows2; + + try { + const auto& result2 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "approvals2") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + rows2 = result2.get_object()["rows"].get_array(); + } catch( ... ) { + new_multisig = false; + } + + if( !rows2.empty() && rows2[0].get_object()["proposal_name"] == proposal_name ) { + const auto& approvals_object = rows2[0].get_object(); + + for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { + const auto& ra_obj = ra.get_object(); + auto pl = ra["level"].as(); + auto res = all_approvals.emplace( pl, std::make_pair(ra["time"].as(), approval_status::unapproved) ); + } + + for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { + const auto& pa_obj = pa.get_object(); + auto pl = pa["level"].as(); + auto res = all_approvals.emplace( pl, std::make_pair(pa["time"].as(), approval_status::approved) ); + provided_approvers[pl.actor].second.push_back( res.first ); + } + } else { + const auto result3 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", proposer) + ("table", "approvals") + ("table_key", "") + ("lower_bound", name(proposal_name).value) + ("upper_bound", name(proposal_name).value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + const auto& rows3 = result3.get_object()["rows"].get_array(); + if( rows3.empty() || rows3[0].get_object()["proposal_name"] != proposal_name ) { + std::cerr << "Proposal not found" << std::endl; + return; + } + + const auto& approvals_object = rows3[0].get_object(); + + for( const auto& ra : approvals_object["requested_approvals"].get_array() ) { + auto pl = ra.as(); + auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::unapproved) ); + } + + for( const auto& pa : approvals_object["provided_approvals"].get_array() ) { + auto pl = pa.as(); + auto res = all_approvals.emplace( pl, std::make_pair(fc::time_point{}, approval_status::approved) ); + provided_approvers[pl.actor].second.push_back( res.first ); + } + } + + if( new_multisig ) { + for( auto& a : provided_approvers ) { + const auto result4 = call(get_table_func, fc::mutable_variant_object("json", true) + ("code", "eosio.msig") + ("scope", "eosio.msig") + ("table", "invals") + ("table_key", "") + ("lower_bound", a.first.value) + ("upper_bound", a.first.value + 1) + // Less than ideal upper_bound usage preserved so cleos can still work with old buggy nodeos versions + // Change to name(proposal_name).value when cleos no longer needs to support nodeos versions older than 1.5.0 + ("limit", 1) + ); + const auto& rows4 = result4.get_object()["rows"].get_array(); + if( rows4.empty() || rows4[0].get_object()["account"].as() != a.first ) { + continue; + } + + auto invalidation_time = rows4[0].get_object()["last_invalidation_time"].as(); + a.second.first = invalidation_time; + + for( auto& itr : a.second.second ) { + if( invalidation_time >= itr->second.first ) { + itr->second.second = approval_status::invalidated; + } + } + } + } } - auto trx_hex = obj["packed_transaction"].as_string(); + + auto trx_hex = proposal_object["packed_transaction"].as_string(); vector trx_blob(trx_hex.size()/2); fc::from_hex(trx_hex, trx_blob.data(), trx_blob.size()); transaction trx = fc::raw::unpack(trx_blob); + fc::mutable_variant_object obj; + obj["proposer"] = proposer; + obj["proposal_name"] = proposal_object["proposal_name"]; + obj["transaction_id"] = trx.id(); + + for( const auto& entry : proposal_object ) { + if( entry.key() == "proposal_name" ) continue; + obj.set( entry.key(), entry.value() ); + } + fc::variant trx_var; abi_serializer abi; abi.to_variant(trx, trx_var, abi_serializer_resolver, abi_serializer_max_time); obj["transaction"] = trx_var; - std::cout << fc::json::to_pretty_string(obj) - << std::endl; + + if( show_approvals_in_multisig_review ) { + fc::variants approvals; + + for( const auto& approval : all_approvals ) { + fc::mutable_variant_object approval_obj; + approval_obj["level"] = approval.first; + switch( approval.second.second ) { + case approval_status::unapproved: + { + approval_obj["status"] = "unapproved"; + if( approval.second.first != fc::time_point{} ) { + approval_obj["last_unapproval_time"] = approval.second.first; + } + } + break; + case approval_status::approved: + { + approval_obj["status"] = "approved"; + if( new_multisig ) { + approval_obj["last_approval_time"] = approval.second.first; + } + } + break; + case approval_status::invalidated: + { + approval_obj["status"] = "invalidated"; + approval_obj["last_approval_time"] = approval.second.first; + approval_obj["invalidation_time"] = provided_approvers[approval.first.actor].first; + } + break; + } + + approvals.push_back( std::move(approval_obj) ); + } + + obj["approvals"] = std::move(approvals); + } + + std::cout << fc::json::to_pretty_string(obj) << std::endl; }); string perm; + string proposal_hash; auto approve_or_unapprove = [&](const string& action) { fc::variant perm_var; try { perm_var = json_from_file_or_string(perm); } EOS_RETHROW_EXCEPTIONS(transaction_type_exception, "Fail to parse permissions JSON '${data}'", ("data",perm)) + auto args = fc::mutable_variant_object() ("proposer", proposer) ("proposal_name", proposal_name) ("level", perm_var); - auto accountPermissions = tx_permission.empty() ? vector{{sender,config::active_name}} : get_account_permissions(tx_permission); + if( proposal_hash.size() ) { + args("proposal_hash", proposal_hash); + } + + auto accountPermissions = get_account_permissions(tx_permission, {proposer,config::active_name}); send_actions({chain::action{accountPermissions, "eosio.msig", action, variant_to_bin( N(eosio.msig), action, args ) }}); }; // multisig approve auto approve = msig->add_subcommand("approve", localized("Approve proposed transaction")); - add_standard_transaction_options(approve); + add_standard_transaction_options(approve, "proposer@active"); approve->add_option("proposer", proposer, localized("proposer name (string)"))->required(); approve->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); approve->add_option("permissions", perm, localized("The JSON string of filename defining approving permissions"))->required(); + approve->add_option("proposal_hash", proposal_hash, localized("Hash of proposed transaction (i.e. transaction ID) to optionally enforce as a condition of the approval")); approve->set_callback([&] { approve_or_unapprove("approve"); }); // multisig unapprove auto unapprove = msig->add_subcommand("unapprove", localized("Unapprove proposed transaction")); - add_standard_transaction_options(unapprove); + add_standard_transaction_options(unapprove, "proposer@active"); unapprove->add_option("proposer", proposer, localized("proposer name (string)"))->required(); unapprove->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); unapprove->add_option("permissions", perm, localized("The JSON string of filename defining approving permissions"))->required(); unapprove->set_callback([&] { approve_or_unapprove("unapprove"); }); + // multisig invalidate + string invalidator; + auto invalidate = msig->add_subcommand("invalidate", localized("Invalidate all multisig approvals of an account")); + add_standard_transaction_options(invalidate, "invalidator@active"); + invalidate->add_option("invalidator", invalidator, localized("invalidator name (string)"))->required(); + invalidate->set_callback([&] { + auto args = fc::mutable_variant_object() + ("account", invalidator); + + auto accountPermissions = get_account_permissions(tx_permission, {invalidator,config::active_name}); + send_actions({chain::action{accountPermissions, "eosio.msig", "invalidate", variant_to_bin( N(eosio.msig), "invalidate", args ) }}); + }); + // multisig cancel string canceler; auto cancel = msig->add_subcommand("cancel", localized("Cancel proposed transaction")); - add_standard_transaction_options(cancel); + add_standard_transaction_options(cancel, "canceler@active"); cancel->add_option("proposer", proposer, localized("proposer name (string)"))->required(); cancel->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); cancel->add_option("canceler", canceler, localized("canceler name (string)")); @@ -3053,7 +3351,7 @@ int main( int argc, char** argv ) { // multisig exec string executer; auto exec = msig->add_subcommand("exec", localized("Execute proposed transaction")); - add_standard_transaction_options(exec); + add_standard_transaction_options(exec, "executer@active"); exec->add_option("proposer", proposer, localized("proposer name (string)"))->required(); exec->add_option("proposal_name", proposal_name, localized("proposal name (string)"))->required(); exec->add_option("executer", executer, localized("account paying for execution (string)")); @@ -3088,7 +3386,7 @@ int main( int argc, char** argv ) { executer = ""; string trx_to_exec; auto wrap_exec = wrap->add_subcommand("exec", localized("Execute a transaction while bypassing authorization checks")); - add_standard_transaction_options(wrap_exec); + add_standard_transaction_options(wrap_exec, "executer@active & --contract@active"); wrap_exec->add_option("executer", executer, localized("Account executing the transaction and paying for the deferred transaction RAM"))->required(); wrap_exec->add_option("transaction", trx_to_exec, localized("The JSON string or filename defining the transaction to execute"))->required(); wrap_exec->add_option("--contract,-c", wrap_con, localized("The account which controls the wrap contract")); diff --git a/programs/eosio-abigen/CMakeLists.txt b/programs/eosio-abigen/CMakeLists.txt deleted file mode 100644 index 93df3c89ef4..00000000000 --- a/programs/eosio-abigen/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -set(SOURCES main.cpp) -find_package(LLVM 4.0 REQUIRED CONFIG) - -link_directories(${LLVM_LIBRARY_DIR}) - -add_executable(eosio-abigen ${SOURCES}) - -set( CMAKE_CXX_STANDARD 14 ) - -if( UNIX AND NOT APPLE ) - set(rt_library rt ) -endif() - -find_package( Gperftools QUIET ) -if( GPERFTOOLS_FOUND ) - message( STATUS "Found gperftools; compiling with TCMalloc") - list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc ) -endif() - -target_link_libraries(eosio-abigen abi_generator) - - -install( TARGETS - eosio-abigen - RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} -) diff --git a/programs/eosio-abigen/main.cpp b/programs/eosio-abigen/main.cpp deleted file mode 100644 index f15cd138ee4..00000000000 --- a/programs/eosio-abigen/main.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include - -using namespace eosio; -using namespace eosio::chain; - -using mvo = fc::mutable_variant_object; - -std::unique_ptr create_factory(bool verbose, bool opt_sfs, string abi_context, abi_def& output, const string& contract, const vector& actions) { - - struct abi_frontend_action_factory : public FrontendActionFactory { - - bool verbose; - bool opt_sfs; - string abi_context; - abi_def& output; - const string& contract; - const vector& actions; - - abi_frontend_action_factory(bool verbose, bool opt_sfs, string abi_context, - abi_def& output, const string& contract, const vector& actions) : verbose(verbose), - abi_context(abi_context), output(output), contract(contract), actions(actions) {} - - clang::FrontendAction *create() override { - return new generate_abi_action(verbose, opt_sfs, abi_context, output, contract, actions); - } - - }; - - return std::unique_ptr( - new abi_frontend_action_factory(verbose, opt_sfs, abi_context, output, contract, actions) - ); -} - -std::unique_ptr create_find_macro_factory(string& contract, vector& actions, string abi_context) { - - struct abi_frontend_macro_action_factory : public FrontendActionFactory { - - string& contract; - vector& actions; - string abi_context; - - abi_frontend_macro_action_factory (string& contract, vector& actions, - string abi_context ) : contract(contract), actions(actions), abi_context(abi_context) {} - - clang::FrontendAction *create() override { - return new find_eosio_abi_macro_action(contract, actions, abi_context); - } - - }; - - return std::unique_ptr( - new abi_frontend_macro_action_factory(contract, actions, abi_context) - ); -} - -static cl::OptionCategory abi_generator_category("ABI generator options"); - -static cl::opt abi_context( - "context", - cl::desc("ABI context"), - cl::cat(abi_generator_category)); - -static cl::opt abi_destination( - "destination-file", - cl::desc("destination json file"), - cl::cat(abi_generator_category)); - -static cl::opt abi_verbose( - "verbose", - cl::desc("show debug info"), - cl::cat(abi_generator_category)); - -static cl::opt abi_opt_sfs( - "optimize-sfs", - cl::desc("Optimize single field struct"), - cl::cat(abi_generator_category)); - -int main(int argc, const char **argv) { abi_def output; try { - CommonOptionsParser op(argc, argv, abi_generator_category); - ClangTool Tool(op.getCompilations(), op.getSourcePathList()); - - string contract; - vector actions; - int result = Tool.run(create_find_macro_factory(contract, actions, abi_context).get()); - if(!result) { - output.version = "eosio::abi/1.0"; - result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output, contract, actions).get()); - if(!result) { - abi_serializer abis(output, fc::seconds(1)); // No risk to client side serialization taking a long time - fc::variant vabi; - to_variant(output, vabi); - - auto comment = fc::format_string( - "This file was generated by eosio-abigen. DO NOT EDIT - ${ts}", - mvo("ts",fc::time_point_sec(fc::time_point::now()).to_iso_string())); - - auto abi_with_comment = mvo("____comment", comment)(mvo(vabi)); - - fc::json::save_to_file(abi_with_comment, abi_destination, true); - } - } - return result; -} FC_CAPTURE_AND_LOG((output)); return -1; } diff --git a/programs/nodeos/CMakeLists.txt b/programs/nodeos/CMakeLists.txt index 946c8c83200..7d03ce0001f 100644 --- a/programs/nodeos/CMakeLists.txt +++ b/programs/nodeos/CMakeLists.txt @@ -51,6 +51,7 @@ target_link_libraries( ${NODE_EXECUTABLE_NAME} PRIVATE appbase PRIVATE -Wl,${whole_archive_flag} login_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} history_plugin -Wl,${no_whole_archive_flag} + PRIVATE -Wl,${whole_archive_flag} state_history_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} bnet_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} history_api_plugin -Wl,${no_whole_archive_flag} PRIVATE -Wl,${whole_archive_flag} chain_api_plugin -Wl,${no_whole_archive_flag} diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index 9ed46f9cb24..52eb9a0e9ab 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -6,10 +6,8 @@ #include #include -#include #include #include -#include #include #include @@ -94,7 +92,6 @@ int main(int argc, char** argv) { try { app().set_version(eosio::nodeos::config::version); - app().register_plugin(); auto root = fc::app_path(); app().set_default_data_dir(root / "eosio/nodeos/data" ); diff --git a/scripts/abi_to_rc/README.md b/scripts/abi_to_rc/README.md deleted file mode 100644 index 70a5439c913..00000000000 --- a/scripts/abi_to_rc/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Purpose -The `abi_to_rc.py` script processes a contract's .abi file in order to generate an overview Ricardian Contract and a Ricardian Contract for each action. The overview Ricardian Contract provides a description of the contract's purpose and also specifies the contract's action(s), input(s), and input type(s). The action Ricardian Contract provides a description of the action's purpose and also specifies the action's input(s), and input type(s). - -## How to run -`$ python abi_to_rc.py /path/to/smart-contract.abi` - -## Example -`$ python abi_to_rc.py ../../contracts/currency/currency.abi` - -## Results -For the example above, `abi_to_rc.py` should generate output files that have the following names: `currency-rc.md`, `currency-transfer-rc.md`, `currency-issue-rc.md`, `currency-create-rc.md`. - -## Notes -Be sure to have `abi_to_rc.py`, `rc-overview-template.md`, and `rc-action-template.md` in the same folder. diff --git a/scripts/abi_to_rc/abi_to_rc.py b/scripts/abi_to_rc/abi_to_rc.py deleted file mode 100644 index 49ccb77bca6..00000000000 --- a/scripts/abi_to_rc/abi_to_rc.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python3 - -# By: Jon-Eric Cook -# Github: @joneric - -from string import Template -import argparse -import json -import sys -import os -import re - -# argument parser -parser = argparse.ArgumentParser( - prog="abi_to_rc.py", - description="The abi_to_rc.py script processes a contract's .abi file in order to generate an overview Ricardian Contract and a Ricardian Contract for each action. The overview Ricardian Contract provides a description of the contract's purpose and also specifies the contract's action(s), input(s), and input type(s). The action Ricardian Contract provides a description of the action's purpose and also specifies the action's input(s), and input type(s).", - epilog="example: $ python abi_to_rc.py ../../contracts/currency/currency.abi", - usage="$ python %(prog)s [-h] abi_file") -parser.add_argument("abi_file", help="path to smart contract's .abi file") -args = parser.parse_args() - -# global variables -_RC_OVERVIEW = "rc-overview-template.md" -_RC_ACTION = "rc-action-template.md" -actions = [] -inputs = {} -types = {} - -# checks for abi and template files -def check_for_files(): - if not os.path.isfile(args.abi_file): - abi_filename = os.path.split(args.abi_file)[1] - print("ERROR: %s could not be found" % abi_filename) - exit(1) - if not os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), _RC_OVERVIEW)): - print("ERROR: %s could not be found" % _RC_OVERVIEW) - exit(1) - if not os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), _RC_ACTION)): - print("ERROR: %s could not be found" % _RC_ACTION) - exit(1) - -# gets actions, inputs and input types from abi file -def get_actions_inputs_types(): - abi_file = open(args.abi_file,'r') - abi_text = abi_file.read() - abi_file.close() - abi_json = json.loads(abi_text) - actions_json = abi_json['actions'] - for obj in actions_json: - actions.append(obj) - structs_json = abi_json['structs'] - for action in actions: - inputs[action['name']] = [] - types[action['name']] = [] - for struct in structs_json: - for action in actions: - if struct['name'] == action['type']: - for field in struct['fields']: - inputs[action['name']].append(field['name']) - types[action['name']].append(field['type']) - -# builds rows for the table -def build_table_rows(is_action): - table_rows = [] - for action in actions: - action_string = "`{{ " + action['name'] + " }}`" - input_string = "" - input_list = [] - type_string = "" - type_list =[] - if len(inputs[action['name']]) >= 1: - for name in inputs[action['name']]: - input_list.append("`{{ " + name + ("Var }}`" if is_action else " }}`")) - input_string = '
'.join(input_list) - else: - input_string = "`{{ " + action['type'] + ("Var }}`" if is_action else " }}`") - if len(types[action['name']]) >= 1: - for name in types[action['name']]: - type_list.append("`{{ " + name + " }}`") - type_string = '
'.join(type_list) - else: - type_string = "`{{ " + action['type'] + " }}`" - table_rows.append('| ' + action_string + ' | ' + input_string + ' | ' + type_string + ' |') - return table_rows - -# generates an overview ricardian contract from the overview template -def generate_rc_overview_file(): - tr = build_table_rows(False) - abi_file_name = os.path.split(args.abi_file)[1] - contract_name = os.path.splitext(abi_file_name)[0] - rc_file_name = contract_name + '-rc.md' - dirname = os.path.split(args.abi_file)[0] - subs = {'contract': "{{ " + contract_name + " }}", - 'action': 'actions' if len(actions) > 1 else 'action', - 'input': 'inputs' if len(inputs) > 1 else 'input', - 'type': 'types' if len(types) > 1 else 'type'} - subs.update([(k+'_header',v.title()) for k,v in subs.copy().items()]) - rc_file = open(os.path.join(dirname, rc_file_name),"w+") - with open(os.path.join(os.path.dirname(sys.argv[0]), _RC_OVERVIEW)) as fp: - overview_template = Template(fp.read()) - rc_file.write(overview_template.substitute(subs)) - rc_file.write('\n'.join(tr)) - rc_file.close() - -# generates a ricardian contract for each action from the action template -def generate_rc_action_files(): - tr = build_table_rows(True) - abi_filename = os.path.split(args.abi_file)[1] - contract_name = os.path.splitext(abi_filename)[0] - dirname = os.path.split(args.abi_file)[0] - for action in actions: - subs = {'action': "{{ " + action['name'] + " }}", - 'input': 'inputs' if len(inputs[action['name']]) > 1 else 'input', - 'type': 'types' if len(types[action['name']]) > 1 else 'type'} - subs.update([(k+'_header',v.title()) for k,v in subs.copy().items()]) - rc_action_file_name = contract_name + "-" + action['name'] + '-rc.md' - rc_file = open(os.path.join(dirname, rc_action_file_name),"w+") - with open(os.path.join(os.path.dirname(sys.argv[0]), _RC_ACTION)) as fp: - action_template = Template(fp.read()) - rc_file.write(action_template.substitute(subs)) - for row in tr: - if re.search("\\b" + action['name'] + "\\b", row): - rc_file.write(row + "\n") - rc_file.close() - -# main program -def main(): - check_for_files() - get_actions_inputs_types() - generate_rc_overview_file() - generate_rc_action_files() - -# runs main -if __name__== "__main__": - main() \ No newline at end of file diff --git a/scripts/abi_to_rc/rc-action-template.md b/scripts/abi_to_rc/rc-action-template.md deleted file mode 100644 index 04934c92e32..00000000000 --- a/scripts/abi_to_rc/rc-action-template.md +++ /dev/null @@ -1,14 +0,0 @@ -# Action - `$action` - -This Contract is legally binding and can be used in the event of a dispute. Disputes shall be settled through the standard arbitration process established by EOS.IO. - -### Description - -The `$action` action... - -### $input_header and Input $type_header - -The `$action` action requires the following `$input` and `input $type`: - -| Action | Input | Input Type | -|:--|:--|:--| diff --git a/scripts/abi_to_rc/rc-overview-template.md b/scripts/abi_to_rc/rc-overview-template.md deleted file mode 100644 index 1f197b1c08e..00000000000 --- a/scripts/abi_to_rc/rc-overview-template.md +++ /dev/null @@ -1,14 +0,0 @@ -# Smart Contract - `$contract` - -This is an overview of the actions for the `$contract` smart contract. This Contract is legally binding and can be used in the event of a dispute. Disputes shall be settled through the standard arbitration process established by EOS.IO. - -### Description - -The `$contract` contract... - -### $action_header, $input_header and Input $type_header - -The table below contains the `$action`, `$input` and `input $type` for the `$contract` contract. - -| Action | Input | Input Type | -|:--|:--|:--| diff --git a/scripts/abigen.sh b/scripts/abigen.sh deleted file mode 100755 index eb5cce98357..00000000000 --- a/scripts/abigen.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if (( $# < 3 )); then - echo "$0 SOURCE_DIR BUILD_DIR ARGS..." - exit 0 -fi - -function get_absolute_dir_path() { - pushd $1 > /dev/null - echo $PWD - popd > /dev/null -} - -SOURCE_DIR=$(get_absolute_dir_path $1) - -BUILD_DIR=$2 - -shift; shift - -#echo "Source directory: ${SOURCE_DIR}" - -eval "${BUILD_DIR}/programs/eosio-abigen/eosio-abigen -extra-arg=--std=c++14 -extra-arg=--target=wasm32 -extra-arg=\"-I${SOURCE_DIR}/contracts/libc++/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts/musl/upstream/include\" -extra-arg=\"-I${SOURCE_DIR}/externals/magic_get/include\" -extra-arg=\"-I${SOURCE_DIR}/contracts\" $@" diff --git a/scripts/eosio_build_amazon.sh b/scripts/eosio_build_amazon.sh index b32d2a51315..2dc523870a8 100644 --- a/scripts/eosio_build_amazon.sh +++ b/scripts/eosio_build_amazon.sh @@ -70,7 +70,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "$YUM" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$("$YUM" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "installed" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " diff --git a/scripts/eosio_build_centos.sh b/scripts/eosio_build_centos.sh index bedf64f6058..60810199f73 100644 --- a/scripts/eosio_build_centos.sh +++ b/scripts/eosio_build_centos.sh @@ -152,7 +152,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$( "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "installed" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " DISPLAY="${DISPLAY}${COUNT}. ${DEP_ARRAY[$i]}\\n\\t" @@ -765,7 +765,7 @@ mongodconf exit 1; fi fi - if ! git clone --depth 1 -b v0.2 https://github.com/boscore/cppkafka.git + if ! git clone --depth 1 -b 0.2 https://github.com/boscore/cppkafka.git then printf "\\tUnable to clone cppkafka repo.\\n" printf "\\n\\tExiting now.\\n" diff --git a/scripts/eosio_build_fedora.sh b/scripts/eosio_build_fedora.sh index 238781f2f8f..fbf6fcbf986 100644 --- a/scripts/eosio_build_fedora.sh +++ b/scripts/eosio_build_fedora.sh @@ -69,7 +69,7 @@ for (( i=0; i<${#DEP_ARRAY[@]}; i++ )); do - pkg=$( sudo "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) + pkg=$( "${YUM}" info "${DEP_ARRAY[$i]}" 2>/dev/null | grep Repo | tr -s ' ' | cut -d: -f2 | sed 's/ //g' ) if [ "$pkg" != "@System" ]; then DEP=$DEP" ${DEP_ARRAY[$i]} " diff --git a/scripts/generate_deb.sh b/scripts/generate_deb.sh index 9b7cb9a54f0..5009f7627b3 100644 --- a/scripts/generate_deb.sh +++ b/scripts/generate_deb.sh @@ -1,10 +1,17 @@ #! /bin/bash -NAME="${PROJECT}_${VERSION}-1_amd64" PREFIX="usr" SPREFIX=${PREFIX} SUBPREFIX="opt/${PROJECT}/${VERSION}" SSUBPREFIX="opt\/${PROJECT}\/${VERSION}" +RELEASE="${VERSION_SUFFIX}" + +# default release to "1" if there is no suffix +if [[ -z $RELEASE ]]; then + RELEASE="1" +fi + +NAME="${PROJECT}_${VERSION_NO_SUFFIX}-${RELEASE}_amd64" DEPS_STR="" for dep in "${DEPS[@]}"; do @@ -12,7 +19,7 @@ for dep in "${DEPS[@]}"; do done mkdir -p ${PROJECT}/DEBIAN echo "Package: ${PROJECT} -Version: ${VERSION} +Version: ${VERSION_NO_SUFFIX}-${RELEASE} Section: devel Priority: optional Depends: libbz2-dev (>= 1.0), libssl-dev (>= 1.0), libgmp3-dev, build-essential, libicu-dev, zlib1g-dev diff --git a/scripts/generate_package.sh.in b/scripts/generate_package.sh.in index 909598cf5d0..5d8aedebb70 100644 --- a/scripts/generate_package.sh.in +++ b/scripts/generate_package.sh.in @@ -2,8 +2,9 @@ VARIANT=$1 -VERSION="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@" - +VERSION_NO_SUFFIX="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@" +VERSION_SUFFIX="@VERSION_SUFFIX@" +VERSION="@VERSION_FULL@" BUILD_DIR="@CMAKE_BINARY_DIR@" VENDOR="@VENDOR@" @@ -13,6 +14,8 @@ URL="@URL@" EMAIL="@EMAIL@" export BUILD_DIR +export VERSION_NO_SUFFIX +export VERSION_SUFFIX export VERSION export VENDOR export PROJECT diff --git a/scripts/generate_rpm.sh b/scripts/generate_rpm.sh index a35efde71ec..35b60a4c816 100644 --- a/scripts/generate_rpm.sh +++ b/scripts/generate_rpm.sh @@ -1,10 +1,17 @@ #! /bin/bash -NAME="${PROJECT}-${VERSION}-1" PREFIX="usr" SPREFIX=${PREFIX} SUBPREFIX="opt/${PROJECT}/${VERSION}" SSUBPREFIX="opt\/${PROJECT}\/${VERSION}" +RELEASE="${VERSION_SUFFIX}" + +# default release to "1" if there is no suffix +if [[ -z $RELEASE ]]; then + RELEASE="1" +fi + +NAME="${PROJECT}-${VERSION_NO_SUFFIX}-${RELEASE}" export PREFIX export SUBPREFIX @@ -26,15 +33,15 @@ echo -e ${PFILES} &> ~/rpmbuild/BUILD/filenames.txt mkdir -p ${PROJECT} echo -e "Name: ${PROJECT} -Version: ${VERSION} +Version: ${VERSION_NO_SUFFIX} License: MIT Vendor: ${VENDOR} Source: ${URL} -Requires: openssl-devel.x86_64, gmp-devel.x86_64, libstdc++-devel.x86_64, bzip2.x86_64, bzip2-devel.x86_64, mongodb.x86_64, mongodb-server.x86_64 +Requires: openssl-devel, gmp-devel, libstdc++-devel, bzip2, bzip2-devel, mongodb, mongodb-server URL: ${URL} Packager: ${VENDOR} <${EMAIL}> Summary: ${DESC} -Release: 1 +Release: ${RELEASE} %description ${DESC} %files -f filenames.txt" &> ${PROJECT}.spec diff --git a/scripts/ricardeos/README.md b/scripts/ricardeos/README.md deleted file mode 100644 index cac5023d953..00000000000 --- a/scripts/ricardeos/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Purpose -The `ricardeos.py` imports or exports recardian contracts to and from a contracts abi - -## Import Example -`$ python3 ricardeos.py import /path/to/sorce-contract.abi /path/to/new-smart-contract-abi.abi` - -Running this will scan the directory of the abi for all rc.md files and add them to their respective actions. All files with a path format of *clause*-rc.md will be added to the ricardian_clauses section. You can provide the same name for the source and new smart contract abi, the script will prompt you before overwriting. - -The script will also notify the user of any actions that the script cannot find rc.md files for. - -## Export Example -`$ python3 ricardeos.py export /path/to/sorce-contract.abi` - -Running this will dump the contents of all ricardian contracts: - -Actions will be exported in the following format: `--rc.md` - -Clauses will be exported in the following format: `-clause--rc.md` - -If a file already exists the user will be asked if they wish to overwrite the file diff --git a/scripts/ricardeos/ricardeos.py b/scripts/ricardeos/ricardeos.py deleted file mode 100755 index 1110328a529..00000000000 --- a/scripts/ricardeos/ricardeos.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python3 - -import json -import sys -import os.path -import fnmatch - -def add_ricardian_contracts_to_actions(source_abi_directory, contract_name, abi_actions): - abi_actions_with_ricardian_contracts = [] - - for abi_action in abi_actions: - action_name = abi_action["name"] - contract_action_filename = '{contract_name}-{action_name}-rc.md'.format(contract_name = contract_name, action_name = action_name) - - # check for rc file - rc_contract_path = os.path.join(source_abi_directory, contract_action_filename) - if os.path.exists(rc_contract_path): - print('Importing Contract {contract_action_filename} for {contract_name}:{action_name}'.format( - contract_action_filename = contract_action_filename, - contract_name = contract_name, - action_name = action_name - )) - - with open(rc_contract_path) as contract_file_handle: - contract_contents = contract_file_handle.read() - - abi_action['ricardian_contract'] = contract_contents - else: - print('Did not find recardian contract file {contract_action_filename} for {contract_name}:{action_name}, skipping inclusion'.format( - contract_action_filename = contract_action_filename, - contract_name = contract_name, - action_name = action_name - )) - - abi_actions_with_ricardian_contracts.append(abi_action) - - return abi_actions_with_ricardian_contracts - -def create_ricardian_clauses_list(source_abi_directory, contract_name): - clause_file_pattern = '*-clause*-rc.md' - clause_files = fnmatch.filter(os.listdir(source_abi_directory), clause_file_pattern) - - clause_prefix = 'clause-' - clause_postfix = '-rc.md' - - abi_ricardian_clauses = [] - - for clause_file_name in clause_files: - rc_contract_path = os.path.join(source_abi_directory, clause_file_name) - with open(rc_contract_path) as contract_file_handle: - contract_contents = contract_file_handle.read() - - start_of_clause_id = clause_file_name.index( clause_prefix ) + len( clause_prefix ) - end_of_clause_id = clause_file_name.rindex(clause_postfix, start_of_clause_id) - - clause_id = clause_file_name[start_of_clause_id:end_of_clause_id] - - abi_ricardian_clauses.append({ - 'id': clause_id, - 'body': contract_contents - }) - - return abi_ricardian_clauses - -def add_ricardian_contracts_to_abi(source_abi, output_abi): - source_abi_directory = os.path.dirname(source_abi) - contract_name = os.path.split(source_abi)[1].rpartition(".")[0] - - print('Creating {output_abi} with ricardian contracts included'.format(output_abi = output_abi)) - - with open(source_abi, 'r') as source_abi_file: - source_abi_json = json.load(source_abi_file) - - source_abi_json['actions'] = add_ricardian_contracts_to_actions(source_abi_directory, contract_name, source_abi_json['actions']) - source_abi_json['ricardian_clauses'] = create_ricardian_clauses_list(source_abi_directory, contract_name) - - with open(output_abi, 'w') as output_abi_file: - json.dump(source_abi_json, output_abi_file, indent=2) - -def import_ricardian_to_abi(source_abi, output_abi): - if not os.path.exists(source_abi): - print('Source ABI not found in {source_abi}'.format(source_abi = source_abi)) - sys.exit(0) - - if os.path.exists(output_abi): - overwrite_prompt_response = input('Output ABI {output_abi} already exists, do you want to proceed? (y|n): '.format(output_abi = output_abi)) - if overwrite_prompt_response == 'y': - print('Overwriting existing output abi') - add_ricardian_contracts_to_abi(source_abi, output_abi) - sys.exit(0) - else: - print('User aborted, not overwriting existing abi') - sys.exit(0) - else: - add_ricardian_contracts_to_abi(source_abi, output_abi) - -def write_rc_file(path, filename, content): - output_filename = os.path.join(path, filename) - write_file = True - - if os.path.exists(output_filename): - overwrite_prompt_response = input('Output rc {output_filename} already exists, do you want to proceed? (y|n): '.format(output_filename = output_filename)) - if overwrite_prompt_response == 'y': - print('Overwriting existing output rc') - elif overwrite_prompt_response == 'n': - print('Skipping overwrite of {output_filename}'.format(output_filename = output_filename)) - write_file = False - - if write_file: - with open(output_filename, 'w') as text_file: - print(content, file=text_file) - - print('Wrote {output_filename}'.format(output_filename = output_filename)) - -def export_ricardian_from_abi(source_abi): - source_abi_directory = os.path.dirname(source_abi) - contract_name = os.path.split(source_abi)[1].rpartition(".")[0] - - if not os.path.exists(source_abi): - print('Source ABI not found in {source_abi}'.format(source_abi = source_abi)) - sys.exit(0) - - with open(source_abi, 'r') as source_abi_file: - source_abi_json = json.load(source_abi_file) - - for abi_action in source_abi_json['actions']: - output_action_rc_file_name = '{contract_name}-{action_name}-rc.md'.format(contract_name = contract_name, action_name = abi_action['name']) - write_rc_file(source_abi_directory, output_action_rc_file_name, abi_action['ricardian_contract']) - - for abi_clause in source_abi_json['ricardian_clauses']: - output_clause_rc_file_name = '{contract_name}-clause-{clause_id}-rc.md'.format(contract_name = contract_name, clause_id = abi_clause['id']) - write_rc_file(source_abi_directory, output_clause_rc_file_name, abi_clause['body']) - -def main(): - if len(sys.argv) == 1: - print('Please specify an operation of export or import: ./ricardeos.py ') - sys.exit(1) - - if sys.argv[1] == 'import': - if len(sys.argv) != 4: - print('Please specify a source and destination abi:') - print('Usage: ./ricardeos.py import /eos/contracts/contract/mycontract.abi /eos/contracts/contract/withricardian-mycontract.abi') - - sys.exit(0) - else: - import_ricardian_to_abi(sys.argv[2], sys.argv[3]) - - sys.exit(0) - elif sys.argv[1] == 'export': - if len(sys.argv) != 3: - print('Please specify a source abi:') - print('Usage: ./ricardeos.py export /eos/contracts/contract/mycontract.abi') - - sys.exit(0) - else: - export_ricardian_from_abi(sys.argv[2]) - - sys.exit(0) - - else: - print('Operation not recognized only import and export operations are supported') - -if __name__ == '__main__': - main() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ad77d850285..c88caa1f995 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,12 +16,11 @@ include_directories("${CMAKE_SOURCE_DIR}/plugins/wallet_plugin/include") file(GLOB UNIT_TESTS "*.cpp") add_executable( plugin_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} ) -target_link_libraries( plugin_test eosio_testing eosio_chain chainbase eos_utilities chain_plugin wallet_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( plugin_test eosio_testing eosio_chain chainbase chain_plugin wallet_plugin fc ${PLATFORM_SPECIFIC_LIBS} ) target_include_directories( plugin_test PUBLIC ${CMAKE_SOURCE_DIR}/plugins/net_plugin/include ${CMAKE_SOURCE_DIR}/plugins/chain_plugin/include ) -add_dependencies(plugin_test asserter test_api test_api_mem test_api_db test_api_multi_index proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop eosio.msig) # configure_file(${CMAKE_CURRENT_SOURCE_DIR}/core_symbol.py.in ${CMAKE_CURRENT_BINARY_DIR}/core_symbol.py) @@ -87,6 +86,8 @@ add_test(NAME nodeos_sanity_bnet_lr_test COMMAND tests/nodeos_run_test.py -v --s set_property(TEST nodeos_sanity_bnet_lr_test PROPERTY LABELS long_running_tests) add_test(NAME nodeos_run_check_lr_test COMMAND tests/nodeos_run_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST nodeos_run_check_lr_test PROPERTY LABELS long_running_tests) +add_test(NAME nodeos_remote_lr_test COMMAND tests/nodeos_run_remote_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST nodeos_remote_lr_test PROPERTY LABELS long_running_tests) #add_test(NAME distributed_transactions_lr_test COMMAND tests/distributed-transactions-test.py -d 2 -p 21 -n 21 -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) #set_property(TEST distributed_transactions_lr_test PROPERTY LABELS long_running_tests) diff --git a/tests/Cluster.py b/tests/Cluster.py index 070edd9b3ba..f26c5980339 100644 --- a/tests/Cluster.py +++ b/tests/Cluster.py @@ -126,6 +126,9 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne if len(self.nodes) > 0: raise RuntimeError("Cluster already running.") + if pnodes > totalNodes: + raise RuntimeError("totalNodes (%d) must be equal to or greater than pnodes(%d)." % (totalNodes, pnodes)) + if self.walletMgr is None: self.walletMgr=WalletMgr(True) diff --git a/tests/Node.py b/tests/Node.py index 82d6581bb02..5fc4e95dcce 100644 --- a/tests/Node.py +++ b/tests/Node.py @@ -259,14 +259,20 @@ def getBlock(self, blockNum, silentErrors=False, exitOnError=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.blocks.findOne( { "block_num": %d } )' % (blockNum) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: block=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) + if block is not None: return block except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db node get block. %s" % (msg) + errorMsg="Exception during get db node get block. cmd Duration: %.3f sec. %s" % (end-start, msg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -280,14 +286,19 @@ def getBlockByIdMdb(self, blockId, silentErrors=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.blocks.findOne( { "block_id": "%s" } )' % (blockId) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if trans is not None: return trans except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during db get block by id. %s" % (msg)) + Utils.Print("ERROR: Exception during db get block by id. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None return None @@ -360,13 +371,18 @@ def getTransactionMdb(self, transId, silentErrors=False, exitOnError=False): #subcommand='db.Transactions.findOne( { $and : [ { "trx_id": "%s" }, {"irreversible":true} ] } )' % (transId) subcommand='db.transactions.findOne( { "trx_id": "%s" } )' % (transId) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if trans is not None: return trans except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db node get trans in mongodb with transaction id=%s. %s" % (transId,msg) + errorMsg="Exception during get db node get trans in mongodb with transaction id=%s. cmd Duration: %.3f sec. %s" % (transId, end-start, msg) if exitOnError: Utils.cmdError("" % (errorMsg)) Utils.errorExit("Failed to retrieve transaction in mongodb for transaction id=%s" % (transId)) @@ -548,15 +564,20 @@ def getEosAccountFromDb(self, name, exitOnError=False): try: timeout = 3 for i in range(0,(int(60/timeout) - 1)): + start=time.perf_counter() trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) if trans is not None: + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return trans time.sleep(timeout) return trans except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if exitOnError: - Utils.cmdError("Exception during get account from db for %s. %s" % (name, msg)) + end=time.perf_counter() + Utils.cmdError("Exception during get account from db for %s. cmd Duration: %.3f sec. %s" % (name, end-start, msg)) Utils.errorExit("Failed during get account from db for %s. %s" % (name, msg)) Utils.Print("ERROR: Exception during get account from db for %s. %s" % (name, msg)) @@ -675,12 +696,17 @@ def transferFunds(self, source, destination, amountStr, memo="memo", force=False s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (s)) trans=None + start=time.perf_counter() try: trans=Utils.runCmdArrReturnJson(cmdArr) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) self.trackCmdTransaction(trans) except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during funds transfer. %s" % (msg)) + Utils.Print("ERROR: Exception during funds transfer. cmd Duration: %.3f sec. %s" % (end-start, msg)) if exitOnError: Utils.cmdError("could not transfer \"%s\" from %s to %s" % (amountStr, source, destination)) Utils.errorExit("Failed to transfer \"%s\" from %s to %s" % (amountStr, source, destination)) @@ -784,13 +810,18 @@ def getActionsMdb(self, account, pos=-1, offset=-1, exitOnError=False): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand='db.action_traces.find({$or: [{"act.data.from":"%s"},{"act.data.to":"%s"}]}).sort({"_id":%d}).limit(%d)' % (account.name, account.name, pos, abs(offset)) if Utils.Debug: Utils.Print("cmd: echo '%s' | %s" % (subcommand, cmd)) + start=time.perf_counter() try: actions=Node.runMongoCmdReturnJson(cmd.split(), subcommand, exitOnError=exitOnError) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) if actions is not None: return actions except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during get db actions. %s" % (msg) + errorMsg="Exception during get db actions. cmd Duration: %.3f sec. %s" % (end-start, msg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -834,8 +865,12 @@ def getAccountEosBalance(self, scope): def getAccountCodeHash(self, account): cmd="%s %s get code %s" % (Utils.EosClientPath, self.eosClientArgs(), account) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + start=time.perf_counter() try: retStr=Utils.checkOutput(cmd.split()) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) #Utils.Print ("get code> %s"% retStr) p=re.compile(r'code\shash: (\w+)\n', re.MULTILINE) m=p.search(retStr) @@ -846,8 +881,9 @@ def getAccountCodeHash(self, account): return m.group(1) except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) + Utils.Print("ERROR: Exception during code hash retrieval. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None # publish contract and return transaction as json object @@ -857,13 +893,18 @@ def publishContract(self, account, contractDir, wasmFile, abiFile, waitForTransB cmd += "" if abiFile is None else (" " + abiFile) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) trans=None + start=time.perf_counter() try: trans=Utils.runCmdReturnJson(cmd, trace=False) self.trackCmdTransaction(trans) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not shouldFail: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during code hash retrieval. %s" % (msg)) + Utils.Print("ERROR: Exception during code hash retrieval. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None else: retMap={} @@ -915,14 +956,19 @@ def pushMessage(self, account, action, data, opts, silentErrors=False): cmdArr += opts.split() s=" ".join(cmdArr) if Utils.Debug: Utils.Print("cmd: %s" % (cmdArr)) + start=time.perf_counter() try: trans=Utils.runCmdArrReturnJson(cmdArr) self.trackCmdTransaction(trans, ignoreNonTrans=True) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return (True, trans) except subprocess.CalledProcessError as ex: msg=ex.output.decode("utf-8") if not silentErrors: - Utils.Print("ERROR: Exception during push message. %s" % (msg)) + end=time.perf_counter() + Utils.Print("ERROR: Exception during push message. cmd Duration=%.3f sec. %s" % (end - start, msg)) return (False, msg) def setPermission(self, account, code, pType, requirement, waitForTransBlock=False, exitOnError=False): @@ -976,6 +1022,7 @@ def processCleosCmd(self, cmd, cmdDesc, silentErrors=True, exitOnError=False, ex else: exitMsg="" trans=None + start=time.perf_counter() try: if returnType==ReturnType.json: trans=Utils.runCmdReturnJson(cmd, silentErrors=silentErrors) @@ -983,10 +1030,15 @@ def processCleosCmd(self, cmd, cmdDesc, silentErrors=True, exitOnError=False, ex trans=Utils.runCmdReturnStr(cmd) else: unhandledEnumType(returnType) + + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during \"%s\". Exception message: %s. %s" % (cmdDesc, msg, exitMsg) + errorMsg="Exception during \"%s\". Exception message: %s. cmd Duration=%.3f sec. %s" % (cmdDesc, msg, end-start, exitMsg) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -1010,6 +1062,7 @@ def killNodeOnProducer(self, producer, whereInSequence, blockType=BlockType.head (self.endpointHttp, producer, whereInSequence, basedOnLib) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) rtn=None + start=time.perf_counter() try: if returnType==ReturnType.json: rtn=Utils.runCmdReturnJson(cmd, silentErrors=silentErrors) @@ -1017,10 +1070,15 @@ def killNodeOnProducer(self, producer, whereInSequence, blockType=BlockType.head rtn=Utils.runCmdReturnStr(cmd) else: unhandledEnumType(returnType) + + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) except subprocess.CalledProcessError as ex: if not silentErrors: + end=time.perf_counter() msg=ex.output.decode("utf-8") - errorMsg="Exception during \"%s\". %s" % (cmd, msg) + errorMsg="Exception during \"%s\". %s. cmd Duration=%.3f sec." % (cmd, msg, end-start) if exitOnError: Utils.cmdError(errorMsg) Utils.errorExit(errorMsg) @@ -1065,12 +1123,17 @@ def getBlockFromDb(self, idx): cmd="%s %s" % (Utils.MongoPath, self.mongoEndpointArgs) subcommand="db.blocks.find().sort({\"_id\":%d}).limit(1).pretty()" % (idx) if Utils.Debug: Utils.Print("cmd: echo \"%s\" | %s" % (subcommand, cmd)) + start=time.perf_counter() try: trans=Node.runMongoCmdReturnJson(cmd.split(), subcommand) + if Utils.Debug: + end=time.perf_counter() + Utils.Print("cmd Duration: %.3f sec" % (end-start)) return trans except subprocess.CalledProcessError as ex: + end=time.perf_counter() msg=ex.output.decode("utf-8") - Utils.Print("ERROR: Exception during get db block. %s" % (msg)) + Utils.Print("ERROR: Exception during get db block. cmd Duration: %.3f sec. %s" % (end-start, msg)) return None def checkPulse(self, exitOnError=False): diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index 2b7867a07e9..5a489c255b4 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -12,15 +12,6 @@ #include #include -#include -#include - -#include -#include - -#include -#include - #include #include diff --git a/tests/chain_tests/proof_tests.cpp b/tests/chain_tests/proof_tests.cpp deleted file mode 100644 index 6240443d77d..00000000000 --- a/tests/chain_tests/proof_tests.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#include -#include -#include -#include - -#ifdef NON_VALIDATING_TEST -#define TESTER tester -#else -#define TESTER validating_tester -#endif - -using namespace eosio; -using namespace eosio::chain; -using namespace eosio::testing; - -struct action_proof_data { - account_name receiver; - scope_name scope; - action_name name; - bytes data; - uint64_t region_id; - uint64_t cycle_index; - vector data_access; -}; -FC_REFLECT(action_proof_data, (receiver)(scope)(name)(data)(region_id)(cycle_index)(data_access)); - - -struct merkle_node { - digest_type digest; - optional left; - optional right; - optional parent; -}; - -digest_type process_merkle(vector& nodes, vector leaf_indices) { - size_t num_nodes = leaf_indices.size(); - size_t base = 0; - - if (num_nodes == 0) { - return digest_type(); - } else if (num_nodes == 1) { - return nodes[leaf_indices.front()].digest; - } - - while (num_nodes > 1) { - size_t new_nodes = (num_nodes / 2) + (num_nodes % 2); - for(size_t idx = 0; idx < new_nodes; idx++) { - size_t l_idx = idx * 2; - size_t r_idx = l_idx + 1; - size_t left = leaf_indices.at(base + l_idx); - if (r_idx >= num_nodes) { - nodes.emplace_back( - merkle_node{ - digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[left].digest)), - left - }); - nodes[left].parent.emplace(nodes.size() - 1); - } else { - size_t right = leaf_indices.at(base + r_idx); - nodes.emplace_back( - merkle_node{ - digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[right].digest)), - left, - right - }); - nodes[left].parent.emplace(nodes.size() - 1); - nodes[right].parent.emplace(nodes.size() - 1); - } - - leaf_indices.emplace_back(nodes.size() - 1); - } - - base += num_nodes; - num_nodes = new_nodes; - } - - return nodes.back().digest; -} - -auto get_proof_path(const vector& nodes, size_t leaf) { - vector path; - digest_type current = nodes[leaf].digest; - while (nodes[leaf].parent.valid()) { - size_t parent = *nodes[leaf].parent; - if (leaf == *nodes[parent].left) { - if (nodes[parent].right.valid()) { - size_t right = *nodes[parent].right; - path.emplace_back(make_canonical_right(nodes[right].digest)); - current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[right].digest)); - } else { - path.emplace_back(make_canonical_right(nodes[leaf].digest)); - current = digest_type::hash(make_canonical_pair(nodes[leaf].digest, nodes[leaf].digest)); - } - } else { - size_t left = *nodes[parent].left; - path.emplace_back(make_canonical_left(nodes[left].digest)); - current = digest_type::hash(make_canonical_pair(nodes[left].digest, nodes[leaf].digest)); - } - - leaf = parent; - } - - return path; -} - -digest_type apply_path(const digest_type& digest, const vector& path) { - digest_type current = digest; - - for (const auto& p: path ) { - if (is_canonical_left(p)) { - current = digest_type::hash(make_canonical_pair(p, current)); - } else { - current = digest_type::hash(make_canonical_pair(current, p)); - } - } - - return current; -} - -bool proof_is_valid(const digest_type& digest, const vector& path, const digest_type& expected_root) { - return apply_path(digest, path) == expected_root; -} - -BOOST_AUTO_TEST_SUITE(proof_tests) - -BOOST_FIXTURE_TEST_CASE( prove_block_in_chain, validating_tester ) { try { - vector known_blocks; - known_blocks.reserve(100); - block_header last_block_header; - - // register a callback on new blocks to record block information - validating_node->applied_block.connect([&](const block_trace& bt){ - known_blocks.emplace_back(bt.block.id()); - last_block_header = bt.block; - }); - - produce_blocks(100); - return; - vector nodes; - vector ids; - vector block_leaves; - nodes.reserve(100); - ids.reserve(100); - for (const auto& blk_id: known_blocks) { - nodes.emplace_back(merkle_node{blk_id}); - ids.push_back(blk_id); - block_leaves.push_back(nodes.size() - 1); - } - - digest_type block_mroot = process_merkle(nodes, move(block_leaves)); - - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)merkle(ids)); - - produce_block(); - - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)last_block_header.block_mroot); - - for (int idx = 0; idx < 100; idx++) { - vector path = get_proof_path(nodes, idx); - - BOOST_REQUIRE_EQUAL(true, proof_is_valid(nodes[idx].digest, path, last_block_header.block_mroot)); - - /** UNCOMMENT TO PRODUCE PROOFS TO STD OUT - std::cout << idx << ":" << std::string(known_blocks.at(idx)) << " = "; - for (const auto& e: path) { - std::cout << std::string(e) << " "; - } - - std::cout << "-> " << std::string(last_block_header.block_mroot) << std::endl; - */ - } - -} FC_LOG_AND_RETHROW() } /// transfer_test - - -struct action_proof_info { - action_trace trace; - - size_t action_leaf; - size_t block_leaf; - - uint32_t cycle_index; - uint32_t region_id; -}; - -/** - * This test case will attempt to allow one account to transfer on behalf - * of another account by updating the active authority. - */ -BOOST_FIXTURE_TEST_CASE( prove_action_in_block, validating_tester ) { try { - vector nodes; - vector block_leaves; - vector known_actions; - map block_action_mroots; - block_header last_block_header; - block_id_type last_block_id; - - // register a callback on new blocks to record block information - validating_node->applied_block.connect([&](const block_trace& bt){ - nodes.emplace_back(merkle_node{bt.block.id()}); - size_t block_leaf = nodes.size() - 1; - block_leaves.push_back(block_leaf); - - vector region_leaves; - - for (uint32_t r_idx = 0; r_idx < bt.region_traces.size(); r_idx++) { - const auto& rt = bt.region_traces.at(r_idx); - - vector shard_leaves; - - for (uint32_t c_idx = 0; c_idx < rt.cycle_traces.size(); c_idx++) { - const auto& ct = rt.cycle_traces.at(c_idx); - - for (const auto& st: ct.shard_traces) { - vector action_leaves; - - for (const auto& tt: st.transaction_traces) { - for (const auto& at: tt.action_traces) { - digest_type::encoder enc; - - auto a_data = action_proof_data { - at.receiver, - at.act.account, - at.act.name, - at.act.data, - tt.region_id, - tt.cycle_index, - at.data_access - }; - fc::raw::pack(enc, a_data); - nodes.emplace_back(merkle_node{enc.result()}); - size_t action_leaf = nodes.size() - 1; - known_actions.emplace_back(action_proof_info{at, action_leaf, block_leaf, c_idx, r_idx }); - action_leaves.emplace_back(action_leaf); - } - } - - if (action_leaves.size() > 0) { - process_merkle(nodes, move(action_leaves)); - } else { - nodes.emplace_back(merkle_node{digest_type()}); - } - shard_leaves.emplace_back(nodes.size() - 1); - } - } - - if (shard_leaves.size() > 0) { - process_merkle(nodes, move(shard_leaves)); - } else { - nodes.emplace_back(merkle_node{digest_type()}); - } - - region_leaves.emplace_back(nodes.size() - 1); - } - - digest_type action_mroot = process_merkle(nodes, move(region_leaves)); - BOOST_REQUIRE_EQUAL((std::string)bt.block.action_mroot, (std::string)action_mroot); - - last_block_header = bt.block; - last_block_id = bt.block.id(); - block_action_mroots[bt.block.id()] = bt.block.action_mroot; - }); - - create_accounts( { N(alice), N(bob), N(carol), N(david), N(elvis) }); - - produce_blocks(50); - - push_dummy(N(alice), "AB"); - push_dummy(N(bob), "BC"); - push_dummy(N(carol), "CD"); - push_dummy(N(david), "DE"); - push_dummy(N(elvis), "EF"); - - produce_blocks(50); - digest_type block_mroot = process_merkle(nodes, move(block_leaves)); - - produce_block(); - BOOST_REQUIRE_EQUAL((std::string)block_mroot, (std::string)last_block_header.block_mroot); - - /* UNCOMMENT TO PRODUCE PROOFS TO STDOUT - std::cout << "Best Block ID: " << (std::string)last_block_id << std::endl; - std::cout << " Merkle Root: " << (std::string)last_block_header.block_mroot << std::endl; - - for(const auto& ai : known_actions) { - auto block_path = get_proof_path(nodes, ai.action_leaf); - auto chain_path = get_proof_path(nodes, ai.block_leaf); - - // prove action in block - auto shard_root = apply_path(nodes[ai.action_leaf].digest, block_path); - BOOST_REQUIRE_EQUAL((std::string)shard_root, (std::string)block_action_mroots[nodes[ai.block_leaf].digest]); - - // prove that block is part of the chain - auto expected_block_mroot = apply_path(nodes[ai.block_leaf].digest, chain_path); - BOOST_REQUIRE_EQUAL((std::string)expected_block_mroot, (std::string)last_block_header.block_mroot); - - std::cout << "Proof for Action:" << std::endl; - std::cout << std::setw(14) << "reciever" << ":" << (std::string) ai.trace.receiver << std::endl; - std::cout << std::setw(14) << "scope" << ":" << (std::string) ai.trace.act.scope << std::endl; - std::cout << std::setw(14) << "name" << ":" << (std::string) ai.trace.act.name << std::endl; - std::cout << std::setw(14) << "data" << ":" << fc::json::to_string(ai.trace.act.as()) << std::endl; - std::cout << std::setw(14) << "data_access" << ":" << fc::json::to_string(ai.trace.data_access) << std::endl; - std::cout << std::setw(14) << "region" << ":" << ai.region_id << std::endl; - std::cout << std::setw(14) << "cycle" << ":" << ai.cycle_index << std::endl; - std::cout << std::setw(14) << "block" << ":" << (std::string)nodes[ai.block_leaf].digest << std::endl; - std::cout << std::setw(14) << "am_root" << ":" << (std::string)block_action_mroots[nodes[ai.block_leaf].digest] << std::endl; - std::cout << std::endl; - - auto a_data = action_proof_data { - ai.trace.receiver, - ai.trace.act.scope, - ai.trace.act.name, - ai.trace.act.data, - ai.trace.region_id, - ai.trace.cycle_index, - ai.trace.data_access - }; - auto action_data = fc::raw::pack(a_data); - - std::cout << "Action Hex: " << fc::to_hex(action_data) << std::endl; - std::cout << "Action Hash: " << (std::string)nodes[ai.action_leaf].digest << std::endl; - - std::cout << "Action Path: "; - for (const auto& p: block_path) { - std::cout << (std::string)p << " "; - } - std::cout << std::endl; - - std::cout << "Block Path: "; - for (const auto& p: chain_path) { - std::cout << (std::string)p << " "; - } - std::cout << std::endl; - }*/ - - -} FC_LOG_AND_RETHROW() } - - - -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/distributed-transactions-remote-test.py b/tests/distributed-transactions-remote-test.py index 1b678f3be03..9e79b352329 100755 --- a/tests/distributed-transactions-remote-test.py +++ b/tests/distributed-transactions-remote-test.py @@ -58,7 +58,7 @@ Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % (pnodes, total_nodes-pnodes, topo, delay)) Print("Stand up cluster") - if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, dontKill=dontKill) is False: + if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay) is False: errorExit("Failed to stand up eos cluster.") Print ("Wait for Cluster stabilization") diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index 818ca5562d2..bb332b9a000 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -12,15 +12,12 @@ #include #include -#include -#include +#include +#include #include #include -#include -#include - #include #include @@ -58,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { set_abi( N(eosio.token), eosio_token_abi ); produce_blocks(1); - // create currency + // create currency auto act = mutable_variant_object() ("issuer", "eosio") ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); @@ -94,13 +91,13 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { } param.lower_bound = "initb"; - param.upper_bound = "initd"; + param.upper_bound = "initc"; result = plugin.read_only::get_table_by_scope(param); BOOST_REQUIRE_EQUAL(2, result.rows.size()); BOOST_REQUIRE_EQUAL("", result.more); if (result.rows.size() >= 2) { BOOST_REQUIRE_EQUAL(name(N(initb)), result.rows[0].scope); - BOOST_REQUIRE_EQUAL(name(N(initc)), result.rows[1].scope); + BOOST_REQUIRE_EQUAL(name(N(initc)), result.rows[1].scope); } param.limit = 1; @@ -116,9 +113,337 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try { param.table = N(invalid); result = plugin.read_only::get_table_by_scope(param); BOOST_REQUIRE_EQUAL(0, result.rows.size()); - BOOST_REQUIRE_EQUAL("", result.more); + BOOST_REQUIRE_EQUAL("", result.more); } FC_LOG_AND_RETHROW() /// get_scope_test -BOOST_AUTO_TEST_SUITE_END() +BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try { + produce_blocks(2); + + create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), + N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) }); + + std::vector accs{N(inita), N(initb)}; + create_accounts(accs); + produce_block(); + + set_code( N(eosio.token), eosio_token_wast ); + set_abi( N(eosio.token), eosio_token_abi ); + produce_blocks(1); + // create currency + auto act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 2 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 AAA")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("9999.0000 AAA") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 3 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 CCC")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("7777.0000 CCC") ) + ("memo", "") + ); + } + produce_blocks(1); + + // create currency 3 + act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 BBB")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("8888.0000 BBB") ) + ("memo", "") + ); + } + produce_blocks(1); + + // get table: normal case + eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX)); + eosio::chain_apis::read_only::get_table_rows_params p; + p.code = N(eosio.token); + p.scope = "inita"; + p.table = N(accounts); + p.json = true; + p.index_position = "primary"; + eosio::chain_apis::read_only::get_table_rows_result result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[0]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[2]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[3]["balance"].as_string()); + } + + // get table: reverse ordered + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[3]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[2]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["balance"].as_string()); + } + + // get table: reverse ordered, with ram payer + p.reverse = true; + p.show_payer = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[3]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[2]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["data"]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[0]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[1]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[2]["payer"].as_string()); + BOOST_REQUIRE_EQUAL("eosio", result.rows[3]["payer"].as_string()); + } + p.show_payer = false; + + // get table: normal case, with bound + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(2, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 2) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[0]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[1]["balance"].as_string()); + } + + // get table: reverse case, with bound + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(2, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 2) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[1]["balance"].as_string()); + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[0]["balance"].as_string()); + } + + // get table: normal case, with limit + p.lower_bound = p.upper_bound = ""; + p.limit = 1; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("9999.0000 AAA", result.rows[0]["balance"].as_string()); + } + + // get table: reverse case, with limit + p.lower_bound = p.upper_bound = ""; + p.limit = 1; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("10000.0000 SYS", result.rows[0]["balance"].as_string()); + } + + // get table: normal case, with bound & limit + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.limit = 1; + p.reverse = false; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("8888.0000 BBB", result.rows[0]["balance"].as_string()); + } + + // get table: reverse case, with bound & limit + p.lower_bound = "BBB"; + p.upper_bound = "CCC"; + p.limit = 1; + p.reverse = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("7777.0000 CCC", result.rows[0]["balance"].as_string()); + } + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try { + produce_blocks(2); + + create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake), + N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) }); + + std::vector accs{N(inita), N(initb), N(initc), N(initd)}; + create_accounts(accs); + produce_block(); + + set_code( N(eosio.token), eosio_token_wast ); + set_abi( N(eosio.token), eosio_token_abi ); + produce_blocks(1); + + // create currency + auto act = mutable_variant_object() + ("issuer", "eosio") + ("maximum_supply", eosio::chain::asset::from_string("1000000000.0000 SYS")); + push_action(N(eosio.token), N(create), N(eosio.token), act ); + + // issue + for (account_name a: accs) { + push_action( N(eosio.token), N(issue), "eosio", mutable_variant_object() + ("to", name(a) ) + ("quantity", eosio::chain::asset::from_string("10000.0000 SYS") ) + ("memo", "") + ); + } + produce_blocks(1); + + set_code( config::system_account_name, eosio_system_wast ); + set_abi( config::system_account_name, eosio_system_abi ); + + // bidname + auto bidname = [this]( const account_name& bidder, const account_name& newname, const asset& bid ) { + return push_action( N(eosio), N(bidname), bidder, fc::mutable_variant_object() + ("bidder", bidder) + ("newname", newname) + ("bid", bid) + ); + }; + + bidname(N(inita), N(com), eosio::chain::asset::from_string("10.0000 SYS")); + bidname(N(initb), N(org), eosio::chain::asset::from_string("11.0000 SYS")); + bidname(N(initc), N(io), eosio::chain::asset::from_string("12.0000 SYS")); + bidname(N(initd), N(html), eosio::chain::asset::from_string("14.0000 SYS")); + produce_blocks(1); + + // get table: normal case + eosio::chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX)); + eosio::chain_apis::read_only::get_table_rows_params p; + p.code = N(eosio); + p.scope = "eosio"; + p.table = N(namebids); + p.json = true; + p.index_position = "secondary"; // ordered by high_bid + p.key_type = "i64"; + eosio::chain_apis::read_only::get_table_rows_result result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("html", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[0]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("io", result.rows[1]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[1]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("120000", result.rows[1]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("org", result.rows[2]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[2]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("110000", result.rows[2]["high_bid"].as_string()); + + BOOST_REQUIRE_EQUAL("com", result.rows[3]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[3]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[3]["high_bid"].as_string()); + } + + // reverse search, with show ram payer + p.reverse = true; + p.show_payer = true; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(4, result.rows.size()); + BOOST_REQUIRE_EQUAL(false, result.more); + if (result.rows.size() >= 4) { + BOOST_REQUIRE_EQUAL("html", result.rows[3]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[3]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[3]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[3]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("io", result.rows[2]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[2]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("120000", result.rows[2]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initc", result.rows[2]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("org", result.rows[1]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[1]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("110000", result.rows[1]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("initb", result.rows[1]["payer"].as_string()); + + BOOST_REQUIRE_EQUAL("com", result.rows[0]["data"]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["data"]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[0]["data"]["high_bid"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["payer"].as_string()); + } + + // limit to 1 (get the highest bidname) + p.reverse = false; + p.show_payer = false; + p.limit = 1; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("html", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("initd", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("140000", result.rows[0]["high_bid"].as_string()); + } + + // limit to 1 reverse, (get the lowest bidname) + p.reverse = true; + p.show_payer = false; + p.limit = 1; + result = plugin.read_only::get_table_rows(p); + BOOST_REQUIRE_EQUAL(1, result.rows.size()); + BOOST_REQUIRE_EQUAL(true, result.more); + if (result.rows.size() >= 1) { + BOOST_REQUIRE_EQUAL("com", result.rows[0]["newname"].as_string()); + BOOST_REQUIRE_EQUAL("inita", result.rows[0]["high_bidder"].as_string()); + BOOST_REQUIRE_EQUAL("100000", result.rows[0]["high_bid"].as_string()); + } + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/launcher_test.py b/tests/launcher_test.py index 9179a69b58d..b7d21b41179 100755 --- a/tests/launcher_test.py +++ b/tests/launcher_test.py @@ -52,7 +52,8 @@ cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") - if cluster.launch(pnodes=4, p2pPlugin=p2pPlugin) is False: + pnodes=4 + if cluster.launch(pnodes=pnodes, totalNodes=pnodes, p2pPlugin=p2pPlugin) is False: cmdError("launcher") errorExit("Failed to stand up eos cluster.") else: diff --git a/tests/nodeos_forked_chain_test.py b/tests/nodeos_forked_chain_test.py index 01115285a6e..1ef2079e878 100755 --- a/tests/nodeos_forked_chain_test.py +++ b/tests/nodeos_forked_chain_test.py @@ -30,7 +30,12 @@ def analyzeBPs(bps0, bps1, expectDivergence): length=len(bps0) firstDivergence=None errorInDivergence=False + analysysPass=0 + bpsStr=None + bpsStr0=None + bpsStr1=None while start < length: + analysysPass+=1 bpsStr=None for i in range(start,length): bp0=bps0[i] diff --git a/tests/nodeos_run_remote_test.py b/tests/nodeos_run_remote_test.py index 6c918f71c64..21e15bb9c72 100755 --- a/tests/nodeos_run_remote_test.py +++ b/tests/nodeos_run_remote_test.py @@ -43,7 +43,7 @@ (pnodes, total_nodes-pnodes, topo, delay)) Print("Stand up cluster") - if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, onlyBios=onlyBios, dontKill=dontKill) is False: + if cluster.launch(pnodes=pnodes, totalNodes=total_nodes, prodCount=prodCount, topo=topo, delay=delay, onlyBios=onlyBios) is False: errorExit("Failed to stand up eos cluster.") Print ("Wait for Cluster stabilization") diff --git a/tests/nodeos_run_test.py b/tests/nodeos_run_test.py index 37b46613aaf..4196eb58a2b 100755 --- a/tests/nodeos_run_test.py +++ b/tests/nodeos_run_test.py @@ -42,7 +42,7 @@ Utils.Debug=debug localTest=True if server == TestHelper.LOCAL_HOST else False -cluster=Cluster(walletd=True, enableMongo=enableMongo, defproduceraPrvtKey=defproduceraPrvtKey, defproducerbPrvtKey=defproducerbPrvtKey) +cluster=Cluster(host=server, port=port, walletd=True, enableMongo=enableMongo, defproduceraPrvtKey=defproduceraPrvtKey, defproducerbPrvtKey=defproducerbPrvtKey) walletMgr=WalletMgr(True, port=walletPort) testSuccessful=False killEosInstances=not dontKill diff --git a/tests/p2p_tests/fuzz_test_generic.sh b/tests/p2p_tests/fuzz_test_generic.sh deleted file mode 100644 index ae913565c86..00000000000 --- a/tests/p2p_tests/fuzz_test_generic.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -# -# This script captures the generic fuzz testing to which -# net_plugin has been subjected. It typically results in -# message buffers in excess of 1 gigabyte. -# -if ! pgrep nodeos > /dev/null; then - echo "Run nodeos with net_plugin configured for port 9876." - exit 1 -fi -for i in `seq 1 10000`; do netcat localhost 9876 < /dev/urandom; done diff --git a/tests/p2p_tests/pump/run_test.pl b/tests/p2p_tests/pump/run_test.pl deleted file mode 100755 index 11e467a5d2e..00000000000 --- a/tests/p2p_tests/pump/run_test.pl +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/perl - -use strict; -use Getopt::Long; -use Env; -use File::Basename; -use File::copy; -use File::Spec; -use File::Path; -use Cwd; - -my $eos_home = defined $ENV{EOS_HOME} ? $ENV{EOS_HOME} : getcwd; -my $eosd = $eos_home . "/programs/eosd/eosd"; -my $eosc = $eos_home . "/programs/eosc/eosc"; - -my $nodes = defined $ENV{EOS_TEST_RING} ? $ENV{EOS_TEST_RING} : "1"; -my $pnodes = defined $ENV{EOS_TEST_PRODUCERS} ? $ENV{EOS_TEST_PRODUCERS} : "1"; - -my $prods = 21; -my $genesis = "$eos_home/genesis.json"; -my $http_port_base = 8888; -my $p2p_port_base = 9876; -my $data_dir_base = "tdn"; -my $hostname = "127.0.0.1"; -my $first_pause = 0; -my $launch_pause = 0; -my $run_duration = 60; -my $topo = "ring"; -my $override_gts = ""; -my $no_delay=0; -my $test=1; - -if (!GetOptions("nodes=i" => \$nodes, - "first-pause=i" => \$first_pause, - "launch-pause=i" => \$launch_pause, - "duration=i" => \$run_duration, - "topo=s" => \$topo, - "test=i" => \$test, - "time-stamp=s" => \$override_gts, - "pnodes=i" => \$pnodes)) { - print "usage: $ARGV[0] [--nodes=] [--pnodes=] [--topo=] [--first-pause=] [--launch-pause=] [--duration=] [--time-stamp=