diff --git a/CMakeLists.txt b/CMakeLists.txt index 6081f35944..b5ad095b81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,8 @@ LIST(APPEND BOOST_COMPONENTS thread chrono unit_test_framework context - locale) + locale + coroutine) SET( Boost_USE_STATIC_LIBS ON CACHE STRING "ON or OFF" ) OPTION( BUILD_STEEM_TESTNET "Build source for test network (ON OR OFF)" OFF ) @@ -89,14 +90,7 @@ IF( WIN32 ) set(BOOST_ALL_DYN_LINK OFF) # force dynamic linking for all libraries ENDIF(WIN32) -FIND_PACKAGE(Boost 1.57 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -# For Boost 1.53 on windows, coroutine was not in BOOST_LIBRARYDIR and do not need it to build, but if boost versin >= 1.54, find coroutine otherwise will cause link errors -IF(NOT "${Boost_VERSION}" MATCHES "1.53(.*)") - SET(BOOST_LIBRARIES_TEMP ${Boost_LIBRARIES}) - FIND_PACKAGE(Boost 1.54 REQUIRED COMPONENTS coroutine) - LIST(APPEND BOOST_COMPONENTS coroutine) - SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES}) -ENDIF() +FIND_PACKAGE(Boost 1.58 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if( WIN32 ) diff --git a/Dockerfile b/Dockerfile index ae6676641a..4063f2d376 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,6 @@ FROM phusion/baseimage:0.9.19 #ARG STEEMD_BLOCKCHAIN=https://example.com/steemd-blockchain.tbz2 ENV LANG=en_US.UTF-8 -ENV VERSION=0.18.1 RUN \ apt-get update && \ @@ -31,6 +30,8 @@ RUN \ s3cmd \ awscli \ jq \ + wget \ + gdb \ && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ @@ -93,6 +94,13 @@ RUN \ make -j$(nproc) && \ make install && \ cd .. && \ + ( /usr/local/steemd-default/bin/steemd --version \ + | grep -o '[0-9]*\.[0-9]*\.[0-9]*' \ + && echo '_' \ + && git rev-parse --short HEAD ) \ + | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n//g' \ + > /etc/steemdversion && \ + cat /etc/steemdversion && \ rm -rfv build && \ mkdir build && \ cd build && \ @@ -205,4 +213,4 @@ RUN chmod +x /usr/local/bin/healthcheck.sh # AWS EB Docker requires a non-daemonized entrypoint ADD contrib/steemdentrypoint.sh /usr/local/bin/steemdentrypoint.sh RUN chmod +x /usr/local/bin/steemdentrypoint.sh -CMD /usr/local/bin/steemdentrypoint.sh +CMD /usr/local/bin/steemdentrypoint.sh \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index 36078bc3a8..fcfe36587b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -4,16 +4,17 @@ The following license applies to code contained within this repository that is created by Steemit, Inc. Other copy right holders have licensed dependencies such as Graphene, FC, and Boost under their own individual licenses. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +The MIT License -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. The currency symbols, 'STEEM' and 'SBD' are not changed and no new currency symbols are added. -4. The STEEMIT_INIT_PUBLIC_KEY_STR is not changed from STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX, -and the software is not modified in any way that would bypass the need for the corresponding private to start -a new blockchain. -5. The software is not used with any forks of the Steem blockchain that are not recognized by Steemit, Inc in writing. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, diff --git a/README.md b/README.md index 959b7b536d..7b1992caed 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Introducing Steem (beta) -Steem is an experimental Proof of Work blockchain with an unproven consensus +Steem is an experimental Delegated Proof of Stake blockchain with an unproven consensus algorithm. - Currency symbol STEEM @@ -23,7 +23,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# Code is Documentation +# Blockchain consensus rules Rather than attempt to describe the rules of the blockchain, it is up to each individual to inspect the code to understand the consensus rules. @@ -49,12 +49,30 @@ To run a node with *all* the data (e.g. for supporting a content website) that uses ca. 14GB of memory and growing: docker run \ - --env USE_WAY_TOO_MUCH_RAM=1 \ + --env USE_WAY_TOO_MUCH_RAM=1 --env USE_FULL_WEB_NODE=1 \ -d -p 2001:2001 -p 8090:8090 --name steemd-full \ steemit/steem docker logs -f steemd-full +# Environment variables + +There are quite a few environment variables that can be set to run steemd in different ways: + +* `USE_WAY_TOO_MUCH_RAM` - if set to true, steemd starts a 'full node' +* `USE_FULL_WEB_NODE` - if set to true, a default config file will be used that enables a full set of API's and associated plugins. +* `USE_NGINX_FRONTEND` - if set to true, this will enable an NGINX reverse proxy in front of steemd that proxies websocket requests to steemd. This will also enable a custom healtcheck at the path '/health' that lists how many seconds away from current blockchain time your node is. It will return a '200' if it's less than 60 seconds away from synced. +* `USE_MULTICORE_READONLY` - if set to true, this will enable steemd in multiple reader mode to take advantage of multiple cores (if available). Read requests are handled by the read-only nodes, and write requests are forwarded back to the single 'writer' node automatically. NGINX load balances all requests to the reader nodes, 4 per available core. This setting is still considered experimental and may have trouble with some API calls until further development is completed. +* `HOME` - set this to the path where you want steemd to store it's data files (block log, shared memory, config file, etc). By default `/var/lib/steemd` is used and exists inside the docker container. If you want to use a different mountpoint (like a ramdisk, or a different drive) then you may want to set this variable to map the volume to your docker container. + +# PaaS mode + +Steemd now supports a PaaS mode (platform as a service) that currently works with Amazon's Elastic Beanstalk service. It can be launched using the following environment variables: + +* `USE_PAAS` - if set to true, steemd will launch in a format that works with AWS EB. Containers will exit upon failure so that they can be relaunched automatically by ECS. This mode assumes `USE_WAY_TOO_MUCH_RAM` and `USE_FULL_WEB_NODE`, they do not need to be also set. +* `S3_BUCKET` - set this to the name of the S3 bucket where you will store shared memory files for steemd in Amazon S3. They will be stored compressed in bz2 format with the file name `blockchain-$VERSION-latest.tar.bz2`, where $VERSION is the release number followed by the git short commit hash stored in each docker image at `/etc/steemdversion`. +* `SYNC_TO_S3` - if set to true, the node will function to only generate shared memory files and upload them to the specified S3 bucket. This makes fast deployments and autoscaling for steemd possible. + # Seed Nodes A list of some seed nodes to get you started can be found in @@ -64,17 +82,6 @@ This same file is baked into the docker images and can be overridden by setting `STEEMD_SEED_NODES` in the container environment at `docker run` time to a whitespace delimited list of seed nodes (with port). -# How to Mine - -The mining algorithm used by Steem requires the owner to have access to the -private key used by the account. This means it does not favor mining pools. - - ./steemd --miner=["accountname","${WIFPRIVATEKEY}"] \ - --witness="accountname" --seed-node="52.38.66.234:2001" - -Make sure that your accountname is unique and not already used by someone -else or your proof of work might not be accepted by the blockchain. - # Building See [doc/building.md](doc/building.md) for detailed build instructions, including @@ -87,9 +94,7 @@ on how to use lcov to check code test coverage. # System Requirements -Minimum 8 GB RAM (16 GB Recommended). -32 GB disk for full node or 12 GB for a consensus node. SSD is preferred. -Any CPU with decent single core performance. +For a full web node, you need at least 55GB of space available. Steemd uses a memory mapped file which currently holds 36GB of data and by default is set to use up to 40GB. The block log of the blockchain itself is a little over 10GB. It's highly recommended to run steemd on a fast disk such as an SSD or by placing the shared memory files in a ramdisk and using the `--shard-file-dir=/path` command line option to specify where. At least 16GB of memory is required for a full web node. Seed nodes (p2p mode) can run with as little as 4GB of memory. Any CPU with decent single core performance should be sufficient. On Linux use the following Virtual Memory configuration for the initial sync and subsequent replays. It is not needed for normal operation. diff --git a/contrib/fullnode.config.ini b/contrib/fullnode.config.ini index e40d487fac..fa6182cac4 100644 --- a/contrib/fullnode.config.ini +++ b/contrib/fullnode.config.ini @@ -1,5 +1,5 @@ # Set larger shared-file-size than default -shared-file-size = 40G +shared-file-size = 48G # Set an API to be publicly available, may be specified multiple times public-api = database_api login_api account_by_key_api network_broadcast_api tag_api follow_api market_history_api raw_block_api diff --git a/contrib/paas-sv-run.sh b/contrib/paas-sv-run.sh index a99e63f742..818e285191 100644 --- a/contrib/paas-sv-run.sh +++ b/contrib/paas-sv-run.sh @@ -13,7 +13,14 @@ fi # if the writer node dies, kill runsv causing the container to exit STEEMD_PID=`pgrep -f p2p-endpoint` if [[ ! $? -eq 0 ]]; then - echo NOTIFYALERT! steemd has quit unexpectedly, starting a new instance.. + echo NOTIFYALERT! steemd has quit unexpectedly, checking for core dump and then starting a new instance.. + sleep 30 + SAVED_PID=`cat /tmp/steemdpid` + if [[ -e /tmp/core.$SAVED_PID ]]; then + gdb --batch --quiet -ex "thread apply all bt full" -ex "quit" /usr/local/steemd-full/bin/steemd /tmp/core.$SAVED_PID >> /tmp/stacktrace + STACKTRACE=`cat /tmp/stacktrace` + echo NOTIFYALERT! steemdsync stacktrace from coredump: $STACKTRACE + fi RUN_SV_PID=`pgrep -f /etc/service/steemd` kill -9 $RUN_SV_PID fi diff --git a/contrib/startpaassteemd.sh b/contrib/startpaassteemd.sh index 43c45544a8..e0855f8417 100644 --- a/contrib/startpaassteemd.sh +++ b/contrib/startpaassteemd.sh @@ -1,10 +1,14 @@ #!/bin/bash -export HOME="/var/lib/steemd" + +VERSION=`cat /etc/steemdversion` STEEMD="/usr/local/steemd-full/bin/steemd" chown -R steemd:steemd $HOME +# clean out data dir since it may be semi-persistent block storage on the ec2 with stale data +rm -rf $HOME/* + # seed nodes come from doc/seednodes.txt which is # installed by docker into /etc/steemd/seednodes.txt SEED_NODES="$(cat /etc/steemd/seednodes.txt | awk -F' ' '{print $1}')" @@ -38,29 +42,41 @@ mv /etc/nginx/nginx.conf /etc/nginx/nginx.original.conf cp /etc/nginx/steemd.nginx.conf /etc/nginx/nginx.conf # get blockchain state from an S3 bucket -# if this url is not provieded then we might as well exit -S3_DOWNLOAD_BUCKET=steemit-$NODE_ENV-blockchainstate -echo steemd: beginning download and decompress of s3://$S3_DOWNLOAD_BUCKET/blockchain-$VERSION-latest.tar.bz2 -if [[ ! "$SYNC_TO_S3" ]]; then +echo steemd: beginning download and decompress of s3://$S3_BUCKET/blockchain-$VERSION-latest.tar.bz2 +if [[ "$USE_RAMDISK" ]]; then mkdir -p /mnt/ramdisk - mount -t ramfs -o size=43008m ramfs /mnt/ramdisk - s3cmd get s3://$S3_DOWNLOAD_BUCKET/blockchain-$VERSION-latest.tar.bz2 - | pbzip2 -m2000dc | tar x --wildcards 'blockchain/block*' -C /mnt/ramdisk 'blockchain/shared*' - ln -s blockchain/block_log /mnt/ramdisk/blockchain/block_log - ln -s blockchain/block_log.index /mnt/ramdisk/blockchain/block_log.index + mount -t ramfs -o size=${RAMDISK_SIZE_IN_MB:-51200}m ramfs /mnt/ramdisk ARGS+=" --shared-file-dir=/mnt/ramdisk/blockchain" + s3cmd get s3://$S3_BUCKET/blockchain-$VERSION-latest.tar.bz2 - | pbzip2 -m2000dc | tar x --wildcards 'blockchain/block*' -C /mnt/ramdisk 'blockchain/shared*' chown -R steemd:steemd /mnt/ramdisk/blockchain -else - s3cmd get s3://$S3_DOWNLOAD_BUCKET/blockchain-$VERSION-latest.tar.bz2 - | pbzip2 -m2000dc | tar x - touch /tmp/issyncnode - chown www-data:www-data /tmp/issyncnode +else + s3cmd get s3://$S3_BUCKET/blockchain-$VERSION-latest.tar.bz2 - | pbzip2 -m2000dc | tar x fi if [[ $? -ne 0 ]]; then - echo error: unable to pull blockchain state from S3 - exitting - exit 1 + if [[ ! "$SYNC_TO_S3" ]]; then + echo notifyalert steemd: unable to pull blockchain state from S3 - exiting + exit 1 + else + echo notifysteemdsync steemdsync: shared memory file for $VERSION not found, creating a new one by replaying the blockchain + mkdir blockchain + aws s3 cp s3://$S3_BUCKET/block_log-latest blockchain/block_log + if [[ $? -ne 0 ]]; then + echo notifysteemdsync steemdsync: unable to pull latest block_log from S3, will sync from scratch. + else + ARGS+=" --replay-blockchain --force-validate" + fi + touch /tmp/isnewsync + fi +fi + +cd $HOME + +if [[ "$SYNC_TO_S3" ]]; then + touch /tmp/issyncnode + chown www-data:www-data /tmp/issyncnode fi -# change owner of downloaded blockchainstate to steemd user -chown -R steemd:steemd /var/lib/steemd/* +chown -R steemd:steemd $HOME/* # start multiple read-only instances based on the number of cores # attach to the local interface since a proxy will be used to loadbalance @@ -92,7 +108,6 @@ if [[ "$USE_MULTICORE_READONLY" ]]; then $STEEMD \ --rpc-endpoint=127.0.0.1:$PORT_NUM \ --data-dir=$HOME \ - --shared-file-dir=/mnt/ramdisk/blockchain \ --read-forward-rpc=127.0.0.1:8091 \ --read-only \ 2>&1 & @@ -127,6 +142,8 @@ else $ARGS \ $STEEMD_EXTRA_OPTS \ 2>&1& + SAVED_PID=`pgrep -f p2p-endpoint` + echo $SAVED_PID >> /tmp/steemdpid mkdir -p /etc/service/steemd if [[ ! "$SYNC_TO_S3" ]]; then cp /usr/local/bin/paas-sv-run.sh /etc/service/steemd/run diff --git a/contrib/steemd.nginx.conf b/contrib/steemd.nginx.conf index 2dd1c4546f..9f807ae9f1 100644 --- a/contrib/steemd.nginx.conf +++ b/contrib/steemd.nginx.conf @@ -10,39 +10,28 @@ events { http { sendfile on; - #tcp_nopush on; - keepalive_timeout 15; + keepalive_timeout 0; server_tokens off; real_ip_header X-Forwarded-For; set_real_ip_from 172.31.0.0/16; - # server_names_hash_bucket_size 64; - # server_name_in_redirect off; - include /etc/nginx/mime.types; default_type application/octet-stream; - # rate limiting disabled for SBDS - #limit_conn_zone $binary_remote_addr zone=addr:100m; - #limit_req_zone $binary_remote_addr zone=public:100m rate=20r/s; - - #limit_conn addr 32; - #limit_req zone=public burst=30; - #limit_conn_log_level error; - #limit_req_log_level error; - - log_format main '$remote_addr - $remote_user [$time_local] ' + log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '|"$http_referer"| "$http_user_agent"'; access_log /dev/stdout main; error_log /dev/stdout info; - log_not_found off; + log_not_found off; gzip on; + proxy_ignore_client_abort on; + include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } diff --git a/contrib/steemd.run b/contrib/steemd.run index 3db2cca6c7..27c1ac0340 100644 --- a/contrib/steemd.run +++ b/contrib/steemd.run @@ -1,9 +1,9 @@ #!/bin/bash -export HOME="/var/lib/steemd" - STEEMD="/usr/local/steemd-default/bin/steemd" +VERSION=`cat /etc/steemdversion` + if [[ "$USE_WAY_TOO_MUCH_RAM" ]]; then STEEMD="/usr/local/steemd-full/bin/steemd" fi @@ -69,9 +69,17 @@ fi # who knows what else it dumps into current dir cd $HOME +if [[ "$USE_PUBLIC_SHARED_MEMORY" ]]; then + echo steemd: Downloading and uncompressing blockchain-$VERSION-latest.tar.bz2 - this may take awhile. + wget -qO- https://s3.amazonaws.com/steemit-dev-blockchainstate/blockchain-$VERSION-latest.tar.bz2 | pbzip2 -m2000dc | tar x +fi + # slow down restart loop if flapping sleep 1 +mv /etc/nginx/nginx.conf /etc/nginx/nginx.original.conf +cp /etc/nginx/steemd.nginx.conf /etc/nginx/nginx.conf + #start multiple read-only instances based on the number of cores #attach to the local interface since a proxy will be used to loadbalance if [[ "$USE_MULTICORE_READONLY" ]]; then @@ -83,21 +91,20 @@ if [[ "$USE_MULTICORE_READONLY" ]]; then $ARGS \ $STEEMD_EXTRA_OPTS \ 2>&1 & - #sleep for a moment to allow the writer node to be ready to accept connections from the readers - sleep 5 + # sleep for a moment to allow the writer node to be ready to accept connections from the readers + sleep 30 PORT_NUM=8092 - #don't generate endpoints in haproxy config if it already exists - #this prevents adding to it if the docker container is stopped/started - if [[ ! -f /etc/haproxy/haproxy.steem.cfg ]]; then - cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.steem.cfg - for (( i=2; i<=$(nproc); i++ )) - do - echo server server$PORT_NUM 127.0.0.1:$PORT_NUM maxconn 10000 weight 10 cookie server$PORT_NUM check >> /etc/haproxy/haproxy.steem.cfg - ((PORT_NUM++)) - done - fi + cp /etc/nginx/healthcheck.conf.template /etc/nginx/healthcheck.conf + CORES=$(nproc) + PROCESSES=$((CORES * 4)) + for (( i=2; i<=$PROCESSES; i++ )) + do + echo server 127.0.0.1:$PORT_NUM\; >> /etc/nginx/healthcheck.conf + ((PORT_NUM++)) + done + echo } >> /etc/nginx/healthcheck.conf PORT_NUM=8092 - for (( i=2; i<=$(nproc); i++ )) + for (( i=2; i<=$PROCESSES; i++ )) do exec chpst -usteemd \ $STEEMD \ @@ -109,10 +116,30 @@ if [[ "$USE_MULTICORE_READONLY" ]]; then ((PORT_NUM++)) sleep 1 done - #start haproxy now that the config file is complete with all endpoints - #all of the read-only processes will connect to the write node onport 8091 - #haproxy will balance all incoming traffic on port 8090 - /usr/sbin/haproxy -f /etc/haproxy/haproxy.steem.cfg 2>&1 + # start nginx now that the config file is complete with all endpoints + # all of the read-only processes will connect to the write node onport 8091 + # nginx will balance all incoming traffic on port 8090 + rm /etc/nginx/sites-enabled/default + cp /etc/nginx/healthcheck.conf /etc/nginx/sites-enabled/default + /etc/init.d/fcgiwrap restart + echo daemon off\; >> /etc/nginx/nginx.conf + service nginx restart +elif [[ "$USE_NGINX_FRONTEND" ]]; then + cp /etc/nginx/healthcheck.conf.template /etc/nginx/healthcheck.conf + echo server 127.0.0.1:8091\; >> /etc/nginx/healthcheck.conf + echo } >> /etc/nginx/healthcheck.conf + rm /etc/nginx/sites-enabled/default + cp /etc/nginx/healthcheck.conf /etc/nginx/sites-enabled/default + /etc/init.d/fcgiwrap restart + service nginx restart + exec chpst -usteemd \ + $STEEMD \ + --rpc-endpoint=0.0.0.0:8091 \ + --p2p-endpoint=0.0.0.0:2001 \ + --data-dir=$HOME \ + $ARGS \ + $STEEMD_EXTRA_OPTS \ + 2>&1 else exec chpst -usteemd \ $STEEMD \ diff --git a/contrib/steemdentrypoint.sh b/contrib/steemdentrypoint.sh index bc2a40ab44..c5d179da84 100644 --- a/contrib/steemdentrypoint.sh +++ b/contrib/steemdentrypoint.sh @@ -1,5 +1,8 @@ #!/bin/bash +echo /tmp/core | tee /proc/sys/kernel/core_pattern +ulimit -c unlimited + # if we're not using PaaS mode then start steemd traditionally with sv to control it if [[ ! "$USE_PAAS" ]]; then mkdir -p /etc/service/steemd diff --git a/contrib/sync-sv-run.sh b/contrib/sync-sv-run.sh index 30a2216233..fe5948f49b 100644 --- a/contrib/sync-sv-run.sh +++ b/contrib/sync-sv-run.sh @@ -1,9 +1,18 @@ #!/bin/bash +VERSION=`cat /etc/steemdversion` + # if the writer node dies by itself, kill runsv causing the container to exit STEEMD_PID=`pgrep -f p2p-endpoint` if [[ ! $? -eq 0 ]]; then - echo NOTIFYALERT! steemdsync has quit unexpectedly, starting a new instance.. + echo NOTIFYALERT! steemdsync has quit unexpectedly, checking for coredump and then starting a new instance.. + sleep 30 + SAVED_PID=`cat /tmp/steemdpid` + if [[ -e /tmp/core.$SAVED_PID ]]; then + gdb --batch --quiet -ex "thread apply all bt full" -ex "quit" /usr/local/steemd-full/bin/steemd /tmp/core.$SAVED_PID >> /tmp/stacktrace + STACKTRACE=`cat /tmp/stacktrace` + echo NOTIFYALERT! steemdsync stacktrace from coredump: $STACKTRACE + fi RUN_SV_PID=`pgrep -f /etc/service/steemd` kill -9 $RUN_SV_PID fi @@ -33,21 +42,27 @@ if [[ ! -z "$BLOCKCHAIN_TIME" ]]; then echo steemdsync: compressing blockchainstate... tar cf blockchain.tar.bz2 --use-compress-prog=pbzip2 blockchain FILE_NAME=blockchain-$VERSION-`date '+%Y%m%d-%H%M%S'`.tar.bz2 - S3_UPLOAD_BUCKET=steemit-$NODE_ENV-blockchainstate - echo steemdsync: uploading $FILE_NAME to $S3_UPLOAD_BUCKET - aws s3 cp blockchain.tar.bz2 s3://$S3_UPLOAD_BUCKET/$FILE_NAME + echo steemdsync: uploading $FILE_NAME to $S3_BUCKET + aws s3 cp blockchain.tar.bz2 s3://$S3_BUCKET/$FILE_NAME if [[ ! $? -eq 0 ]]; then - echo NOTIFYALERT! steemdsync was unable to upload $FILE_NAME to s3://$S3_UPLOAD_BUCKET + echo NOTIFYALERT! steemdsync was unable to upload $FILE_NAME to s3://$S3_BUCKET exit 1 fi echo steemdsync: replacing current version of blockchain-latest.tar.bz2 with $FILE_NAME - aws s3 cp s3://$S3_UPLOAD_BUCKET/$FILE_NAME s3://$S3_UPLOAD_BUCKET/blockchain-$VERSION-latest.tar.bz2 + aws s3 cp s3://$S3_BUCKET/$FILE_NAME s3://$S3_BUCKET/blockchain-$VERSION-latest.tar.bz2 + aws s3api put-object-acl --bucket $S3_BUCKET --key blockchain-$VERSION-latest.tar.bz2 --acl public-read if [[ ! $? -eq 0 ]]; then echo NOTIFYALERT! steemdsync was unable to overwrite the current blockchainstate with $FILE_NAME exit 1 fi + # upload a current block_log + aws s3 cp blockchain/block_log s3://$S3_BUCKET/block_log-intransit + aws s3 cp s3://$S3_BUCKET/block_log-intransit s3://$S3_BUCKET/block_log-latest # kill the container starting the process over again echo steemdsync: stopping the container after a sync operation + if [[ -e /tmp/isnewsync ]]; then + echo notifysteemdsync: steemdsync: successfully generated and uploaded new blockchain-$VERSION-latest.tar.bz2 to s3://$S3_BUCKET + fi RUN_SV_PID=`pgrep -f /etc/service/steemd` kill -9 $RUN_SV_PID fi diff --git a/doc/building.md b/doc/building.md index b02cc81db2..4fd41653ae 100644 --- a/doc/building.md +++ b/doc/building.md @@ -83,6 +83,8 @@ will build out of the box without further effort: ## Building on Ubuntu 14.04 +(It is strongly advised to use Ubuntu 16.04 LTS instead) + Here are the required packages: # Required packages @@ -94,42 +96,36 @@ Here are the required packages: libssl-dev \ libtool \ make \ - pkg-config - - # Packages required to build Boost - sudo apt-get install -y \ - libbz2-dev \ - python-dev - - # Optional packages (not required, but will make a nicer experience) - sudo apt-get install -y + pkg-config \ doxygen \ libncurses5-dev \ libreadline-dev \ + libbz2-dev \ + python-dev \ perl -Steem requires Boost 1.57 or later. The Boost provided in the Ubuntu 14.04 -package manager (Boost 1.55) is too old. So building Steem on Ubuntu 14.04 -requires downloading and installing a more recent version of Boost. +The Boost provided in the Ubuntu 14.04 package manager (Boost 1.55) is too old. +Steem requires Boost 1.58 (as in Ubuntu 16.04) and works with versions up to 1.60 (including). +So building Steem on Ubuntu 14.04 requires downloading and installing a more recent +version of Boost. According to [this mailing list post](http://boost.2283326.n4.nabble.com/1-58-1-bugfix-release-necessary-td4674686.html), Boost 1.58 is not compatible with gcc 4.8 (the default C++ compiler for -Ubuntu 14.04) when compiling in C++11 mode (which Steem does). So we will -use Boost 1.57; if you try to build with any other version, you will -probably have a bad time. +Ubuntu 14.04) when compiling in C++11 mode (which Steem does). +So we will use Boost 1.60. -Here is how to build and install Boost 1.57 into your user's home directory +Here is how to build and install Boost 1.60 into your user's home directory (make sure you install all the packages above first): - BOOST_ROOT=$HOME/opt/boost_1_57_0 - URL='http://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.bz2/download' - wget -c "$URL" -O boost_1_57_0.tar.bz2 - [ $( sha256sum boost_1_57_0.tar.bz2 | cut -d ' ' -f 1 ) == \ - "910c8c022a33ccec7f088bd65d4f14b466588dda94ba2124e78b8c57db264967" ] \ + export BOOST_ROOT=$HOME/opt/boost_1_60_0 + URL='http://sourceforge.net/projects/boost/files/boost/1.60.0/boost_1_60_0.tar.bz2/download' + wget -c "$URL" -O boost_1_60_0.tar.bz2 + [ $( sha256sum boost_1_60_0.tar.bz2 | cut -d ' ' -f 1 ) == \ + "686affff989ac2488f79a97b9479efb9f2abae035b5ed4d8226de6857933fd3b" ] \ || ( echo 'Corrupt download' ; exit 1 ) - tar xjf boost_1_57_0.tar.bz2 - cd boost_1_57_0 + tar xjf boost_1_60_0.tar.bz2 + cd boost_1_60_0 ./bootstrap.sh "--prefix=$BOOST_ROOT" ./b2 install @@ -181,6 +177,11 @@ steem. Until then, this will allow you to install boost 1.60.0. brew install google-perftools +*Optional.* To use cli_wallet and override macOS's default readline installation: + + brew install --force readline + brew link --force readline + ### Clone the Repository git clone https://github.com/steemit/steem.git diff --git a/doc/seednodes.txt b/doc/seednodes.txt index 10ad6b880b..5a5383392b 100644 --- a/doc/seednodes.txt +++ b/doc/seednodes.txt @@ -5,7 +5,7 @@ seed.steemd.com:34191 # roadscape steemwitness.matthewniemerg.com:2001 # complexring steemd.pharesim.me:2001 # pharesim seed.jesta.us:2001 # jesta -212.117.213.186:2016 # liondani +seed.liondani.com:2016 # liondani anyx.co:2001 # anyx seed.xeldal.com:12150 # xeldal seed.steemnodes.com:2001 # wackou diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index bd16731c99..29e8340001 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory( chainbase ) add_subdirectory( chain ) add_subdirectory( protocol ) add_subdirectory( net ) -add_subdirectory( time ) add_subdirectory( utilities ) add_subdirectory( app ) add_subdirectory( plugins ) diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index 1cab664a5c..d03fbd2938 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -9,7 +9,7 @@ add_library( steemit_app ${HEADERS} ) -target_link_libraries( steemit_app steemit_chain steemit_protocol steemit_tags steemit_follow steemit_mf_plugins fc graphene_net steemit_time graphene_utilities ) +target_link_libraries( steemit_app steemit_chain steemit_protocol steemit_tags steemit_follow steemit_witness steemit_mf_plugins fc graphene_net graphene_utilities ) target_include_directories( steemit_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index e096e51701..8a234617ee 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include @@ -143,7 +143,7 @@ namespace steemit { namespace app { if( max_block_age < 0 ) return false; - fc::time_point_sec now = steemit::time::now(); + fc::time_point_sec now = fc::time_point::now(); std::shared_ptr< database > db = _app.chain_database(); const dynamic_global_property_object& dgpo = db->get_dynamic_global_properties(); diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 9fa2cb2b31..e44f19387c 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -136,9 +136,14 @@ namespace detail { ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint())); _p2p_network->connect_to_p2p_network(); - idump( (_chain_db->head_block_id()) ); + block_id_type head_block_id; + _chain_db->with_read_lock( [&]() + { + head_block_id = _chain_db->head_block_id(); + }); + idump( (head_block_id) ); _p2p_network->sync_from(graphene::net::item_id(graphene::net::core_message_type_enum::block_message_type, - _chain_db->head_block_id()), + head_block_id), std::vector()); } FC_CAPTURE_AND_RETHROW() } @@ -316,16 +321,6 @@ namespace detail { ilog( "All transaction signatures will be validated" ); _force_validate = true; } - - if( _options->at("enable-ntp").as() ) - { - ilog( "Enable NTP" ); - steemit::time::set_ntp_enabled(true); - } - else - { - ilog( "Launching with NTP disabled" ); - } } else { @@ -436,10 +431,13 @@ namespace detail { try { - if( id.item_type == graphene::net::block_message_type ) - return _chain_db->is_known_block(id.item_hash); - else - return _chain_db->is_known_transaction(id.item_hash); + return _chain_db->with_read_lock( [&]() + { + if( id.item_type == graphene::net::block_message_type ) + return _chain_db->is_known_block(id.item_hash); + else + return _chain_db->is_known_transaction(id.item_hash); + }); } FC_CAPTURE_AND_RETHROW( (id) ) } @@ -457,18 +455,25 @@ namespace detail { { try { if( _running ) { + uint32_t head_block_num; + + _chain_db->with_read_lock( [&]() + { + head_block_num = _chain_db->head_block_num(); + }); + if (sync_mode) fc_ilog(fc::logger::get("sync"), "chain pushing sync block #${block_num} ${block_hash}, head is ${head}", ("block_num", blk_msg.block.block_num()) ("block_hash", blk_msg.block_id) - ("head", _chain_db->head_block_num())); + ("head", head_block_num)); else fc_ilog(fc::logger::get("sync"), "chain pushing block #${block_num} ${block_hash}, head is ${head}", ("block_num", blk_msg.block.block_num()) ("block_hash", blk_msg.block_id) - ("head", _chain_db->head_block_num())); + ("head", head_block_num)); if (sync_mode && blk_msg.block.block_num() % 10000 == 0) { ilog("Syncing Blockchain --- Got block: #${n} time: ${t}", @@ -476,7 +481,7 @@ namespace detail { ("n", blk_msg.block.block_num()) ); } - time_point_sec now = steemit::time::now(); + time_point_sec now = fc::time_point::now(); uint64_t max_accept_time = now.sec_since_epoch(); max_accept_time += allow_future_time; @@ -505,14 +510,14 @@ namespace detail { fc_elog(fc::logger::get("sync"), "Error when pushing block, current head block is ${head}:\n${e}", ("e", e.to_detail_string()) - ("head", _chain_db->head_block_num())); + ("head", head_block_num)); elog("Error when pushing block:\n${e}", ("e", e.to_detail_string())); FC_THROW_EXCEPTION(graphene::net::unlinkable_block_exception, "Error when pushing block:\n${e}", ("e", e.to_detail_string())); } catch( const fc::exception& e ) { fc_elog(fc::logger::get("sync"), "Error when pushing block, current head block is ${head}:\n${e}", ("e", e.to_detail_string()) - ("head", _chain_db->head_block_num())); + ("head", head_block_num)); elog("Error when pushing block:\n${e}", ("e", e.to_detail_string())); throw; } @@ -534,9 +539,12 @@ namespace detail { bool is_included_block(const block_id_type& block_id) { - uint32_t block_num = block_header::num_from_id(block_id); - block_id_type block_id_in_preferred_chain = _chain_db->get_block_id_for_num(block_num); - return block_id == block_id_in_preferred_chain; + return _chain_db->with_read_lock( [&]() + { + uint32_t block_num = block_header::num_from_id(block_id); + block_id_type block_id_in_preferred_chain = _chain_db->get_block_id_for_num(block_num); + return block_id == block_id_in_preferred_chain; + }); } /** @@ -552,47 +560,56 @@ namespace detail { uint32_t& remaining_item_count, uint32_t limit) override { try { - vector result; - remaining_item_count = 0; - if( _chain_db->head_block_num() == 0 ) - return result; + return _chain_db->with_read_lock( [&]() + { + vector result; + remaining_item_count = 0; + if( _chain_db->head_block_num() == 0 ) + return result; - result.reserve(limit); - block_id_type last_known_block_id; + result.reserve( limit ); + block_id_type last_known_block_id; - if (blockchain_synopsis.empty() || - (blockchain_synopsis.size() == 1 && blockchain_synopsis[0] == block_id_type())) - { - // peer has sent us an empty synopsis meaning they have no blocks. - // A bug in old versions would cause them to send a synopsis containing block 000000000 - // when they had an empty blockchain, so pretend they sent the right thing here. + if( blockchain_synopsis.empty() + || ( blockchain_synopsis.size() == 1 && blockchain_synopsis[0] == block_id_type() ) ) + { + // peer has sent us an empty synopsis meaning they have no blocks. + // A bug in old versions would cause them to send a synopsis containing block 000000000 + // when they had an empty blockchain, so pretend they sent the right thing here. + // do nothing, leave last_known_block_id set to zero + } + else + { + bool found_a_block_in_synopsis = false; - // do nothing, leave last_known_block_id set to zero - } - else - { - bool found_a_block_in_synopsis = false; - for (const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis)) - if (block_id_in_synopsis == block_id_type() || - (_chain_db->is_known_block(block_id_in_synopsis) && is_included_block(block_id_in_synopsis))) - { - last_known_block_id = block_id_in_synopsis; - found_a_block_in_synopsis = true; - break; - } - if (!found_a_block_in_synopsis) - FC_THROW_EXCEPTION(graphene::net::peer_is_on_an_unreachable_fork, "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis"); - } - for( uint32_t num = block_header::num_from_id(last_known_block_id); - num <= _chain_db->head_block_num() && result.size() < limit; - ++num ) - if( num > 0 ) - result.push_back(_chain_db->get_block_id_for_num(num)); + for( const item_hash_t& block_id_in_synopsis : boost::adaptors::reverse(blockchain_synopsis) ) + { + if (block_id_in_synopsis == block_id_type() || + (_chain_db->is_known_block(block_id_in_synopsis) && is_included_block(block_id_in_synopsis))) + { + last_known_block_id = block_id_in_synopsis; + found_a_block_in_synopsis = true; + break; + } + } - if( !result.empty() && block_header::num_from_id(result.back()) < _chain_db->head_block_num() ) - remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back()); + if (!found_a_block_in_synopsis) + FC_THROW_EXCEPTION(graphene::net::peer_is_on_an_unreachable_fork, "Unable to provide a list of blocks starting at any of the blocks in peer's synopsis"); + } - return result; + for( uint32_t num = block_header::num_from_id(last_known_block_id); + num <= _chain_db->head_block_num() && result.size() < limit; + ++num ) + { + if( num > 0 ) + result.push_back(_chain_db->get_block_id_for_num(num)); + } + + if( !result.empty() && block_header::num_from_id(result.back()) < _chain_db->head_block_num() ) + remaining_item_count = _chain_db->head_block_num() - block_header::num_from_id(result.back()); + + return result; + }); } FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) } /** @@ -600,18 +617,24 @@ namespace detail { */ virtual message get_item(const item_id& id) override { try { - // ilog("Request for item ${id}", ("id", id)); + // ilog("Request for item ${id}", ("id", id)); if( id.item_type == graphene::net::block_message_type ) { - auto opt_block = _chain_db->fetch_block_by_id(id.item_hash); - if( !opt_block ) - elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}", - ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash)))); - FC_ASSERT( opt_block.valid() ); - // ilog("Serving up block #${num}", ("num", opt_block->block_num())); - return block_message(std::move(*opt_block)); + return _chain_db->with_read_lock( [&]() + { + auto opt_block = _chain_db->fetch_block_by_id(id.item_hash); + if( !opt_block ) + elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}", + ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block_header::num_from_id(id.item_hash)))); + FC_ASSERT( opt_block.valid() ); + // ilog("Serving up block #${num}", ("num", opt_block->block_num())); + return block_message(std::move(*opt_block)); + }); } - return trx_message( _chain_db->get_recent_transaction( id.item_hash ) ); + return _chain_db->with_read_lock( [&]() + { + return trx_message( _chain_db->get_recent_transaction( id.item_hash ) ); + }); } FC_CAPTURE_AND_RETHROW( (id) ) } /** @@ -675,120 +698,125 @@ namespace detail { virtual std::vector get_blockchain_synopsis(const item_hash_t& reference_point, uint32_t number_of_blocks_after_reference_point) override { try { - std::vector synopsis; - synopsis.reserve(30); - uint32_t high_block_num; - uint32_t non_fork_high_block_num; - uint32_t low_block_num = _chain_db->last_non_undoable_block_num(); - std::vector fork_history; - - if (reference_point != item_hash_t()) - { - // the node is asking for a summary of the block chain up to a specified - // block, which may or may not be on a fork - // for now, assume it's not on a fork - if (is_included_block(reference_point)) + std::vector synopsis; + _chain_db->with_read_lock( [&]() + { + synopsis.reserve(30); + uint32_t high_block_num; + uint32_t non_fork_high_block_num; + uint32_t low_block_num = _chain_db->last_non_undoable_block_num(); + std::vector fork_history; + + if (reference_point != item_hash_t()) { - // reference_point is a block we know about and is on the main chain - uint32_t reference_point_block_num = block_header::num_from_id(reference_point); - assert(reference_point_block_num > 0); - high_block_num = reference_point_block_num; - non_fork_high_block_num = high_block_num; - - if (reference_point_block_num < low_block_num) - { - // we're on the same fork (at least as far as reference_point) but we've passed - // reference point and could no longer undo that far if we diverged after that - // block. This should probably only happen due to a race condition where - // the network thread calls this function, and then immediately pushes a bunch of blocks, - // then the main thread finally processes this function. - // with the current framework, there's not much we can do to tell the network - // thread what our current head block is, so we'll just pretend that - // our head is actually the reference point. - // this *may* enable us to fetch blocks that we're unable to push, but that should - // be a rare case (and correctly handled) - low_block_num = reference_point_block_num; - } + // the node is asking for a summary of the block chain up to a specified + // block, which may or may not be on a fork + // for now, assume it's not on a fork + if (is_included_block(reference_point)) + { + // reference_point is a block we know about and is on the main chain + uint32_t reference_point_block_num = block_header::num_from_id(reference_point); + assert(reference_point_block_num > 0); + high_block_num = reference_point_block_num; + non_fork_high_block_num = high_block_num; + + if (reference_point_block_num < low_block_num) + { + // we're on the same fork (at least as far as reference_point) but we've passed + // reference point and could no longer undo that far if we diverged after that + // block. This should probably only happen due to a race condition where + // the network thread calls this function, and then immediately pushes a bunch of blocks, + // then the main thread finally processes this function. + // with the current framework, there's not much we can do to tell the network + // thread what our current head block is, so we'll just pretend that + // our head is actually the reference point. + // this *may* enable us to fetch blocks that we're unable to push, but that should + // be a rare case (and correctly handled) + low_block_num = reference_point_block_num; + } + } + else + { + // block is a block we know about, but it is on a fork + try + { + fork_history = _chain_db->get_block_ids_on_fork(reference_point); + // returns a vector where the last element is the common ancestor with the preferred chain, + // and the first element is the reference point you passed in + assert(fork_history.size() >= 2); + + if( fork_history.front() != reference_point ) + { + edump( (fork_history)(reference_point) ); + assert(fork_history.front() == reference_point); + } + block_id_type last_non_fork_block = fork_history.back(); + fork_history.pop_back(); // remove the common ancestor + boost::reverse(fork_history); + + if (last_non_fork_block == block_id_type()) // if the fork goes all the way back to genesis (does graphene's fork db allow this?) + non_fork_high_block_num = 0; + else + non_fork_high_block_num = block_header::num_from_id(last_non_fork_block); + + high_block_num = non_fork_high_block_num + fork_history.size(); + assert(high_block_num == block_header::num_from_id(fork_history.back())); + } + catch (const fc::exception& e) + { + // unable to get fork history for some reason. maybe not linked? + // we can't return a synopsis of its chain + elog("Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}", ("hash", reference_point)("exception", e)); + throw; + } + if (non_fork_high_block_num < low_block_num) + { + wlog("Unable to generate a usable synopsis because the peer we're generating it for forked too long ago " + "(our chains diverge after block #${non_fork_high_block_num} but only undoable to block #${low_block_num})", + ("low_block_num", low_block_num) + ("non_fork_high_block_num", non_fork_high_block_num)); + FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history, "Peer is are on a fork I'm unable to switch to"); + } + } } else { - // block is a block we know about, but it is on a fork - try - { - fork_history = _chain_db->get_block_ids_on_fork(reference_point); - // returns a vector where the last element is the common ancestor with the preferred chain, - // and the first element is the reference point you passed in - assert(fork_history.size() >= 2); - - if( fork_history.front() != reference_point ) - { - edump( (fork_history)(reference_point) ); - assert(fork_history.front() == reference_point); - } - block_id_type last_non_fork_block = fork_history.back(); - fork_history.pop_back(); // remove the common ancestor - boost::reverse(fork_history); - - if (last_non_fork_block == block_id_type()) // if the fork goes all the way back to genesis (does graphene's fork db allow this?) - non_fork_high_block_num = 0; - else - non_fork_high_block_num = block_header::num_from_id(last_non_fork_block); - - high_block_num = non_fork_high_block_num + fork_history.size(); - assert(high_block_num == block_header::num_from_id(fork_history.back())); - } - catch (const fc::exception& e) - { - // unable to get fork history for some reason. maybe not linked? - // we can't return a synopsis of its chain - elog("Unable to construct a blockchain synopsis for reference hash ${hash}: ${exception}", ("hash", reference_point)("exception", e)); - throw; - } - if (non_fork_high_block_num < low_block_num) - { - wlog("Unable to generate a usable synopsis because the peer we're generating it for forked too long ago " - "(our chains diverge after block #${non_fork_high_block_num} but only undoable to block #${low_block_num})", - ("low_block_num", low_block_num) - ("non_fork_high_block_num", non_fork_high_block_num)); - FC_THROW_EXCEPTION(graphene::net::block_older_than_undo_history, "Peer is are on a fork I'm unable to switch to"); - } + // no reference point specified, summarize the whole block chain + high_block_num = _chain_db->head_block_num(); + non_fork_high_block_num = high_block_num; + if (high_block_num == 0) + return; // we have no blocks } - } - else - { - // no reference point specified, summarize the whole block chain - high_block_num = _chain_db->head_block_num(); - non_fork_high_block_num = high_block_num; - if (high_block_num == 0) - return synopsis; // we have no blocks - } - - if( low_block_num == 0) - low_block_num = 1; - - // at this point: - // low_block_num is the block before the first block we can undo, - // non_fork_high_block_num is the block before the fork (if the peer is on a fork, or otherwise it is the same as high_block_num) - // high_block_num is the block number of the reference block, or the end of the chain if no reference provided - - // true_high_block_num is the ending block number after the network code appends any item ids it - // knows about that we don't - uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point; - do - { - // for each block in the synopsis, figure out where to pull the block id from. - // if it's <= non_fork_high_block_num, we grab it from the main blockchain; - // if it's not, we pull it from the fork history - if (low_block_num <= non_fork_high_block_num) - synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num)); - else - synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]); - low_block_num += (true_high_block_num - low_block_num + 2) / 2; - } - while (low_block_num <= high_block_num); - //idump((synopsis)); - return synopsis; + if( low_block_num == 0) + low_block_num = 1; + + // at this point: + // low_block_num is the block before the first block we can undo, + // non_fork_high_block_num is the block before the fork (if the peer is on a fork, or otherwise it is the same as high_block_num) + // high_block_num is the block number of the reference block, or the end of the chain if no reference provided + + // true_high_block_num is the ending block number after the network code appends any item ids it + // knows about that we don't + uint32_t true_high_block_num = high_block_num + number_of_blocks_after_reference_point; + do + { + // for each block in the synopsis, figure out where to pull the block id from. + // if it's <= non_fork_high_block_num, we grab it from the main blockchain; + // if it's not, we pull it from the fork history + if( low_block_num <= non_fork_high_block_num ) + synopsis.push_back(_chain_db->get_block_id_for_num(low_block_num)); + else + synopsis.push_back(fork_history[low_block_num - non_fork_high_block_num - 1]); + low_block_num += (true_high_block_num - low_block_num + 2) / 2; + } + while( low_block_num <= high_block_num ); + + //idump((synopsis)); + return; + }); + + return synopsis; } FC_CAPTURE_AND_RETHROW() } /** @@ -822,20 +850,26 @@ namespace detail { */ virtual fc::time_point_sec get_block_time(const item_hash_t& block_id) override { try { - auto opt_block = _chain_db->fetch_block_by_id( block_id ); - if( opt_block.valid() ) return opt_block->timestamp; - return fc::time_point_sec::min(); + return _chain_db->with_read_lock( [&]() + { + auto opt_block = _chain_db->fetch_block_by_id( block_id ); + if( opt_block.valid() ) return opt_block->timestamp; + return fc::time_point_sec::min(); + }); } FC_CAPTURE_AND_RETHROW( (block_id) ) } - /** returns steemit::time::now() */ + /** returns fc::time_point::now(); */ virtual fc::time_point_sec get_blockchain_now() override { - return steemit::time::now(); + return fc::time_point::now(); } virtual item_hash_t get_head_block_id() const override { - return _chain_db->head_block_id(); + return _chain_db->with_read_lock( [&]() + { + return _chain_db->head_block_id(); + }); } virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override @@ -865,7 +899,6 @@ namespace detail { } if( _chain_db ) _chain_db->close(); - steemit::time::set_ntp_enabled(false); } application* _self; @@ -948,7 +981,6 @@ void application::set_program_options(boost::program_options::options_descriptio ("enable-plugin", bpo::value< vector >()->composing()->default_value(default_plugins, str_default_plugins), "Plugin(s) to enable, may be specified multiple times") ("max-block-age", bpo::value< int32_t >()->default_value(200), "Maximum age of head block when broadcasting tx via API") ("flush", bpo::value< uint32_t >()->default_value(100000), "Flush shared memory file to disk this many blocks") - ("enable-ntp", bpo::value< bool >()->default_value(false), "Enable built-in NTP client") ; command_line_options.add(configuration_file_options); command_line_options.add_options() @@ -1093,7 +1125,9 @@ void application::initialize_plugins( const boost::program_options::variables_ma boost::split(names, arg, boost::is_any_of(" \t,")); for( const std::string& name : names ) { - enable_plugin( name ); + // When no plugins are specified, the empty string is returned. Only enable non-empty plugin names + if( name.size() ) + enable_plugin( name ); } } } diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d2f2684400..ebdae1831e 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -40,7 +40,7 @@ class database_api_impl : public std::enable_shared_from_this // Blocks and transactions optional get_block_header(uint32_t block_num)const; - optional get_block(uint32_t block_num)const; + optional get_block(uint32_t block_num)const; vector get_ops_in_block(uint32_t block_num, bool only_virtual)const; // Globals @@ -239,7 +239,7 @@ optional database_api_impl::get_block_header(uint32_t block_num) c return {}; } -optional database_api::get_block(uint32_t block_num)const +optional database_api::get_block(uint32_t block_num)const { return my->_db.with_read_lock( [&]() { @@ -247,7 +247,7 @@ optional database_api::get_block(uint32_t block_num)const }); } -optional database_api_impl::get_block(uint32_t block_num)const +optional database_api_impl::get_block(uint32_t block_num)const { return _db.fetch_block_by_number(block_num); } @@ -632,12 +632,16 @@ vector< withdraw_route > database_api::get_withdraw_routes( string account, with }); } -optional< account_bandwidth_api_obj > database_api::get_account_bandwidth( string account, bandwidth_type type )const +optional< account_bandwidth_api_obj > database_api::get_account_bandwidth( string account, witness::bandwidth_type type )const { optional< account_bandwidth_api_obj > result; - auto band = my->_db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( account, type ) ); - if( band != nullptr ) - result = *band; + + if( my->_db.has_index< witness::account_bandwidth_index >() ) + { + auto band = my->_db.find< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( account, type ) ); + if( band != nullptr ) + result = *band; + } return result; } @@ -1166,7 +1170,28 @@ void database_api::set_pending_payout( discussion& d )const void database_api::set_url( discussion& d )const { const comment_api_obj root( my->_db.get< comment_object, by_id >( d.root_comment ) ); - d.url = "/" + root.category + "/@" + root.author + "/" + root.permlink; + std::vector< std::string > tags; + if( root.json_metadata.size() ) + { + try + { + tags = fc::json::from_string( root.json_metadata )["tags"].as< std::vector< std::string > >(); + if(tags.at(0) != ""){ + d.url = "/" + tags.at(0) + "/@" + root.author + "/" + root.permlink; + } + else { + d.url = "/" + tags.at(1) + "/@" + root.author + "/" + root.permlink; + } + } + catch( const fc::exception& e ) + { + // Do nothing on malformed json_metadata + } + } + if(!tags.size()) { + d.url = "/@" + root.author + "/" + root.permlink; + } + d.root_title = root.title; if( root.id != d.id ) d.url += "#@" + d.author + "/" + d.permlink; @@ -1526,7 +1551,7 @@ vector database_api::get_discussions_by_cashout( const discussion_qu const auto& tidx = my->_db.get_index().indices().get(); auto tidx_itr = tidx.lower_bound( boost::make_tuple( tag, fc::time_point::now() - fc::minutes(60) ) ); - return get_discussions( query, tag, parent, tidx, tidx_itr, query.truncate_body, []( const comment_api_obj& c ){ return c.children_rshares2 <= 0; } ); + return get_discussions( query, tag, parent, tidx, tidx_itr, query.truncate_body, []( const comment_api_obj& c ){ return c.net_rshares < 0; }); }); } @@ -1745,63 +1770,6 @@ vector database_api::get_discussions_by_comments( const discussion_q }); } -vector database_api::get_trending_categories( string after, uint32_t limit )const -{ - return my->_db.with_read_lock( [&]() - { - limit = std::min( limit, uint32_t(100) ); - vector result; result.reserve( limit ); - - const auto& nidx = my->_db.get_index().indices().get(); - - const auto& ridx = my->_db.get_index().indices().get(); - auto itr = ridx.begin(); - if( after != "" && nidx.size() ) - { - auto nitr = nidx.lower_bound( after ); - if( nitr == nidx.end() ) itr = ridx.end(); - else itr = ridx.iterator_to( *nitr ); - } - - while( itr != ridx.end() && result.size() < limit ) { - result.push_back( category_api_obj( *itr ) ); - ++itr; - } - return result; - }); -} - -vector database_api::get_best_categories( string after, uint32_t limit )const -{ - return my->_db.with_read_lock( [&]() - { - limit = std::min( limit, uint32_t(100) ); - vector result; result.reserve( limit ); - return result; - }); -} - -vector database_api::get_active_categories( string after, uint32_t limit )const -{ - return my->_db.with_read_lock( [&]() - { - limit = std::min( limit, uint32_t(100) ); - vector result; result.reserve( limit ); - return result; - }); -} - -vector database_api::get_recent_categories( string after, uint32_t limit )const -{ - return my->_db.with_read_lock( [&]() - { - limit = std::min( limit, uint32_t(100) ); - vector result; result.reserve( limit ); - return result; - }); -} - - /** * This call assumes root already stored as part of state, it will * modify root.replies to contain links to the reply posts and then @@ -2158,9 +2126,7 @@ state database_api::get_state( string path )const } /// pull a complete discussion else if( part[1].size() && part[1][0] == '@' ) { - auto account = part[1].substr( 1 ); - auto category = part[0]; auto slug = part[2]; auto key = account +"/" + slug; diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp index fb395a9b5b..f877f5da0e 100644 --- a/libraries/app/impacted.cpp +++ b/libraries/app/impacted.cpp @@ -48,15 +48,17 @@ struct get_impacted_account_visitor op.get_required_owner_authorities( _impacted ); } + // ops void operator()( const account_create_operation& op ) { _impacted.insert( op.new_account_name ); _impacted.insert( op.creator ); } - void operator()( const account_update_operation& op ) + void operator()( const account_create_with_delegation_operation& op ) { - _impacted.insert( op.account ); + _impacted.insert( op.new_account_name ); + _impacted.insert( op.creator ); } void operator()( const comment_operation& op ) @@ -66,9 +68,10 @@ struct get_impacted_account_visitor _impacted.insert( op.parent_author ); } - void operator()( const delete_comment_operation& op ) + void operator()( const challenge_authority_operation& op ) { - _impacted.insert( op.author ); + _impacted.insert( op.challenger ); + _impacted.insert( op.challenged ); } void operator()( const vote_operation& op ) @@ -77,35 +80,38 @@ struct get_impacted_account_visitor _impacted.insert( op.author ); } - void operator()( const author_reward_operation& op ) - { - _impacted.insert( op.author ); - } - - void operator()( const curation_reward_operation& op ) + void operator()( const transfer_operation& op ) { - _impacted.insert( op.curator ); + _impacted.insert( op.from ); + _impacted.insert( op.to ); } - void operator()( const liquidity_reward_operation& op ) + void operator()( const escrow_transfer_operation& op ) { - _impacted.insert( op.owner ); + _impacted.insert( op.from ); + _impacted.insert( op.to ); + _impacted.insert( op.agent ); } - void operator()( const interest_operation& op ) + void operator()( const escrow_approve_operation& op ) { - _impacted.insert( op.owner ); + _impacted.insert( op.from ); + _impacted.insert( op.to ); + _impacted.insert( op.agent ); } - void operator()( const fill_convert_request_operation& op ) + void operator()( const escrow_dispute_operation& op ) { - _impacted.insert( op.owner ); + _impacted.insert( op.from ); + _impacted.insert( op.to ); + _impacted.insert( op.agent ); } - void operator()( const transfer_operation& op ) + void operator()( const escrow_release_operation& op ) { _impacted.insert( op.from ); _impacted.insert( op.to ); + _impacted.insert( op.agent ); } void operator()( const transfer_to_vesting_operation& op ) @@ -118,14 +124,10 @@ struct get_impacted_account_visitor } } - void operator()( const withdraw_vesting_operation& op ) - { - _impacted.insert( op.account ); - } - - void operator()( const witness_update_operation& op ) + void operator()( const set_withdraw_vesting_route_operation& op ) { - _impacted.insert( op.owner ); + _impacted.insert( op.from_account ); + _impacted.insert( op.to_account ); } void operator()( const account_witness_vote_operation& op ) @@ -145,47 +147,33 @@ struct get_impacted_account_visitor _impacted.insert( op.publisher ); } - void operator()( const limit_order_create_operation& op ) - { - _impacted.insert( op.owner ); - } - - void operator()( const fill_order_operation& op ) - { - _impacted.insert( op.current_owner ); - _impacted.insert( op.open_owner ); - } - - void operator()( const limit_order_cancel_operation& op ) - { - _impacted.insert( op.owner ); - } - void operator()( const pow_operation& op ) { _impacted.insert( op.worker_account ); } - void operator()( const fill_vesting_withdraw_operation& op ) + struct pow2_impacted_visitor { - _impacted.insert( op.from_account ); - _impacted.insert( op.to_account ); - } + pow2_impacted_visitor(){} - void operator()( const shutdown_witness_operation& op ) - { - _impacted.insert( op.owner ); - } + typedef const account_name_type& result_type; - void operator()( const custom_operation& op ) + template< typename WorkType > + result_type operator()( const WorkType& work )const + { + return work.input.worker_account; + } + }; + + void operator()( const pow2_operation& op ) { - for( auto s: op.required_auths ) - _impacted.insert( s ); + _impacted.insert( op.work.visit( pow2_impacted_visitor() ) ); } void operator()( const request_account_recovery_operation& op ) { _impacted.insert( op.account_to_recover ); + _impacted.insert( op.recovery_account ); } void operator()( const recover_account_operation& op ) @@ -198,60 +186,73 @@ struct get_impacted_account_visitor _impacted.insert( op.account_to_recover ); } - void operator()( const escrow_transfer_operation& op ) + void operator()( const transfer_to_savings_operation& op ) { _impacted.insert( op.from ); _impacted.insert( op.to ); - _impacted.insert( op.agent ); } - void operator()( const escrow_approve_operation& op ) + void operator()( const transfer_from_savings_operation& op ) { _impacted.insert( op.from ); _impacted.insert( op.to ); - _impacted.insert( op.agent ); } - void operator()( const escrow_dispute_operation& op ) + void operator()( const delegate_vesting_shares_operation& op ) { - _impacted.insert( op.from ); - _impacted.insert( op.to ); - _impacted.insert( op.agent ); + _impacted.insert( op.delegator ); + _impacted.insert( op.delegatee ); } - void operator()( const escrow_release_operation& op ) + + // vops + + void operator()( const author_reward_operation& op ) { - _impacted.insert( op.from ); - _impacted.insert( op.to ); - _impacted.insert( op.agent ); + _impacted.insert( op.author ); } - void operator()( const transfer_to_savings_operation& op ) + void operator()( const curation_reward_operation& op ) { - _impacted.insert( op.from ); - _impacted.insert( op.to ); + _impacted.insert( op.curator ); } - void operator()( const transfer_from_savings_operation& op ) + void operator()( const liquidity_reward_operation& op ) { - _impacted.insert( op.from ); - _impacted.insert( op.to ); + _impacted.insert( op.owner ); } - void operator()( const cancel_transfer_from_savings_operation& op ) + void operator()( const interest_operation& op ) { - _impacted.insert( op.from ); + _impacted.insert( op.owner ); } - void operator()( const decline_voting_rights_operation& op ) + void operator()( const fill_convert_request_operation& op ) { - _impacted.insert( op.account ); + _impacted.insert( op.owner ); } - void operator()( const delegate_vesting_shares_operation& op ) + void operator()( const fill_vesting_withdraw_operation& op ) { - _impacted.insert( op.delegator ); - _impacted.insert( op.delegatee ); + _impacted.insert( op.from_account ); + _impacted.insert( op.to_account ); + } + + void operator()( const shutdown_witness_operation& op ) + { + _impacted.insert( op.owner ); + } + + void operator()( const fill_order_operation& op ) + { + _impacted.insert( op.current_owner ); + _impacted.insert( op.open_owner ); + } + + void operator()( const fill_transfer_from_savings_operation& op ) + { + _impacted.insert( op.from ); + _impacted.insert( op.to ); } void operator()( const return_vesting_delegation_operation& op ) @@ -264,8 +265,6 @@ struct get_impacted_account_visitor _impacted.insert( op.benefactor ); _impacted.insert( op.author ); } - - //void operator()( const operation& op ){} }; void operation_get_impacted_accounts( const operation& op, flat_set& result ) diff --git a/libraries/app/include/steemit/app/database_api.hpp b/libraries/app/include/steemit/app/database_api.hpp index 35da6f4358..3020565887 100755 --- a/libraries/app/include/steemit/app/database_api.hpp +++ b/libraries/app/include/steemit/app/database_api.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -131,10 +132,6 @@ class database_api * with a single query. */ state get_state( string path )const; - vector get_trending_categories( string after, uint32_t limit )const; - vector get_best_categories( string after, uint32_t limit )const; - vector get_active_categories( string after, uint32_t limit )const; - vector get_recent_categories( string after, uint32_t limit )const; vector< account_name_type > get_active_witnesses()const; vector< account_name_type > get_miner_queue()const; @@ -155,7 +152,7 @@ class database_api * @param block_num Height of the block to be returned * @return the referenced block, or null if no matching block was found */ - optional get_block(uint32_t block_num)const; + optional get_block(uint32_t block_num)const; /** * @brief Get sequence of operations included/generated within a particular block @@ -238,7 +235,7 @@ class database_api vector< withdraw_route > get_withdraw_routes( string account, withdraw_route_type type = outgoing )const; - optional< account_bandwidth_api_obj > get_account_bandwidth( string account, bandwidth_type type )const; + optional< account_bandwidth_api_obj > get_account_bandwidth( string account, witness::bandwidth_type type )const; vector< savings_withdraw_api_obj > get_savings_withdraw_from( string account )const; vector< savings_withdraw_api_obj > get_savings_withdraw_to( string account )const; @@ -488,10 +485,6 @@ FC_API(steemit::app::database_api, (get_block) (get_ops_in_block) (get_state) - (get_trending_categories) - (get_best_categories) - (get_active_categories) - (get_recent_categories) // Globals (get_config) @@ -558,4 +551,3 @@ FC_API(steemit::app::database_api, (get_active_witnesses) (get_miner_queue) ) - diff --git a/libraries/app/include/steemit/app/plugin.hpp b/libraries/app/include/steemit/app/plugin.hpp index 7125c55bf0..8171a05d60 100644 --- a/libraries/app/include/steemit/app/plugin.hpp +++ b/libraries/app/include/steemit/app/plugin.hpp @@ -24,7 +24,9 @@ #pragma once #include + #include +#include #include diff --git a/libraries/app/include/steemit/app/state.hpp b/libraries/app/include/steemit/app/state.hpp index 5590046fb5..7313124047 100644 --- a/libraries/app/include/steemit/app/state.hpp +++ b/libraries/app/include/steemit/app/state.hpp @@ -21,7 +21,6 @@ namespace steemit { namespace app { struct discussion_index { - string category; /// category by which everything is filtered vector< string > trending; /// trending posts over the last 24 hours vector< string > payout; /// pending posts by payout vector< string > payout_comments; /// pending comments by payout @@ -38,13 +37,6 @@ namespace steemit { namespace app { vector< string > promoted; /// pending lifetime payout }; - struct category_index - { - vector< string > active; /// recent activity - vector< string > recent; /// recently created - vector< string > best; /// total lifetime payout - }; - struct tag_index { vector< string > trending; /// pending payouts @@ -111,7 +103,6 @@ namespace steemit { namespace app { optional> blog; /// blog posts for this user optional> feed; /// feed posts for this user optional> recent_replies; /// blog posts for this user - map> blog_category; /// blog posts for this user optional> recommended; /// posts recommened for this user }; @@ -155,20 +146,13 @@ namespace steemit { namespace app { dynamic_global_property_api_obj props; - /** - * Tracks the top categories by name, any category in this index - * will have its full status stored in the categories map. - */ - app::category_index category_idx; - app::tag_index tag_idx; /** - * "" is the global discussion index, otherwise the indicies are ranked by category + * "" is the global discussion index */ map discussion_idx; - map< string, category_api_obj > categories; map< string, tag_api_obj > tags; /** @@ -193,18 +177,17 @@ namespace steemit { namespace app { FC_REFLECT_DERIVED( steemit::app::extended_account, (steemit::app::account_api_obj), (vesting_balance)(reputation) - (transfer_history)(market_history)(post_history)(vote_history)(other_history)(witness_votes)(tags_usage)(guest_bloggers)(open_orders)(comments)(feed)(blog)(recent_replies)(blog_category)(recommended) ) + (transfer_history)(market_history)(post_history)(vote_history)(other_history)(witness_votes)(tags_usage)(guest_bloggers)(open_orders)(comments)(feed)(blog)(recent_replies)(recommended) ) FC_REFLECT( steemit::app::vote_state, (voter)(weight)(rshares)(percent)(reputation)(time) ); FC_REFLECT( steemit::app::account_vote, (authorperm)(weight)(rshares)(percent)(time) ); -FC_REFLECT( steemit::app::discussion_index, (category)(trending)(payout)(payout_comments)(trending30)(updated)(created)(responses)(active)(votes)(maturing)(best)(hot)(promoted)(cashout) ) -FC_REFLECT( steemit::app::category_index, (active)(recent)(best) ) +FC_REFLECT( steemit::app::discussion_index, (trending)(payout)(payout_comments)(trending30)(updated)(created)(responses)(active)(votes)(maturing)(best)(hot)(promoted)(cashout) ) FC_REFLECT( steemit::app::tag_index, (trending) ) FC_REFLECT_DERIVED( steemit::app::discussion, (steemit::app::comment_api_obj), (url)(root_title)(pending_payout_value)(total_pending_payout_value)(active_votes)(replies)(author_reputation)(promoted)(body_length)(reblogged_by)(first_reblogged_by)(first_reblogged_on) ) -FC_REFLECT( steemit::app::state, (current_route)(props)(category_idx)(tag_idx)(categories)(tags)(content)(accounts)(pow_queue)(witnesses)(discussion_idx)(witness_schedule)(feed_price)(error)(market_data) ) +FC_REFLECT( steemit::app::state, (current_route)(props)(tag_idx)(tags)(content)(accounts)(pow_queue)(witnesses)(discussion_idx)(witness_schedule)(feed_price)(error)(market_data) ) FC_REFLECT_DERIVED( steemit::app::extended_limit_order, (steemit::app::limit_order_api_obj), (real_price)(rewarded) ) FC_REFLECT( steemit::app::order_history_item, (time)(type)(sbd_quantity)(steem_quantity)(real_price) ); diff --git a/libraries/app/include/steemit/app/steem_api_objects.hpp b/libraries/app/include/steemit/app/steem_api_objects.hpp index 93bd19dea2..a6670c1837 100644 --- a/libraries/app/include/steemit/app/steem_api_objects.hpp +++ b/libraries/app/include/steemit/app/steem_api_objects.hpp @@ -10,6 +10,8 @@ #include +#include + namespace steemit { namespace app { using namespace steemit::chain; @@ -49,16 +51,15 @@ typedef chain::withdraw_vesting_route_object withdraw_vesting_route_ap typedef chain::decline_voting_rights_request_object decline_voting_rights_request_api_obj; typedef chain::witness_vote_object witness_vote_api_obj; typedef chain::witness_schedule_object witness_schedule_api_obj; -typedef chain::account_bandwidth_object account_bandwidth_api_obj; typedef chain::vesting_delegation_object vesting_delegation_api_obj; typedef chain::vesting_delegation_expiration_object vesting_delegation_expiration_api_obj; typedef chain::reward_fund_object reward_fund_api_obj; +typedef witness::account_bandwidth_object account_bandwidth_api_obj; struct comment_api_obj { comment_api_obj( const chain::comment_object& o ): id( o.id ), - category( to_string( o.category ) ), parent_author( o.parent_author ), parent_permlink( to_string( o.parent_permlink ) ), author( o.author ), @@ -72,7 +73,6 @@ struct comment_api_obj last_payout( o.last_payout ), depth( o.depth ), children( o.children ), - children_rshares2( o.children_rshares2 ), net_rshares( o.net_rshares ), abs_rshares( o.abs_rshares ), vote_rshares( o.vote_rshares ), @@ -101,7 +101,6 @@ struct comment_api_obj comment_api_obj(){} comment_id_type id; - string category; account_name_type parent_author; string parent_permlink; account_name_type author; @@ -118,8 +117,6 @@ struct comment_api_obj uint8_t depth = 0; uint32_t children = 0; - uint128_t children_rshares2; - share_type net_rshares; share_type abs_rshares; share_type vote_rshares; @@ -148,45 +145,24 @@ struct comment_api_obj vector< beneficiary_route_type > beneficiaries; }; -struct category_api_obj -{ - category_api_obj( const chain::category_object& c ) : - id( c.id ), - name( to_string( c.name ) ), - abs_rshares( c.abs_rshares ), - total_payouts( c.total_payouts ), - discussions( c.discussions ), - last_update( c.last_update ) - {} - - category_api_obj() {} - - category_id_type id; - string name; - share_type abs_rshares; - asset total_payouts; - uint32_t discussions = 0; - time_point_sec last_update; -}; - struct tag_api_obj { tag_api_obj( const tags::tag_stats_object& o ) : name( o.tag ), - total_children_rshares2(o.total_children_rshares2), total_payouts(o.total_payout), net_votes(o.net_votes), top_posts(o.top_posts), - comments(o.comments) {} + comments(o.comments), + trending(o.total_trending) {} tag_api_obj() {} string name; - fc::uint128_t total_children_rshares2; asset total_payouts; int32_t net_votes = 0; uint32_t top_posts = 0; uint32_t comments = 0; + fc::uint128 trending = 0; }; struct account_api_obj @@ -239,7 +215,8 @@ struct account_api_obj to_withdraw( a.to_withdraw ), withdraw_routes( a.withdraw_routes ), witnesses_voted_for( a.witnesses_voted_for ), - last_post( a.last_post ) + last_post( a.last_post ), + last_root_post( a.last_root_post ) { size_t n = a.proxied_vsf_votes.size(); proxied_vsf_votes.reserve( n ); @@ -252,38 +229,25 @@ struct account_api_obj posting = authority( auth.posting ); last_owner_update = auth.last_owner_update; - auto old_forum = db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( name, bandwidth_type::old_forum ) ); - if( old_forum != nullptr ) - { - average_bandwidth = old_forum->average_bandwidth; - lifetime_bandwidth = old_forum->lifetime_bandwidth; - last_bandwidth_update = old_forum->last_bandwidth_update; - } - - auto old_market = db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( name, bandwidth_type::old_market ) ); - if( old_market != nullptr ) + if( db.has_index< witness::account_bandwidth_index >() ) { - average_market_bandwidth = old_market->average_bandwidth; - last_market_bandwidth_update = old_market->last_bandwidth_update; - } - - auto post = db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( name, bandwidth_type::post ) ); - if( post != nullptr ) - { - last_root_post = post->last_bandwidth_update; - post_bandwidth = post->average_bandwidth; - } - - auto forum = db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( name, bandwidth_type::forum ) ); - if( forum != nullptr ) - { - new_average_bandwidth = forum->average_bandwidth; - } - - auto market = db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( name, bandwidth_type::market ) ); - if( market != nullptr ) - { - new_average_market_bandwidth = market->average_bandwidth; + auto forum_bandwidth = db.find< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( name, witness::bandwidth_type::forum ) ); + + if( forum_bandwidth != nullptr ) + { + average_bandwidth = forum_bandwidth->average_bandwidth; + lifetime_bandwidth = forum_bandwidth->lifetime_bandwidth; + last_bandwidth_update = forum_bandwidth->last_bandwidth_update; + } + + auto market_bandwidth = db.find< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( name, witness::bandwidth_type::market ) ); + + if( market_bandwidth != nullptr ) + { + average_market_bandwidth = market_bandwidth->average_bandwidth; + lifetime_market_bandwidth = market_bandwidth->lifetime_bandwidth; + last_market_bandwidth_update = market_bandwidth->last_bandwidth_update; + } } } @@ -361,13 +325,11 @@ struct account_api_obj time_point_sec last_bandwidth_update; share_type average_market_bandwidth = 0; + share_type lifetime_market_bandwidth = 0; time_point_sec last_market_bandwidth_update; + time_point_sec last_post; time_point_sec last_root_post; - share_type post_bandwidth = STEEMIT_100_PERCENT; - - share_type new_average_bandwidth; - share_type new_average_market_bandwidth; }; struct owner_authority_history_api_obj @@ -497,13 +459,30 @@ struct witness_api_obj time_point_sec hardfork_time_vote; }; +struct signed_block_api_obj : public signed_block +{ + signed_block_api_obj( const signed_block& block ) : signed_block( block ) + { + block_id = id(); + signing_key = signee(); + transaction_ids.reserve( transactions.size() ); + for( const signed_transaction& tx : transactions ) + transaction_ids.push_back( tx.id() ); + } + signed_block_api_obj() {} + + block_id_type block_id; + public_key_type signing_key; + vector< transaction_id_type > transaction_ids; +}; + } } // steemit::app FC_REFLECT( steemit::app::comment_api_obj, (id)(author)(permlink) - (category)(parent_author)(parent_permlink) + (parent_author)(parent_permlink) (title)(body)(json_metadata)(last_update)(created)(active)(last_payout) - (depth)(children)(children_rshares2) + (depth)(children) (net_rshares)(abs_rshares)(vote_rshares) (children_abs_rshares)(cashout_time)(max_cashout_time) (total_vote_weight)(reward_weight)(total_payout_value)(curator_payout_value)(author_rewards)(net_votes)(root_comment) @@ -511,10 +490,6 @@ FC_REFLECT( steemit::app::comment_api_obj, (beneficiaries) ) -FC_REFLECT( steemit::app::category_api_obj, - (id)(name)(abs_rshares)(total_payouts)(discussions)(last_update) - ) - FC_REFLECT( steemit::app::account_api_obj, (id)(name)(owner)(active)(posting)(memo_key)(json_metadata)(proxy)(last_owner_update)(last_account_update) (created)(mined) @@ -530,9 +505,8 @@ FC_REFLECT( steemit::app::account_api_obj, (posting_rewards) (proxied_vsf_votes)(witnesses_voted_for) (average_bandwidth)(lifetime_bandwidth)(last_bandwidth_update) - (average_market_bandwidth)(last_market_bandwidth_update) - (last_post)(last_root_post)(post_bandwidth) - (new_average_bandwidth)(new_average_market_bandwidth) + (average_market_bandwidth)(lifetime_market_bandwidth)(last_market_bandwidth_update) + (last_post)(last_root_post) ) FC_REFLECT( steemit::app::owner_authority_history_api_obj, @@ -567,11 +541,11 @@ FC_REFLECT( steemit::app::feed_history_api_obj, FC_REFLECT( steemit::app::tag_api_obj, (name) - (total_children_rshares2) (total_payouts) (net_votes) (top_posts) (comments) + (trending) ) FC_REFLECT( steemit::app::witness_api_obj, @@ -586,3 +560,9 @@ FC_REFLECT( steemit::app::witness_api_obj, (running_version) (hardfork_version_vote)(hardfork_time_vote) ) + +FC_REFLECT_DERIVED( steemit::app::signed_block_api_obj, (steemit::protocol::signed_block), + (block_id) + (signing_key) + (transaction_ids) + ) diff --git a/libraries/chain/block_log.cpp b/libraries/chain/block_log.cpp index a49d29786e..b43edd7f45 100644 --- a/libraries/chain/block_log.cpp +++ b/libraries/chain/block_log.cpp @@ -21,46 +21,58 @@ namespace steemit { namespace chain { inline void check_block_read() { - if( block_write ) + try { - block_stream.close(); - block_stream.open( block_file.generic_string().c_str(), LOG_READ ); - block_write = false; + if( block_write ) + { + block_stream.close(); + block_stream.open( block_file.generic_string().c_str(), LOG_READ ); + block_write = false; + } } + FC_LOG_AND_RETHROW() } inline void check_block_write() { - if( !block_write ) + try { - block_stream.close(); - block_stream.open( block_file.generic_string().c_str(), LOG_WRITE ); - block_write = true; + if( !block_write ) + { + block_stream.close(); + block_stream.open( block_file.generic_string().c_str(), LOG_WRITE ); + block_write = true; + } } + FC_LOG_AND_RETHROW() } inline void check_index_read() { try { - if( index_write ) - { - index_stream.close(); - index_stream.open( index_file.generic_string().c_str(), LOG_READ ); - index_write = false; - } + if( index_write ) + { + index_stream.close(); + index_stream.open( index_file.generic_string().c_str(), LOG_READ ); + index_write = false; + } } FC_LOG_AND_RETHROW() } inline void check_index_write() { - if( !index_write ) + try { - index_stream.close(); - index_stream.open( index_file.generic_string().c_str(), LOG_WRITE ); - index_write = true; + if( !index_write ) + { + index_stream.close(); + index_stream.open( index_file.generic_string().c_str(), LOG_WRITE ); + index_write = true; + } } + FC_LOG_AND_RETHROW() } }; } @@ -199,13 +211,17 @@ namespace steemit { namespace chain { std::pair< signed_block, uint64_t > block_log::read_block( uint64_t pos )const { - my->check_block_read(); + try + { + my->check_block_read(); - my->block_stream.seekg( pos ); - std::pair result; - fc::raw::unpack( my->block_stream, result.first ); - result.second = uint64_t(my->block_stream.tellg()) + 8; - return result; + my->block_stream.seekg( pos ); + std::pair result; + fc::raw::unpack( my->block_stream, result.first ); + result.second = uint64_t(my->block_stream.tellg()) + 8; + return result; + } + FC_LOG_AND_RETHROW() } optional< signed_block > block_log::read_block_by_num( uint32_t block_num )const @@ -226,24 +242,32 @@ namespace steemit { namespace chain { uint64_t block_log::get_block_pos( uint32_t block_num ) const { - my->check_index_read(); - - if( !( my->head.valid() && block_num <= protocol::block_header::num_from_id( my->head_id ) && block_num > 0 ) ) - return npos; - my->index_stream.seekg( sizeof( uint64_t ) * ( block_num - 1 ) ); - uint64_t pos; - my->index_stream.read( (char*)&pos, sizeof( pos ) ); - return pos; + try + { + my->check_index_read(); + + if( !( my->head.valid() && block_num <= protocol::block_header::num_from_id( my->head_id ) && block_num > 0 ) ) + return npos; + my->index_stream.seekg( sizeof( uint64_t ) * ( block_num - 1 ) ); + uint64_t pos; + my->index_stream.read( (char*)&pos, sizeof( pos ) ); + return pos; + } + FC_LOG_AND_RETHROW() } signed_block block_log::read_head()const { - my->check_block_read(); + try + { + my->check_block_read(); - uint64_t pos; - my->block_stream.seekg( -sizeof(pos), std::ios::end ); - my->block_stream.read( (char*)&pos, sizeof(pos) ); - return read_block( pos ).first; + uint64_t pos; + my->block_stream.seekg( -sizeof(pos), std::ios::end ); + my->block_stream.read( (char*)&pos, sizeof(pos) ); + return read_block( pos ).first; + } + FC_LOG_AND_RETHROW() } const optional< signed_block >& block_log::head()const @@ -253,27 +277,31 @@ namespace steemit { namespace chain { void block_log::construct_index() { - ilog( "Reconstructing Block Log Index..." ); - my->index_stream.close(); - fc::remove_all( my->index_file ); - my->index_stream.open( my->index_file.generic_string().c_str(), LOG_WRITE ); - my->index_write = true; + try + { + ilog( "Reconstructing Block Log Index..." ); + my->index_stream.close(); + fc::remove_all( my->index_file ); + my->index_stream.open( my->index_file.generic_string().c_str(), LOG_WRITE ); + my->index_write = true; - uint64_t pos = 0; - uint64_t end_pos; - my->check_block_read(); + uint64_t pos = 0; + uint64_t end_pos; + my->check_block_read(); - my->block_stream.seekg( -sizeof( uint64_t), std::ios::end ); - my->block_stream.read( (char*)&end_pos, sizeof( end_pos ) ); - signed_block tmp; + my->block_stream.seekg( -sizeof( uint64_t), std::ios::end ); + my->block_stream.read( (char*)&end_pos, sizeof( end_pos ) ); + signed_block tmp; - my->block_stream.seekg( pos ); + my->block_stream.seekg( pos ); - while( pos < end_pos ) - { - fc::raw::unpack( my->block_stream, tmp ); - my->block_stream.read( (char*)&pos, sizeof( pos ) ); - my->index_stream.write( (char*)&pos, sizeof( pos ) ); + while( pos < end_pos ) + { + fc::raw::unpack( my->block_stream, tmp ); + my->block_stream.read( (char*)&pos, sizeof( pos ) ); + my->index_stream.write( (char*)&pos, sizeof( pos ) ); + } } + FC_LOG_AND_RETHROW() } -} } +} } // steemit::chain diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 8984e8cb42..b775cb5e55 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -364,16 +364,6 @@ const comment_object* database::find_comment( const account_name_type& author, c return find< comment_object, by_permlink >( boost::make_tuple( author, permlink ) ); } -const category_object& database::get_category( const shared_string& name )const -{ try { - return get< category_object, by_name >( name ); -} FC_CAPTURE_AND_RETHROW( (name) ) } - -const category_object* database::find_category( const shared_string& name )const -{ - return find< category_object, by_name >( name ); -} - const escrow_object& database::get_escrow( const account_name_type& name, uint32_t escrow_id )const { try { return get< escrow_object, by_from_id >( boost::make_tuple( name, escrow_id ) ); @@ -459,114 +449,6 @@ void database::pay_fee( const account_object& account, asset fee ) adjust_supply( -fee ); } -void database::old_update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ) -{ try { - const auto& props = get_dynamic_global_properties(); - if( props.total_vesting_shares.amount > 0 ) - { - FC_ASSERT( a.vesting_shares.amount > 0, "Only accounts with a postive vesting balance may transact." ); - - auto band = find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( a.name, type ) ); - - if( band == nullptr ) - { - band = &create< account_bandwidth_object >( [&](account_bandwidth_object& b ) - { - b.account = a.name; - b.type = type; - }); - } - - modify( *band, [&]( account_bandwidth_object& b ) - { - b.lifetime_bandwidth += trx_size * STEEMIT_BANDWIDTH_PRECISION; - - auto now = head_block_time(); - auto delta_time = (now - b.last_bandwidth_update).to_seconds(); - uint64_t N = trx_size * STEEMIT_BANDWIDTH_PRECISION; - if( delta_time >= STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS ) - b.average_bandwidth = N; - else - { - auto old_weight = b.average_bandwidth * ( STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - delta_time ); - auto new_weight = delta_time * N; - b.average_bandwidth = ( old_weight + new_weight ) / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS; - } - - b.last_bandwidth_update = now; - }); - - fc::uint128 account_vshares( a.vesting_shares.amount.value ); - fc::uint128 total_vshares( props.total_vesting_shares.amount.value ); - - fc::uint128 account_average_bandwidth( band->average_bandwidth.value ); - fc::uint128 max_virtual_bandwidth( props.max_virtual_bandwidth ); - - FC_ASSERT( ( account_vshares * max_virtual_bandwidth ) > ( account_average_bandwidth * total_vshares ), - "Account exceeded maximum allowed bandwidth per vesting share.", - ("account_vshares", account_vshares) - ("account_average_bandwidth", account_average_bandwidth) - ("max_virtual_bandwidth", max_virtual_bandwidth) - ("total_vesting_shares", total_vshares) ); - } -} FC_CAPTURE_AND_RETHROW() } - -bool database::update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ) -{ - const auto& props = get_dynamic_global_properties(); - bool has_bandwidth = true; - - if( props.total_vesting_shares.amount > 0 ) - { - auto band = find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( a.name, type ) ); - - if( band == nullptr ) - { - band = &create< account_bandwidth_object >( [&]( account_bandwidth_object& b ) - { - b.account = a.name; - b.type = type; - }); - } - - share_type new_bandwidth; - share_type trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION; - auto delta_time = ( head_block_time() - band->last_bandwidth_update ).to_seconds(); - - if( delta_time > STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS ) - new_bandwidth = 0; - else - new_bandwidth = ( ( ( STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - delta_time ) * fc::uint128( band->average_bandwidth.value ) ) - / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS ).to_uint64(); - - new_bandwidth += trx_bandwidth; - - modify( *band, [&]( account_bandwidth_object& b ) - { - b.average_bandwidth = new_bandwidth; - b.lifetime_bandwidth += trx_bandwidth; - b.last_bandwidth_update = head_block_time(); - }); - - fc::uint128 account_vshares( a.effective_vesting_shares().amount.value ); - fc::uint128 total_vshares( props.total_vesting_shares.amount.value ); - fc::uint128 account_average_bandwidth( band->average_bandwidth.value ); - fc::uint128 max_virtual_bandwidth( props.max_virtual_bandwidth ); - - has_bandwidth = ( account_vshares * max_virtual_bandwidth ) > ( account_average_bandwidth * total_vshares ); - - if( is_producing() ) - FC_ASSERT( has_bandwidth, - "Account exceeded maximum allowed bandwidth per vesting share.", - ("account_vshares", account_vshares) - ("account_average_bandwidth", account_average_bandwidth) - ("max_virtual_bandwidth", max_virtual_bandwidth) - ("total_vesting_shares", total_vshares) ); - } - - return has_bandwidth; -} - uint32_t database::witness_participation_rate()const { const dynamic_global_property_object& dpo = get_dynamic_global_properties(); @@ -983,6 +865,11 @@ void database::notify_on_pending_transaction( const signed_transaction& tx ) STEEMIT_TRY_NOTIFY( on_pending_transaction, tx ) } +void database::notify_on_pre_apply_transaction( const signed_transaction& tx ) +{ + STEEMIT_TRY_NOTIFY( on_pre_apply_transaction, tx ) +} + void database::notify_on_applied_transaction( const signed_transaction& tx ) { STEEMIT_TRY_NOTIFY( on_applied_transaction, tx ) @@ -1359,26 +1246,6 @@ void database::clear_null_account_balance() adjust_supply( -total_sbd ); } -void update_children_rshares2( database& db, const comment_object& c, const fc::uint128_t& old_rshares2, const fc::uint128_t& new_rshares2 ) -{ - // Iteratively updates the children_rshares2 of this comment and all of its ancestors - - const comment_object* current_comment = &c; - while( true ) - { - db.modify( *current_comment, [&]( comment_object& comment ) - { - comment.children_rshares2 -= old_rshares2; - comment.children_rshares2 += new_rshares2; - } ); - - if( current_comment->depth == 0 ) - break; - - current_comment = &db.get_comment( current_comment->parent_author, current_comment->parent_permlink ); - } -} - /** * This method updates total_reward_shares2 on DGPO, and children_rshares2 on comments, when a comment's rshares2 changes * from old_rshares2 to new_rshares2. Maintaining invariants that children_rshares2 is the sum of all descendants' rshares2, @@ -1386,7 +1253,6 @@ void update_children_rshares2( database& db, const comment_object& c, const fc:: */ void database::adjust_rshares2( const comment_object& c, fc::uint128_t old_rshares2, fc::uint128_t new_rshares2 ) { - update_children_rshares2( *this, c, old_rshares2, new_rshares2 ); const auto& dgpo = get_dynamic_global_properties(); modify( dgpo, [&]( dynamic_global_property_object& p ) @@ -1610,7 +1476,6 @@ share_type database::cashout_comment_helper( util::comment_reward_context& ctx, { try { - const auto& cat = get_category( comment.category ); share_type claimed_reward = 0; if( comment.net_rshares > 0 ) @@ -1664,22 +1529,12 @@ share_type database::cashout_comment_helper( util::comment_reward_context& ctx, }); #endif - modify( cat, [&]( category_object& c ) - { - c.total_payouts += to_sbd( asset( claimed_reward, STEEM_SYMBOL ) ); - }); } if( !has_hardfork( STEEMIT_HARDFORK_0_17__774 ) ) adjust_rshares2( comment, util::calculate_claims( comment.net_rshares.value ), 0 ); } - modify( cat, [&]( category_object& c ) - { - c.abs_rshares -= comment.abs_rshares; - c.last_update = head_block_time(); - } ); - modify( comment, [&]( comment_object& c ) { /** @@ -1824,15 +1679,6 @@ void database::process_comment_cashout() ctx.total_reward_shares2 = gpo.total_reward_shares2; ctx.total_reward_fund_steem = gpo.total_reward_fund_steem; - // This extra logic is for when the funds are created in HF 16. We are using this data to preload - // recent rshares 2 to prevent any downtime in payouts at HF 17. After HF 17, we can capture - // the value of recent rshare 2 and set it at the hardfork instead of computing it every reindex - if( funds.size() && comment.net_rshares > 0 ) - { - const auto& rf = get_reward_fund( comment ); - funds[ rf.id._id ].recent_claims += util::calculate_claims( comment.net_rshares.value, rf ); - } - auto reward = cashout_comment_helper( ctx, comment ); if( reward > 0 ) @@ -2335,7 +2181,6 @@ void database::initialize_indexes() add_core_index< dynamic_global_property_index >(*this); add_core_index< account_index >(*this); add_core_index< account_authority_index >(*this); - add_core_index< account_bandwidth_index >(*this); add_core_index< witness_index >(*this); add_core_index< transaction_index >(*this); add_core_index< block_summary_index >(*this); @@ -2349,7 +2194,6 @@ void database::initialize_indexes() add_core_index< liquidity_reward_balance_index >(*this); add_core_index< operation_index >(*this); add_core_index< account_history_index >(*this); - add_core_index< category_index >(*this); add_core_index< hardfork_property_index >(*this); add_core_index< withdraw_vesting_route_index >(*this); add_core_index< owner_authority_history_index >(*this); @@ -2922,32 +2766,6 @@ void database::_apply_transaction(const signed_transaction& trx) throw e; } } - flat_set required; vector other; - trx.get_required_authorities( required, required, required, other ); - - auto trx_size = fc::raw::pack_size(trx); - - for( const auto& auth : required ) { - const auto& acnt = get_account(auth); - - if( !has_hardfork( STEEMIT_HARDFORK_0_17__766 ) ) - old_update_account_bandwidth( acnt, trx_size, bandwidth_type::old_forum ); - - update_account_bandwidth( acnt, trx_size, bandwidth_type::forum ); - - for( const auto& op : trx.operations ) { - if( is_market_operation( op ) ) - { - if( !has_hardfork( STEEMIT_HARDFORK_0_17__766 ) ) - old_update_account_bandwidth( acnt, trx_size, bandwidth_type::old_market ); - - update_account_bandwidth( acnt, trx_size * 10, bandwidth_type::market ); - break; - } - } - } - - //Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is //expired, and TaPoS makes no sense as no blocks exist. @@ -2966,7 +2784,7 @@ void database::_apply_transaction(const signed_transaction& trx) FC_ASSERT( trx.expiration <= now + fc::seconds(STEEMIT_MAX_TIME_UNTIL_EXPIRATION), "", ("trx.expiration",trx.expiration)("now",now)("max_til_exp",STEEMIT_MAX_TIME_UNTIL_EXPIRATION)); - if( is_producing() || has_hardfork( STEEMIT_HARDFORK_0_9 ) ) // Simple solution to pending trx bug when now == trx.expiration + if( has_hardfork( STEEMIT_HARDFORK_0_9 ) ) // Simple solution to pending trx bug when now == trx.expiration FC_ASSERT( now < trx.expiration, "", ("now",now)("trx.exp",trx.expiration) ); FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) ); } @@ -2981,6 +2799,8 @@ void database::_apply_transaction(const signed_transaction& trx) }); } + notify_on_pre_apply_transaction( trx ); + //Finally process the operations _current_op_in_trx = 0; for( const auto& op : trx.operations ) @@ -3894,19 +3714,6 @@ void database::apply_hardfork( uint32_t hardfork ) while( fho.price_history.size() > STEEMIT_FEED_HISTORY_WINDOW ) fho.price_history.pop_front(); }); - - auto post_rf = create< reward_fund_object >( [&]( reward_fund_object& rfo ) - { - rfo.name = STEEMIT_POST_REWARD_FUND_NAME; - rfo.last_update = head_block_time(); - rfo.content_constant = STEEMIT_CONTENT_CONSTANT_HF0; - rfo.percent_curation_rewards = STEEMIT_1_PERCENT * 25; - rfo.percent_content_rewards = 0; - }); - - // As a shortcut in payout processing, we use the id as an array index. - // The IDs must be assigned this way. The assertion is a dummy check to ensure this happens. - FC_ASSERT( post_rf.id._id == 0 ); } break; case STEEMIT_HARDFORK_0_17: @@ -3926,14 +3733,24 @@ void database::apply_hardfork( uint32_t hardfork ) }); const auto& gpo = get_dynamic_global_properties(); - auto reward_steem = gpo.total_reward_fund_steem; - modify( get< reward_fund_object, by_name >( STEEMIT_POST_REWARD_FUND_NAME ), [&]( reward_fund_object& rfo) + auto post_rf = create< reward_fund_object >( [&]( reward_fund_object& rfo ) { + rfo.name = STEEMIT_POST_REWARD_FUND_NAME; + rfo.last_update = head_block_time(); + rfo.content_constant = STEEMIT_CONTENT_CONSTANT_HF0; + rfo.percent_curation_rewards = STEEMIT_1_PERCENT * 25; rfo.percent_content_rewards = STEEMIT_100_PERCENT; rfo.reward_balance = gpo.total_reward_fund_steem; +#ifndef IS_TEST_NET + rfo.recent_claims = STEEMIT_HF_17_RECENT_CLAIMS; +#endif }); + // As a shortcut in payout processing, we use the id as an array index. + // The IDs must be assigned this way. The assertion is a dummy check to ensure this happens. + FC_ASSERT( post_rf.id._id == 0 ); + modify( gpo, [&]( dynamic_global_property_object& g ) { g.total_reward_fund_steem = asset( 0, STEEM_SYMBOL ); @@ -3955,9 +3772,9 @@ void database::apply_hardfork( uint32_t hardfork ) const auto& comment_idx = get_index< comment_index, by_cashout_time >(); const auto& by_root_idx = get_index< comment_index, by_root >(); vector< const comment_object* > root_posts; - root_posts.reserve( 60000 ); + root_posts.reserve( STEEMIT_HF_17_NUM_POSTS ); vector< const comment_object* > replies; - replies.reserve( 100000 ); + replies.reserve( STEEMIT_HF_17_NUM_REPLIES ); for( auto itr = comment_idx.begin(); itr != comment_idx.end() && itr->cashout_time < fc::time_point_sec::maximum(); ++itr ) { @@ -3974,7 +3791,6 @@ void database::apply_hardfork( uint32_t hardfork ) modify( *itr, [&]( comment_object& c ) { c.cashout_time = std::max( c.created + STEEMIT_CASHOUT_WINDOW_SECONDS, c.cashout_time ); - c.children_rshares2 = 0; }); } @@ -3983,7 +3799,6 @@ void database::apply_hardfork( uint32_t hardfork ) modify( *itr, [&]( comment_object& c ) { c.cashout_time = std::max( calculate_discussion_payout_time( c ), c.created + STEEMIT_CASHOUT_WINDOW_SECONDS ); - c.children_rshares2 = 0; }); } } @@ -4107,9 +3922,7 @@ void database::validate_invariants()const else FC_ASSERT( false, "found savings withdraw that is not SBD or STEEM" ); } - fc::uint128_t total_rshares2; - fc::uint128_t total_children_rshares2; const auto& comment_idx = get_index< comment_index >().indices(); @@ -4120,8 +3933,6 @@ void database::validate_invariants()const auto delta = util::calculate_claims( itr->net_rshares.value ); total_rshares2 += delta; } - if( itr->parent_author == STEEMIT_ROOT_POST_PARENT ) - total_children_rshares2 += itr->children_rshares2; } const auto& reward_idx = get_index< reward_fund_index, by_id >(); @@ -4184,7 +3995,6 @@ void database::perform_vesting_share_split( uint32_t magnitude ) c.net_rshares *= magnitude; c.abs_rshares *= magnitude; c.vote_rshares *= magnitude; - c.children_rshares2 = 0; } ); } @@ -4194,19 +4004,6 @@ void database::perform_vesting_share_split( uint32_t magnitude ) adjust_rshares2( c, 0, util::calculate_claims( c.net_rshares.value ) ); } - // Update category rshares - const auto& cat_idx = get_index< category_index >().indices().get< by_name >(); - auto cat_itr = cat_idx.begin(); - while( cat_itr != cat_idx.end() ) - { - modify( *cat_itr, [&]( category_object& c ) - { - c.abs_rshares *= magnitude; - } ); - - ++cat_itr; - } - } FC_CAPTURE_AND_RETHROW() } diff --git a/libraries/chain/hardfork.d/0_17.hf b/libraries/chain/hardfork.d/0_17.hf index 506949d3f7..be9b66df1d 100644 --- a/libraries/chain/hardfork.d/0_17.hf +++ b/libraries/chain/hardfork.d/0_17.hf @@ -19,4 +19,8 @@ #define STEEMIT_HARDFORK_0_17_VERSION hardfork_version( 0, 17 ) +#define STEEMIT_HF_17_NUM_POSTS (49357) +#define STEEMIT_HF_17_NUM_REPLIES (242051) +#define STEEMIT_HF_17_RECENT_CLAIMS (fc::uint128_t(808638359297ull,13744269167557038121ull)) // 14916744862149894120447332012073 + #endif diff --git a/libraries/chain/include/steemit/chain/account_object.hpp b/libraries/chain/include/steemit/chain/account_object.hpp index 60f748b4df..0045eb1169 100644 --- a/libraries/chain/include/steemit/chain/account_object.hpp +++ b/libraries/chain/include/steemit/chain/account_object.hpp @@ -108,6 +108,8 @@ namespace steemit { namespace chain { uint16_t witnesses_voted_for = 0; time_point_sec last_post; + time_point_sec last_root_post = fc::time_point_sec::min(); + uint32_t post_bandwidth = 0; /// This function should be used only when the account votes for a witness directly share_type witness_vote_weight()const { @@ -147,26 +149,6 @@ namespace steemit { namespace chain { time_point_sec last_owner_update; }; - class account_bandwidth_object : public object< account_bandwidth_object_type, account_bandwidth_object > - { - public: - template< typename Constructor, typename Allocator > - account_bandwidth_object( Constructor&& c, allocator< Allocator > a ) - { - c( *this ); - } - - account_bandwidth_object() {} - - id_type id; - - account_name_type account; - bandwidth_type type; - share_type average_bandwidth; - share_type lifetime_bandwidth; - time_point_sec last_bandwidth_update; - }; - class vesting_delegation_object : public object< vesting_delegation_object_type, vesting_delegation_object > { public: @@ -275,8 +257,7 @@ namespace steemit { namespace chain { ordered_unique< tag< by_id >, member< account_object, account_id_type, &account_object::id > >, ordered_unique< tag< by_name >, - member< account_object, account_name_type, &account_object::name >, - protocol::string_less >, + member< account_object, account_name_type, &account_object::name > >, ordered_unique< tag< by_proxy >, composite_key< account_object, member< account_object, account_name_type, &account_object::proxy >, @@ -380,24 +361,6 @@ namespace steemit { namespace chain { allocator< account_authority_object > > account_authority_index; - - struct by_account_bandwidth_type; - - typedef multi_index_container < - account_bandwidth_object, - indexed_by < - ordered_unique< tag< by_id >, - member< account_bandwidth_object, account_bandwidth_id_type, &account_bandwidth_object::id > >, - ordered_unique< tag< by_account_bandwidth_type >, - composite_key< account_bandwidth_object, - member< account_bandwidth_object, account_name_type, &account_bandwidth_object::account >, - member< account_bandwidth_object, bandwidth_type, &account_bandwidth_object::type > - > - > - >, - allocator< account_bandwidth_object > - > account_bandwidth_index; - struct by_delegation; typedef multi_index_container < @@ -410,7 +373,7 @@ namespace steemit { namespace chain { member< vesting_delegation_object, account_name_type, &vesting_delegation_object::delegator >, member< vesting_delegation_object, account_name_type, &vesting_delegation_object::delegatee > >, - composite_key_compare< protocol::string_less, protocol::string_less > + composite_key_compare< std::less< account_name_type >, std::less< account_name_type > > > >, allocator< vesting_delegation_object > @@ -509,7 +472,7 @@ FC_REFLECT( steemit::chain::account_object, (curation_rewards) (posting_rewards) (proxied_vsf_votes)(witnesses_voted_for) - (last_post) + (last_post)(last_root_post)(post_bandwidth) ) CHAINBASE_SET_INDEX_TYPE( steemit::chain::account_object, steemit::chain::account_index ) @@ -518,10 +481,6 @@ FC_REFLECT( steemit::chain::account_authority_object, ) CHAINBASE_SET_INDEX_TYPE( steemit::chain::account_authority_object, steemit::chain::account_authority_index ) -FC_REFLECT( steemit::chain::account_bandwidth_object, - (id)(account)(type)(average_bandwidth)(lifetime_bandwidth)(last_bandwidth_update) ) -CHAINBASE_SET_INDEX_TYPE( steemit::chain::account_bandwidth_object, steemit::chain::account_bandwidth_index ) - FC_REFLECT( steemit::chain::vesting_delegation_object, (id)(delegator)(delegatee)(vesting_shares)(min_delegation_time) ) CHAINBASE_SET_INDEX_TYPE( steemit::chain::vesting_delegation_object, steemit::chain::vesting_delegation_index ) diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index 435085b95a..c268d2b0f0 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -37,64 +37,6 @@ namespace steemit { namespace chain { } }; - /** - * Used to track the trending categories - */ - class category_object : public object< category_object_type, category_object > - { - category_object() = delete; - - public: - template< typename Constructor, typename Allocator > - category_object( Constructor&& c, allocator< Allocator > a ) - :name( a ) - { - c( *this ); - } - - id_type id; - - shared_string name; - share_type abs_rshares; - asset total_payouts = asset(0, SBD_SYMBOL); - uint32_t discussions = 0; - time_point_sec last_update; - }; - - struct by_name; - struct by_rshares; - struct by_total_payouts; - struct by_last_update; - typedef multi_index_container< - category_object, - indexed_by< - ordered_unique< tag< by_id >, member< category_object, category_id_type, &category_object::id > >, - ordered_unique< tag< by_name >, member< category_object, shared_string, &category_object::name >, strcmp_less >, - ordered_unique< tag< by_rshares >, - composite_key< category_object, - member< category_object, share_type, &category_object::abs_rshares>, - member< category_object, category_id_type, &category_object::id > - >, - composite_key_compare< std::greater< share_type >, std::less< category_id_type > > - >, - ordered_unique< tag< by_total_payouts >, - composite_key< category_object, - member< category_object, asset, &category_object::total_payouts>, - member< category_object, category_id_type, &category_object::id > - >, - composite_key_compare< std::greater, std::less< category_id_type > > - >, - ordered_unique< tag< by_last_update >, - composite_key< category_object, - member< category_object, time_point_sec, &category_object::last_update>, - member< category_object, category_id_type, &category_object::id > - >, - composite_key_compare< std::greater< time_point_sec >, std::less< category_id_type > > - > - >, - allocator< category_object > - > category_index; - class comment_object : public object < comment_object_type, comment_object > { comment_object() = delete; @@ -126,13 +68,6 @@ namespace steemit { namespace chain { uint16_t depth = 0; ///< used to track max nested depth uint32_t children = 0; ///< used to track the total number of children, grandchildren, etc... - /** - * Used to track the total rshares^2 of all children, this is used for indexing purposes. A discussion - * that has a nested comment of high value should promote the entire discussion so that the comment can - * be reviewed. - */ - fc::uint128_t children_rshares2; - /// index on pending_payout for "things happning now... needs moderation" /// TRENDING = UNCLAIMED + PENDING share_type net_rshares; // reward is proportional to rshares^2, this is the sum of all votes (positive and negative) @@ -309,10 +244,10 @@ namespace steemit { namespace chain { } } // steemit::chain FC_REFLECT( steemit::chain::comment_object, - (id)(author)(permlink) - (category)(parent_author)(parent_permlink) + (id)(category)(author)(permlink) + (parent_author)(parent_permlink) (title)(body)(json_metadata)(last_update)(created)(active)(last_payout) - (depth)(children)(children_rshares2) + (depth)(children) (net_rshares)(abs_rshares)(vote_rshares) (children_abs_rshares)(cashout_time)(max_cashout_time) (total_vote_weight)(reward_weight)(total_payout_value)(curator_payout_value)(beneficiary_payout_value)(author_rewards)(net_votes)(root_comment) @@ -325,8 +260,3 @@ FC_REFLECT( steemit::chain::comment_vote_object, (id)(voter)(comment)(weight)(rshares)(vote_percent)(last_update)(num_changes) ) CHAINBASE_SET_INDEX_TYPE( steemit::chain::comment_vote_object, steemit::chain::comment_vote_index ) - -FC_REFLECT( steemit::chain::category_object, - (id)(name)(abs_rshares)(total_payouts)(discussions)(last_update) - ) -CHAINBASE_SET_INDEX_TYPE( steemit::chain::category_object, steemit::chain::category_index ) diff --git a/libraries/chain/include/steemit/chain/database.hpp b/libraries/chain/include/steemit/chain/database.hpp index a2bdcb1ecc..e7f06eb738 100644 --- a/libraries/chain/include/steemit/chain/database.hpp +++ b/libraries/chain/include/steemit/chain/database.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -28,7 +29,6 @@ namespace steemit { namespace chain { class database_impl; class custom_operation_interpreter; - struct operation_notification; namespace util { struct comment_reward_context; @@ -127,9 +127,6 @@ namespace steemit { namespace chain { const comment_object& get_comment( const account_name_type& author, const string& permlink )const; const comment_object* find_comment( const account_name_type& author, const string& permlink )const; - const category_object& get_category( const shared_string& name )const; - const category_object* find_category( const shared_string& name )const; - const escrow_object& get_escrow( const account_name_type& name, uint32_t escrow_id )const; const escrow_object* find_escrow( const account_name_type& name, uint32_t escrow_id )const; @@ -152,12 +149,6 @@ namespace steemit { namespace chain { * Deducts fee from the account and the share supply */ void pay_fee( const account_object& a, asset fee ); - void old_update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ); - - /** - * Update an account's bandwidth and returns if the account had the requisite bandwidth for the trx - */ - bool update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ); void max_bandwidth_per_share()const; @@ -202,6 +193,7 @@ namespace steemit { namespace chain { inline const void push_virtual_operation( const operation& op, bool force = false ); // vops are not needed for low mem. Force will push them on low mem. void notify_applied_block( const signed_block& block ); void notify_on_pending_transaction( const signed_transaction& tx ); + void notify_on_pre_apply_transaction( const signed_transaction& tx ); void notify_on_applied_transaction( const signed_transaction& tx ); /** @@ -226,6 +218,12 @@ namespace steemit { namespace chain { */ fc::signal on_pending_transaction; + /** + * This signla is emitted any time a new transaction is about to be applied + * to the chain state. + */ + fc::signal on_pre_apply_transaction; + /** * This signal is emitted any time a new transaction has been applied to the * chain state. diff --git a/libraries/chain/include/steemit/chain/database_exceptions.hpp b/libraries/chain/include/steemit/chain/database_exceptions.hpp index fa65a8b348..fa71fce399 100644 --- a/libraries/chain/include/steemit/chain/database_exceptions.hpp +++ b/libraries/chain/include/steemit/chain/database_exceptions.hpp @@ -49,7 +49,6 @@ } \ catch( const steemit::chain::plugin_exception& e ) \ { \ - elog( "Caught plugin exception: ${e}", ("e", e.to_detail_string() ) ); \ throw; \ } \ catch( const fc::exception& e ) \ diff --git a/libraries/chain/include/steemit/chain/shared_authority.hpp b/libraries/chain/include/steemit/chain/shared_authority.hpp index d9a7f2bbbc..08889a6886 100644 --- a/libraries/chain/include/steemit/chain/shared_authority.hpp +++ b/libraries/chain/include/steemit/chain/shared_authority.hpp @@ -81,17 +81,17 @@ namespace steemit { namespace chain { void clear(); void validate()const; - typedef bip::allocator< shared_authority, bip::managed_mapped_file::segment_manager > allocator_type; + typedef bip::allocator< shared_authority, bip::managed_mapped_file::segment_manager > allocator_type; - typedef bip::allocator< std::pair< account_name_type, weight_type >, bip::managed_mapped_file::segment_manager > account_pair_allocator_type; - typedef bip::allocator< std::pair< public_key_type, weight_type >, bip::managed_mapped_file::segment_manager > key_pair_allocator_type; + typedef bip::allocator< std::pair< account_name_type, weight_type >, bip::managed_mapped_file::segment_manager > account_pair_allocator_type; + typedef bip::allocator< std::pair< public_key_type, weight_type >, bip::managed_mapped_file::segment_manager > key_pair_allocator_type; - typedef bip::flat_map< account_name_type, weight_type, protocol::string_less, account_pair_allocator_type > account_authority_map; - typedef bip::flat_map< public_key_type, weight_type, std::less< public_key_type >, key_pair_allocator_type > key_authority_map; + typedef bip::flat_map< account_name_type, weight_type, std::less< account_name_type >, account_pair_allocator_type > account_authority_map; + typedef bip::flat_map< public_key_type, weight_type, std::less< public_key_type >, key_pair_allocator_type > key_authority_map; - uint32_t weight_threshold = 0; - account_authority_map account_auths; - key_authority_map key_auths; + uint32_t weight_threshold = 0; + account_authority_map account_auths; + key_authority_map key_auths; }; bool operator == ( const shared_authority& a, const shared_authority& b ); diff --git a/libraries/chain/include/steemit/chain/steem_object_types.hpp b/libraries/chain/include/steemit/chain/steem_object_types.hpp index f2a67c4bfc..f524707bb0 100644 --- a/libraries/chain/include/steemit/chain/steem_object_types.hpp +++ b/libraries/chain/include/steemit/chain/steem_object_types.hpp @@ -41,7 +41,6 @@ enum object_type dynamic_global_property_object_type, account_object_type, account_authority_object_type, - account_bandwidth_object_type, witness_object_type, transaction_object_type, block_summary_object_type, @@ -55,7 +54,6 @@ enum object_type liquidity_reward_balance_object_type, operation_object_type, account_history_object_type, - category_object_type, hardfork_property_object_type, withdraw_vesting_route_object_type, owner_authority_history_object_type, @@ -73,7 +71,6 @@ enum object_type class dynamic_global_property_object; class account_object; class account_authority_object; -class account_bandwidth_object; class witness_object; class transaction_object; class block_summary_object; @@ -87,7 +84,6 @@ class convert_request_object; class liquidity_reward_balance_object; class operation_object; class account_history_object; -class category_object; class hardfork_property_object; class withdraw_vesting_route_object; class owner_authority_history_object; @@ -104,7 +100,6 @@ class vesting_delegation_expiration_object; typedef oid< dynamic_global_property_object > dynamic_global_property_id_type; typedef oid< account_object > account_id_type; typedef oid< account_authority_object > account_authority_id_type; -typedef oid< account_bandwidth_object > account_bandwidth_id_type; typedef oid< witness_object > witness_id_type; typedef oid< transaction_object > transaction_object_id_type; typedef oid< block_summary_object > block_summary_id_type; @@ -118,7 +113,6 @@ typedef oid< convert_request_object > convert_request_id_type; typedef oid< liquidity_reward_balance_object > liquidity_reward_balance_id_type; typedef oid< operation_object > operation_id_type; typedef oid< account_history_object > account_history_id_type; -typedef oid< category_object > category_id_type; typedef oid< hardfork_property_object > hardfork_property_id_type; typedef oid< withdraw_vesting_route_object > withdraw_vesting_route_id_type; typedef oid< owner_authority_history_object > owner_authority_history_id_type; @@ -136,9 +130,7 @@ enum bandwidth_type { post, ///< Rate limiting posting reward eligibility over time forum, ///< Rate limiting for all forum related actins - market, ///< Rate limiting for all other actions - old_forum, ///< Rate limiting for all forum related actions (deprecated) - old_market ///< Rate limiting for all other actions (deprecated) + market ///< Rate limiting for all other actions }; } } //steemit::chain @@ -218,13 +210,11 @@ FC_REFLECT_ENUM( steemit::chain::object_type, (dynamic_global_property_object_type) (account_object_type) (account_authority_object_type) - (account_bandwidth_object_type) (witness_object_type) (transaction_object_type) (block_summary_object_type) (witness_schedule_object_type) (comment_object_type) - (category_object_type) (comment_vote_object_type) (witness_vote_object_type) (limit_order_object_type) @@ -250,4 +240,4 @@ FC_REFLECT_ENUM( steemit::chain::object_type, FC_REFLECT_TYPENAME( steemit::chain::shared_string ) FC_REFLECT_TYPENAME( steemit::chain::buffer_type ) -FC_REFLECT_ENUM( steemit::chain::bandwidth_type, (post)(forum)(market)(old_forum)(old_market) ) +FC_REFLECT_ENUM( steemit::chain::bandwidth_type, (post)(forum)(market) ) diff --git a/libraries/chain/include/steemit/chain/steem_objects.hpp b/libraries/chain/include/steemit/chain/steem_objects.hpp index a8991704fb..a530ef0087 100755 --- a/libraries/chain/include/steemit/chain/steem_objects.hpp +++ b/libraries/chain/include/steemit/chain/steem_objects.hpp @@ -15,7 +15,7 @@ namespace steemit { namespace chain { using steemit::protocol::price; using steemit::protocol::asset_symbol_type; - typedef fc::fixed_string<> reward_fund_name_type; + typedef protocol::fixed_string reward_fund_name_type; /** * This object is used to track pending requests to convert sbd to steem diff --git a/libraries/chain/include/steemit/chain/witness_objects.hpp b/libraries/chain/include/steemit/chain/witness_objects.hpp index 8a046e0b31..3f2a5030a5 100644 --- a/libraries/chain/include/steemit/chain/witness_objects.hpp +++ b/libraries/chain/include/steemit/chain/witness_objects.hpp @@ -188,7 +188,7 @@ namespace steemit { namespace chain { member< witness_object, share_type, &witness_object::votes >, member< witness_object, account_name_type, &witness_object::owner > >, - composite_key_compare< std::greater< share_type >, steemit::protocol::string_less > //std::less< account_name_type > > + composite_key_compare< std::greater< share_type >, std::less< account_name_type > > >, ordered_unique< tag< by_schedule_time >, composite_key< witness_object, diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index e3923156be..74dd8b55b5 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -63,7 +63,6 @@ struct strcmp_equal void witness_update_evaluator::do_apply( const witness_update_operation& o ) { - database& _db = db(); _db.get_account( o.owner ); // verify owner exists if ( _db.has_hardfork( STEEMIT_HARDFORK_0_1 ) ) @@ -110,7 +109,6 @@ void witness_update_evaluator::do_apply( const witness_update_operation& o ) void account_create_evaluator::do_apply( const account_create_operation& o ) { - database& _db = db(); const auto& creator = _db.get_account( o.creator ); const auto& props = _db.get_dynamic_global_properties(); @@ -134,7 +132,7 @@ void account_create_evaluator::do_apply( const account_create_operation& o ) ("p", o.fee) ); } - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) { for( auto& a : o.owner.account_auths ) { @@ -190,7 +188,6 @@ void account_create_evaluator::do_apply( const account_create_operation& o ) void account_create_with_delegation_evaluator::do_apply( const account_create_with_delegation_operation& o ) { - database& _db = db(); FC_ASSERT( _db.has_hardfork( STEEMIT_HARDFORK_0_17__818 ), "Account creation with delegation is not enabled until hardfork 17" ); const auto& creator = _db.get_account( o.creator ); @@ -282,10 +279,9 @@ void account_create_with_delegation_evaluator::do_apply( const account_create_wi void account_update_evaluator::do_apply( const account_update_operation& o ) { - database& _db = db(); if( _db.has_hardfork( STEEMIT_HARDFORK_0_1 ) ) FC_ASSERT( o.account != STEEMIT_TEMP_ACCOUNT, "Cannot update temp account." ); - if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) && o.posting ) // TODO: Add HF 15 + if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) && o.posting ) o.posting->validate(); const auto& account = _db.get_account( o.account ); @@ -298,7 +294,7 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) FC_ASSERT( _db.head_block_time() - account_auth.last_owner_update > STEEMIT_OWNER_UPDATE_LIMIT, "Owner authority can only be updated once an hour." ); #endif - if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) ) // TODO: Add HF 15 + if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) ) { for( auto a: o.owner->account_auths ) { @@ -310,7 +306,7 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) _db.update_owner_authority( account, *o.owner ); } - if( o.active && ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) ) // TODO: Add HF 15 + if( o.active && ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) ) { for( auto a: o.active->account_auths ) { @@ -318,7 +314,7 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) } } - if( o.posting && ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) ) // TODO: Add HF 15 + if( o.posting && ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) ) { for( auto a: o.posting->account_auths ) { @@ -362,7 +358,6 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) */ void delete_comment_evaluator::do_apply( const delete_comment_operation& o ) { - database& _db = db(); if( _db.has_hardfork( STEEMIT_HARDFORK_0_10 ) ) { const auto& auth = _db.get_account( o.author ); @@ -406,14 +401,6 @@ void delete_comment_evaluator::do_apply( const delete_comment_operation& o ) } } - /** TODO move category behavior to a plugin, this is not part of consensus */ - const category_object* cat = _db.find_category( comment.category ); - _db.modify( *cat, [&]( category_object& c ) - { - c.discussions--; - c.last_update = _db.head_block_time(); - }); - _db.remove( comment ); } @@ -428,9 +415,6 @@ struct comment_options_extension_visitor void operator()( const comment_payout_beneficiaries& cpb ) const { - if( _db.is_producing() ) - FC_ASSERT( cpb.beneficiaries.size() <= 8, "Cannot specify more than 8 beneficiaries." ); - FC_ASSERT( _c.beneficiaries.size() == 0, "Comment already has beneficiaries specified." ); FC_ASSERT( _c.abs_rshares == 0, "Comment must not have been voted on before specifying beneficiaries." ); @@ -448,7 +432,6 @@ struct comment_options_extension_visitor void comment_options_evaluator::do_apply( const comment_options_operation& o ) { - database& _db = db(); if( _db.has_hardfork( STEEMIT_HARDFORK_0_10 ) ) { const auto& auth = _db.get_account( o.author ); @@ -481,9 +464,7 @@ void comment_options_evaluator::do_apply( const comment_options_operation& o ) void comment_evaluator::do_apply( const comment_operation& o ) { try { - database& _db = db(); - - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_5__55 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_5__55 ) ) FC_ASSERT( o.title.size() + o.body.size() + o.json_metadata.size(), "Cannot update comment because nothing appears to be changing." ); const auto& by_permlink_idx = _db.get_index< comment_index >().indices().get< by_permlink >(); @@ -502,13 +483,11 @@ void comment_evaluator::do_apply( const comment_operation& o ) parent = &_db.get_comment( o.parent_author, o.parent_permlink ); if( !_db.has_hardfork( STEEMIT_HARDFORK_0_17__767 ) ) FC_ASSERT( parent->depth < STEEMIT_MAX_COMMENT_DEPTH_PRE_HF17, "Comment is nested ${x} posts deep, maximum depth is ${y}.", ("x",parent->depth)("y",STEEMIT_MAX_COMMENT_DEPTH_PRE_HF17) ); - else if( _db.is_producing() ) - FC_ASSERT( parent->depth < STEEMIT_SOFT_MAX_COMMENT_DEPTH, "Comment is nested ${x} posts deep, maximum depth is ${y}.", ("x",parent->depth)("y",STEEMIT_SOFT_MAX_COMMENT_DEPTH) ); else FC_ASSERT( parent->depth < STEEMIT_MAX_COMMENT_DEPTH, "Comment is nested ${x} posts deep, maximum depth is ${y}.", ("x",parent->depth)("y",STEEMIT_MAX_COMMENT_DEPTH) ); } - if( ( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_17__926 ) ) && o.json_metadata.size() ) // TODO: Remove is_producing after HF 17 + if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_17__926 ) ) && o.json_metadata.size() ) FC_ASSERT( fc::is_utf8( o.json_metadata ), "JSON Metadata must be UTF-8" ); auto now = _db.head_block_time(); @@ -522,21 +501,10 @@ void comment_evaluator::do_apply( const comment_operation& o ) FC_ASSERT( _db.calculate_discussion_payout_time( *parent ) != fc::time_point_sec::maximum(), "Discussion is frozen." ); } - auto band = _db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( o.author, bandwidth_type::post ) ); - - if( band == nullptr ) - { - band = &_db.create< account_bandwidth_object >( [&]( account_bandwidth_object& b ) - { - b.account = o.author; - b.type = bandwidth_type::post; - }); - } - if( _db.has_hardfork( STEEMIT_HARDFORK_0_12__176 ) ) { if( o.parent_author == STEEMIT_ROOT_POST_PARENT ) - FC_ASSERT( ( now - band->last_bandwidth_update ) > STEEMIT_MIN_ROOT_COMMENT_INTERVAL, "You may only post once every 5 minutes.", ("now",now)("last_root_post", band->last_bandwidth_update) ); + FC_ASSERT( ( now - auth.last_root_post ) > STEEMIT_MIN_ROOT_COMMENT_INTERVAL, "You may only post once every 5 minutes.", ("now",now)("last_root_post", auth.last_root_post) ); else FC_ASSERT( (now - auth.last_post) > STEEMIT_MIN_REPLY_INTERVAL, "You may only comment once every 20 seconds.", ("now",now)("auth.last_post",auth.last_post) ); } @@ -553,28 +521,22 @@ void comment_evaluator::do_apply( const comment_operation& o ) } uint16_t reward_weight = STEEMIT_100_PERCENT; + uint64_t post_bandwidth = auth.post_bandwidth; - if( o.parent_author == STEEMIT_ROOT_POST_PARENT ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_12__176 ) && !_db.has_hardfork( STEEMIT_HARDFORK_0_17__733 ) && o.parent_author == STEEMIT_ROOT_POST_PARENT ) { - auto post_bandwidth = band->average_bandwidth; + uint64_t post_delta_time = std::min( _db.head_block_time().sec_since_epoch() - auth.last_root_post.sec_since_epoch(), STEEMIT_POST_AVERAGE_WINDOW ); + uint32_t old_weight = uint32_t( ( post_bandwidth * ( STEEMIT_POST_AVERAGE_WINDOW - post_delta_time ) ) / STEEMIT_POST_AVERAGE_WINDOW ); + post_bandwidth = ( old_weight + STEEMIT_100_PERCENT ); + reward_weight = uint16_t( std::min( ( STEEMIT_POST_WEIGHT_CONSTANT * STEEMIT_100_PERCENT ) / ( post_bandwidth * post_bandwidth ), uint64_t( STEEMIT_100_PERCENT ) ) ); + } - if( _db.has_hardfork( STEEMIT_HARDFORK_0_12__176 ) && !_db.has_hardfork( STEEMIT_HARDFORK_0_17__733 ) ) + _db.modify( auth, [&]( account_object& a ) { + if( o.parent_author == STEEMIT_ROOT_POST_PARENT ) { - auto post_delta_time = std::min( now.sec_since_epoch() - band->last_bandwidth_update.sec_since_epoch(), STEEMIT_POST_AVERAGE_WINDOW ); - auto old_weight = ( post_bandwidth * ( STEEMIT_POST_AVERAGE_WINDOW - post_delta_time ) ) / STEEMIT_POST_AVERAGE_WINDOW; - post_bandwidth = ( old_weight + STEEMIT_100_PERCENT ); - reward_weight = uint16_t( std::min( ( STEEMIT_POST_WEIGHT_CONSTANT * STEEMIT_100_PERCENT ) / ( post_bandwidth.value * post_bandwidth.value ), uint64_t( STEEMIT_100_PERCENT ) ) ); + a.last_root_post = now; + a.post_bandwidth = uint32_t( post_bandwidth ); } - - _db.modify( *band, [&]( account_bandwidth_object& b ) - { - b.last_bandwidth_update = now; - b.average_bandwidth = post_bandwidth; - }); - } - - db().modify( auth, [&]( account_object& a ) - { a.last_post = now; a.post_count++; }); @@ -600,7 +562,6 @@ void comment_evaluator::do_apply( const comment_operation& o ) { com.parent_author = ""; from_string( com.parent_permlink, o.parent_permlink ); - from_string( com.category, o.parent_permlink ); com.root_comment = com.id; com.cashout_time = _db.has_hardfork( STEEMIT_HARDFORK_0_12__177 ) ? _db.head_block_time() + STEEMIT_CASHOUT_WINDOW_SECONDS_PRE_HF17 : @@ -611,7 +572,6 @@ void comment_evaluator::do_apply( const comment_operation& o ) com.parent_author = parent->author; com.parent_permlink = parent->permlink; com.depth = parent->depth + 1; - com.category = parent->category; com.root_comment = parent->root_comment; com.cashout_time = fc::time_point_sec::maximum(); } @@ -634,21 +594,6 @@ void comment_evaluator::do_apply( const comment_operation& o ) #endif }); - /** TODO move category behavior to a plugin, this is not part of consensus */ - const category_object* cat = _db.find_category( new_comment.category ); - if( !cat ) { - cat = &_db.create( [&]( category_object& c ){ - c.name = new_comment.category; - c.discussions = 1; - c.last_update = _db.head_block_time(); - }); - } else { - _db.modify( *cat, [&]( category_object& c ){ - c.discussions++; - c.last_update = _db.head_block_time(); - }); - } - id = new_comment.id; /// this loop can be skiped for validate-only nodes as it is merely gathering stats for indicies @@ -671,20 +616,13 @@ void comment_evaluator::do_apply( const comment_operation& o ) { const auto& comment = *itr; - if( _db.has_hardfork( STEEMIT_HARDFORK_0_17__772 ) ) + if( !_db.has_hardfork( STEEMIT_HARDFORK_0_17__772 ) ) { - // This will be moved to the witness plugin in a later release - if( _db.is_producing() ) - { - // For now, use the same editting rules, but implement it as a soft fork. - FC_ASSERT( comment.cashout_time != fc::time_point_sec::maximum(), "The comment is archived." ); - } + if( _db.has_hardfork( STEEMIT_HARDFORK_0_14__306 ) ) + FC_ASSERT( _db.calculate_discussion_payout_time( comment ) != fc::time_point_sec::maximum(), "The comment is archived." ); + else if( _db.has_hardfork( STEEMIT_HARDFORK_0_10 ) ) + FC_ASSERT( comment.last_payout == fc::time_point_sec::min(), "Can only edit during the first 24 hours." ); } - else if( _db.has_hardfork( STEEMIT_HARDFORK_0_14__306 ) ) - FC_ASSERT( _db.calculate_discussion_payout_time( comment ) != fc::time_point_sec::maximum(), "The comment is archived." ); - else if( _db.has_hardfork( STEEMIT_HARDFORK_0_10 ) ) - FC_ASSERT( comment.last_payout == fc::time_point_sec::min(), "Can only edit during the first 24 hours." ); - _db.modify( comment, [&]( comment_object& com ) { com.last_update = _db.head_block_time(); @@ -743,8 +681,6 @@ void escrow_transfer_evaluator::do_apply( const escrow_transfer_operation& o ) { try { - database& _db = db(); - const auto& from_account = _db.get_account(o.from); _db.get_account(o.to); _db.get_account(o.agent); @@ -785,7 +721,7 @@ void escrow_approve_evaluator::do_apply( const escrow_approve_operation& o ) { try { - database& _db = db(); + const auto& escrow = _db.get_escrow( o.from, o.escrow_id ); FC_ASSERT( escrow.to == o.to, "Operation 'to' (${o}) does not match escrow 'to' (${e}).", ("o", o.to)("e", escrow.to) ); @@ -846,7 +782,6 @@ void escrow_dispute_evaluator::do_apply( const escrow_dispute_operation& o ) { try { - database& _db = db(); _db.get_account( o.from ); // Verify from account exists const auto& e = _db.get_escrow( o.from, o.escrow_id ); @@ -868,7 +803,6 @@ void escrow_release_evaluator::do_apply( const escrow_release_operation& o ) { try { - database& _db = db(); _db.get_account(o.from); // Verify from account exists const auto& receiver_account = _db.get_account(o.receiver); @@ -923,7 +857,6 @@ void escrow_release_evaluator::do_apply( const escrow_release_operation& o ) void transfer_evaluator::do_apply( const transfer_operation& o ) { - database& _db = db(); const auto& from_account = _db.get_account(o.from); const auto& to_account = _db.get_account(o.to); @@ -943,8 +876,6 @@ void transfer_evaluator::do_apply( const transfer_operation& o ) void transfer_to_vesting_evaluator::do_apply( const transfer_to_vesting_operation& o ) { - database& _db = db(); - const auto& from_account = _db.get_account(o.from); const auto& to_account = o.to.size() ? _db.get_account(o.to) : from_account; @@ -955,8 +886,6 @@ void transfer_to_vesting_evaluator::do_apply( const transfer_to_vesting_operatio void withdraw_vesting_evaluator::do_apply( const withdraw_vesting_operation& o ) { - database& _db = db(); - const auto& account = _db.get_account( o.account ); FC_ASSERT( account.vesting_shares >= asset( 0, VESTS_SYMBOL ), "Account does not have sufficient Steem Power for withdraw." ); @@ -976,7 +905,7 @@ void withdraw_vesting_evaluator::do_apply( const withdraw_vesting_operation& o ) if( o.vesting_shares.amount == 0 ) { - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_5__57 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_5__57 ) ) FC_ASSERT( account.vesting_withdraw_rate.amount != 0, "This operation would not change the vesting withdraw rate." ); _db.modify( account, [&]( account_object& a ) { @@ -999,7 +928,7 @@ void withdraw_vesting_evaluator::do_apply( const withdraw_vesting_operation& o ) if( new_vesting_withdraw_rate.amount == 0 ) new_vesting_withdraw_rate.amount = 1; - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_5__57 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_5__57 ) ) FC_ASSERT( account.vesting_withdraw_rate != new_vesting_withdraw_rate, "This operation would not change the vesting withdraw rate." ); a.vesting_withdraw_rate = new_vesting_withdraw_rate; @@ -1014,7 +943,6 @@ void set_withdraw_vesting_route_evaluator::do_apply( const set_withdraw_vesting_ { try { - database& _db = db(); const auto& from_account = _db.get_account( o.from_account ); const auto& to_account = _db.get_account( o.to_account ); const auto& wd_idx = _db.get_index< withdraw_vesting_route_index >().indices().get< by_withdraw_route >(); @@ -1074,7 +1002,6 @@ void set_withdraw_vesting_route_evaluator::do_apply( const set_withdraw_vesting_ void account_witness_proxy_evaluator::do_apply( const account_witness_proxy_operation& o ) { - database& _db = db(); const auto& account = _db.get_account( o.account ); FC_ASSERT( account.proxy != o.proxy, "Proxy must change." ); @@ -1122,7 +1049,6 @@ void account_witness_proxy_evaluator::do_apply( const account_witness_proxy_oper void account_witness_vote_evaluator::do_apply( const account_witness_vote_operation& o ) { - database& _db = db(); const auto& voter = _db.get_account( o.account ); FC_ASSERT( voter.proxy.size() == 0, "A proxy is currently set, please clear the proxy before voting for a witness." ); @@ -1190,8 +1116,6 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat void vote_evaluator::do_apply( const vote_operation& o ) { try { - database& _db = db(); - const auto& comment = _db.get_comment( o.author, o.permlink ); const auto& voter = _db.get_account( o.voter ); @@ -1276,7 +1200,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) // Lazily delete vote if( itr != comment_vote_idx.end() && itr->num_changes == -1 ) { - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_12__177 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_12__177 ) ) FC_ASSERT( false, "Cannot vote again on a comment after payout." ); _db.remove( *itr ); @@ -1363,12 +1287,6 @@ void vote_evaluator::do_apply( const vote_operation& o ) new_rshares = util::calculate_claims( new_rshares ); old_rshares = util::calculate_claims( old_rshares ); - const auto& cat = _db.get_category( comment.category ); - _db.modify( cat, [&]( category_object& c ){ - c.abs_rshares += abs_rshares; - c.last_update = _db.head_block_time(); - }); - uint64_t max_vote_weight = 0; /** this verifies uniqueness of voter @@ -1466,7 +1384,6 @@ void vote_evaluator::do_apply( const vote_operation& o ) c.total_vote_weight += max_vote_weight; }); } - if( !_db.has_hardfork( STEEMIT_HARDFORK_0_17__774) ) _db.adjust_rshares2( comment, old_rshares, new_rshares ); } @@ -1474,7 +1391,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) { FC_ASSERT( itr->num_changes < STEEMIT_MAX_VOTE_CHANGES, "Voter has used the maximum number of vote changes on this comment." ); - if( _db.is_producing() || _db.has_hardfork( STEEMIT_HARDFORK_0_6__112 ) ) + if( _db.has_hardfork( STEEMIT_HARDFORK_0_6__112 ) ) FC_ASSERT( itr->vote_percent != o.weight, "You have already voted in a similar way." ); /// this is the rshares voting for or against the post @@ -1559,6 +1476,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) new_rshares = util::calculate_claims( new_rshares ); old_rshares = util::calculate_claims( old_rshares ); + _db.modify( comment, [&]( comment_object& c ) { c.total_vote_weight -= itr->weight; @@ -1634,7 +1552,7 @@ void pow_apply( database& db, Operation o ) { const auto& dgp = db.get_dynamic_global_properties(); - if( db.is_producing() || db.has_hardfork( STEEMIT_HARDFORK_0_5__59 ) ) + if( db.has_hardfork( STEEMIT_HARDFORK_0_5__59 ) ) { const auto& witness_by_work = db.get_index().indices().get(); auto work_itr = witness_by_work.find( o.work.work ); @@ -1820,7 +1738,6 @@ void pow2_evaluator::do_apply( const pow2_operation& o ) void feed_publish_evaluator::do_apply( const feed_publish_operation& o ) { - database& _db = db(); const auto& witness = _db.get_witness( o.publisher ); _db.modify( witness, [&]( witness_object& w ){ w.sbd_exchange_rate = o.exchange_rate; @@ -1830,7 +1747,6 @@ void feed_publish_evaluator::do_apply( const feed_publish_operation& o ) void convert_evaluator::do_apply( const convert_operation& o ) { - database& _db = db(); const auto& owner = _db.get_account( o.owner ); FC_ASSERT( _db.get_balance( owner, o.amount.symbol ) >= o.amount, "Account does not have sufficient balance for conversion." ); @@ -1855,7 +1771,6 @@ void convert_evaluator::do_apply( const convert_operation& o ) void limit_order_create_evaluator::do_apply( const limit_order_create_operation& o ) { - database& _db = db(); FC_ASSERT( o.expiration > _db.head_block_time(), "Limit order has to expire after head block time." ); const auto& owner = _db.get_account( o.owner ); @@ -1881,7 +1796,6 @@ void limit_order_create_evaluator::do_apply( const limit_order_create_operation& void limit_order_create2_evaluator::do_apply( const limit_order_create2_operation& o ) { - database& _db = db(); FC_ASSERT( o.expiration > _db.head_block_time(), "Limit order has to expire after head block time." ); const auto& owner = _db.get_account( o.owner ); @@ -1907,19 +1821,16 @@ void limit_order_create2_evaluator::do_apply( const limit_order_create2_operatio void limit_order_cancel_evaluator::do_apply( const limit_order_cancel_operation& o ) { - database& _db = db(); _db.cancel_order( _db.get_limit_order( o.owner, o.orderid ) ); } void report_over_production_evaluator::do_apply( const report_over_production_operation& o ) { - database& _db = db(); FC_ASSERT( !_db.has_hardfork( STEEMIT_HARDFORK_0_4 ), "report_over_production_operation is disabled." ); } void challenge_authority_evaluator::do_apply( const challenge_authority_operation& o ) { - database& _db = db(); if( _db.has_hardfork( STEEMIT_HARDFORK_0_14__307 ) ) FC_ASSERT( false, "Challenge authority operation is currently disabled." ); const auto& challenged = _db.get_account( o.challenged ); const auto& challenger = _db.get_account( o.challenger ); @@ -1957,7 +1868,6 @@ void challenge_authority_evaluator::do_apply( const challenge_authority_operatio void prove_authority_evaluator::do_apply( const prove_authority_operation& o ) { - database& _db = db(); const auto& challenged = _db.get_account( o.challenged ); FC_ASSERT( challenged.owner_challenged || challenged.active_challenged, "Account is not challeneged. No need to prove authority." ); @@ -1975,7 +1885,6 @@ void prove_authority_evaluator::do_apply( const prove_authority_operation& o ) void request_account_recovery_evaluator::do_apply( const request_account_recovery_operation& o ) { - database& _db = db(); const auto& account_to_recover = _db.get_account( o.account_to_recover ); if ( account_to_recover.recovery_account.length() ) // Make sure recovery matches expected recovery account @@ -1992,7 +1901,7 @@ void request_account_recovery_evaluator::do_apply( const request_account_recover FC_ASSERT( o.new_owner_authority.weight_threshold, "Cannot recover using an open authority." ); // Check accounts in the new authority exist - if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) ) + if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) ) { for( auto& a : o.new_owner_authority.account_auths ) { @@ -2016,7 +1925,7 @@ void request_account_recovery_evaluator::do_apply( const request_account_recover FC_ASSERT( !o.new_owner_authority.is_impossible(), "Cannot recover using an impossible authority." ); // Check accounts in the new authority exist - if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) || _db.is_producing() ) ) + if( ( _db.has_hardfork( STEEMIT_HARDFORK_0_15__465 ) ) ) { for( auto& a : o.new_owner_authority.account_auths ) { @@ -2034,7 +1943,6 @@ void request_account_recovery_evaluator::do_apply( const request_account_recover void recover_account_evaluator::do_apply( const recover_account_operation& o ) { - database& _db = db(); const auto& account = _db.get_account( o.account_to_recover ); if( _db.has_hardfork( STEEMIT_HARDFORK_0_12 ) ) @@ -2069,7 +1977,6 @@ void recover_account_evaluator::do_apply( const recover_account_operation& o ) void change_recovery_account_evaluator::do_apply( const change_recovery_account_operation& o ) { - database& _db = db(); _db.get_account( o.new_recovery_account ); // Simply validate account exists const auto& account_to_recover = _db.get_account( o.account_to_recover ); @@ -2101,7 +2008,6 @@ void change_recovery_account_evaluator::do_apply( const change_recovery_account_ void transfer_to_savings_evaluator::do_apply( const transfer_to_savings_operation& op ) { - database& _db = db(); const auto& from = _db.get_account( op.from ); const auto& to = _db.get_account(op.to); FC_ASSERT( _db.get_balance( from, op.amount.symbol ) >= op.amount, "Account does not have sufficient funds to transfer to savings." ); @@ -2112,7 +2018,6 @@ void transfer_to_savings_evaluator::do_apply( const transfer_to_savings_operatio void transfer_from_savings_evaluator::do_apply( const transfer_from_savings_operation& op ) { - database& _db = db(); const auto& from = _db.get_account( op.from ); _db.get_account(op.to); // Verify to account exists @@ -2139,7 +2044,6 @@ void transfer_from_savings_evaluator::do_apply( const transfer_from_savings_oper void cancel_transfer_from_savings_evaluator::do_apply( const cancel_transfer_from_savings_operation& op ) { - database& _db = db(); const auto& swo = _db.get_savings_withdraw( op.from, op.request_id ); _db.adjust_savings_balance( _db.get_account( swo.from ), swo.amount ); _db.remove( swo ); @@ -2153,7 +2057,6 @@ void cancel_transfer_from_savings_evaluator::do_apply( const cancel_transfer_fro void decline_voting_rights_evaluator::do_apply( const decline_voting_rights_operation& o ) { - database& _db = db(); FC_ASSERT( _db.has_hardfork( STEEMIT_HARDFORK_0_14__324 ) ); const auto& account = _db.get_account( o.account ); @@ -2179,9 +2082,8 @@ void decline_voting_rights_evaluator::do_apply( const decline_voting_rights_oper void reset_account_evaluator::do_apply( const reset_account_operation& op ) { - database& _db = db(); FC_ASSERT( false, "Reset Account Operation is currently disabled." ); - +/* const auto& acnt = _db.get_account( op.account_to_reset ); auto band = _db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( op.account_to_reset, bandwidth_type::old_forum ) ); if( band != nullptr ) @@ -2189,13 +2091,13 @@ void reset_account_evaluator::do_apply( const reset_account_operation& op ) FC_ASSERT( acnt.reset_account == op.reset_account, "Reset account does not match reset account on account." ); _db.update_owner_authority( acnt, op.new_owner_authority ); +*/ } void set_reset_account_evaluator::do_apply( const set_reset_account_operation& op ) { - database& _db = db(); FC_ASSERT( false, "Set Reset Account Operation is currently disabled." ); - +/* const auto& acnt = _db.get_account( op.account ); _db.get_account( op.reset_account ); @@ -2206,11 +2108,11 @@ void set_reset_account_evaluator::do_apply( const set_reset_account_operation& o { a.reset_account = op.reset_account; }); +*/ } void claim_reward_balance_evaluator::do_apply( const claim_reward_balance_operation& op ) { - database& _db = db(); const auto& acnt = _db.get_account( op.account ); FC_ASSERT( op.reward_steem <= acnt.reward_steem_balance, "Cannot claim that much STEEM." ); @@ -2250,7 +2152,6 @@ void claim_reward_balance_evaluator::do_apply( const claim_reward_balance_operat void delegate_vesting_shares_evaluator::do_apply( const delegate_vesting_shares_operation& op ) { - database& _db = db(); FC_ASSERT( _db.has_hardfork( STEEMIT_HARDFORK_0_17__818 ), "delegate_vesting_shares_operation is not enabled until HF 17" ); //TODO: Delete after hardfork const auto& delegator = _db.get_account( op.delegator ); diff --git a/libraries/chain2/CMakeLists.txt b/libraries/chain2/CMakeLists.txt deleted file mode 100644 index 7629ea78e6..0000000000 --- a/libraries/chain2/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ - -file(GLOB HEADERS "include/graphene/db2/*.hpp") -add_library( steemit_chain2 chain_database.cpp block_database.cpp ${HEADERS} ) -target_link_libraries( steemit_chain2 steemit_chain fc graphene_db2 steemit_protocol ) -target_include_directories( steemit_chain2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) - -install( TARGETS - steemit_chain2 - - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) -install( FILES ${HEADERS} DESTINATION "include/graphene/db" ) - - -add_executable( test_chain2 main.cpp ) -target_link_libraries( test_chain2 steemit_chain2 steemit_protocol graphene_db2 fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/libraries/chain2/block_database.cpp b/libraries/chain2/block_database.cpp deleted file mode 100644 index b885edc283..0000000000 --- a/libraries/chain2/block_database.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include - - -namespace steemit { namespace chain2 { - - namespace detail { - class block_database_impl { - public: - signed_block head; - std::fstream out_blocks; - std::fstream in_blocks; - }; - } - - block_database::block_database() - :my( new detail::block_database_impl() ){} - - block_database::~block_database(){ - } - - void block_database::open( const fc::path& file ) { - my->out_blocks.close(); - my->in_blocks.close(); - my->out_blocks.open( file.generic_string().c_str(), std::ios::app | std::ios::binary ); - my->in_blocks.open( file.generic_string().c_str(), std::ios::in | std::ios::binary ); - if( fc::file_size( file ) > 8 ) - my->head = head(); - } - - uint64_t block_database::append( const signed_block& b ) { - uint64_t pos = my->out_blocks.tellp(); - fc::raw::pack( my->out_blocks, b ); - my->out_blocks.write( (char*)&pos, sizeof(pos) ); - my->out_blocks.flush(); - my->head = b; - return pos; - } - - signed_block block_database::read_block( uint64_t pos )const { - my->in_blocks.seekg( pos ); - signed_block result; - fc::raw::unpack( my->in_blocks, result ); - return result; - } - - signed_block block_database::head()const { - uint64_t pos; - my->in_blocks.seekg( -sizeof(pos), std::ios::end ); - my->in_blocks.read( (char*)&pos, sizeof(pos) ); - return read_block( pos ); - } - -} } diff --git a/libraries/chain2/chain_database.cpp b/libraries/chain2/chain_database.cpp deleted file mode 100644 index 82e07fce13..0000000000 --- a/libraries/chain2/chain_database.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include - -namespace steemit { namespace chain2 { - database::database() - { - } - database::~database() - { - } - - void database::open( const fc::path& dir ) { - graphene::db2::database::open( dir ); - - add_index(); - add_index(); - - if( head_block_num() ) { - const auto& head = head_block(); - signed_block front; - front.previous = head.previous; - //_fork_db.set_head( branches.second.front() ); - } - } - - - - void database::push_block( const signed_block& b ) - { try { - if( !head_block_num() ) { - _fork_db.start_block( b ); - } - - auto restore_pending = clear_pending(); - - const auto& head = head_block(); - - auto new_head = _fork_db.push_block( b ); - if( new_head->previous_id() == head.previous ) { - try { - apply( *this, b, skip_undo_transaction | skip_undo_operation ); - } catch ( const fc::exception& e ) { - _fork_db.remove( b.id() ); - throw; - } - } else { - - auto branches = _fork_db.fetch_branch_from( new_head->id, head.block_id ); - while( head_block().block_id != branches.second.back()->previous_id() ) { - undo(); - } - - for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) - { - optional except; - try { - apply( *this, (*ritr)->data, skip_undo_transaction | skip_undo_operation ); - } catch ( const fc::exception& e ) { except = e; } - - if( except ) - { - // wlog( "exception thrown while switching forks ${e}", ("e",except->to_detail_string() ) ); - // remove the rest of branches.first from the fork_db, those blocks are invalid - while( ritr != branches.first.rend() ) - { - _fork_db.remove( (*ritr)->id ); //data.id() ); - ++ritr; - } - _fork_db.set_head( branches.second.front() ); - - // pop all blocks from the bad fork - while( head_block().block_id != branches.second.back()->data.previous ) - undo(); - - // restore all blocks from the good fork - for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) - apply( *this, (*ritr)->data, skip_undo_transaction | skip_undo_operation ); - throw *except; - } - } - } - } FC_CAPTURE_AND_RETHROW( (b) ) } - - void database::push_transaction( const signed_transaction& trx ) - { try { - - if( !_pending_tx_session ) - _pending_tx_session = start_undo_session( true ); - - auto undos = start_undo_session( true ); - apply( *this, trx ); - _pending_transactions.emplace_back( trx ); - - } FC_CAPTURE_AND_RETHROW( (trx) ) } - - signed_block database::generate_block( time_point_sec time, const account_name_type& witness, const fc::ecc::private_key& block_signing_key ) { - signed_block result; - - return result; - } - - const block_object& database::head_block()const { - const auto& block_idx = get_index(); - auto head_block_itr = block_idx.rbegin(); - FC_ASSERT( head_block_itr != block_idx.rend() ); - return *head_block_itr; - } - - uint32_t database::head_block_num()const { - const auto& block_idx = get_index(); - auto head_block_itr = block_idx.rbegin(); - if( head_block_itr != block_idx.rend() ) - return head_block_itr->block_num; - return 0; - } - - void apply( database& db, const signed_block& b, const options_type& opts ) { - auto undo_session = db.start_undo_session( !(opts & skip_undo_block) ); - db.pre_apply_block( b ); - - if( !(opts & skip_validation) ) { - FC_ASSERT( b.timestamp.sec_since_epoch() % 3 == 0 ); - if( b.block_num() > 1 ) { - idump((b.block_num())); - const auto& head = db.head_block(); - FC_ASSERT( b.block_num() == head.block_num + 1 ); - FC_ASSERT( b.timestamp >= head.timestamp + fc::seconds(3) ); - } - } - - db.create( [&]( block_object& obj ) { - obj.block_num = b.block_num(); - obj.block_id = b.id(); - obj.ref_prefix = obj.block_id._hash[1]; - obj.previous = b.previous; - obj.timestamp = b.timestamp; - obj.witness = b.witness; - obj.transaction_merkle_root = b.transaction_merkle_root; - obj.witness_signature = b.witness_signature; - - obj.transactions.reserve( b.transactions.size() ); - for( const auto& t : b.transactions ) { - obj.transactions.emplace_back( t.id() ); - } - }); - - for( const auto& trx : b.transactions ) { - apply( db, trx, opts ); - } - - db.post_apply_block( b ); - undo_session.push(); - } - - void apply( database& db, const signed_transaction& t, const options_type& opts ){ - auto undo_session = db.start_undo_session( !(opts & skip_undo_transaction) ); - db.pre_apply_transaction( t ); - - db.create( [&]( transaction_object& trx ) { - trx.trx_id = t.id(); - trx.block_num = db.head_block().block_num; - auto pack_size = fc::raw::pack_size( t ); - trx.packed_transaction.resize( pack_size ); - fc::datastream ds( trx.packed_transaction.data(), pack_size ); - fc::raw::pack( ds, t ); - }); - - for( const auto& op : t.operations ) { - apply( db, op, opts ); - } - - db.post_apply_transaction( t ); - undo_session.squash(); - } - - struct apply_operation_visitor { - apply_operation_visitor( database& db, const options_type& opts ):_db(db),_opts(opts){} - - typedef void result_type; - - template - void operator()( T&& op )const { - apply( _db, std::forward(op), _opts ); - } - - database& _db; - const options_type& _opts; - }; - - void apply( database& db, const operation& o, const options_type& opts ) { - auto undo_session = db.start_undo_session( !(opts & skip_undo_operation) ); - db.pre_apply_operation( o ); - o.visit( apply_operation_visitor( db, opts ) ); - db.post_apply_operation( o ); - undo_session.squash(); - } - - struct validate_operation_visitor { - validate_operation_visitor( const options_type& opts ):_opts(opts){} - - typedef void result_type; - - template - void operator()( T&& op )const { - validate( std::forward(op), _opts ); - } - const options_type& _opts; - }; - - void validate( const operation& o, const options_type& opts ) { - o.visit( validate_operation_visitor( opts ) ); - } - -} } // steemit::chain2 diff --git a/libraries/chain2/include/steemit/chain2/account_objects.hpp b/libraries/chain2/include/steemit/chain2/account_objects.hpp deleted file mode 100644 index 77857e5a23..0000000000 --- a/libraries/chain2/include/steemit/chain2/account_objects.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include - - -namespace steemit { namespace chain2 { - - class account_object : public - -} } diff --git a/libraries/chain2/include/steemit/chain2/block_database.hpp b/libraries/chain2/include/steemit/chain2/block_database.hpp deleted file mode 100644 index 2e7e5fdfef..0000000000 --- a/libraries/chain2/include/steemit/chain2/block_database.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include - -namespace steemit { namespace chain2 { - - using namespace steemit::protocol; - - namespace detail { class block_database_impl; } - - class block_database { - public: - block_database(); - ~block_database(); - - void open( const fc::path& file ); - - uint64_t append( const signed_block& b ); - signed_block read_block( uint64_t file_pos )const; - signed_block head()const; - - private: - std::unique_ptr my; - }; - -} } diff --git a/libraries/chain2/include/steemit/chain2/block_objects.hpp b/libraries/chain2/include/steemit/chain2/block_objects.hpp deleted file mode 100644 index 828b667640..0000000000 --- a/libraries/chain2/include/steemit/chain2/block_objects.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include -#include - -namespace steemit { namespace chain2 { - - using namespace steemit::protocol; - - struct by_id; - struct by_ref_prefix; - struct by_trx_id; - struct by_block_num; - struct by_timestamp; - - class block_object : public db2::object { - public: - - template - block_object( Constructor&& c, allocator a ) - :transactions( allocator< transaction_id_type >( a.get_segment_manager() ) ) - { c(*this); } - - id_type id; - uint32_t ref_prefix = 0; ///< used for TaPoS checks - uint32_t block_num = 0; ///< used for TaPoS checks - block_id_type block_id; - block_id_type previous; - account_name_type witness; - time_point_sec timestamp; - checksum_type transaction_merkle_root; - signature_type witness_signature; - bip::vector > transactions; - }; - - typedef multi_index_container < - block_object, - indexed_by< - ordered_unique< tag< by_id >, member >, - ordered_unique< tag< by_block_num >, member >, - ordered_unique< tag< by_timestamp >, member, std::greater >, - ordered_unique< tag< by_ref_prefix >, - composite_key< block_object, - member< block_object, uint32_t, &block_object::ref_prefix >, - member< block_object, uint32_t, &block_object::block_num > - >, - composite_key_compare< std::less, std::greater > - > - >, - bip::allocator - > block_index; - - - class transaction_object : public db2::object { - public: - template - transaction_object( Constructor&& c, allocator a ) - :packed_transaction( buffer_type::allocator_type( a.get_segment_manager() ) ) - { - c(*this); - }; - - id_type id; - uint32_t block_num = 0; ///< block the transaction was included in - transaction_id_type trx_id; - buffer_type packed_transaction; - }; - - - typedef multi_index_container < - transaction_object, - indexed_by< - ordered_unique< tag< by_id >, - member >, - ordered_unique< tag< by_trx_id >, - member< transaction_object, transaction_id_type, &transaction_object::trx_id > > - >, - bip::allocator - > transaction_index; - -} } /// namespace steemit::chain2 - -FC_REFLECT( steemit::chain2::block_object, - (id)(ref_prefix)(block_num)(block_id)(previous)(witness)(timestamp) - (transaction_merkle_root)(witness_signature)(transactions) ) -GRAPHENE_DB2_SET_INDEX_TYPE( steemit::chain2::block_object, steemit::chain2::block_index ); - - -FC_REFLECT( steemit::chain2::transaction_object, (id)(block_num)(trx_id)(packed_transaction) ); -GRAPHENE_DB2_SET_INDEX_TYPE( steemit::chain2::transaction_object, steemit::chain2::transaction_index ); diff --git a/libraries/chain2/include/steemit/chain2/chain_database.hpp b/libraries/chain2/include/steemit/chain2/chain_database.hpp deleted file mode 100644 index cbb771b8b7..0000000000 --- a/libraries/chain2/include/steemit/chain2/chain_database.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include -#include -#include - -#include -#include - -namespace steemit { namespace chain2 { - - enum skip_flags { - skip_undo_block, - skip_undo_transaction, - skip_undo_operation, - skip_validation ///< apply changes without validation checks - }; - - class database : public db2::database { - public: - database(); - ~database(); - - void open( const fc::path& dir ); - - const block_object& head_block()const; - uint32_t head_block_num()const; - - fc::signal pre_apply_operation; - fc::signal post_apply_operation; - fc::signal pre_apply_transaction; - fc::signal post_apply_transaction; - fc::signal pre_apply_block; - fc::signal post_apply_block; - - void push_block( const signed_block& b ); - void push_transaction( const signed_transaction& trx ); - signed_block generate_block( time_point_sec time, const account_name_type& witness, const fc::ecc::private_key& block_signing_key ); - - - - struct restore_pending { - restore_pending( database& db, vector&& p ):_db(db),_pending( std::move(p) ){} - restore_pending( restore_pending&& mv ):_db(mv._db),_pending( std::move(mv._pending) ){} - - ~restore_pending() { - try { - for( const auto& t : _pending ) { - try { - _db.push_transaction( t ); - } catch ( ... ){} - } - } catch ( ... ){} - } - - private: - database& _db; - vector _pending; - }; - - restore_pending clear_pending() { - _pending_tx_session.reset(); - return restore_pending( *this, std::move(_pending_transactions) ); - } - - private: - - chain::fork_database _fork_db; - vector< signed_transaction > _pending_transactions; - optional _pending_tx_session; - }; - - void apply( database& db, const signed_block& b, const options_type& opts = options_type() ); - void apply( database& db, const signed_transaction& t, const options_type& opts = options_type() ); - void apply( database& db, const operation& o, const options_type& opts = options_type() ); - - void validate( const signed_block& o, const options_type& opts = options_type() ); - void validate( const signed_transaction& o, const options_type& opts = options_type() ); - void validate( const operation& o, const options_type& opts = options_type() ); - - /** provide a default implementation of validate for types that don't have any specific - * validation logic - */ - template - void validate( const T&, const options_type& opts = options_type() ){} - -} } // namespace steemit::chain2 - - - diff --git a/libraries/chain2/include/steemit/chain2/object_types.hpp b/libraries/chain2/include/steemit/chain2/object_types.hpp deleted file mode 100644 index 637a3eb105..0000000000 --- a/libraries/chain2/include/steemit/chain2/object_types.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace steemit { namespace chain2 { - - using namespace boost::multi_index; - namespace db2 = graphene::db2; - namespace bip = boost::interprocess; - using db2::allocator; - - typedef uint64_t options_type; - - typedef bip::vector > buffer_type; - typedef buffer_type packed_operation_type; - typedef bip::vector packed_operations_type; - - enum object_types { - block_object_type, - transaction_object_type, - account_object_type - }; - -} } diff --git a/libraries/chain2/main.cpp b/libraries/chain2/main.cpp deleted file mode 100644 index fbf15aab2b..0000000000 --- a/libraries/chain2/main.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include -#include - -#include -using namespace steemit::chain2; - - -int main( int argc, char** argv ) { - - try { - steemit::chain2::database db; - db.open( "." ); - - idump((db.head_block_num())); - - signed_block genesis; - genesis.witness = "dantheman"; - - if( db.head_block_num() ) { - genesis.previous = db.head_block().block_id; - genesis.timestamp = db.head_block().timestamp + fc::seconds(3); - } else { - apply( db, genesis ); - return 0; - } - - idump((genesis)); - db.push_block( genesis ); - idump((db.revision())); - - const auto& head = db.head_block(); - auto packed_block = fc::raw::pack( genesis ); - auto packed_db_obj = fc::raw::pack( head ); - - idump((packed_db_obj)(packed_db_obj.size())); - - db.modify( head, [&]( block_object& b ) { - fc::datastream ds( packed_db_obj.data(), packed_db_obj.size() ); - fc::raw::unpack( ds, b ); - }); - packed_db_obj = fc::raw::pack( head ); - idump((packed_db_obj)); - idump((head)); - auto js = fc::json::to_string( head ); - idump((js)(js.size())); - db.modify( head, [&]( block_object& b ) { - auto var = fc::json::from_string( js ); - var.as(b); - }); - js = fc::json::to_string( head ); - idump((js)(js.size())); - - db.export_to_directory( "export_db" ); - - fc::temp_directory temp_dir( "." ); - steemit::chain2::database import_db; - import_db.open( temp_dir.path() ); - import_db.import_from_directory( "export_db" ); - idump((import_db.head_block())); - - - - } catch ( const fc::exception& e ) { - edump( (e.to_detail_string()) ); - } - - return 0; -} diff --git a/libraries/chainbase/include/chainbase/chainbase.hpp b/libraries/chainbase/include/chainbase/chainbase.hpp index 53b125b692..5a8cbac408 100644 --- a/libraries/chainbase/include/chainbase/chainbase.hpp +++ b/libraries/chainbase/include/chainbase/chainbase.hpp @@ -787,14 +787,27 @@ namespace chainbase { return _segment->get_segment_manager()->get_free_memory(); } + template + bool has_index()const + { + CHAINBASE_REQUIRE_READ_LOCK("get_index", typename MultiIndexType::value_type); + typedef generic_index index_type; + return _index_map.size() > index_type::value_type::type_id && _index_map[index_type::value_type::type_id]; + } + template const generic_index& get_index()const { CHAINBASE_REQUIRE_READ_LOCK("get_index", typename MultiIndexType::value_type); typedef generic_index index_type; typedef index_type* index_type_ptr; - assert( _index_map.size() > index_type::value_type::type_id ); - assert( _index_map[index_type::value_type::type_id] ); + + if( !has_index< MultiIndexType >() ) + { + std::string type_name = boost::core::demangle( typeid( typename index_type::value_type ).name() ); + BOOST_THROW_EXCEPTION( std::runtime_error( "unable to find index for " + type_name + " in database" ) ); + } + return *index_type_ptr( _index_map[index_type::value_type::type_id]->get() ); } @@ -802,8 +815,13 @@ namespace chainbase { void add_index_extension( std::shared_ptr< index_extension > ext ) { typedef generic_index index_type; - assert( _index_map.size() > index_type::value_type::type_id ); - assert( _index_map[index_type::value_type::type_id] ); + + if( !has_index< MultiIndexType >() ) + { + std::string type_name = boost::core::demangle( typeid( typename index_type::value_type ).name() ); + BOOST_THROW_EXCEPTION( std::runtime_error( "unable to find index for " + type_name + " in database" ) ); + } + _index_map[index_type::value_type::type_id]->add_index_extension( ext ); } @@ -813,8 +831,13 @@ namespace chainbase { CHAINBASE_REQUIRE_READ_LOCK("get_index", typename MultiIndexType::value_type); typedef generic_index index_type; typedef index_type* index_type_ptr; - assert( _index_map.size() > index_type::value_type::type_id ); - assert( _index_map[index_type::value_type::type_id] ); + + if( !has_index< MultiIndexType >() ) + { + std::string type_name = boost::core::demangle( typeid( typename index_type::value_type ).name() ); + BOOST_THROW_EXCEPTION( std::runtime_error( "unable to find index for " + type_name + " in database" ) ); + } + return index_type_ptr( _index_map[index_type::value_type::type_id]->get() )->indicies().template get(); } @@ -824,8 +847,13 @@ namespace chainbase { CHAINBASE_REQUIRE_WRITE_LOCK("get_mutable_index", typename MultiIndexType::value_type); typedef generic_index index_type; typedef index_type* index_type_ptr; - assert( _index_map.size() > index_type::value_type::type_id ); - assert( _index_map[index_type::value_type::type_id] ); + + if( !has_index< MultiIndexType >() ) + { + std::string type_name = boost::core::demangle( typeid( typename index_type::value_type ).name() ); + BOOST_THROW_EXCEPTION( std::runtime_error( "unable to find index for " + type_name + " in database" ) ); + } + return *index_type_ptr( _index_map[index_type::value_type::type_id]->get() ); } diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index a407771abf..337580c791 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -34,7 +34,7 @@ class account_history_plugin_impl void on_operation( const operation_notification& note ); account_history_plugin& _self; - flat_map _tracked_accounts; + flat_map< account_name_type, account_name_type > _tracked_accounts; bool _filter_content = false; }; @@ -45,13 +45,13 @@ account_history_plugin_impl::~account_history_plugin_impl() struct operation_visitor { - operation_visitor( database& db, const operation_notification& note, const operation_object*& n, string i ):_db(db),_note(note),new_obj(n),item(i){}; + operation_visitor( database& db, const operation_notification& note, const operation_object*& n, account_name_type i ):_db(db),_note(note),new_obj(n),item(i){}; typedef void result_type; database& _db; const operation_notification& _note; const operation_object*& new_obj; - string item; + account_name_type item; /// ignore these ops /* @@ -97,7 +97,7 @@ struct operation_visitor struct operation_visitor_filter : operation_visitor { - operation_visitor_filter( database& db, const operation_notification& note, const operation_object*& n, string i ):operation_visitor(db,note,n,i){} + operation_visitor_filter( database& db, const operation_notification& note, const operation_object*& n, account_name_type i ):operation_visitor(db,note,n,i){} void operator()( const comment_operation& )const {} void operator()( const vote_operation& )const {} @@ -179,6 +179,32 @@ void account_history_plugin_impl::on_operation( const operation_notification& no for( const auto& item : impacted ) { auto itr = _tracked_accounts.lower_bound( item ); + + /* + * The map containing the ranges uses the key as the lower bound and the value as the upper bound. + * Because of this, if a value exists with the range (key, value], then calling lower_bound on + * the map will return the key of the next pair. Under normal circumstances of those ranges not + * intersecting, the value we are looking for will not be present in range that is returned via + * lower_bound. + * + * Consider the following example using ranges ["a","c"], ["g","i"] + * If we are looking for "bob", it should be tracked because it is in the lower bound. + * However, lower_bound( "bob" ) returns an iterator to ["g","i"]. So we need to decrement the iterator + * to get the correct range. + * + * If we are looking for "g", lower_bound( "g" ) will return ["g","i"], so we need to make sure we don't + * decrement. + * + * If the iterator points to the end, we should check the previous (equivalent to rbegin) + * + * And finally if the iterator is at the beginning, we should not decrement it for obvious reasons + */ + if( itr != _tracked_accounts.begin() && + ( ( itr != _tracked_accounts.end() && itr->first != item ) || itr == _tracked_accounts.end() ) ) + { + --itr; + } + if( !_tracked_accounts.size() || (itr != _tracked_accounts.end() && itr->first <= item && item <= itr->second ) ) { if( _filter_content ) note.op.visit( operation_visitor_filter(db, note, new_obj, item) ); @@ -211,7 +237,7 @@ void account_history_plugin::plugin_set_program_options( ) { cli.add_options() - ("track-account-range", boost::program_options::value>()->composing()->multitoken(), "Defines a range of accounts to track as a json pair [\"from\",\"to\"] [from,to]") + ("track-account-range", boost::program_options::value>()->composing()->multitoken(), "Defines a range of accounts to track as a json pair [\"from\",\"to\"] [from,to] Can be specified multiple times") ("filter-posting-ops", "Ignore posting operations, only track transfers and account updates") ; cfg.add(cli); @@ -222,7 +248,7 @@ void account_history_plugin::plugin_initialize(const boost::program_options::var //ilog("Intializing account history plugin" ); database().pre_apply_operation.connect( [&]( const operation_notification& note ){ my->on_operation(note); } ); - typedef pair pairstring; + typedef pair pairstring; LOAD_VALUE_SET(options, "track-account-range", my->_tracked_accounts, pairstring); if( options.count( "filter-posting-ops" ) ) { my->_filter_content = true; @@ -236,7 +262,7 @@ void account_history_plugin::plugin_startup() ilog( "account_history plugin: plugin_startup() end" ); } -flat_map account_history_plugin::tracked_accounts() const +flat_map< account_name_type, account_name_type > account_history_plugin::tracked_accounts() const { return my->_tracked_accounts; } diff --git a/libraries/plugins/account_history/include/steemit/account_history/account_history_plugin.hpp b/libraries/plugins/account_history/include/steemit/account_history/account_history_plugin.hpp index 514e0c403b..f48c517baf 100644 --- a/libraries/plugins/account_history/include/steemit/account_history/account_history_plugin.hpp +++ b/libraries/plugins/account_history/include/steemit/account_history/account_history_plugin.hpp @@ -76,7 +76,7 @@ class account_history_plugin : public steemit::app::plugin virtual void plugin_startup() override; - flat_map tracked_accounts()const; /// map start_range to end_range + flat_map< account_name_type, account_name_type > tracked_accounts()const; /// map start_range to end_range friend class detail::account_history_plugin_impl; std::unique_ptr my; diff --git a/libraries/plugins/auth_util/auth_util_api.cpp b/libraries/plugins/auth_util/auth_util_api.cpp index 92c1f354c6..8de940a46d 100644 --- a/libraries/plugins/auth_util/auth_util_api.cpp +++ b/libraries/plugins/auth_util/auth_util_api.cpp @@ -1,6 +1,4 @@ -#include - #include #include @@ -13,6 +11,8 @@ #include #include +#include + namespace steemit { namespace plugin { namespace auth_util { using boost::container::flat_set; diff --git a/libraries/plugins/auth_util/include/steemit/plugins/auth_util/auth_util_api.hpp b/libraries/plugins/auth_util/include/steemit/plugins/auth_util/auth_util_api.hpp index 7762aeb998..a1186be1ab 100644 --- a/libraries/plugins/auth_util/include/steemit/plugins/auth_util/auth_util_api.hpp +++ b/libraries/plugins/auth_util/include/steemit/plugins/auth_util/auth_util_api.hpp @@ -1,11 +1,11 @@ #pragma once +#include + #include #include -#include - #include namespace steemit { namespace app { diff --git a/libraries/plugins/tags/include/steemit/tags/tags_plugin.hpp b/libraries/plugins/tags/include/steemit/tags/tags_plugin.hpp index d5a80a3af2..1d86c2387d 100644 --- a/libraries/plugins/tags/include/steemit/tags/tags_plugin.hpp +++ b/libraries/plugins/tags/include/steemit/tags/tags_plugin.hpp @@ -35,7 +35,7 @@ using chainbase::allocator; #define TAGS_PLUGIN_NAME "tags" -typedef fc::fixed_string< fc::sha256 > tag_name_type; +typedef protocol::fixed_string tag_name_type; // Plugins need to define object type IDs such that they do not conflict // globally. If each plugin uses the upper 8 bits as a space identifier, @@ -87,13 +87,6 @@ class tag_object : public object< tag_object_type, tag_object > double trending = 0; share_type promoted_balance = 0; - /** - * Used to track the total rshares^2 of all children, this is used for indexing purposes. A discussion - * that has a nested comment of high value should promote the entire discussion so that the comment can - * be reviewed. - */ - fc::uint128_t children_rshares2; - account_id_type author; comment_id_type parent; comment_id_type comment; @@ -111,13 +104,11 @@ struct by_parent_active; struct by_parent_promoted; struct by_parent_net_rshares; /// all top level posts by direct pending payout struct by_parent_net_votes; /// all top level posts by direct votes -struct by_parent_children_rshares2; /// all top level posts by total cumulative payout (aka payout) struct by_parent_trending; struct by_parent_children; /// all top level posts with the most discussion (replies at all levels) struct by_parent_hot; struct by_author_parent_created; /// all blog posts by author with tag struct by_author_comment; -struct by_mode_parent_children_rshares2; struct by_reward_fund_net_rshares; struct by_comment; struct by_tag; @@ -199,15 +190,6 @@ typedef multi_index_container< >, composite_key_compare< std::less, std::less, std::greater< double >, std::less< tag_id_type > > >, - ordered_unique< tag< by_parent_children_rshares2 >, - composite_key< tag_object, - member< tag_object, tag_name_type, &tag_object::tag >, - member< tag_object, comment_id_type, &tag_object::parent >, - member< tag_object, fc::uint128_t, &tag_object::children_rshares2 >, - member< tag_object, tag_id_type, &tag_object::id > - >, - composite_key_compare< std::less, std::less, std::greater< fc::uint128_t >, std::less< tag_id_type > > - >, ordered_unique< tag< by_parent_trending >, composite_key< tag_object, member< tag_object, tag_name_type, &tag_object::tag >, @@ -273,11 +255,11 @@ class tag_stats_object : public object< tag_stats_object_type, tag_stats_object id_type id; tag_name_type tag; - fc::uint128_t total_children_rshares2; asset total_payout = asset( 0, SBD_SYMBOL ); int32_t net_votes = 0; uint32_t top_posts = 0; uint32_t comments = 0; + fc::uint128 total_trending = 0; }; typedef oid< tag_stats_object > tag_stats_id_type; @@ -309,10 +291,10 @@ typedef multi_index_container< */ ordered_non_unique< tag< by_trending >, composite_key< tag_stats_object, - member< tag_stats_object, fc::uint128_t, &tag_stats_object::total_children_rshares2 >, + member< tag_stats_object, fc::uint128 , &tag_stats_object::total_trending >, member< tag_stats_object, tag_name_type, &tag_stats_object::tag > >, - composite_key_compare< std::greater< uint128_t >, std::less< tag_name_type > > + composite_key_compare< std::greater< fc::uint128 >, std::less< tag_name_type > > > >, allocator< tag_stats_object > @@ -516,11 +498,11 @@ class tag_api : public std::enable_shared_from_this { FC_API( steemit::tags::tag_api, (get_tags) ); FC_REFLECT( steemit::tags::tag_object, - (id)(tag)(created)(active)(cashout)(net_rshares)(net_votes)(hot)(trending)(promoted_balance)(children)(children_rshares2)(author)(parent)(comment) ) + (id)(tag)(created)(active)(cashout)(net_rshares)(net_votes)(hot)(trending)(promoted_balance)(children)(author)(parent)(comment) ) CHAINBASE_SET_INDEX_TYPE( steemit::tags::tag_object, steemit::tags::tag_index ) FC_REFLECT( steemit::tags::tag_stats_object, - (id)(tag)(total_children_rshares2)(total_payout)(net_votes)(top_posts)(comments) ); + (id)(tag)(total_payout)(net_votes)(top_posts)(comments)(total_trending) ); CHAINBASE_SET_INDEX_TYPE( steemit::tags::tag_stats_object, steemit::tags::tag_stats_index ) FC_REFLECT( steemit::tags::peer_stats_object, diff --git a/libraries/plugins/tags/tags_plugin.cpp b/libraries/plugins/tags/tags_plugin.cpp index 09531c1cc4..4a9bbf755e 100644 --- a/libraries/plugins/tags/tags_plugin.cpp +++ b/libraries/plugins/tags/tags_plugin.cpp @@ -57,22 +57,22 @@ struct operation_visitor { void remove_stats( const tag_object& tag, const tag_stats_object& stats )const { _db.modify( stats, [&]( tag_stats_object& s ) { if( tag.parent == comment_id_type() ) { - s.total_children_rshares2 -= tag.children_rshares2; s.top_posts--; } else { s.comments--; } + s.total_trending -= static_cast(tag.trending); s.net_votes -= tag.net_votes; }); } void add_stats( const tag_object& tag, const tag_stats_object& stats )const { _db.modify( stats, [&]( tag_stats_object& s ) { if( tag.parent == comment_id_type() ) { - s.total_children_rshares2 += tag.children_rshares2; s.top_posts++; } else { s.comments++; } + s.total_trending += static_cast(tag.trending); s.net_votes += tag.net_votes; }); } @@ -117,8 +117,6 @@ struct operation_visitor { } set< string > lower_tags; - if( c.category != "" ) - meta.tags.insert( fc::to_lower( to_string( c.category ) ) ); uint8_t tag_limit = 5; uint8_t count = 0; @@ -155,7 +153,6 @@ struct operation_visitor { obj.children = comment.children; obj.net_rshares = comment.net_rshares.value; obj.net_votes = comment.net_votes; - obj.children_rshares2 = comment.children_rshares2; obj.hot = hot; obj.trending = trending; if( obj.cashout == fc::time_point_sec() ) @@ -185,7 +182,6 @@ struct operation_visitor { obj.net_votes = comment.net_votes; obj.children = comment.children; obj.net_rshares = comment.net_rshares.value; - obj.children_rshares2 = comment.children_rshares2; obj.author = author; obj.hot = hot; obj.trending = trending; diff --git a/libraries/plugins/witness/CMakeLists.txt b/libraries/plugins/witness/CMakeLists.txt index 3ccc5cd241..fef150a36f 100644 --- a/libraries/plugins/witness/CMakeLists.txt +++ b/libraries/plugins/witness/CMakeLists.txt @@ -1,10 +1,12 @@ file(GLOB HEADERS "include/steemit/witness/*.hpp") add_library( steemit_witness - witness.cpp + witness_plugin.cpp + witness_evaluators.cpp + witness_operations.cpp ) -target_link_libraries( steemit_witness steemit_chain steemit_protocol steemit_app steemit_time ) +target_link_libraries( steemit_witness steemit_chain steemit_protocol steemit_app ) target_include_directories( steemit_witness PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/plugins/witness/include/steemit/witness/witness_objects.hpp b/libraries/plugins/witness/include/steemit/witness/witness_objects.hpp new file mode 100644 index 0000000000..c56735002b --- /dev/null +++ b/libraries/plugins/witness/include/steemit/witness/witness_objects.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include + +#include + +namespace steemit { namespace witness { + +using namespace std; +using namespace steemit::chain; + +#ifndef WITNESS_SPACE_ID +#define WITNESS_SPACE_ID 12 +#endif + +enum witness_plugin_object_type +{ + account_bandwidth_object_type = ( WITNESS_SPACE_ID << 8 ), + content_edit_lock_object_type = ( WITNESS_SPACE_ID << 8 ) + 1 +}; + +enum bandwidth_type +{ + post, ///< Rate limiting posting reward eligibility over time + forum, ///< Rate limiting for all forum related actins + market ///< Rate limiting for all other actions +}; + +class account_bandwidth_object : public object< account_bandwidth_object_type, account_bandwidth_object > +{ + public: + template< typename Constructor, typename Allocator > + account_bandwidth_object( Constructor&& c, allocator< Allocator > a ) + { + c( *this ); + } + + account_bandwidth_object() {} + + id_type id; + + account_name_type account; + bandwidth_type type; + share_type average_bandwidth; + share_type lifetime_bandwidth; + time_point_sec last_bandwidth_update; +}; + +typedef oid< account_bandwidth_object > account_bandwidth_id_type; + +class content_edit_lock_object : public object< content_edit_lock_object_type, content_edit_lock_object > +{ + public: + template< typename Constructor, typename Allocator > + content_edit_lock_object( Constructor&& c, allocator< Allocator > a ) + { + c( *this ); + } + + content_edit_lock_object() {} + + id_type id; + account_name_type account; + time_point_sec lock_time; +}; + +typedef oid< content_edit_lock_object > content_edit_lock_id_type; + +struct by_account_bandwidth_type; + +typedef multi_index_container < + account_bandwidth_object, + indexed_by < + ordered_unique< tag< by_id >, + member< account_bandwidth_object, account_bandwidth_id_type, &account_bandwidth_object::id > >, + ordered_unique< tag< by_account_bandwidth_type >, + composite_key< account_bandwidth_object, + member< account_bandwidth_object, account_name_type, &account_bandwidth_object::account >, + member< account_bandwidth_object, bandwidth_type, &account_bandwidth_object::type > + > + > + >, + allocator< account_bandwidth_object > +> account_bandwidth_index; + +struct by_account; + +typedef multi_index_container < + content_edit_lock_object, + indexed_by < + ordered_unique< tag< by_id >, + member< content_edit_lock_object, content_edit_lock_id_type, &content_edit_lock_object::id > >, + ordered_unique< tag< by_account >, + member< content_edit_lock_object, account_name_type, &content_edit_lock_object::account > > + >, + allocator< content_edit_lock_object > +> content_edit_lock_index; + +} } // steemit::witness + +FC_REFLECT_ENUM( steemit::witness::bandwidth_type, (post)(forum)(market) ) + +FC_REFLECT( steemit::witness::account_bandwidth_object, + (id)(account)(type)(average_bandwidth)(lifetime_bandwidth)(last_bandwidth_update) ) +CHAINBASE_SET_INDEX_TYPE( steemit::witness::account_bandwidth_object, steemit::witness::account_bandwidth_index ) + +FC_REFLECT( steemit::witness::content_edit_lock_object, + (id)(account)(lock_time) ) +CHAINBASE_SET_INDEX_TYPE( steemit::witness::content_edit_lock_object, steemit::witness::content_edit_lock_index ) diff --git a/libraries/plugins/witness/include/steemit/witness/witness_operations.hpp b/libraries/plugins/witness/include/steemit/witness/witness_operations.hpp new file mode 100644 index 0000000000..ea67bae53d --- /dev/null +++ b/libraries/plugins/witness/include/steemit/witness/witness_operations.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include + +namespace steemit { namespace witness { + +using namespace std; +using steemit::protocol::base_operation; +using steemit::chain::database; + +class witness_plugin; + +struct enable_content_editing_operation : base_operation +{ + protocol::account_name_type account; + fc::time_point_sec relock_time; + + void validate()const; + + void get_required_active_authorities( flat_set< protocol::account_name_type>& a )const { a.insert( account ); } +}; + +typedef fc::static_variant< + enable_content_editing_operation + > witness_plugin_operation; + +DEFINE_PLUGIN_EVALUATOR( witness_plugin, witness_plugin_operation, enable_content_editing ); + +} } // steemit::witness + +FC_REFLECT( steemit::witness::enable_content_editing_operation, (account)(relock_time) ) + +FC_REFLECT_TYPENAME( steemit::witness::witness_plugin_operation ) + +DECLARE_OPERATION_TYPE( steemit::witness::witness_plugin_operation ) diff --git a/libraries/plugins/witness/include/steemit/witness/witness.hpp b/libraries/plugins/witness/include/steemit/witness/witness_plugin.hpp similarity index 85% rename from libraries/plugins/witness/include/steemit/witness/witness.hpp rename to libraries/plugins/witness/include/steemit/witness/witness_plugin.hpp index db718eb4bb..522ddfebe6 100644 --- a/libraries/plugins/witness/include/steemit/witness/witness.hpp +++ b/libraries/plugins/witness/include/steemit/witness/witness_plugin.hpp @@ -28,7 +28,7 @@ #include -namespace steemit { namespace witness_plugin { +namespace steemit { namespace witness { using std::string; using protocol::public_key_type; @@ -52,20 +52,16 @@ namespace block_production_condition }; } +namespace detail +{ + class witness_plugin_impl; +} + class witness_plugin : public steemit::app::plugin { public: - witness_plugin( application* app ) : plugin( app ) {} - ~witness_plugin() { - try { - if( _block_production_task.valid() ) - _block_production_task.cancel_and_wait(__FUNCTION__); - } catch(fc::canceled_exception&) { - //Expected exception. Move along. - } catch(fc::exception& e) { - edump((e.to_detail_string())); - } - } + witness_plugin( application* app ); + virtual ~witness_plugin(); std::string plugin_name()const override; @@ -90,14 +86,15 @@ class witness_plugin : public steemit::app::plugin uint32_t _required_witness_participation = 33 * STEEMIT_1_PERCENT; uint32_t _production_skip_flags = steemit::chain::database::skip_nothing; - uint64_t _head_block_num = 0; block_id_type _head_block_id = block_id_type(); - uint64_t _total_hashes = 0; fc::time_point _hash_start_time; std::map _private_keys; std::set _witnesses; fc::future _block_production_task; + + friend class detail::witness_plugin_impl; + std::unique_ptr< detail::witness_plugin_impl > _my; }; -} } //steemit::witness_plugin +} } //steemit::witness diff --git a/libraries/plugins/witness/witness_evaluators.cpp b/libraries/plugins/witness/witness_evaluators.cpp new file mode 100644 index 0000000000..16aab861e8 --- /dev/null +++ b/libraries/plugins/witness/witness_evaluators.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include + +namespace steemit { namespace witness { + +void enable_content_editing_evaluator::do_apply( const enable_content_editing_operation& o ) +{ + try + { + auto edit_lock = _db.find< content_edit_lock_object, by_account >( o.account ); + + if( edit_lock == nullptr ) + { + _db.create< content_edit_lock_object >( [&]( content_edit_lock_object& lock ) + { + lock.account = o.account; + lock.lock_time = o.relock_time; + }); + } + else + { + _db.modify( *edit_lock, [&]( content_edit_lock_object& lock ) + { + lock.lock_time = o.relock_time; + }); + } + } + FC_CAPTURE_AND_RETHROW( (o) ) +} + +} } // steemit::witness diff --git a/libraries/plugins/witness/witness_operations.cpp b/libraries/plugins/witness/witness_operations.cpp new file mode 100644 index 0000000000..8ef0393127 --- /dev/null +++ b/libraries/plugins/witness/witness_operations.cpp @@ -0,0 +1,14 @@ +#include + +#include + +namespace steemit { namespace witness { + +void enable_content_editing_operation::validate()const +{ + chain::validate_account_name( account ); +} + +} } // steemit::witness + +DEFINE_OPERATION_TYPE( steemit::witness::witness_plugin_operation ) diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness_plugin.cpp similarity index 58% rename from libraries/plugins/witness/witness.cpp rename to libraries/plugins/witness/witness_plugin.cpp index 0c7fcb6f3c..c877699a35 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness_plugin.cpp @@ -21,15 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include +#include +#include +#include -#include #include #include +#include +#include +#include #include -#include -#include +#include #include @@ -37,12 +40,17 @@ #include #include +#include + +namespace steemit { namespace witness { + +namespace bpo = boost::program_options; -using namespace steemit::witness_plugin; using std::string; using std::vector; -namespace bpo = boost::program_options; +using protocol::signed_transaction; +using chain::account_object; void new_chain_banner( const steemit::chain::database& db ) { @@ -58,6 +66,212 @@ void new_chain_banner( const steemit::chain::database& db ) return; } +namespace detail +{ + using namespace steemit::chain; + + class witness_plugin_impl + { + public: + witness_plugin_impl( witness_plugin& plugin ) + : _self( plugin ){} + + void plugin_initialize(); + + void pre_transaction( const signed_transaction& trx ); + void pre_operation( const operation_notification& note ); + + void update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ); + + witness_plugin& _self; + std::shared_ptr< generic_custom_operation_interpreter< witness_plugin_operation > > _custom_operation_interpreter; + }; + + void witness_plugin_impl::plugin_initialize() + { + _custom_operation_interpreter = std::make_shared< generic_custom_operation_interpreter< witness_plugin_operation > >( _self.database() ); + + _custom_operation_interpreter->register_evaluator< enable_content_editing_evaluator >( &_self ); + + _self.database().set_custom_operation_interpreter( _self.plugin_name(), _custom_operation_interpreter ); + } + + struct comment_options_extension_visitor + { + comment_options_extension_visitor( const comment_object& c, const database& db ) : _c( c ), _db( db ) {} + + typedef void result_type; + + const comment_object& _c; + const database& _db; + + void operator()( const comment_payout_beneficiaries& cpb )const + { + STEEMIT_ASSERT( cpb.beneficiaries.size() <= 8, + chain::plugin_exception, + "Cannot specify more than 8 beneficiaries." ); + } + }; + + struct operation_visitor + { + operation_visitor( const chain::database& db ) : _db( db ) {} + + const chain::database& _db; + + typedef void result_type; + + template< typename T > + void operator()( const T& )const {} + + void operator()( const comment_options_operation& o )const + { + const auto& comment = _db.get_comment( o.author, o.permlink ); + + comment_options_extension_visitor v( comment, _db ); + + for( auto& e : o.extensions ) + { + e.visit( v ); + } + } + + void operator()( const comment_operation& o )const + { + if( o.parent_author != STEEMIT_ROOT_POST_PARENT ) + { + const auto& parent = _db.find_comment( o.parent_author, o.parent_permlink ); + + if( parent != nullptr ) + STEEMIT_ASSERT( parent->depth < STEEMIT_SOFT_MAX_COMMENT_DEPTH, + chain::plugin_exception, + "Comment is nested ${x} posts deep, maximum depth is ${y}.", ("x",parent->depth)("y",STEEMIT_SOFT_MAX_COMMENT_DEPTH) ); + } + + auto itr = _db.find< comment_object, by_permlink >( boost::make_tuple( o.author, o.permlink ) ); + + if( itr != nullptr && itr->cashout_time == fc::time_point_sec::maximum() ) + { + auto edit_lock = _db.find< content_edit_lock_object, by_account >( o.author ); + + STEEMIT_ASSERT( edit_lock != nullptr && _db.head_block_time() < edit_lock->lock_time, + chain::plugin_exception, + "The comment is archived" ); + } + } + }; + + void witness_plugin_impl::pre_transaction( const signed_transaction& trx ) + { + const auto& _db = _self.database(); + flat_set< account_name_type > required; vector other; + trx.get_required_authorities( required, required, required, other ); + + auto trx_size = fc::raw::pack_size(trx); + + for( const auto& auth : required ) + { + const auto& acnt = _db.get_account( auth ); + + update_account_bandwidth( acnt, trx_size, bandwidth_type::forum ); + + for( const auto& op : trx.operations ) + { + if( is_market_operation( op ) ) + { + update_account_bandwidth( acnt, trx_size * 10, bandwidth_type::market ); + break; + } + } + } + } + + void witness_plugin_impl::pre_operation( const operation_notification& note ) + { + const auto& _db = _self.database(); + if( _db.is_producing() ) + { + note.op.visit( operation_visitor( _db ) ); + } + } + + void witness_plugin_impl::update_account_bandwidth( const account_object& a, uint32_t trx_size, const bandwidth_type type ) + { + database& _db = _self.database(); + const auto& props = _db.get_dynamic_global_properties(); + bool has_bandwidth = true; + + if( props.total_vesting_shares.amount > 0 ) + { + auto band = _db.find< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( a.name, type ) ); + + if( band == nullptr ) + { + band = &_db.create< account_bandwidth_object >( [&]( account_bandwidth_object& b ) + { + b.account = a.name; + b.type = type; + }); + } + + share_type new_bandwidth; + share_type trx_bandwidth = trx_size * STEEMIT_BANDWIDTH_PRECISION; + auto delta_time = ( _db.head_block_time() - band->last_bandwidth_update ).to_seconds(); + + if( delta_time > STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS ) + new_bandwidth = 0; + else + new_bandwidth = ( ( ( STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS - delta_time ) * fc::uint128( band->average_bandwidth.value ) ) + / STEEMIT_BANDWIDTH_AVERAGE_WINDOW_SECONDS ).to_uint64(); + + new_bandwidth += trx_bandwidth; + + _db.modify( *band, [&]( account_bandwidth_object& b ) + { + b.average_bandwidth = new_bandwidth; + b.lifetime_bandwidth += trx_bandwidth; + b.last_bandwidth_update = _db.head_block_time(); + }); + + fc::uint128 account_vshares( a.effective_vesting_shares().amount.value ); + fc::uint128 total_vshares( props.total_vesting_shares.amount.value ); + fc::uint128 account_average_bandwidth( band->average_bandwidth.value ); + fc::uint128 max_virtual_bandwidth( props.max_virtual_bandwidth ); + + has_bandwidth = ( account_vshares * max_virtual_bandwidth ) > ( account_average_bandwidth * total_vshares ); + + if( _db.is_producing() ) + STEEMIT_ASSERT( has_bandwidth, chain::plugin_exception, + "Account: ${account} bandwidth limit exeeded. Please wait to transact or power up STEEM.", + ("account", a.name) + ("account_vshares", account_vshares) + ("account_average_bandwidth", account_average_bandwidth) + ("max_virtual_bandwidth", max_virtual_bandwidth) + ("total_vesting_shares", total_vshares) ); + } + } +} + +witness_plugin::witness_plugin( application* app ) + : plugin( app ), _my( new detail::witness_plugin_impl( *this ) ) {} + +witness_plugin::~witness_plugin() +{ + try + { + if( _block_production_task.valid() ) + _block_production_task.cancel_and_wait(__FUNCTION__); + } + catch(fc::canceled_exception&) + { + //Expected exception. Move along. + } + catch(fc::exception& e) + { + edump((e.to_detail_string())); + } +} + void witness_plugin::plugin_set_program_options( boost::program_options::options_description& command_line_options, boost::program_options::options_description& config_file_options) @@ -84,10 +298,8 @@ using std::string; void witness_plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { - ilog("witness plugin: plugin_initialize() begin"); _options = &options; LOAD_VALUE_SET(options, "witness", _witnesses, string) - edump((_witnesses)); if( options.count("private-key") ) { @@ -100,7 +312,13 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m } } - ilog("witness plugin: plugin_initialize() end"); + chain::database& db = database(); + + db.on_pre_apply_transaction.connect( [&]( const signed_transaction& tx ){ _my->pre_transaction( tx ); } ); + db.pre_apply_operation.connect( [&]( const operation_notification& note ){ _my->pre_operation( note ); } ); + + add_plugin_index< account_bandwidth_index >( db ); + add_plugin_index< content_edit_lock_index >( db ); } FC_LOG_AND_RETHROW() } void witness_plugin::plugin_startup() @@ -111,6 +329,7 @@ void witness_plugin::plugin_startup() if( !_witnesses.empty() ) { ilog("Launching block production for ${n} witnesses.", ("n", _witnesses.size())); + idump( (_witnesses) ); app().set_block_production(true); if( _production_enabled ) { @@ -136,9 +355,8 @@ void witness_plugin::schedule_production_loop() { //Schedule for the next second's tick regardless of chain state // If we would wait less than 50ms, wait for the whole second. - fc::time_point ntp_now = steemit::time::now(); fc::time_point fc_now = fc::time_point::now(); - int64_t time_to_next_second = 1000000 - (ntp_now.time_since_epoch().count() % 1000000); + int64_t time_to_next_second = 1000000 - (fc_now.time_since_epoch().count() % 1000000); if( time_to_next_second < 50000 ) // we must sleep for at least 50ms time_to_next_second += 1000000; @@ -221,7 +439,7 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc block_production_condition::block_production_condition_enum witness_plugin::maybe_produce_block( fc::mutable_variant_object& capture ) { chain::database& db = database(); - fc::time_point now_fine = steemit::time::now(); + fc::time_point now_fine = fc::time_point::now(); fc::time_point_sec now = now_fine + fc::microseconds( 500000 ); // If the next block production opportunity is in the present or future, we're synced. @@ -314,4 +532,6 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb return block_production_condition::exception_producing_block; } -STEEMIT_DEFINE_PLUGIN( witness, steemit::witness_plugin::witness_plugin ) +} } // steemit::witness + +STEEMIT_DEFINE_PLUGIN( witness, steemit::witness::witness_plugin ) diff --git a/libraries/protocol/CMakeLists.txt b/libraries/protocol/CMakeLists.txt index fb572b58d2..3d8fbcc88a 100644 --- a/libraries/protocol/CMakeLists.txt +++ b/libraries/protocol/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( steemit_protocol transaction.cpp block.cpp asset.cpp + fixed_string.cpp version.cpp get_config.cpp diff --git a/libraries/protocol/fixed_string.cpp b/libraries/protocol/fixed_string.cpp new file mode 100644 index 0000000000..df18e98893 --- /dev/null +++ b/libraries/protocol/fixed_string.cpp @@ -0,0 +1,51 @@ +#include + +#include + +namespace fc { + void to_variant( const steemit::protocol::fixed_string& s, variant& v ) { v = std::string( s ); } + void from_variant( const variant& v, steemit::protocol::fixed_string& s ) { s = v.as_string(); } + + uint128 endian_reverse( const uint128& u ) + { + return uint128( boost::endian::endian_reverse( u.hi ), boost::endian::endian_reverse( u.lo ) ); + } +} // fc + +namespace steemit { namespace protocol { + +fixed_string::fixed_string( const std::string& str ) +{ + Storage d; + if( str.size() <= sizeof(d) ) + memcpy( (char*)&d, str.c_str(), str.size() ); + else + memcpy( (char*)&d, str.c_str(), sizeof(d) ); + + data = boost::endian::big_to_native( d ); +} + +fixed_string::operator std::string()const +{ + Storage d = boost::endian::native_to_big( data ); + size_t s; + + if( *(((const char*)&d) + sizeof(d) - 1) ) + s = sizeof(d); + else + s = strnlen( (const char*)&d, sizeof(d) ); + + const char* self = (const char*)&d; + + return std::string( self, self + s ); +} + +uint32_t fixed_string::size()const +{ + Storage d = boost::endian::native_to_big( data ); + if( *(((const char*)&d) + sizeof(d) - 1) ) + return sizeof(d); + return strnlen( (const char*)&d, sizeof(d) ); +} + +} } // steemit::protocol \ No newline at end of file diff --git a/libraries/protocol/get_config.cpp b/libraries/protocol/get_config.cpp index ac013f43cc..86807111e9 100644 --- a/libraries/protocol/get_config.cpp +++ b/libraries/protocol/get_config.cpp @@ -16,7 +16,6 @@ fc::variant_object get_config() result[ "IS_TEST_NET" ] = false; #endif - result["GRAPHENE_CURRENT_DB_VERSION"] = GRAPHENE_CURRENT_DB_VERSION; result["SBD_SYMBOL"] = SBD_SYMBOL; result["STEEMIT_100_PERCENT"] = STEEMIT_100_PERCENT; result["STEEMIT_1_PERCENT"] = STEEMIT_1_PERCENT; diff --git a/libraries/protocol/include/steemit/protocol/authority.hpp b/libraries/protocol/include/steemit/protocol/authority.hpp index ff883a88b8..9499c951ac 100644 --- a/libraries/protocol/include/steemit/protocol/authority.hpp +++ b/libraries/protocol/include/steemit/protocol/authority.hpp @@ -46,7 +46,7 @@ namespace steemit { namespace protocol { void clear(); void validate()const; - typedef flat_map< account_name_type, weight_type, string_less > account_authority_map; + typedef flat_map< account_name_type, weight_type > account_authority_map; typedef flat_map< public_key_type, weight_type > key_authority_map; uint32_t weight_threshold = 0; diff --git a/libraries/protocol/include/steemit/protocol/config.hpp b/libraries/protocol/include/steemit/protocol/config.hpp index a5b5b18fdb..51243b8e97 100644 --- a/libraries/protocol/include/steemit/protocol/config.hpp +++ b/libraries/protocol/include/steemit/protocol/config.hpp @@ -3,7 +3,7 @@ */ #pragma once -#define STEEMIT_BLOCKCHAIN_VERSION ( version(0, 18, 2) ) +#define STEEMIT_BLOCKCHAIN_VERSION ( version(0, 18, 3) ) #define STEEMIT_BLOCKCHAIN_HARDFORK_VERSION ( hardfork_version( STEEMIT_BLOCKCHAIN_VERSION ) ) #ifdef IS_TEST_NET @@ -90,7 +90,7 @@ #define STEEMIT_MAX_MINER_WITNESSES_HF17 0 #define STEEMIT_MAX_RUNNER_WITNESSES_HF17 1 -#define STEEMIT_HARDFORK_REQUIRED_WITNESSES 17 // 17 of the 20 dpos witnesses (19 elected and 1 virtual time) required for hardfork. This guarantees 75% participation on all subsequent rounds. +#define STEEMIT_HARDFORK_REQUIRED_WITNESSES 17 // 17 of the 21 dpos witnesses (20 elected and 1 virtual time) required for hardfork. This guarantees 75% participation on all subsequent rounds. #define STEEMIT_MAX_TIME_UNTIL_EXPIRATION (60*60) // seconds, aka: 1 hour #define STEEMIT_MAX_MEMO_SIZE 2048 #define STEEMIT_MAX_PROXY_RECURSION_DEPTH 4 @@ -247,8 +247,6 @@ #define STEEMIT_MAX_ASSET_WHITELIST_AUTHORITIES 10 #define STEEMIT_MAX_URL_LENGTH 127 -#define GRAPHENE_CURRENT_DB_VERSION "GPH2.4" - #define STEEMIT_IRREVERSIBLE_THRESHOLD (75 * STEEMIT_1_PERCENT) #define VIRTUAL_SCHEDULE_LAP_LENGTH ( fc::uint128(uint64_t(-1)) ) diff --git a/libraries/protocol/include/steemit/protocol/fixed_string.hpp b/libraries/protocol/include/steemit/protocol/fixed_string.hpp new file mode 100644 index 0000000000..6895494ea8 --- /dev/null +++ b/libraries/protocol/include/steemit/protocol/fixed_string.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +namespace steemit { namespace protocol { + +/** + * This class is an in-place memory allocation of a 16 character string. + * + * The string will serialize the same way as std::string for variant and raw formats, + * but will be in memory as a 128-bit integer so that we can exploit efficient + * integer comparisons for sorting. + */ +class fixed_string +{ + public: + typedef fc::uint128_t Storage; + + fixed_string(){} + fixed_string( const fixed_string& c ) : data( c.data ){} + fixed_string( const char* str ) : fixed_string( std::string( str ) ) {} + fixed_string( const std::string& str ); + + operator std::string()const; + + uint32_t size()const; + + uint32_t length()const { return size(); } + + fixed_string& operator = ( const fixed_string& str ) + { + data = str.data; + return *this; + } + + fixed_string& operator = ( const char* str ) + { + *this = fixed_string( str ); + return *this; + } + + fixed_string& operator = ( const std::string& str ) + { + *this = fixed_string( str ); + return *this; + } + + friend std::string operator + ( const fixed_string& a, const std::string& b ) { return std::string( a ) + b; } + friend std::string operator + ( const std::string& a, const fixed_string& b ){ return a + std::string( b ); } + friend bool operator < ( const fixed_string& a, const fixed_string& b ) { return a.data < b.data; } + friend bool operator <= ( const fixed_string& a, const fixed_string& b ) { return a.data <= b.data; } + friend bool operator > ( const fixed_string& a, const fixed_string& b ) { return a.data > b.data; } + friend bool operator >= ( const fixed_string& a, const fixed_string& b ) { return a.data >= b.data; } + friend bool operator == ( const fixed_string& a, const fixed_string& b ) { return a.data == b.data; } + friend bool operator != ( const fixed_string& a, const fixed_string& b ) { return a.data != b.data; } + + Storage data; +}; + +} } // steemit::protocol + +namespace fc { namespace raw { + + template< typename Stream > + inline void pack( Stream& s, const steemit::protocol::fixed_string& u ) + { + pack( s, std::string( u ) ); + } + + template< typename Stream > + inline void unpack( Stream& s, steemit::protocol::fixed_string& u ) + { + std::string str; + unpack( s, str ); + u = str; + } + +} // raw + + void to_variant( const steemit::protocol::fixed_string& s, variant& v ); + void from_variant( const variant& v, steemit::protocol::fixed_string& s ); +} // fc diff --git a/libraries/protocol/include/steemit/protocol/steem_operations.hpp b/libraries/protocol/include/steemit/protocol/steem_operations.hpp index 6375c62ae8..885646e8ab 100644 --- a/libraries/protocol/include/steemit/protocol/steem_operations.hpp +++ b/libraries/protocol/include/steemit/protocol/steem_operations.hpp @@ -8,6 +8,17 @@ namespace steemit { namespace protocol { + inline void validate_account_name( const string& name ) + { + FC_ASSERT( is_valid_account_name( name ), "Account name ${n} is invalid", ("n", name) ); + } + + inline void validate_permlink( const string& permlink ) + { + FC_ASSERT( permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH, "permlink is too long" ); + FC_ASSERT( fc::is_utf8( permlink ), "permlink not formatted in UTF8" ); + } + struct account_create_operation : public base_operation { asset fee; @@ -87,7 +98,7 @@ namespace steemit { namespace protocol { uint16_t weight; // For use by std::sort such that the route is sorted first by name (ascending) - bool operator < ( const beneficiary_route_type& o )const { return string_less()( account, o.account ); } + bool operator < ( const beneficiary_route_type& o )const { return account < o.account; } }; struct comment_payout_beneficiaries diff --git a/libraries/protocol/include/steemit/protocol/types.hpp b/libraries/protocol/include/steemit/protocol/types.hpp index 8229055e03..ad321cc04d 100644 --- a/libraries/protocol/include/steemit/protocol/types.hpp +++ b/libraries/protocol/include/steemit/protocol/types.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include @@ -66,45 +66,16 @@ namespace steemit { namespace protocol { - typedef fc::ecc::private_key private_key_type; - typedef fc::sha256 chain_id_type; - typedef fc::fixed_string<> account_name_type; - // typedef std::string account_name_type; - - struct string_less - { - bool operator()( const std::string& a, const std::string& b )const - { - return a < b; - } - - bool operator()( const fc::fixed_string<>& a, const fc::fixed_string<>& b )const - { - const char* ap = (const char*)&a; - const char* ab = (const char*)&b; - int count = sizeof(a) - 1; - while( *ap == *ab && count > 0 ) { ++ap; ++ab; --count; } - return *ap < *ab; - } - - bool operator()( const fc::fixed_string<>& a, const std::string& b )const - { - return std::string( a ) < b; - } - - bool operator()( const std::string& a, const fc::fixed_string<>& b )const - { - return a < std::string( b ); - } - }; - - typedef fc::ripemd160 block_id_type; - typedef fc::ripemd160 checksum_type; - typedef fc::ripemd160 transaction_id_type; - typedef fc::sha256 digest_type; - typedef fc::ecc::compact_signature signature_type; - typedef safe share_type; - typedef uint16_t weight_type; + typedef fc::ecc::private_key private_key_type; + typedef fc::sha256 chain_id_type; + typedef fixed_string account_name_type; + typedef fc::ripemd160 block_id_type; + typedef fc::ripemd160 checksum_type; + typedef fc::ripemd160 transaction_id_type; + typedef fc::sha256 digest_type; + typedef fc::ecc::compact_signature signature_type; + typedef safe share_type; + typedef uint16_t weight_type; struct public_key_type diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 9f29680ae8..0fd83e6603 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -5,20 +5,6 @@ namespace steemit { namespace protocol { - /// TODO: after the hardfork, we can rename this method validate_permlink because it is strictily less restrictive than before - /// Issue #56 contains the justificiation for allowing any UTF-8 string to serve as a permlink, content will be grouped by tags - /// going forward. - inline void validate_permlink( const string& permlink ) - { - FC_ASSERT( permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH, "permlink is too long" ); - FC_ASSERT( fc::is_utf8( permlink ), "permlink not formatted in UTF8" ); - } - - inline void validate_account_name( const string& name ) - { - FC_ASSERT( is_valid_account_name( name ), "Account name ${n} is invalid", ("n", name) ); - } - bool inline is_asset_type( asset asset, asset_symbol_type symbol ) { return asset.symbol == symbol; @@ -116,8 +102,6 @@ namespace steemit { namespace protocol { FC_ASSERT( beneficiaries.size(), "Must specify at least one beneficiary" ); FC_ASSERT( beneficiaries.size() < 128, "Cannot specify more than 127 beneficiaries." ); // Require size serializtion fits in one byte. - string_less str_cmp; - validate_account_name( beneficiaries[0].account ); FC_ASSERT( beneficiaries[0].weight <= STEEMIT_100_PERCENT, "Cannot allocate more than 100% of rewards to one account" ); sum += beneficiaries[0].weight; diff --git a/libraries/time/CMakeLists.txt b/libraries/time/CMakeLists.txt deleted file mode 100644 index 2b9afb6128..0000000000 --- a/libraries/time/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -file(GLOB HEADERS "include/steemit/time/*.hpp") - -add_library( steemit_time - time.cpp - ) - -target_link_libraries( steemit_time fc ) -target_include_directories( steemit_time - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) - -install( TARGETS - steemit_time - - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) -install( FILES ${HEADERS} DESTINATION "include/steemit/time" ) diff --git a/libraries/time/include/steemit/time/time.hpp b/libraries/time/include/steemit/time/time.hpp deleted file mode 100644 index eaa4c737c6..0000000000 --- a/libraries/time/include/steemit/time/time.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -namespace steemit { namespace time { - -void set_ntp_enabled( bool enabled ); -fc::time_point now(); - -} } // steemit::time diff --git a/libraries/time/time.cpp b/libraries/time/time.cpp deleted file mode 100644 index f9ae2e3f20..0000000000 --- a/libraries/time/time.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -#include - -#include -#include - -#include - -#include - -namespace steemit { namespace time { - -fc::ntp* ntp_service = nullptr; - -void startup_ntp_time() -{ - if( ntp_service == nullptr ) - { - ntp_service = new fc::ntp; - } - else - { - wlog( "Called startup_ntp_time() when NTP already running" ); - } -} - -void shutdown_ntp_time() -{ - if( ntp_service != nullptr ) - { - delete ntp_service; - ntp_service = nullptr; - } - else - { - wlog( "Called shutdown_ntp_time() when NTP not in use" ); - } -} - -void set_ntp_enabled( bool enabled ) -{ - bool old_enabled = (ntp_service != nullptr); - if( (!old_enabled) && enabled ) - { - ilog( "Calling startup_ntp_time()" ); - startup_ntp_time(); - } - else if( old_enabled && (!enabled) ) - { - ilog( "Calling shutdown_ntp_time()" ); - shutdown_ntp_time(); - } -} - -fc::time_point now() -{ - if( ntp_service != nullptr ) - { - fc::optional< fc::time_point > ntp_time = ntp_service->get_time(); - if( ntp_time.valid() ) - return *ntp_time; - } - return fc::time_point::now(); -} - -} } // steemit::time diff --git a/libraries/wallet/include/steemit/wallet/wallet.hpp b/libraries/wallet/include/steemit/wallet/wallet.hpp index ed73366521..d00a809347 100644 --- a/libraries/wallet/include/steemit/wallet/wallet.hpp +++ b/libraries/wallet/include/steemit/wallet/wallet.hpp @@ -67,16 +67,6 @@ struct wallet_data string ws_password; }; -struct signed_block_with_info : public signed_block -{ - signed_block_with_info( const signed_block& block ); - signed_block_with_info( const signed_block_with_info& block ) = default; - - block_id_type block_id; - public_key_type signing_key; - vector< transaction_id_type > transaction_ids; -}; - enum authority_type { owner, @@ -126,7 +116,7 @@ class wallet_api * * @returns Public block data on the blockchain */ - optional get_block( uint32_t num ); + optional get_block( uint32_t num ); /** Returns sequence of operations included/generated in a specified block * @@ -997,9 +987,6 @@ FC_REFLECT( steemit::wallet::wallet_data, FC_REFLECT( steemit::wallet::brain_key_info, (brain_priv_key)(wif_priv_key) (pub_key)) -FC_REFLECT_DERIVED( steemit::wallet::signed_block_with_info, (steemit::chain::signed_block), - (block_id)(signing_key)(transaction_ids) ) - FC_REFLECT( steemit::wallet::plain_keys, (checksum)(keys) ) FC_REFLECT_ENUM( steemit::wallet::authority_type, (owner)(active)(posting) ) @@ -1050,6 +1037,10 @@ FC_API( steemit::wallet::wallet_api, (vote_for_witness) (follow) (transfer) + (escrow_transfer) + (escrow_approve) + (escrow_dispute) + (escrow_release) (transfer_to_vesting) (withdraw_vesting) (set_withdraw_vesting_route) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 4fd181c3ed..aa680c23e1 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1,3 +1,17 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + #include #include #include @@ -39,20 +53,6 @@ #include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - #ifndef WIN32 # include # include @@ -983,7 +983,7 @@ bool wallet_api::copy_wallet_file(string destination_filename) return my->copy_wallet_file(destination_filename); } -optional wallet_api::get_block(uint32_t num) +optional wallet_api::get_block(uint32_t num) { return my->_remote_db->get_block(num); } @@ -1273,16 +1273,6 @@ pair wallet_api::get_private_key_from_password( string a return std::make_pair( public_key_type( priv.get_public_key() ), key_to_wif( priv ) ); } -signed_block_with_info::signed_block_with_info( const signed_block& block ) - : signed_block( block ) -{ - block_id = id(); - signing_key = signee(); - transaction_ids.reserve( transactions.size() ); - for( const signed_transaction& tx : transactions ) - transaction_ids.push_back( tx.id() ); -} - feed_history_api_obj wallet_api::get_feed_history()const { return my->_remote_db->get_feed_history(); } /** diff --git a/programs/steemd/main.cpp b/programs/steemd/main.cpp index e52d9b360c..16f4e17da2 100644 --- a/programs/steemd/main.cpp +++ b/programs/steemd/main.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include diff --git a/programs/util/CMakeLists.txt b/programs/util/CMakeLists.txt index 94c47ca63a..50ec4962a0 100644 --- a/programs/util/CMakeLists.txt +++ b/programs/util/CMakeLists.txt @@ -78,3 +78,15 @@ install( TARGETS LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) + +add_executable( test_fixed_string test_fixed_string.cpp ) +target_link_libraries( test_fixed_string + PRIVATE steemit_chain steemit_protocol fc ${CMAKE_DL_LIB} ${PLATFORM_SPECIFIC_LIBS} ) + +install( TARGETS + test_fixed_string + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) diff --git a/programs/util/test_fixed_string.cpp b/programs/util/test_fixed_string.cpp new file mode 100644 index 0000000000..72131d6c9e --- /dev/null +++ b/programs/util/test_fixed_string.cpp @@ -0,0 +1,169 @@ + +#include + +#include + +#include +#include +#include +#include + +inline int popcount( uint32_t x ) +{ + int result = 0; + for( size_t i=0; i<8*sizeof(x); i++ ) + { + result += (x&1); + x >>= 1; + } + return result; +} + +int errors = 0; + +void check( const std::string& s, const std::string& t, + bool cond ) +{ + if( !cond ) + { + std::cout << "problem with " << s << " " << t << std::endl; + ++errors; + } +} + +void check_variant( const std::string& s, const steemit::protocol::fixed_string& fs ) +{ + fc::variant vs, vfs; + fc::to_variant( s, vs ); + fc::to_variant( fs, vfs ); + if( !(vs.is_string() && vfs.is_string() && + (vs.get_string() == s) && (vfs.get_string() == s) + ) ) + { + std::cout << "to_variant() check failed on " << s << std::endl; + ++errors; + } + + std::string s2; + steemit::protocol::fixed_string fs2; + fc::from_variant( vs, s2 ); + fc::from_variant( vfs, fs2 ); + if( s2 != s ) + { + std::cout << "from_variant() check failed on " << s << std::endl; + ++errors; + } + + if( fs2 != fs ) + { + std::cout << "from_variant() check failed on " << s << std::endl; + ++errors; + } +} + +void check_pack( const std::string& s, const steemit::protocol::fixed_string& fs ) +{ + std::stringstream ss, sfs; + fc::raw::pack( ss, s ); + fc::raw::pack( sfs, fs ); + std::string packed = ss.str(); + if( packed != sfs.str() ) + { + std::cout << "check_pack() check failed on " << s << std::endl; + ++errors; + } + + ss.seekg(0); + steemit::protocol::fixed_string unpacked; + fc::raw::unpack( ss, unpacked ); + if( unpacked != fs ) + { + std::cout << "check_pack() check failed on " << s << std::endl; + ++errors; + } +} + +int main( int argc, char** argv, char** envp ) +{ + std::vector< std::string > all_strings; + std::vector< steemit::protocol::fixed_string > all_fixed_strings; + std::vector< std::vector< uint32_t > > sim_index; + + std::cout << "setting up LUT's" << std::endl; + for( int len=0; len<=16; len++ ) + { + int b_max = 1 << len; + size_t begin_offset = all_strings.size(); + + std::vector< uint32_t > hops; + for( int b=0; b t) == (fs> ft) ); + check( s, t, (s>=t) == (fs>=ft) ); + check( s, t, (s==t) == (fs==ft) ); + check( s, t, (s!=t) == (fs!=ft) ); + } + } + + std::cout << "test_fixed_string found " << errors << " errors" << std::endl; + + int result = (errors == 0) ? 0 : 1; + return result; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 041e0a3ddc..605d111376 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,11 +8,11 @@ endif() file(GLOB UNIT_TESTS "tests/*.cpp") add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( chain_test chainbase steemit_chain steemit_protocol steemit_app steemit_account_history steemit_market_history steemit_debug_node fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( chain_test chainbase steemit_chain steemit_protocol steemit_app steemit_account_history steemit_market_history steemit_witness steemit_debug_node fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB PLUGIN_TESTS "plugin_tests/*.cpp") add_executable( plugin_test ${PLUGIN_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( plugin_test steemit_chain steemit_protocol steemit_app steemit_account_history steemit_market_history steemit_debug_node fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( plugin_test steemit_chain steemit_protocol steemit_app steemit_account_history steemit_market_history steemit_witness steemit_debug_node fc ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 41a9227afd..799107c0cf 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -40,15 +41,17 @@ clean_database_fixture::clean_database_fixture() } auto ahplugin = app.register_plugin< steemit::account_history::account_history_plugin >(); db_plugin = app.register_plugin< steemit::plugin::debug_node::debug_node_plugin >(); + auto wit_plugin = app.register_plugin< steemit::witness::witness_plugin >(); init_account_pub_key = init_account_priv_key.get_public_key(); boost::program_options::variables_map options; - open_database(); - db_plugin->logging = false; ahplugin->plugin_initialize( options ); db_plugin->plugin_initialize( options ); + wit_plugin->plugin_initialize( options ); + + open_database(); generate_block(); db.set_hardfork( STEEMIT_NUM_HARDFORKS ); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 44cfcbecdf..2d9ac0361c 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -4,11 +4,14 @@ #include #include +#include #include #include #include +#include + #include #include "../common/database_fixture.hpp" @@ -541,17 +544,6 @@ BOOST_AUTO_TEST_CASE( comment_apply ) { com.net_rshares = 10; com.abs_rshares = 10; - com.children_rshares2 = steemit::chain::util::calculate_claims( 10 ); - }); - - db.modify( mod_bob_comment, [&]( comment_object& com) - { - com.children_rshares2 = steemit::chain::util::calculate_claims( 10 ); - }); - - db.modify( mod_alice_comment, [&]( comment_object& com) - { - com.children_rshares2 = steemit::chain::util::calculate_claims( 10 ); }); db.modify( db.get_dynamic_global_properties(), [&]( dynamic_global_property_object& o) @@ -830,8 +822,6 @@ BOOST_AUTO_TEST_CASE( vote_apply ) tx.sign( sam_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - auto old_rshares2 = db.get_comment( "alice", string( "foo" ) ).children_rshares2; - op.weight = STEEMIT_100_PERCENT; op.voter = "alice"; op.author = "sam"; @@ -844,7 +834,6 @@ BOOST_AUTO_TEST_CASE( vote_apply ) auto new_rshares = ( ( fc::uint128_t( db.get_account( "alice" ).vesting_shares.amount.value ) * used_power ) / STEEMIT_100_PERCENT ).to_uint64(); - BOOST_REQUIRE( db.get_comment( "alice", string( "foo" ) ).children_rshares2 == db.get_comment( "sam", string( "foo" ) ).children_rshares2 + old_rshares2 ); BOOST_REQUIRE( db.get_comment( "alice", string( "foo" ) ).cashout_time == db.get_comment( "alice", string( "foo" ) ).created + STEEMIT_CASHOUT_WINDOW_SECONDS ); validate_database(); @@ -5639,6 +5628,7 @@ BOOST_AUTO_TEST_CASE( account_bandwidth ) { try { + BOOST_TEST_MESSAGE( "Testing: account_bandwidth" ); ACTORS( (alice)(bob) ) generate_block(); vest( "alice", ASSET( "10.000 TESTS" ) ); @@ -5648,6 +5638,8 @@ BOOST_AUTO_TEST_CASE( account_bandwidth ) generate_block(); db.skip_transaction_delta_check = false; + BOOST_TEST_MESSAGE( "--- Test first tx in block" ); + signed_transaction tx; transfer_operation op; @@ -5661,12 +5653,14 @@ BOOST_AUTO_TEST_CASE( account_bandwidth ) db.push_transaction( tx, 0 ); - auto last_bandwidth_update = db.get< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( "alice", bandwidth_type::market ) ).last_bandwidth_update; - auto average_bandwidth = db.get< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( "alice", bandwidth_type::market ) ).average_bandwidth; + auto last_bandwidth_update = db.get< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( "alice", witness::bandwidth_type::market ) ).last_bandwidth_update; + auto average_bandwidth = db.get< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( "alice", witness::bandwidth_type::market ) ).average_bandwidth; BOOST_REQUIRE( last_bandwidth_update == db.head_block_time() ); BOOST_REQUIRE( average_bandwidth == fc::raw::pack_size( tx ) * 10 * STEEMIT_BANDWIDTH_PRECISION ); auto total_bandwidth = average_bandwidth; + BOOST_TEST_MESSAGE( "--- Test second tx in block" ); + op.amount = ASSET( "0.100 TESTS" ); tx.clear(); tx.operations.push_back( op ); @@ -5675,8 +5669,8 @@ BOOST_AUTO_TEST_CASE( account_bandwidth ) db.push_transaction( tx, 0 ); - last_bandwidth_update = db.get< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( "alice", bandwidth_type::market ) ).last_bandwidth_update; - average_bandwidth = db.get< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( "alice", bandwidth_type::market ) ).average_bandwidth; + last_bandwidth_update = db.get< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( "alice", witness::bandwidth_type::market ) ).last_bandwidth_update; + average_bandwidth = db.get< witness::account_bandwidth_object, witness::by_account_bandwidth_type >( boost::make_tuple( "alice", witness::bandwidth_type::market ) ).average_bandwidth; BOOST_REQUIRE( last_bandwidth_update == db.head_block_time() ); BOOST_REQUIRE( average_bandwidth == total_bandwidth + fc::raw::pack_size( tx ) * 10 * STEEMIT_BANDWIDTH_PRECISION ); } @@ -6412,7 +6406,7 @@ BOOST_AUTO_TEST_CASE( comment_beneficiaries_apply ) tx.clear(); tx.operations.push_back( op ); tx.sign( alice_private_key, db.get_chain_id() ); - STEEMIT_REQUIRE_THROW( db.push_transaction( tx ), fc::assert_exception ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx ), chain::plugin_exception ); BOOST_TEST_MESSAGE( "--- Test specifying a non-existent benefactor" ); diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index a3e517bb7b..e5b07520e4 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -2479,8 +2479,6 @@ BOOST_AUTO_TEST_CASE( post_rate_limit ) tx.sign( alice_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - auto bandwidth = db.get< account_bandwidth_object, by_account_bandwidth_type >( boost::make_tuple( "alice", bandwidth_type::post ) ).average_bandwidth; - BOOST_REQUIRE( db.get_comment( "alice", string( "test1" ) ).reward_weight == STEEMIT_100_PERCENT ); tx.operations.clear();