Compare commits

...

81 commits

Author SHA1 Message Date
Brannon King
71fc94b1de
Merge pull request #410 from mjovanc/master 2021-11-26 18:37:08 -05:00
Marcus Cvjeticanin
927876e0c0 Changing download path artifactory URL for Boost 2021-11-26 20:52:04 +01:00
Alex Grin
73893d2f6b
Update README.md 2021-05-03 18:05:10 -04:00
Brannon King
7afc4c418a scale the cache change down a bit 2021-04-15 23:35:41 -04:00
Brannon King
db7e0b59e4 backport the rest of the depends adjustments from v17.4 2021-04-15 23:27:32 -04:00
Brannon King
1236c13a00 tweaked cache and minwork 2021-04-15 21:46:45 -04:00
Brannon King
a35385a5c0 backport wakeup fix 2021-04-15 21:15:40 -04:00
Brannon King
60a3d11df2 backport glib version fix, lsn_reset fix 2021-04-15 21:15:16 -04:00
Brannon King
cd7c2961dc rolling version 2021-04-15 10:13:33 -04:00
Alex Grintsvayg
03b1287359
Merge branch 'dnsseeds'
* dnsseeds:
  add a couple dns seeds
2021-04-13 10:12:14 -04:00
Alex Grintsvayg
131bcc8c9d
add a couple dns seeds 2021-04-12 13:49:13 -04:00
Alex Grintsvayg
29cc82db45
update github issue template 2021-04-05 10:07:20 -04:00
Brannon King
be118de19a raised default max tx fee 2019-11-26 15:16:59 -07:00
Brannon King
bf8cb69987 worked around an off-by-1 issue on the normalization fork block 2019-11-26 15:16:59 -07:00
Brannon King
37d177178f changed flush to have min height
don't flush blocks on regtest
2019-11-26 15:16:59 -07:00
gahag
f05b5973ae Implement basic log rotation (closes #211) (#344)
* Remove shrinkdebugfile flag (#211)

To implement a basic form of log rotation, two instances of the log file are to
be adopted: one for the current execution, and one for the previous
execution. On startup, if the log file exists, it will be renamed into the old
log file. This implies the deprecation and removal of the log shrink flag, since
the log is no longer forever growing.

* Implement log backup

To implement a basic form of log rotation, two instances of the log file are to
be adopted: one for the current execution, and one for the previous
execution. On startup, if the log file exists, it is renamed into the old
log file. This means that you should always have logs for the last 2 executions.

closes #211
2019-10-29 14:21:04 -06:00
Aditya J Karia
4a3c2e6504 Docs: Updated README.md files with TOC and best practices in Mar… (#339)
* Added table of contents to README.md

* Restructured headings and contents to follow Markdown best Practices
2019-10-29 14:20:05 -06:00
Bharat Raghunathan
8010681915 Update hyperlinks in README (#326) 2019-10-29 14:11:49 -06:00
GwanYeong Kim
6fe70b58ce Fix 'Use $(...) notation instead of legacy backticked ....' issue in shell script 2019-10-29 14:05:48 -06:00
Eric Brian Anil
51ec0a92f7 MIT License badge
Added the MIT license badge that redirects to the license page
2019-10-21 07:37:04 -06:00
Thomas Zarebczan
d3a8722ea8
Merge pull request #340 from addy1510/master
Fix typo in README.md
2019-10-17 21:06:08 -04:00
addy1510
ab08f6b35e
Fix typo in README.md 2019-10-18 06:33:42 +05:30
Brannon King
76e3d8861c error w/o segwit after fork 2019-10-11 14:16:38 -06:00
Brannon King
b16356b927
added segwit instructions 2019-10-10 10:50:02 -06:00
Brannon King
1bbedef565 ensure we don't return witness data in the transaction w/o segwit rule 2019-10-09 21:53:07 -06:00
Jeremy Kauffman
e5f049e5ed mention mailing list on README 2019-10-02 18:01:46 -06:00
Brannon King
9dee2eee5f windows compilation fix round 2 2019-09-30 13:58:11 -06:00
Brannon King
785471745c fixed compilation on Windows 2019-09-30 13:22:10 -06:00
Brannon King
7afebb02f4 Use memory mapped file for claim data allocations
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>

match previous serialization


tweaks


added check for RC's data
2019-09-30 12:21:55 -06:00
Brannon King
8932d90a9e rolled version, added info to chaintips 2019-09-27 09:26:26 -06:00
Brannon King
96fdb05689 added helper method, enabled signing 2019-09-26 12:29:40 -06:00
Brannon King
9149e371ed fixed fee calc issue, removed segwit enable fallback 2019-09-25 13:42:34 -06:00
Anthony Fieroni
12ab16f50e Show bid and sequence as optional parameters
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-19 10:59:15 -06:00
Anthony Fieroni
c185b49ede Show claimtrie help in cli rpc
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-19 10:59:15 -06:00
Brannon King
d05eee35e8 updated go-live heights 2019-09-18 13:53:07 -06:00
lbrynaut
4df4136c5d Fix unit tests after recent breaks. 2019-09-17 09:46:44 -06:00
Brannon King
b7cdd9f2a0 added staked totals to getwalletinfo 2019-09-16 16:04:57 -06:00
Brannon King
ffe828b1d9 rolled version, fix txindex_test, other tweaks 2019-09-16 14:54:05 -06:00
Brannon King
71bd612c4a Fix broken test on previous checkin 2019-09-16 14:49:35 -06:00
Brannon King
f176db058e change rpc enablement mechanism 2019-09-13 16:18:36 -06:00
Brannon King
b434864f18 initial commit of metadata on supports 2019-09-13 16:18:36 -06:00
Brannon King
4da4ab1995 restored nonstandard output on getrawtransaction
attempting to make index pointer problems more obvious


reverted strip in Solver


synced subtype
2019-09-13 16:16:08 -06:00
Brannon King
920a9b09dc proposed fix for issue 242 2019-09-13 16:16:08 -06:00
Brannon King
8b98a9a4e9 Organize unit tests by type
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>

moved a few more tests out
2019-09-11 09:21:45 -06:00
Anthony Fieroni
476eae3e93 Match network id to regtest
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-10 11:54:04 -06:00
Anthony Fieroni
6575fb9534 Show correct script ops in asm
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-10 10:02:16 -06:00
Brannon King
1583082acc added support for tips in RPC, minor cleanup 2019-09-06 14:03:38 -06:00
Anthony Fieroni
f71d6a4263 Introduce pending amount, the value when claim and its supports got valid
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-06 14:03:38 -06:00
Anthony Fieroni
d2b78a7fc3 Make optional claimid and amount in supportclaim
Return destination claim address as well

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-06 14:03:38 -06:00
Anthony Fieroni
a98288aa80 Logic fixes, unit test
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-06 14:03:38 -06:00
Anthony Fieroni
3a0b4232a5 Add bid, sequence like rpc methods
Reuse a bunch of rpc help texts
2019-09-06 14:03:38 -06:00
Anthony Fieroni
5bdbc9e0d6 Split help and rpc methods
Use constants for field names

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-06 14:03:38 -06:00
Anthony Fieroni
9d4ef899a6 Unify claimtrie rpc methods
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-09-06 14:03:38 -06:00
Brannon King
d0e8374636 more thoroughly tested tx signing 2019-09-05 14:17:22 -06:00
Brannon King
d2b26da3e8 added parameter for claim db cache size 2019-08-30 15:19:09 -06:00
Brannon King
59faea9815 added unit test for signing claims 2019-08-30 13:54:19 -06:00
Brannon King
ce6be620a5 setting go-live heights 2019-08-30 13:52:32 -06:00
Anthony Fieroni
580f6e20eb Implement binary tree hash algorithm
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-08-30 13:52:32 -06:00
Brannon King
7d93edf776 fix osx unit test failure 2019-08-30 09:22:58 -06:00
Brannon King
b3c5b1e88d simplified claim stripping, removed TX_CLAIM 2019-08-29 14:49:54 -06:00
Brannon King
a84c196916 reduced max open files on levelDB 2019-08-29 08:57:45 -06:00
Brannon King
b52f47f273 removed shared_ptr on TData, set minWork 2019-08-29 08:57:45 -06:00
Anthony Fieroni
e9d37a8c81 Trying to minimize disk reads / writes
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-08-29 08:57:45 -06:00
Brannon King
d96253cd40 attempted optimization of dbwrapper
it will only work for single-threaded access
2019-08-29 08:57:45 -06:00
Brannon King
4a5d310fd3 separate claim from children storage 2019-08-29 08:57:45 -06:00
Brannon King
c6e267e970 optimized a little 2019-08-29 08:57:45 -06:00
Brannon King
7b5ae24bea first pass at not loading full claimtrie into RAM
tweaks
2019-08-29 08:57:45 -06:00
lbrynaut
92037d786a Detect "claim" type transactions.
Add code to enable a hardfork into witness support, in addition to
possible BIP9 fiddling.
Fix a bug in abandonclaim and abandonsupport that burns coins on
abandon, rather than sending to the intended destination.
2019-08-28 13:35:04 -06:00
lbrynaut
494c48875d Fix unit tests. 2019-08-28 13:35:04 -06:00
Brannon King
fc0da99894 updated to support using bech32 addresses with claim ops 2019-08-28 13:35:04 -06:00
Brannon King
20e96d1233 fix unit test crash on OSX
pulled in some fixes from v18
2019-08-08 10:11:09 -06:00
Brannon King
43214bc6d2 removed superfluous fRequireTakeoverHeights 2019-07-29 10:25:41 -06:00
AlessandroSpallina
15b61996b5 fix lbrycrd-cli command typo 2019-07-29 09:54:33 -06:00
Brannon King
328ee12e8b made a new "claims" logging category (off by default) 2019-07-29 09:47:33 -06:00
Brannon King
6259378466 renamed some of the cache fields 2019-07-29 09:23:56 -06:00
Anthony Fieroni
e5c8b6b8ff Better use copies on iterate claim and support re-add
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-07-29 09:23:56 -06:00
Anthony Fieroni
c02b04f120 A bit more cleanup
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-07-29 09:23:56 -06:00
Anthony Fieroni
216cc51825 Code refactor
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-07-29 09:23:56 -06:00
Brannon King
b1aa5e04e1 revert regtest expiration change 2019-07-22 14:27:24 -06:00
Anthony Fieroni
0947307e14 Fix consensus
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-07-22 14:27:24 -06:00
Anthony Fieroni
966e7386d9 Fix expiration fork usage
Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
2019-07-22 14:27:24 -06:00
110 changed files with 10463 additions and 4850 deletions

View file

@ -1,8 +1,8 @@
<!-- This issue tracker is only for technical issues related to Bitcoin Core. <!-- This issue tracker is only for technical issues related to lbrycrd (the LBRY blockchain).
General bitcoin questions and/or support requests are best directed to the Bitcoin StackExchange at https://bitcoin.stackexchange.com. General questions and/or support requests are best directed to the community chat at https://chat.lbry.org.
For reporting security issues, please read instructions at https://bitcoincore.org/en/contact/. For reporting security issues, please email security@lbry.com.
If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue! --> If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue! -->
@ -13,7 +13,7 @@ If the node is "stuck" during sync or giving "block checksum mismatch" errors, p
<!--- How reliably can you reproduce the issue, what are the steps to do so? --> <!--- How reliably can you reproduce the issue, what are the steps to do so? -->
<!-- What version of Bitcoin Core are you using, where did you get it (website, self-compiled, etc)? --> <!-- What version of lbrycrd are you using, where did you get it (website, self-compiled, etc)? -->
<!-- What type of machine are you observing the error on (OS/CPU and disk type)? --> <!-- What type of machine are you observing the error on (OS/CPU and disk type)? -->

2
.gitignore vendored
View file

@ -119,3 +119,5 @@ contrib/devtools/split-debug.sh
.idea .idea
cmake-build-*/ cmake-build-*/
compile_commands\.json

View file

@ -7,7 +7,6 @@ cache:
stages: stages:
- build - build
- test - test
- quality
jobs: jobs:
include: include:
@ -15,7 +14,7 @@ jobs:
- &build-template - &build-template
stage: build stage: build
name: linux name: linux
env: NAME=linux EXT= env: NAME=linux DOCKER_IMAGE=lbry/build_lbrycrd_gcc EXT=
os: linux os: linux
dist: xenial dist: xenial
language: minimal language: minimal
@ -23,8 +22,9 @@ jobs:
- docker - docker
install: install:
- mkdir -p ${HOME}/ccache - mkdir -p ${HOME}/ccache
- docker pull $DOCKER_BUILD_IMAGE - docker pull $DOCKER_IMAGE
script: script:
- echo "build..."
- docker run -v "$(pwd):/lbrycrd" -v "${HOME}/ccache:/ccache" -w /lbrycrd -e CCACHE_DIR=/ccache ${DOCKER_IMAGE} packaging/build_${NAME}_64bit.sh - docker run -v "$(pwd):/lbrycrd" -v "${HOME}/ccache:/ccache" -w /lbrycrd -e CCACHE_DIR=/ccache ${DOCKER_IMAGE} packaging/build_${NAME}_64bit.sh
before_deploy: before_deploy:
- mkdir -p dist - mkdir -p dist
@ -48,11 +48,11 @@ jobs:
- <<: *build-template - <<: *build-template
name: windows name: windows
env: NAME=windows EXT=.exe env: NAME=windows DOCKER_IMAGE=lbry/build_lbrycrd EXT=.exe
- <<: *build-template - <<: *build-template
name: osx name: osx
env: NAME=darwin EXT= env: NAME=darwin DOCKER_IMAGE=lbry/build_lbrycrd EXT=
before_install: before_install:
- mkdir -p ./depends/SDKs && pushd depends/SDKs && curl -C - ${MAC_OS_SDK} | tar --skip-old-files -xJ && popd - mkdir -p ./depends/SDKs && pushd depends/SDKs && curl -C - ${MAC_OS_SDK} | tar --skip-old-files -xJ && popd
@ -63,12 +63,12 @@ jobs:
dist: xenial dist: xenial
language: minimal language: minimal
git: git:
depth: 3 clone: false
install: install:
- mkdir -p testrun && cd testrun - mkdir -p testrun && cd testrun
- curl http://build.lbry.io/lbrycrd/${TRAVIS_BRANCH}/lbrycrd-${NAME}-test.zip -o temp.zip - curl http://build.lbry.io/lbrycrd/${TRAVIS_BRANCH}/lbrycrd-${NAME}-test.zip -o temp.zip
- unzip temp.zip - unzip temp.zip
script: ./test_lbrycrd script: TRIEHASH_FUZZER_BLOCKS=1000 ./test_lbrycrd
- <<: *test-template - <<: *test-template
# os: windows # doesn't support secrets at the moment # os: windows # doesn't support secrets at the moment
@ -78,20 +78,11 @@ jobs:
services: services:
- docker - docker
script: script:
- docker pull $DOCKER_WINE_IMAGE - docker pull lbry/wine
- docker run -v "$(pwd):/test" -e "WINEDEBUG=-all" -it $DOCKER_WINE_IMAGE wine "/test/test_lbrycrd.exe" - docker run -v "$(pwd):/test" -e "WINEDEBUG=-all" -e "TRIEHASH_FUZZER_BLOCKS=1000" -it lbry/wine wine "/test/test_lbrycrd.exe"
- <<: *test-template - <<: *test-template
os: osx os: osx
osx_image: xcode8.3 osx_image: xcode8.3
env: NAME=darwin env: NAME=darwin
- stage: quality
name: "check format"
os: linux
dist: xenial
language: minimal
install:
- sudo apt-get install -y clang-format-3.9
script: git diff -U0 origin/master -- '*.h' '*.cpp' | ./contrib/devtools/clang-format-diff.py -p1

115
README.md
View file

@ -1,14 +1,35 @@
# LBRYcrd - The LBRY blockchain # LBRYcrd - The LBRY blockchain
[![Build Status](https://travis-ci.org/lbryio/lbrycrd.svg?branch=master)](https://travis-ci.org/lbryio/lbrycrd) [![Build Status](https://travis-ci.org/lbryio/lbrycrd.svg?branch=master)](https://travis-ci.org/lbryio/lbrycrd)
[![MIT licensed](https://img.shields.io/dub/l/vibe-d.svg?style=flat)](https://github.com/lbryio/lbry-desktop/blob/master/LICENSE)
LBRYcrd uses a blockchain similar to bitcoin's to implement an index and payment system for content on the LBRY network. It is a fork of bitcoin core. In addition to the libraries used by bitcoin, LBRYcrd also uses icu4c. LBRYcrd uses a blockchain similar to bitcoin's to implement an index and payment system for content on the LBRY network. It is a fork of [bitcoin core](https://github.com/bitcoin/bitcoin). In addition to the libraries used by bitcoin, LBRYcrd also uses [icu4c](https://github.com/unicode-org/icu/tree/master/icu4c).
Please read the [lbry.tech overview](https://lbry.tech/overview) for a general understanding of the LBRY pieces. From there you could read the [LBRY spec](https://spec.lbry.com/) for specifics on the data in the blockchain. Please read the [lbry.tech overview](https://lbry.tech/overview) for a general understanding of the LBRY pieces. From there you could read the [LBRY spec](https://spec.lbry.com/) for specifics on the data in the blockchain.
## Table of Contents
1. [Installation](#installation)
2. [Usage](#usage)
1. [Examples](#examples)
2. [Data directory](#data-directory)
3. [Running from Source](#running-from-source)
1. [Ubuntu with pulled static dependencies](#ubuntu-with-pulled-static-dependencies)
2. [Ubuntu with local shared dependencies](#ubuntu-with-local-shared-dependencies)
3. [MacOS (cross-compiled)](<#macos-(cross-compiled)>)
4. [MacOS with local shared dependencies](#macos-with-local-shared-dependencies)
5. [Windows (cross-compiled)](<#windows-(cross-compiled)>)
6. [Use with CLion](#use-with-clion)
4. [Contributing](#contributing)
- [Testnet](#testnet)
5. [Mailing List](#mailing-list)
6. [License](#license)
7. [Security](#security)
8. [Contact](#contact)
## Installation ## Installation
Latest binaries are available from https://github.com/lbryio/lbrycrd/releases. There is no installation procedure; the CLI binaries will run as-is and will have any uncommon dependencies statically linked into the binary. The QT GUI is not supported. LBRYcrd is distributed as a collection of executable files; traditional installers are not provided. Latest binaries are available from https://github.com/lbryio/lbrycrd/releases. There is no installation procedure; the CLI binaries will run as-is and will have any uncommon dependencies statically linked into the binary. The QT GUI is not supported. LBRYcrd is distributed as a collection of executable files; traditional installers are not provided.
## Usage ## Usage
@ -16,16 +37,17 @@ The `lbrycrdd` executable will start a LBRYcrd node and connect you to the LBRYc
to interact with lbrycrdd through the command line. Command-line help for both executables are available through to interact with lbrycrdd through the command line. Command-line help for both executables are available through
the "--help" flag (e.g. `lbrycrdd --help`). Examples: the "--help" flag (e.g. `lbrycrdd --help`). Examples:
#### Examples: #### Examples
Run `./lbrycrdd -server -daemon` to start lbrycrdd in the background. Run `./lbrycrdd -server -daemon` to start lbrycrdd in the background.
Run `./lbrycrd-cli getinfo` to check for some basic information about your LBRYcrd node. Run `./lbrycrd-cli -getinfo` to check for some basic information about your LBRYcrd node.
Run `./lbrycrd-cli help` to get a list of all commands that you can run. To get help on specific commands run `./lbrycrd-cli [command_name] help` Run `./lbrycrd-cli help` to get a list of all commands that you can run. To get help on specific commands run `./lbrycrd-cli [command_name] help`
Test locally: Test locally:
```
```sh
./lbrycrdd -server -regtest -txindex # run this in its own window ./lbrycrdd -server -regtest -txindex # run this in its own window
./lbrycrd-cli -regtest generate 120 # mine 20 spendable coins ./lbrycrd-cli -regtest generate 120 # mine 20 spendable coins
./lbrycrd-cli -regtest claimname my_name deadbeef 1 # hold a name claim with 1 coin ./lbrycrd-cli -regtest claimname my_name deadbeef 1 # hold a name claim with 1 coin
@ -35,24 +57,26 @@ Test locally:
./lbrycrd-cli -regtest stop # kill lbrycrdd ./lbrycrd-cli -regtest stop # kill lbrycrdd
rm -fr ~/.lbrycrd/regtest/ # destroy regtest data rm -fr ~/.lbrycrd/regtest/ # destroy regtest data
``` ```
For further understanding of a "regtest" setup, see the local stack setup instructions here: https://lbry.tech/resources/regtest-setup For further understanding of a "regtest" setup, see the local stack setup instructions here: https://lbry.tech/resources/regtest-setup
The CLI help is also browsable online at https://lbry.tech/api/blockchain The CLI help is also browsable online at https://lbry.tech/api/blockchain
#### Data directory: #### Data directory
Lbrycrdd will use the below default data directories (changeable with -datadir): Lbrycrdd will use the below default data directories (changeable with -datadir):
``` ```sh
Windows: %APPDATA%\lbrycrd Windows: %APPDATA%\lbrycrd
Mac: ~/Library/Application Support/lbrycrd Mac: ~/Library/Application Support/lbrycrd
Unix: ~/.lbrycrd Unix: ~/.lbrycrd
``` ```
The data directory contains various things such as your default wallet (wallet.dat), debug logs (debug.log), and blockchain data. You can optionally create a configuration file lbrycrd.conf in the default data directory which will be used by default when running lbrycrdd. The data directory contains various things such as your default wallet (wallet.dat), debug logs (debug.log), and blockchain data. You can optionally create a configuration file lbrycrd.conf in the default data directory which will be used by default when running lbrycrdd.
For a list of configuration parameters, run `./lbrycrdd --help`. Below is a sample lbrycrd.conf to enable JSON RPC server on lbrycrdd. For a list of configuration parameters, run `./lbrycrdd --help`. Below is a sample lbrycrd.conf to enable JSON RPC server on lbrycrdd.
``` ```sh
rpcuser=lbry rpcuser=lbry
rpcpassword=xyz123456790 rpcpassword=xyz123456790
daemon=1 daemon=1
@ -61,15 +85,19 @@ txindex=1
``` ```
## Running from Source ## Running from Source
The easiest way to compile is to utilize the Docker image that contains the necessary compilers: lbry/build_lbrycrd. This will allow you to reproduce the build as made on our build servers. I this sample we map a local lbrycrd folder and a local ccache folder inside the image:
``` The easiest way to compile is to utilize the Docker image that contains the necessary compilers: lbry/build_lbrycrd. This will allow you to reproduce the build as made on our build servers. In this sample we map a local lbrycrd folder and a local ccache folder inside the image:
```sh
git clone https://github.com/lbryio/lbrycrd.git git clone https://github.com/lbryio/lbrycrd.git
cd lbrycrd cd lbrycrd
docker run -v "$(pwd):/lbrycrd" --rm -v "${HOME}/ccache:/ccache" -w /lbrycrd -e CCACHE_DIR=/ccache lbry/build_lbrycrd packaging/build_linux_64bit.sh docker run -v "$(pwd):/lbrycrd" --rm -v "${HOME}/ccache:/ccache" -w /lbrycrd -e CCACHE_DIR=/ccache lbry/build_lbrycrd packaging/build_linux_64bit.sh
``` ```
Some examples of compiling directly: Some examples of compiling directly:
#### Ubuntu with pulled static dependencies:
``` #### Ubuntu with pulled static dependencies
```sh
sudo apt install build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates sudo apt install build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates
git clone https://github.com/lbryio/lbrycrd.git git clone https://github.com/lbryio/lbrycrd.git
cd lbrycrd cd lbrycrd
@ -77,16 +105,20 @@ cd lbrycrd
./src/test/test_lbrycrd ./src/test/test_lbrycrd
``` ```
Other Linux distros would be similar. The build shell script is fairly trivial; take a peek at its contents. Other Linux distros would be similar. The build shell script is fairly trivial; take a peek at its contents.
#### Ubuntu with local shared dependencies:
#### Ubuntu with local shared dependencies
Note: using untested dependencies may lead to conflicting results. Note: using untested dependencies may lead to conflicting results.
```
```sh
sudo add-apt-repository ppa:bitcoin/bitcoin sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update sudo apt-get update
sudo apt-get install libdb4.8-dev libdb4.8++-dev libicu-dev libssl-dev libevent-dev \ sudo apt-get install libdb4.8-dev libdb4.8++-dev libicu-dev libssl-dev libevent-dev \
build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \ build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \
libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev
# optionally include libminiupnpc-dev libzmq3-dev # optionally include libminiupnpc-dev libzmq3-dev
git clone https://github.com/lbryio/lbrycrd.git git clone https://github.com/lbryio/lbrycrd.git
@ -97,11 +129,13 @@ make -j$(nproc)
./src/lbrycrdd -server ... ./src/lbrycrdd -server ...
``` ```
#### MacOS (cross-compiled):
``` #### MacOS (cross-compiled)
```sh
sudo apt-get install clang llvm git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \ sudo apt-get install clang llvm git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \
libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev
git clone https://github.com/lbryio/lbrycrd.git git clone https://github.com/lbryio/lbrycrd.git
cd lbrycrd cd lbrycrd
# download MacOS SDK from your favorite source # download MacOS SDK from your favorite source
@ -110,9 +144,12 @@ tar ... extract SDK to depends/SDKs/MacOSX10.11.sdk
./packaging/build_darwin_64bit.sh ./packaging/build_darwin_64bit.sh
``` ```
Look in packaging/build_darwin_64bit.sh for further understanding. Look in packaging/build_darwin_64bit.sh for further understanding.
#### MacOS with local shared dependencies:
``` #### MacOS with local shared dependencies
```sh
brew install boost berkeley-db@4 icu4c libevent brew install boost berkeley-db@4 icu4c libevent
# fix conflict with gawk pulled first: # fix conflict with gawk pulled first:
brew reinstall readline brew reinstall readline
@ -127,14 +164,17 @@ CONFIG_SITE=$(pwd)/depends/x86_64-apple-darwin15.6.0/share/config.site ./configu
make -j$(sysctl -n hw.ncpu) make -j$(sysctl -n hw.ncpu)
``` ```
#### Windows (cross-compiled):
#### Windows (cross-compiled)
Compiling on MS Windows (outside of WSL) is not supported. The Windows build is cross-compiled from Linux like so: Compiling on MS Windows (outside of WSL) is not supported. The Windows build is cross-compiled from Linux like so:
```
```sh
sudo apt-get install build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \ sudo apt-get install build-essential git libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates \
g++-mingw-w64-x86-64 mingw-w64-x86-64-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
git clone https://github.com/lbryio/lbrycrd.git git clone https://github.com/lbryio/lbrycrd.git
cd lbrycrd cd lbrycrd
./packaging/build_windows_64bit.sh ./packaging/build_windows_64bit.sh
@ -143,13 +183,16 @@ cd lbrycrd
If you encounter any errors, please check `doc/build-*.md` for further instructions. If you're still stuck, [create an issue](https://github.com/lbryio/lbrycrd/issues/new) with the output of that command, your system info, and any other information you think might be helpful. The scripts in the packaging folder are simple and will grant extra light on the build process as needed. If you encounter any errors, please check `doc/build-*.md` for further instructions. If you're still stuck, [create an issue](https://github.com/lbryio/lbrycrd/issues/new) with the output of that command, your system info, and any other information you think might be helpful. The scripts in the packaging folder are simple and will grant extra light on the build process as needed.
#### Use with CLion: #### Use with CLion
CLion has not traditionally supported Autotools projects, although some progress on that is now in the works. We do include a cmake build file for compiling lbrycrd. See contrib/cmake. Alas, CLion doesn't support external projects in cmake, so that particular approach is also insufficient. CLion does support "compile_commands.json" projects. Fortunately, this can be easily generated for lbrycrd like so: CLion has not traditionally supported Autotools projects, although some progress on that is now in the works. We do include a cmake build file for compiling lbrycrd. See contrib/cmake. Alas, CLion doesn't support external projects in cmake, so that particular approach is also insufficient. CLion does support "compile_commands.json" projects. Fortunately, this can be easily generated for lbrycrd like so:
```
```sh
pip install --user compiledb pip install --user compiledb
./autogen.sh && ./configure --enable-static=no --enable-shared --with-pic --without-gui CXXFLAGS="-O0 -g" CFLAGS="-O0 -g" # or whatever normal lbrycrd config ./autogen.sh && ./configure --enable-static=no --enable-shared --with-pic --without-gui CXXFLAGS="-O0 -g" CFLAGS="-O0 -g" # or whatever normal lbrycrd config
compiledb make -j10 compiledb make -j10
``` ```
Then open the newly generated compile_commands.json file as a project in CLion. Debugging is supported if you compiled with `-g`. To enable that you will need to create a target in CLion by going to File -> Settings -> Build -> Custom Build Targets. Add an empty target with your choice of name. From there you can go to "Edit Configurations", typically found in a drop-down at the top of the editor. Add a Custom Build Application, select your new target, select the compiled file (i.e. test_lbrycrd or lbrycrdd, etc), and then add any necessary command line parameters. Ensure that there is nothing in the "Before launch" section. Then open the newly generated compile_commands.json file as a project in CLion. Debugging is supported if you compiled with `-g`. To enable that you will need to create a target in CLion by going to File -> Settings -> Build -> Custom Build Targets. Add an empty target with your choice of name. From there you can go to "Edit Configurations", typically found in a drop-down at the top of the editor. Add a Custom Build Application, select your new target, select the compiled file (i.e. test_lbrycrd or lbrycrdd, etc), and then add any necessary command line parameters. Ensure that there is nothing in the "Before launch" section.
## Contributing ## Contributing
@ -167,8 +210,8 @@ regularly to indicate new official, stable release versions.
Testing and code review is the bottleneck for development; we get more pull Testing and code review is the bottleneck for development; we get more pull
requests than we can review and test on short notice. Please be patient and help out by testing requests than we can review and test on short notice. Please be patient and help out by testing
other people's pull requests, and remember this is a security-critical project where any mistake might cost people other people's pull requests, and remember this is a security-critical project where any mistake might cost people
lots of money. Developers are strongly encouraged to write [unit tests](/doc/unit-tests.md) for new code and to lots of money. Developers are strongly encouraged to write [unit tests](/src/test/README.md) for new code and to
submit new unit tests for old code. Unit tests are compiled by default and can be run with `src/test/test_lbrycrd`. submit new unit tests for old code. Unit tests are compiled by default and can be run with `src/test/test_lbrycrd`
The Travis CI system makes sure that every pull request is built, and that unit and sanity tests are automatically run. See https://travis-ci.org/lbryio/lbrycrd The Travis CI system makes sure that every pull request is built, and that unit and sanity tests are automatically run. See https://travis-ci.org/lbryio/lbrycrd
@ -176,7 +219,11 @@ The Travis CI system makes sure that every pull request is built, and that unit
Testnet is maintained for testing purposes and can be accessed using the command `./lbrycrdd -testnet`. If you would like to obtain testnet credits, please contact brannon@lbry.com or grin@lbry.com . Testnet is maintained for testing purposes and can be accessed using the command `./lbrycrdd -testnet`. If you would like to obtain testnet credits, please contact brannon@lbry.com or grin@lbry.com .
It is easy to solo mine on testnet. (It's easy on mainnet too, but much harder to win.) For instructions see https://github.com/lbryio/sgminer-gm and https://github.com/lbryio/lbrycrd/tree/master/contrib/mining It is easy to solo mine on testnet. (It's easy on mainnet too, but much harder to win.) For instructions see [SGMiner](https://github.com/lbryio/sgminer-gm) and [Mining Contributions](https://github.com/lbryio/lbrycrd/tree/master/contrib/mining)
## Mailing List
We maintain a mailing list for notifications of upgrades, security issues, and soft/hard forks. To join, visit [https://lbry.com/forklist](https://lbry.com/forklist).
## License ## License
@ -184,11 +231,9 @@ This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
## Security ## Security
We take security seriously. Please contact security@lbry.com regarding any security issues. We take security seriously. Please contact [security@lbry.com](mailto:security@lbry.com) regarding any security issues.
Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it. Our PGP key is [here](https://lbry.com/faq/pgp-key) if you need it.
## Contact ## Contact
The primary contact for this project is [@BrannonKing](https://github.com/BrannonKing) (brannon@lbry.com) The primary contact for this project is [@BrannonKing](https://github.com/BrannonKing) (brannon@lbry.com)

View file

@ -7,7 +7,7 @@ export LC_ALL=C
set -e set -e
srcdir="$(dirname $0)" srcdir="$(dirname $0)"
cd "$srcdir" cd "$srcdir"
if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="$(which glibtoolize 2>/dev/null)"; then
LIBTOOLIZE="${GLIBTOOLIZE}" LIBTOOLIZE="${GLIBTOOLIZE}"
export LIBTOOLIZE export LIBTOOLIZE
fi fi

View file

@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 17) define(_CLIENT_VERSION_MINOR, 17)
define(_CLIENT_VERSION_REVISION, 2) define(_CLIENT_VERSION_REVISION, 3)
define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_BUILD, 3)
define(_CLIENT_VERSION_IS_RELEASE, true) define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2019) define(_COPYRIGHT_YEAR, 2021)
define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[LBRYcrd Core]]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[LBRYcrd Core]])
AC_INIT([LBRYcrd Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/lbryio/lbrycrd/issues],[lbrycrd],[https://lbry.com/]) AC_INIT([LBRYcrd Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/lbryio/lbrycrd/issues],[lbrycrd],[https://lbry.com/])

View file

@ -36,13 +36,13 @@ if [ -z "${CODESIGN_ALLOCATE}" ]; then
fi fi
find ${TEMPDIR} -name "*.sign" | while read i; do find ${TEMPDIR} -name "*.sign" | while read i; do
SIZE=`stat -c %s "${i}"` SIZE=$(stat -c %s "${i}")
TARGET_FILE="`echo "${i}" | sed 's/\.sign$//'`" TARGET_FILE="$(echo "${i}" | sed 's/\.sign$//')"
echo "Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}" echo "Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}"
${CODESIGN_ALLOCATE} -i "${TARGET_FILE}" -a ${ARCH} ${SIZE} -o "${i}.tmp" ${CODESIGN_ALLOCATE} -i "${TARGET_FILE}" -a ${ARCH} ${SIZE} -o "${i}.tmp"
OFFSET=`${PAGESTUFF} "${i}.tmp" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` OFFSET=$(${PAGESTUFF} "${i}.tmp" -p | tail -2 | grep offset | sed 's/[^0-9]*//g')
if [ -z ${QUIET} ]; then if [ -z ${QUIET} ]; then
echo "Attaching signature at offset ${OFFSET}" echo "Attaching signature at offset ${OFFSET}"
fi fi

View file

@ -27,19 +27,19 @@ ${CODESIGN} -f --file-list ${TEMPLIST} "$@" "${BUNDLE}"
grep -v CodeResources < "${TEMPLIST}" | while read i; do grep -v CodeResources < "${TEMPLIST}" | while read i; do
TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`" TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`"
SIZE=`pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g'` SIZE=$(pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g')
OFFSET=`pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'` OFFSET=$(pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g')
SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign" SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign"
DIRNAME="`dirname "${SIGNFILE}"`" DIRNAME="$(dirname "${SIGNFILE}")"
mkdir -p "${DIRNAME}" mkdir -p "${DIRNAME}"
echo "Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}" echo "Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}"
dd if="$i" of="${SIGNFILE}" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null dd if="$i" of="${SIGNFILE}" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null
done done
grep CodeResources < "${TEMPLIST}" | while read i; do grep CodeResources < "${TEMPLIST}" | while read i; do
TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`" TARGETFILE="${BUNDLE}/$(echo "${i}" | sed "s|.*${BUNDLE}/||")"
RESOURCE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}" RESOURCE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}"
DIRNAME="`dirname "${RESOURCE}"`" DIRNAME="$(dirname "${RESOURCE}")"
mkdir -p "${DIRNAME}" mkdir -p "${DIRNAME}"
echo "Adding resource for: \"${TARGETFILE}\"" echo "Adding resource for: \"${TARGETFILE}\""
cp "${i}" "${RESOURCE}" cp "${i}" "${RESOURCE}"

View file

@ -36,7 +36,7 @@ insert into coins(name, symbol, symbol2, algo, enable, auto_ready, rpcuser, rpcp
values('Local LBRY Instance', 'LBC', 'LBC', 'lbry', 1, 1, 'ruser', 'rpswd', '127.0.0.1', 19245, 1, 'utf-8', 0, 1, 0, 0, 0); values('Local LBRY Instance', 'LBC', 'LBC', 'lbry', 1, 1, 'ruser', 'rpswd', '127.0.0.1', 19245, 1, 'utf-8', 0, 1, 0, 0, 0);
exit exit
``` ```
Use port 19245 for testnet, port 9245 for main. Use port 19245 for testnet, port 9245 for main. Set usesegwit to 1 after the segwit fork is enabled on December 11, 2019.
#### 3. Run the stratum server: #### 3. Run the stratum server:
``` ```
docker run --network host -d lbry/yiimp_stratum docker run --network host -d lbry/yiimp_stratum
@ -47,10 +47,11 @@ docker run --network host -it lbry/yiimp_stratum bash
cat config/lbry.conf cat config/lbry.conf
./stratum config/lbry ./stratum config/lbry
``` ```
When testing with an ASIC you may need to modify the TCP server address in said lbry.conf file to be an external IP address.
#### 4. Connect sgminer to it: #### 4. Connect sgminer to it:
``` ```
sgminer -k lbry -o stratum+tcp://127.0.0.1:3334/ -D -T -O mn824Su1wX7ip8WcNYzXwwWqvBvkeWGRo6:x sgminer -k lbry -o stratum+tcp://127.0.0.1:3334/ -D -T -O mn824Su1wX7ip8WcNYzXwwWqvBvkeWGRo6:x
``` ```
The username there is the account to receive payments from the pool. The password is unused. Tested with https://github.com/lbryio/sgminer-gm. The username there is the account to receive payments from the pool. The password is unused. Tested with https://github.com/lbryio/sgminer-gm.
You can use whatever miner you prefer. You can use whatever miner you prefer.

View file

@ -23,7 +23,7 @@ TIMESERVER=http://timestamp.comodoca.com
CERTFILE="win-codesign.cert" CERTFILE="win-codesign.cert"
mkdir -p "${OUTSUBDIR}" mkdir -p "${OUTSUBDIR}"
basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do basename -a $(ls -1 "${SRCDIR}"/*-unsigned.exe) | while read UNSIGNED; do
echo Signing "${UNSIGNED}" echo Signing "${UNSIGNED}"
"${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@" "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
"${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}" "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}"

View file

@ -131,7 +131,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@build_os@|$(build_os)|' \ -e 's|@build_os@|$(build_os)|' \
-e 's|@host_os@|$(host_os)|' \ -e 's|@host_os@|$(host_os)|' \
-e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \
-e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ -e 's|@CXXFLAGS@|$(strip -pipe $(host_$(release_type)_CXXFLAGS))|' \
-e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \
-e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \
-e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \

File diff suppressed because it is too large Load diff

View file

@ -7,12 +7,13 @@ darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) -isysroo
darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) -isysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -B $(host_prefix)/native/bin darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) -isysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -B $(host_prefix)/native/bin
darwin_CFLAGS=-pipe darwin_CFLAGS=-pipe
darwin_CXXFLAGS=$(darwin_CFLAGS) darwin_CXXFLAGS=$(darwin_CFLAGS) -std=c++11
darwin_release_CFLAGS=-O2 darwin_release_CFLAGS=-O2 -g
darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) darwin_release_CXXFLAGS=$(darwin_release_CFLAGS)
darwin_debug_CFLAGS=-Og darwin_debug_CFLAGS=-Og -g
darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) darwin_debug_CXXFLAGS=-O0 -g
darwin_native_toolchain=native_cctools
darwin_native_toolchain=native_cctools

View file

@ -1,11 +1,14 @@
linux_CFLAGS=-pipe linux_CFLAGS=-pipe
linux_CXXFLAGS=$(linux_CFLAGS) linux_CXXFLAGS=$(linux_CFLAGS) -std=c++11
linux_release_CFLAGS=-O2 linux_release_CFLAGS=-O3 -g
ifeq (1,$(shell ldd --version | head -1 | awk '{print $$NF < 2.28}'))
linux_release_CFLAGS+= -include $(BASEDIR)/glibc_version_header/force_link_glibc_2.19.h
endif
linux_release_CXXFLAGS=$(linux_release_CFLAGS) linux_release_CXXFLAGS=$(linux_release_CFLAGS)
linux_debug_CFLAGS=-Og linux_debug_CFLAGS=-O1 -g
linux_debug_CXXFLAGS=$(linux_debug_CFLAGS) linux_debug_CXXFLAGS=-O0 -g
linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC

View file

@ -1,10 +1,11 @@
mingw32_CFLAGS=-pipe mingw32_CFLAGS=-pipe
mingw32_CXXFLAGS=$(mingw32_CFLAGS) mingw32_CXXFLAGS=$(mingw32_CFLAGS) -std=c++11
mingw32_release_CFLAGS=-O2 mingw32_release_CFLAGS=-O2 -g
mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS)
mingw32_debug_CFLAGS=-O1 mingw32_debug_CFLAGS=-O1 -g
mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) mingw32_debug_CXXFLAGS=-O0 -g
mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC

View file

@ -1,6 +1,6 @@
package=bdb package=bdb
$(package)_version=4.8.30 $(package)_version=4.8.30
$(package)_download_path=http://download.oracle.com/berkeley-db $(package)_download_path=https://download.oracle.com/berkeley-db
$(package)_file_name=db-$($(package)_version).NC.tar.gz $(package)_file_name=db-$($(package)_version).NC.tar.gz
$(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef $(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef
$(package)_build_subdir=build_unix $(package)_build_subdir=build_unix
@ -9,7 +9,7 @@ define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts=--disable-shared --enable-cxx --disable-replication
$(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_mingw32=--enable-mingw
$(package)_config_opts_linux=--with-pic $(package)_config_opts_linux=--with-pic
$(package)_cxxflags=-std=c++11 $(package)_cppflags_mingw32=-DUNICODE -D_UNICODE
endef endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
@ -29,3 +29,4 @@ endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install_lib install_include $(MAKE) DESTDIR=$($(package)_staging_dir) install_lib install_include
endef endef

View file

@ -1,6 +1,6 @@
package=boost package=boost
$(package)_version=1_69_0 $(package)_version=1_69_0
$(package)_download_path=https://dl.bintray.com/boostorg/release/1.69.0/source/ $(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/1.69.0/source/
$(package)_file_name=$(package)_$($(package)_version).tar.bz2 $(package)_file_name=$(package)_$($(package)_version).tar.bz2
$(package)_sha256_hash=8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406 $(package)_sha256_hash=8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406
$(package)_dependencies=icu $(package)_dependencies=icu

View file

@ -22,7 +22,6 @@ define $(package)_preprocess_cmds
PKG_CONFIG_SYSROOT_DIR=/ \ PKG_CONFIG_SYSROOT_DIR=/ \
PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig \ PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig \
PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig \ PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig \
sed -i.old 's/^GEN_DEPS.cc.*/& $(CXXFLAGS)/' source/config/mh-mingw* && \
mkdir -p build && cd build && \ mkdir -p build && cd build && \
../source/runConfigureICU Linux $($(package)_standard_opts) CXXFLAGS=-std=c++11 && \ ../source/runConfigureICU Linux $($(package)_standard_opts) CXXFLAGS=-std=c++11 && \
$(MAKE) && cd .. $(MAKE) && cd ..
@ -32,6 +31,8 @@ define $(package)_config_cmds
PKG_CONFIG_SYSROOT_DIR=/ \ PKG_CONFIG_SYSROOT_DIR=/ \
PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig \ PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig \
PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig \ PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig \
sed -i.old 's|^GEN_DEPS.c=.*|& $($(package)_cflags)|' config/mh-mingw* && \
sed -i.old 's|^GEN_DEPS.cc=.*|& $($(package)_cxxflags)|' config/mh-mingw* && \
$($(package)_autoconf) $($(package)_autoconf)
endef endef

View file

@ -27,4 +27,5 @@ define $(package)_stage_cmds
endef endef
define $(package)_postprocess_cmds define $(package)_postprocess_cmds
rm lib/*.la
endef endef

View file

@ -1,6 +1,6 @@
package=miniupnpc package=miniupnpc
$(package)_version=2.0.20180203 $(package)_version=2.0.20180203
$(package)_download_path=http://miniupnp.free.fr/files $(package)_download_path=https://miniupnp.tuxfamily.org/files/
$(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7 $(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7

View file

@ -5,7 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c $(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c
define $(package)_set_vars define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc) $($(package)_cflags) $($(package)_cppflags)"
$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl
$(package)_config_opts+=no-camellia $(package)_config_opts+=no-camellia
$(package)_config_opts+=no-capieng $(package)_config_opts+=no-capieng
@ -42,7 +42,6 @@ $(package)_config_opts+=no-weak-ssl-ciphers
$(package)_config_opts+=no-whirlpool $(package)_config_opts+=no-whirlpool
$(package)_config_opts+=no-zlib $(package)_config_opts+=no-zlib
$(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=no-zlib-dynamic
$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags)
$(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_linux=-fPIC -Wa,--noexecstack
$(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_x86_64_linux=linux-x86_64
$(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_i686_linux=linux-generic32

View file

@ -4,7 +4,6 @@ $(package)_download_path=$(native_$(package)_download_path)
$(package)_file_name=$(native_$(package)_file_name) $(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash) $(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package) $(package)_dependencies=native_$(package)
$(package)_cxxflags=-std=c++11
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc

View file

@ -6,9 +6,10 @@ $(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d83
$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch $(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror --disable-drafts
$(package)_config_opts += --without-libsodium --without-libgssapi_krb5 --without-pgm --without-norm --without-vmci
$(package)_config_opts += --disable-libunwind --disable-radix-tree --without-gcov
$(package)_config_opts_linux=--with-pic $(package)_config_opts_linux=--with-pic
$(package)_cxxflags=-std=c++11
endef endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
@ -31,5 +32,5 @@ endef
define $(package)_postprocess_cmds define $(package)_postprocess_cmds
sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \ sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \
rm -rf bin share rm -rf bin share lib/*.la
endef endef

View file

@ -30,13 +30,13 @@ if which ccache >/dev/null; then
fi fi
pushd depends pushd depends
make -j`getconf _NPROCESSORS_ONLN` HOST=x86_64-apple-darwin14 NO_QT=1 V=1 make -j$(getconf _NPROCESSORS_ONLN) HOST=x86_64-apple-darwin14 NO_QT=1 V=1
popd popd
./autogen.sh ./autogen.sh
DEPS_DIR=`pwd`/depends/x86_64-apple-darwin14 DEPS_DIR=$(pwd)/depends/x86_64-apple-darwin14
CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --enable-reduce-exports --without-gui --with-icu="${DEPS_DIR}" --enable-static --disable-shared CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --enable-reduce-exports --without-gui --with-icu="${DEPS_DIR}" --enable-static --disable-shared
make -j`getconf _NPROCESSORS_ONLN` make -j$(getconf _NPROCESSORS_ONLN)
${DEPS_DIR}/native/bin/x86_64-apple-darwin14-strip src/lbrycrdd src/lbrycrd-cli src/lbrycrd-tx ${DEPS_DIR}/native/bin/x86_64-apple-darwin14-strip src/lbrycrdd src/lbrycrd-cli src/lbrycrd-tx
if which ccache >/dev/null; then if which ccache >/dev/null; then

View file

@ -20,13 +20,13 @@ export CXXFLAGS="${CXXFLAGS:--frecord-gcc-switches}"
echo "CXXFLAGS set to $CXXFLAGS" echo "CXXFLAGS set to $CXXFLAGS"
cd depends cd depends
make -j`getconf _NPROCESSORS_ONLN` HOST=x86_64-pc-linux-gnu NO_QT=1 V=1 make -j$(getconf _NPROCESSORS_ONLN) HOST=x86_64-pc-linux-gnu NO_QT=1 V=1
cd .. cd ..
./autogen.sh ./autogen.sh
DEPS_DIR=`pwd`/depends/x86_64-pc-linux-gnu DEPS_DIR=$(pwd)/depends/x86_64-pc-linux-gnu
CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --enable-static --disable-shared --with-pic --without-gui CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --enable-static --disable-shared --with-pic --without-gui
make -j`getconf _NPROCESSORS_ONLN` make -j$(getconf _NPROCESSORS_ONLN)
strip src/lbrycrdd src/lbrycrd-cli src/lbrycrd-tx strip src/lbrycrdd src/lbrycrd-cli src/lbrycrd-tx
if which ccache >/dev/null; then if which ccache >/dev/null; then
@ -34,4 +34,4 @@ if which ccache >/dev/null; then
ccache -s ccache -s
fi fi
echo "Linux 64bit build is complete" echo "Linux 64bit build is complete"

View file

@ -20,17 +20,14 @@ if which ccache >/dev/null; then
ccache -ps ccache -ps
fi fi
export CXXFLAGS="${CXXFLAGS:--frecord-gcc-switches}"
echo "CXXFLAGS set to $CXXFLAGS"
pushd depends pushd depends
make -j`getconf _NPROCESSORS_ONLN` HOST=i686-w64-mingw32 NO_QT=1 V=1 make -j$(getconf _NPROCESSORS_ONLN) HOST=i686-w64-mingw32 NO_QT=1 V=1
popd popd
./autogen.sh ./autogen.sh
DEPS_DIR=`pwd`/depends/i686-w64-mingw32 DEPS_DIR=$(pwd)/depends/i686-w64-mingw32
CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --prefix=/ --without-gui --with-icu="$DEPS_DIR" --enable-static --disable-shared CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --prefix=/ --without-gui --with-icu="$DEPS_DIR" --enable-static --disable-shared
make -j`getconf _NPROCESSORS_ONLN` make -j$(getconf _NPROCESSORS_ONLN)
i686-w64-mingw32-strip src/lbrycrdd.exe src/lbrycrd-cli.exe src/lbrycrd-tx.exe i686-w64-mingw32-strip src/lbrycrdd.exe src/lbrycrd-cli.exe src/lbrycrd-tx.exe
if which ccache >/dev/null; then if which ccache >/dev/null; then

View file

@ -19,17 +19,14 @@ if which ccache >/dev/null; then
ccache -ps ccache -ps
fi fi
export CXXFLAGS="${CXXFLAGS:--frecord-gcc-switches}"
echo "CXXFLAGS set to $CXXFLAGS"
pushd depends pushd depends
make -j`getconf _NPROCESSORS_ONLN` HOST=x86_64-w64-mingw32 NO_QT=1 V=1 make -j$(getconf _NPROCESSORS_ONLN) HOST=x86_64-w64-mingw32 NO_QT=1 V=1
popd popd
./autogen.sh ./autogen.sh
DEPS_DIR=`pwd`/depends/x86_64-w64-mingw32 DEPS_DIR=$(pwd)/depends/x86_64-w64-mingw32
CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --prefix=/ --without-gui --with-icu="$DEPS_DIR" --enable-static --disable-shared CONFIG_SITE=${DEPS_DIR}/share/config.site ./configure --prefix=/ --without-gui --with-icu="$DEPS_DIR" --enable-static --disable-shared
make -j`getconf _NPROCESSORS_ONLN` make -j$(getconf _NPROCESSORS_ONLN)
x86_64-w64-mingw32-strip src/lbrycrdd.exe src/lbrycrd-cli.exe src/lbrycrd-tx.exe x86_64-w64-mingw32-strip src/lbrycrdd.exe src/lbrycrd-cli.exe src/lbrycrd-tx.exe
if which ccache >/dev/null; then if which ccache >/dev/null; then

View file

@ -155,6 +155,7 @@ BITCOIN_CORE_H = \
reverse_iterator.h \ reverse_iterator.h \
reverselock.h \ reverselock.h \
rpc/blockchain.h \ rpc/blockchain.h \
rpc/claimrpchelp.h \
rpc/client.h \ rpc/client.h \
rpc/mining.h \ rpc/mining.h \
rpc/protocol.h \ rpc/protocol.h \

View file

@ -66,6 +66,11 @@ BITCOIN_TESTS =\
test/net_tests.cpp \ test/net_tests.cpp \
test/claimtriecache_tests.cpp \ test/claimtriecache_tests.cpp \
test/claimtriebranching_tests.cpp \ test/claimtriebranching_tests.cpp \
test/claimtrieexpirationfork_tests.cpp \
test/claimtriefixture.cpp \
test/claimtriehashfork_tests.cpp \
test/claimtrienormalization_tests.cpp \
test/claimtrierpc_tests.cpp \
test/nameclaim_tests.cpp \ test/nameclaim_tests.cpp \
test/netbase_tests.cpp \ test/netbase_tests.cpp \
test/pmt_tests.cpp \ test/pmt_tests.cpp \

View file

@ -98,7 +98,7 @@ bool DeserializeFileDB(const fs::path& path, Data& data)
FILE *file = fsbridge::fopen(path, "rb"); FILE *file = fsbridge::fopen(path, "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION); CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull()) if (filein.IsNull())
return error("%s: Failed to open file %s", __func__, path.string()); return false;
return DeserializeDB(filein, data); return DeserializeDB(filein, data);
} }

View file

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bloom.h> #include <bloom.h>
#include <nameclaim.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <hash.h> #include <hash.h>

View file

@ -123,7 +123,7 @@ void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64
class CMainParams : public CChainParams { class CMainParams : public CChainParams {
public: public:
CMainParams() { CMainParams() {
strNetworkID = "lbrycrd"; strNetworkID = CBaseChainParams::MAIN;
consensus.nSubsidyLevelInterval = 1<<5; consensus.nSubsidyLevelInterval = 1<<5;
consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityEnforceBlockUpgrade = 750;
consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityRejectBlockOutdated = 950;
@ -144,7 +144,9 @@ public:
consensus.nAllowMinDiffMaxHeight = -1; consensus.nAllowMinDiffMaxHeight = -1;
consensus.nNormalizedNameForkHeight = 539940; // targeting 21 March 2019 consensus.nNormalizedNameForkHeight = 539940; // targeting 21 March 2019
consensus.nMinTakeoverWorkaroundHeight = 496850; consensus.nMinTakeoverWorkaroundHeight = 496850;
consensus.nMaxTakeoverWorkaroundHeight = 10000000; consensus.nMaxTakeoverWorkaroundHeight = 658300; // targeting 30 Oct 2019
consensus.nWitnessForkHeight = 680770; // targeting 11 Dec 2019
consensus.nAllClaimsInMerkleForkHeight = 658310; // targeting 30 Oct 2019
consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1916; // 95% of a half week consensus.nRuleChangeActivationThreshold = 1916; // 95% of a half week
@ -158,17 +160,16 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
// Deployment of SegWit (BIP141, BIP143, and BIP147) // Deployment of SegWit (BIP141, BIP143, and BIP147) -- Unused (see nWitnessForkHeight).
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1547942400; // Jan 20, 2019 consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1547942400; // Jan 20, 2019
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1548288000; // Jan 24, 2019 consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1548288000; // Jan 24, 2019
// The best chain should have at least this much work. // The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000607ca7e806c4c1e9"); //400000 consensus.nMinimumChainWork = uint256S("000000000000000000000000000000000000000000000499ed6684d1bf6f6fd3"); //946000
// By default assume that the signatures in ancestors of this block are valid. // By default assume that the signatures in ancestors of this block are valid.
//consensus.defaultAssumeValid = uint256S("0xf0e56e70782af63ccb49c76e852540688755869ba59ec68cac9c04a6b4d9f5ca"); //400000 consensus.defaultAssumeValid = uint256S("0d3b537afe49820e1c6efc555463f955251b1293c6e5130137e1e25744431172"); //946000
consensus.defaultAssumeValid = uint256S("0xa6bbb48f5343eb9b0287c22f3ea8b29f36cf10794a37f8a925a894d6f4519913"); //4000
/** /**
* The message start string is designed to be unlikely to occur in normal data. * The message start string is designed to be unlikely to occur in normal data.
@ -194,9 +195,11 @@ public:
vSeeds.clear(); vSeeds.clear();
vFixedSeeds.clear(); vFixedSeeds.clear();
vSeeds.emplace_back("dnsseed1.lbry.io"); // lbry.io vSeeds.emplace_back("dnsseed1.lbry.io"); // LBRY Inc
vSeeds.emplace_back("dnsseed2.lbry.io"); // lbry.io vSeeds.emplace_back("dnsseed2.lbry.io"); // LBRY Inc
vSeeds.emplace_back("dnsseed3.lbry.io"); // lbry.io vSeeds.emplace_back("dnsseed3.lbry.io"); // LBRY Inc
vSeeds.emplace_back("seed.lbry.grin.io"); // Grin
vSeeds.emplace_back("seed.allaboutlbc.com"); // Madiator2011
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 0x55); base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 0x55);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 0x7a); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 0x7a);
@ -204,8 +207,6 @@ public:
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E}; base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4}; base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
bech32_hrp = "lbc"; bech32_hrp = "lbc";
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
@ -240,7 +241,7 @@ public:
class CTestNetParams : public CChainParams { class CTestNetParams : public CChainParams {
public: public:
CTestNetParams() { CTestNetParams() {
strNetworkID = "lbrycrdtest"; strNetworkID = CBaseChainParams::TESTNET;
consensus.nSubsidyLevelInterval = 1 << 5; consensus.nSubsidyLevelInterval = 1 << 5;
consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityRejectBlockOutdated = 75;
@ -261,7 +262,9 @@ public:
consensus.nAllowMinDiffMaxHeight = 1100000; consensus.nAllowMinDiffMaxHeight = 1100000;
consensus.nNormalizedNameForkHeight = 993380; // targeting, 21 Feb 2019 consensus.nNormalizedNameForkHeight = 993380; // targeting, 21 Feb 2019
consensus.nMinTakeoverWorkaroundHeight = 99; consensus.nMinTakeoverWorkaroundHeight = 99;
consensus.nMaxTakeoverWorkaroundHeight = 10000000; consensus.nMaxTakeoverWorkaroundHeight = 1198550; // targeting 30 Sep 2019
consensus.nWitnessForkHeight = 1198600;
consensus.nAllClaimsInMerkleForkHeight = 1198560; // targeting 30 Sep 2019
consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
@ -275,7 +278,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
// Deployment of SegWit (BIP141, BIP143, and BIP147) // Deployment of SegWit (BIP141, BIP143, and BIP147) -- Unused (see nWitnessForkHeight).
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1; consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016 consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017 consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
@ -348,7 +351,7 @@ public:
class CRegTestParams : public CChainParams { class CRegTestParams : public CChainParams {
public: public:
CRegTestParams() { CRegTestParams() {
strNetworkID = "lbrycrdreg"; strNetworkID = CBaseChainParams::REGTEST;
consensus.nSubsidyLevelInterval = 1 << 5; consensus.nSubsidyLevelInterval = 1 << 5;
consensus.BIP16Exception = uint256(); consensus.BIP16Exception = uint256();
consensus.BIP34Height = 1000; // BIP34 is needed for validation_block_tests consensus.BIP34Height = 1000; // BIP34 is needed for validation_block_tests
@ -361,12 +364,14 @@ public:
consensus.nPowTargetSpacing = 1; consensus.nPowTargetSpacing = 1;
consensus.nOriginalClaimExpirationTime = 500; consensus.nOriginalClaimExpirationTime = 500;
consensus.nExtendedClaimExpirationTime = 600; consensus.nExtendedClaimExpirationTime = 600;
consensus.nExtendedClaimExpirationForkHeight = 8000; consensus.nExtendedClaimExpirationForkHeight = 800;
consensus.nAllowMinDiffMinHeight = -1; consensus.nAllowMinDiffMinHeight = -1;
consensus.nAllowMinDiffMaxHeight = -1; consensus.nAllowMinDiffMaxHeight = -1;
consensus.nNormalizedNameForkHeight = 250; // SDK depends upon this number consensus.nNormalizedNameForkHeight = 250; // SDK depends upon this number
consensus.nMinTakeoverWorkaroundHeight = -1; consensus.nMinTakeoverWorkaroundHeight = -1;
consensus.nMaxTakeoverWorkaroundHeight = -1; consensus.nMaxTakeoverWorkaroundHeight = -1;
consensus.nWitnessForkHeight = 150;
consensus.nAllClaimsInMerkleForkHeight = 350;
consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false; consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains

View file

@ -13,7 +13,7 @@
const std::string CBaseChainParams::MAIN = "lbrycrd"; const std::string CBaseChainParams::MAIN = "lbrycrd";
const std::string CBaseChainParams::TESTNET = "lbrycrdtest"; const std::string CBaseChainParams::TESTNET = "lbrycrdtest";
const std::string CBaseChainParams::REGTEST = "regtest"; const std::string CBaseChainParams::REGTEST = "lbrycrdreg";
void SetupChainParamsBaseOptions() void SetupChainParamsBaseOptions()
{ {

View file

@ -2,8 +2,9 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "claimscriptop.h" #include <coins.h>
#include "nameclaim.h" #include <claimscriptop.h>
#include <nameclaim.h>
CClaimScriptAddOp::CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int nHeight) CClaimScriptAddOp::CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int nHeight)
: point(point), nValue(nValue), nHeight(nHeight) : point(point), nValue(nValue), nHeight(nHeight)
@ -37,32 +38,37 @@ CClaimScriptUndoAddOp::CClaimScriptUndoAddOp(const COutPoint& point, int nHeight
bool CClaimScriptUndoAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name) bool CClaimScriptUndoAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
{ {
auto claimId = ClaimIdHash(point.hash, point.n); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrintf("--- [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "--- [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
return undoAddClaim(trieCache, name, claimId); return undoAddClaim(trieCache, name, claimId);
} }
bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("--- [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "--- [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
return undoAddClaim(trieCache, name, claimId); return undoAddClaim(trieCache, name, claimId);
} }
bool CClaimScriptUndoAddOp::undoAddClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptUndoAddOp::undoAddClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
bool res = trieCache.undoAddClaim(name, point, nHeight); bool res = trieCache.undoAddClaim(name, point, nHeight);
if (!res) if (!res)
LogPrintf("%s: Removing fails\n", __func__); LogPrint(BCLog::CLAIMS, "%s: Removing claim fails\n", __func__);
return res; return res;
} }
bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("--- [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); if (LogAcceptCategory(BCLog::CLAIMS)) {
LogPrintf("%s: (txid: %s, nOut: %d) Removing support for %s, claimId: %s, from the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrintf("--- [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name,
claimId.GetHex(), point.hash.ToString(), point.n);
LogPrintf(
"%s: (txid: %s, nOut: %d) Removing support for %s, claimId: %s, from the claim trie due to block disconnect\n",
__func__, point.hash.ToString(), point.n, name, claimId.ToString());
}
bool res = trieCache.undoAddSupport(name, point, nHeight); bool res = trieCache.undoAddSupport(name, point, nHeight);
if (!res) if (!res)
LogPrintf("%s: Removing support fails\n", __func__); LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__);
return res; return res;
} }
@ -74,32 +80,36 @@ CClaimScriptSpendOp::CClaimScriptSpendOp(const COutPoint& point, int nHeight, in
bool CClaimScriptSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name) bool CClaimScriptSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
{ {
auto claimId = ClaimIdHash(point.hash, point.n); auto claimId = ClaimIdHash(point.hash, point.n);
LogPrintf("+++ [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "+++ [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
return spendClaim(trieCache, name, claimId); return spendClaim(trieCache, name, claimId);
} }
bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("+++ [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); LogPrint(BCLog::CLAIMS, "+++ [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
return spendClaim(trieCache, name, claimId); return spendClaim(trieCache, name, claimId);
} }
bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
bool res = trieCache.spendClaim(name, point, nHeight, nValidHeight); bool res = trieCache.spendClaim(name, point, nHeight, nValidHeight);
if (!res) if (!res)
LogPrintf("%s: Removing fails\n", __func__); LogPrint(BCLog::CLAIMS, "%s: Removing fails\n", __func__);
return res; return res;
} }
bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("+++ [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n); if (LogAcceptCategory(BCLog::CLAIMS)) {
LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrintf("+++ [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name,
claimId.GetHex(), point.hash.ToString(), point.n);
LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie\n", __func__,
point.hash.ToString(), point.n, name, claimId.ToString());
}
bool res = trieCache.spendSupport(name, point, nHeight, nValidHeight); bool res = trieCache.spendSupport(name, point, nHeight, nValidHeight);
if (!res) if (!res)
LogPrintf("%s: Removing support fails\n", __func__); LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__);
return res; return res;
} }
@ -120,13 +130,13 @@ bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std:
bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("%s: (txid: %s, nOut: %d) Restoring %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Restoring %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
return trieCache.undoSpendClaim(name, point, claimId, nValue, nHeight, nValidHeight); return trieCache.undoSpendClaim(name, point, claimId, nValue, nHeight, nValidHeight);
} }
bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
{ {
LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString()); LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
return trieCache.undoSpendSupport(name, point, claimId, nValue, nHeight, nValidHeight); return trieCache.undoSpendSupport(name, point, claimId, nValue, nHeight, nValidHeight);
} }
@ -139,7 +149,7 @@ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CSc
{ {
int op; int op;
std::vector<std::vector<unsigned char> > vvchParams; std::vector<std::vector<unsigned char> > vvchParams;
if (!DecodeClaimScript(scriptPubKey, op, vvchParams)) if (!DecodeClaimScript(scriptPubKey, op, vvchParams, trieCache.allowSupportMetadata()))
return false; return false;
switch (op) { switch (op) {
@ -153,59 +163,81 @@ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CSc
throw std::runtime_error("Unimplemented OP handler."); throw std::runtime_error("Unimplemented OP handler.");
} }
bool SpendClaim(CClaimTrieCache& trieCache, const CScript& scriptPubKey, const COutPoint& point, int nHeight, int& nValidHeight, spentClaimsType& spentClaims) void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoinsViewCache& view, int nHeight, const CUpdateCacheCallbacks& callbacks)
{ {
class CSpendClaimHistory : public CClaimScriptSpendOp class CSpendClaimHistory : public CClaimScriptSpendOp
{ {
public: public:
CSpendClaimHistory(spentClaimsType& spentClaims, const COutPoint& point, int nHeight, int& nValidHeight) using CClaimScriptSpendOp::CClaimScriptSpendOp;
: CClaimScriptSpendOp(point, nHeight, nValidHeight), spentClaims(spentClaims)
{
}
bool spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override bool spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override
{ {
if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) { if (CClaimScriptSpendOp::spendClaim(trieCache, name, claimId)) {
spentClaims.emplace_back(name, claimId); callback(name, claimId);
return true; return true;
} }
return false; return false;
} }
std::function<void(const std::string& name, const uint160& claimId)> callback;
private:
spentClaimsType& spentClaims;
}; };
CSpendClaimHistory spendClaim(spentClaims, point, nHeight, nValidHeight); spentClaimsType spentClaims;
return ProcessClaim(spendClaim, trieCache, scriptPubKey);
} for (std::size_t j = 0; j < tx.vin.size(); j++) {
const CTxIn& txin = tx.vin[j];
const Coin& coin = view.AccessCoin(txin.prevout);
CScript scriptPubKey;
int scriptHeight = nHeight;
if (coin.out.IsNull() && callbacks.findScriptKey) {
scriptPubKey = callbacks.findScriptKey(txin.prevout);
} else {
scriptHeight = coin.nHeight;
scriptPubKey = coin.out.scriptPubKey;
}
if (scriptPubKey.empty())
continue;
int nValidAtHeight;
CSpendClaimHistory spendClaim(COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, nValidAtHeight);
spendClaim.callback = [&spentClaims](const std::string& name, const uint160& claimId) {
spentClaims.emplace_back(name, claimId);
};
if (ProcessClaim(spendClaim, trieCache, scriptPubKey) && callbacks.claimUndoHeights)
callbacks.claimUndoHeights(j, nValidAtHeight);
}
bool AddSpendClaim(CClaimTrieCache& trieCache, const CScript& scriptPubKey, const COutPoint& point, CAmount nValue, int nHeight, spentClaimsType& spentClaims)
{
class CAddSpendClaim : public CClaimScriptAddOp class CAddSpendClaim : public CClaimScriptAddOp
{ {
public: public:
CAddSpendClaim(spentClaimsType& spentClaims, const COutPoint& point, CAmount nValue, int nHeight) using CClaimScriptAddOp::CClaimScriptAddOp;
: CClaimScriptAddOp(point, nValue, nHeight), spentClaims(spentClaims)
{
}
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override
{ {
spentClaimsType::iterator itSpent = spentClaims.begin(); if (callback(name, claimId))
for (; itSpent != spentClaims.end(); ++itSpent) { return CClaimScriptAddOp::updateClaim(trieCache, name, claimId);
return false;
}
std::function<bool(const std::string& name, const uint160& claimId)> callback;
};
for (std::size_t j = 0; j < tx.vout.size(); j++) {
const CTxOut& txout = tx.vout[j];
if (txout.scriptPubKey.empty())
continue;
CAddSpendClaim addClaim(COutPoint(tx.GetHash(), j), txout.nValue, nHeight);
addClaim.callback = [&trieCache, &spentClaims](const std::string& name, const uint160& claimId) -> bool {
for (auto itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) {
if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) { if (itSpent->second == claimId && trieCache.normalizeClaimName(name) == trieCache.normalizeClaimName(itSpent->first)) {
spentClaims.erase(itSpent); spentClaims.erase(itSpent);
return CClaimScriptAddOp::updateClaim(trieCache, name, claimId); return true;
} }
} }
return false; return false;
} };
ProcessClaim(addClaim, trieCache, txout.scriptPubKey);
private: }
spentClaimsType& spentClaims; }
};
CAddSpendClaim addClaim(spentClaims, point, nValue, nHeight);
return ProcessClaim(addClaim, trieCache, scriptPubKey);
}

View file

@ -59,17 +59,17 @@ public:
*/ */
CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int nHeight); CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int nHeight);
/** /**
* Implamention of OP_CLAIM_NAME handler * Implementation of OP_CLAIM_NAME handler
* @see CClaimScriptOp::claimName * @see CClaimScriptOp::claimName
*/ */
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override; bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
/** /**
* Implamention of OP_UPDATE_CLAIM handler * Implementation of OP_UPDATE_CLAIM handler
* @see CClaimScriptOp::updateClaim * @see CClaimScriptOp::updateClaim
*/ */
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
/** /**
* Implamention of OP_SUPPORT_CLAIM handler * Implementation of OP_SUPPORT_CLAIM handler
* @see CClaimScriptOp::supportClaim * @see CClaimScriptOp::supportClaim
*/ */
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
@ -100,17 +100,17 @@ public:
*/ */
CClaimScriptUndoAddOp(const COutPoint& point, int nHeight); CClaimScriptUndoAddOp(const COutPoint& point, int nHeight);
/** /**
* Implamention of OP_CLAIM_NAME handler * Implementation of OP_CLAIM_NAME handler
* @see CClaimScriptOp::claimName * @see CClaimScriptOp::claimName
*/ */
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override; bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
/** /**
* Implamention of OP_UPDATE_CLAIM handler * Implementation of OP_UPDATE_CLAIM handler
* @see CClaimScriptOp::updateClaim * @see CClaimScriptOp::updateClaim
*/ */
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
/** /**
* Implamention of OP_SUPPORT_CLAIM handler * Implementation of OP_SUPPORT_CLAIM handler
* @see CClaimScriptOp::supportClaim * @see CClaimScriptOp::supportClaim
*/ */
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
@ -141,17 +141,17 @@ public:
*/ */
CClaimScriptSpendOp(const COutPoint& point, int nHeight, int& nValidHeight); CClaimScriptSpendOp(const COutPoint& point, int nHeight, int& nValidHeight);
/** /**
* Implamention of OP_CLAIM_NAME handler * Implementation of OP_CLAIM_NAME handler
* @see CClaimScriptOp::claimName * @see CClaimScriptOp::claimName
*/ */
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override; bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
/** /**
* Implamention of OP_UPDATE_CLAIM handler * Implementation of OP_UPDATE_CLAIM handler
* @see CClaimScriptOp::updateClaim * @see CClaimScriptOp::updateClaim
*/ */
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
/** /**
* Implamention of OP_SUPPORT_CLAIM handler * Implementation of OP_SUPPORT_CLAIM handler
* @see CClaimScriptOp::supportClaim * @see CClaimScriptOp::supportClaim
*/ */
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
@ -184,17 +184,17 @@ public:
*/ */
CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight); CClaimScriptUndoSpendOp(const COutPoint& point, CAmount nValue, int nHeight, int nValidHeight);
/** /**
* Implamention of OP_CLAIM_NAME handler * Implementation of OP_CLAIM_NAME handler
* @see CClaimScriptOp::claimName * @see CClaimScriptOp::claimName
*/ */
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override; bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
/** /**
* Implamention of OP_UPDATE_CLAIM handler * Implementation of OP_UPDATE_CLAIM handler
* @see CClaimScriptOp::updateClaim * @see CClaimScriptOp::updateClaim
*/ */
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
/** /**
* Implamention of OP_SUPPORT_CLAIM handler * Implementation of OP_SUPPORT_CLAIM handler
* @see CClaimScriptOp::supportClaim * @see CClaimScriptOp::supportClaim
*/ */
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override; bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
@ -225,26 +225,21 @@ typedef std::pair<std::string, uint160> spentClaimType;
typedef std::vector<spentClaimType> spentClaimsType; typedef std::vector<spentClaimType> spentClaimsType;
struct CUpdateCacheCallbacks
{
std::function<CScript(const COutPoint& point)> findScriptKey;
std::function<void(int, int)> claimUndoHeights;
};
/** /**
* Function to spend claim from tie, keeping the successful list on * Function to spend claim from tie, keeping the successful list on
* @param[in] tx transaction inputs/outputs
* @param[in] trieCache trie to operate on * @param[in] trieCache trie to operate on
* @param[in] scriptPubKey claim script to be decoded * @param[in] view coins cache
* @param[in] point pair of transaction hash and its index * @param[in] point pair of transaction hash and its index
* @param[in] nHeight entry height of the claim * @param[in] nHeight entry height of the claim
* @param[out] nValidHeight valid height of the claim * @param[out] fallback optional callbacks
* @param[out] spentClaims inserts successfully spent claim
*/ */
bool SpendClaim(CClaimTrieCache& trieCache, const CScript& scriptPubKey, const COutPoint& point, int nHeight, int& nValidHeight, spentClaimsType& spentClaims); void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoinsViewCache& view, int nHeight, const CUpdateCacheCallbacks& callbacks = {});
/**
* Function to add / update (that present in spent list) claim in trie
* @param[in] trieCache trie to operate on
* @param[in] scriptPubKey claim script to be decoded
* @param[in] point pair of transaction hash and its index
* @param[in] nValue ` value of the claim
* @param[in] nHeight entry height of the claim
* @param[out] spentClaims erases successfully added claim
*/
bool AddSpendClaim(CClaimTrieCache& trieCache, const CScript& scriptPubKey, const COutPoint& point, CAmount nValue, int nHeight, spentClaimsType& spentClaims);
#endif // CLAIMSCRIPTOP_H #endif // CLAIMSCRIPTOP_H

File diff suppressed because it is too large Load diff

View file

@ -19,10 +19,11 @@
// leveldb keys // leveldb keys
#define TRIE_NODE 'n' #define TRIE_NODE 'n'
#define TRIE_NODE_CHILDREN 'b'
#define CLAIM_BY_ID 'i' #define CLAIM_BY_ID 'i'
#define CLAIM_QUEUE_ROW 'r' #define CLAIM_QUEUE_ROW 'r'
#define CLAIM_QUEUE_NAME_ROW 'm' #define CLAIM_QUEUE_NAME_ROW 'm'
#define EXP_QUEUE_ROW 'e' #define CLAIM_EXP_QUEUE_ROW 'e'
#define SUPPORT 's' #define SUPPORT 's'
#define SUPPORT_QUEUE_ROW 'u' #define SUPPORT_QUEUE_ROW 'u'
#define SUPPORT_QUEUE_NAME_ROW 'p' #define SUPPORT_QUEUE_NAME_ROW 'p'
@ -34,14 +35,12 @@ struct CClaimValue
{ {
COutPoint outPoint; COutPoint outPoint;
uint160 claimId; uint160 claimId;
CAmount nAmount; CAmount nAmount = 0;
CAmount nEffectiveAmount; CAmount nEffectiveAmount = 0;
int nHeight; int nHeight = 0;
int nValidAtHeight; int nValidAtHeight = 0;
CClaimValue() CClaimValue() = default;
{
}
CClaimValue(const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight, int nValidAtHeight) CClaimValue(const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight, int nValidAtHeight)
: outPoint(outPoint), claimId(claimId), nAmount(nAmount), nEffectiveAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight) : outPoint(outPoint), claimId(claimId), nAmount(nAmount), nEffectiveAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
@ -93,13 +92,11 @@ struct CSupportValue
{ {
COutPoint outPoint; COutPoint outPoint;
uint160 supportedClaimId; uint160 supportedClaimId;
CAmount nAmount; CAmount nAmount = 0;
int nHeight; int nHeight = 0;
int nValidAtHeight; int nValidAtHeight = 0;
CSupportValue() CSupportValue() = default;
{
}
CSupportValue(const COutPoint& outPoint, const uint160& supportedClaimId, CAmount nAmount, int nHeight, int nValidAtHeight) CSupportValue(const COutPoint& outPoint, const uint160& supportedClaimId, CAmount nAmount, int nHeight, int nValidAtHeight)
: outPoint(outPoint), supportedClaimId(supportedClaimId), nAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight) : outPoint(outPoint), supportedClaimId(supportedClaimId), nAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
@ -195,11 +192,9 @@ struct CClaimTrieData
struct COutPointHeightType struct COutPointHeightType
{ {
COutPoint outPoint; COutPoint outPoint;
int nHeight; int nHeight = 0;
COutPointHeightType() COutPointHeightType() = default;
{
}
COutPointHeightType(const COutPoint& outPoint, int nHeight) COutPointHeightType(const COutPoint& outPoint, int nHeight)
: outPoint(outPoint), nHeight(nHeight) : outPoint(outPoint), nHeight(nHeight)
@ -220,11 +215,9 @@ struct CNameOutPointHeightType
{ {
std::string name; std::string name;
COutPoint outPoint; COutPoint outPoint;
int nHeight; int nHeight = 0;
CNameOutPointHeightType() CNameOutPointHeightType() = default;
{
}
CNameOutPointHeightType(std::string name, const COutPoint& outPoint, int nHeight) CNameOutPointHeightType(std::string name, const COutPoint& outPoint, int nHeight)
: name(std::move(name)), outPoint(outPoint), nHeight(nHeight) : name(std::move(name)), outPoint(outPoint), nHeight(nHeight)
@ -247,15 +240,18 @@ struct CNameOutPointType
std::string name; std::string name;
COutPoint outPoint; COutPoint outPoint;
CNameOutPointType() CNameOutPointType() = default;
{
}
CNameOutPointType(std::string name, const COutPoint& outPoint) CNameOutPointType(std::string name, const COutPoint& outPoint)
: name(std::move(name)), outPoint(outPoint) : name(std::move(name)), outPoint(outPoint)
{ {
} }
bool operator==(const CNameOutPointType& other) const
{
return name == other.name && outPoint == other.outPoint;
}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
@ -268,6 +264,13 @@ struct CNameOutPointType
struct CClaimIndexElement struct CClaimIndexElement
{ {
CClaimIndexElement() = default;
CClaimIndexElement(std::string name, CClaimValue claim)
: name(std::move(name)), claim(std::move(claim))
{
}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
@ -281,36 +284,73 @@ struct CClaimIndexElement
CClaimValue claim; CClaimValue claim;
}; };
struct CClaimsForNameType struct CClaimNsupports
{ {
claimEntryType claims; CClaimNsupports() = default;
supportEntryType supports; CClaimNsupports(CClaimNsupports&&) = default;
int nLastTakeoverHeight; CClaimNsupports(const CClaimNsupports&) = default;
std::string name;
CClaimsForNameType(claimEntryType claims, supportEntryType supports, int nLastTakeoverHeight, const std::string& name) CClaimNsupports& operator=(CClaimNsupports&&) = default;
: claims(std::move(claims)), supports(std::move(supports)), nLastTakeoverHeight(nLastTakeoverHeight), name(name) CClaimNsupports& operator=(const CClaimNsupports&) = default;
CClaimNsupports(const CClaimValue& claim, CAmount effectiveAmount, const std::vector<CSupportValue>& supports = {})
: claim(claim), effectiveAmount(effectiveAmount), supports(supports)
{ {
} }
CClaimsForNameType(CClaimsForNameType&&) = default; bool IsNull() const
CClaimsForNameType(const CClaimsForNameType&) = default; {
CClaimsForNameType& operator=(CClaimsForNameType&&) = default; return claim.claimId.IsNull();
CClaimsForNameType& operator=(const CClaimsForNameType&) = default; }
CClaimValue claim;
CAmount effectiveAmount = 0;
std::vector<CSupportValue> supports;
};
static const CClaimNsupports invalid;
struct CClaimSupportToName
{
CClaimSupportToName(const std::string& name, int nLastTakeoverHeight, std::vector<CClaimNsupports> claimsNsupports, std::vector<CSupportValue> unmatchedSupports)
: name(name), nLastTakeoverHeight(nLastTakeoverHeight), claimsNsupports(std::move(claimsNsupports)), unmatchedSupports(std::move(unmatchedSupports))
{
}
const CClaimNsupports& find(const uint160& claimId) const
{
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&claimId](const CClaimNsupports& value) {
return claimId == value.claim.claimId;
});
return it != claimsNsupports.end() ? *it : invalid;
}
const CClaimNsupports& find(const std::string& partialId) const
{
std::string lowered(partialId);
for (auto& c: lowered)
c = std::tolower(c);
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&lowered](const CClaimNsupports& value) {
return value.claim.claimId.GetHex().find(lowered) == 0;
});
return it != claimsNsupports.end() ? *it : invalid;
}
const std::string name;
const int nLastTakeoverHeight;
const std::vector<CClaimNsupports> claimsNsupports;
const std::vector<CSupportValue> unmatchedSupports;
}; };
class CClaimTrie : public CPrefixTrie<std::string, CClaimTrieData> class CClaimTrie : public CPrefixTrie<std::string, CClaimTrieData>
{ {
int nNextHeight = 0;
int nExpirationTime = 0;
int nProportionalDelayFactor = 0;
std::unique_ptr<CDBWrapper> db;
public: public:
CClaimTrie() = default; CClaimTrie() = default;
virtual ~CClaimTrie() = default;
CClaimTrie(CClaimTrie&&) = delete; CClaimTrie(CClaimTrie&&) = delete;
CClaimTrie(const CClaimTrie&) = delete; CClaimTrie(const CClaimTrie&) = delete;
CClaimTrie(bool fMemory, bool fWipe, int proportionalDelayFactor = 32); CClaimTrie(bool fMemory, bool fWipe, int proportionalDelayFactor = 32, std::size_t cacheMB=200);
CClaimTrie& operator=(CClaimTrie&&) = delete; CClaimTrie& operator=(CClaimTrie&&) = delete;
CClaimTrie& operator=(const CClaimTrie&) = delete; CClaimTrie& operator=(const CClaimTrie&) = delete;
@ -321,11 +361,21 @@ public:
friend struct ClaimTrieChainFixture; friend struct ClaimTrieChainFixture;
friend class CClaimTrieCacheExpirationFork; friend class CClaimTrieCacheExpirationFork;
friend class CClaimTrieCacheNormalizationFork; friend class CClaimTrieCacheNormalizationFork;
friend bool getClaimById(const uint160&, std::string&, CClaimValue*);
friend bool getClaimById(const std::string&, std::string&, CClaimValue*);
std::size_t getTotalNamesInTrie() const;
std::size_t getTotalClaimsInTrie() const;
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
protected:
int nNextHeight = 0;
int nProportionalDelayFactor = 0;
std::unique_ptr<CDBWrapper> db;
}; };
class CClaimTrieProofNode struct CClaimTrieProofNode
{ {
public:
CClaimTrieProofNode(std::vector<std::pair<unsigned char, uint256>> children, bool hasValue, const uint256& valHash) CClaimTrieProofNode(std::vector<std::pair<unsigned char, uint256>> children, bool hasValue, const uint256& valHash)
: children(std::move(children)), hasValue(hasValue), valHash(valHash) : children(std::move(children)), hasValue(hasValue), valHash(valHash)
{ {
@ -341,35 +391,78 @@ public:
uint256 valHash; uint256 valHash;
}; };
class CClaimTrieProof struct CClaimTrieProof
{ {
public: CClaimTrieProof() = default;
CClaimTrieProof()
{
}
CClaimTrieProof(std::vector<CClaimTrieProofNode> nodes, bool hasValue, const COutPoint& outPoint, int nHeightOfLastTakeover)
: nodes(std::move(nodes)), hasValue(hasValue), outPoint(outPoint), nHeightOfLastTakeover(nHeightOfLastTakeover)
{
}
CClaimTrieProof(CClaimTrieProof&&) = default; CClaimTrieProof(CClaimTrieProof&&) = default;
CClaimTrieProof(const CClaimTrieProof&) = default; CClaimTrieProof(const CClaimTrieProof&) = default;
CClaimTrieProof& operator=(CClaimTrieProof&&) = default; CClaimTrieProof& operator=(CClaimTrieProof&&) = default;
CClaimTrieProof& operator=(const CClaimTrieProof&) = default; CClaimTrieProof& operator=(const CClaimTrieProof&) = default;
std::vector<std::pair<bool, uint256>> pairs;
std::vector<CClaimTrieProofNode> nodes; std::vector<CClaimTrieProofNode> nodes;
bool hasValue; int nHeightOfLastTakeover = 0;
bool hasValue = false;
COutPoint outPoint; COutPoint outPoint;
int nHeightOfLastTakeover;
}; };
typedef std::pair<std::string, CClaimValue> claimQueueEntryType; template <typename T>
typedef std::vector<claimQueueEntryType> claimQueueRowType; class COptional
{
bool own;
T* value;
public:
COptional(T* value = nullptr) : own(false), value(value) {}
COptional(COptional&& o)
{
own = o.own;
value = o.value;
o.own = false;
o.value = nullptr;
}
COptional(T&& o) : own(true)
{
value = new T(std::move(o));
}
~COptional()
{
if (own)
delete value;
}
COptional& operator=(COptional&&) = delete;
bool unique() const
{
return own;
}
operator bool() const
{
return value;
}
operator T*() const
{
return value;
}
T* operator->() const
{
return value;
}
operator T&() const
{
return *value;
}
T& operator*() const
{
return *value;
}
};
template <typename T>
using queueEntryType = std::pair<std::string, T>;
typedef std::vector<queueEntryType<CClaimValue>> claimQueueRowType;
typedef std::map<int, claimQueueRowType> claimQueueType; typedef std::map<int, claimQueueRowType> claimQueueType;
typedef std::pair<std::string, CSupportValue> supportQueueEntryType; typedef std::vector<queueEntryType<CSupportValue>> supportQueueRowType;
typedef std::vector<supportQueueEntryType> supportQueueRowType;
typedef std::map<int, supportQueueRowType> supportQueueType; typedef std::map<int, supportQueueRowType> supportQueueType;
typedef std::vector<COutPointHeightType> queueNameRowType; typedef std::vector<COutPointHeightType> queueNameRowType;
@ -386,27 +479,21 @@ typedef std::vector<CClaimIndexElement> claimIndexElementListType;
class CClaimTrieCacheBase class CClaimTrieCacheBase
{ {
public: public:
explicit CClaimTrieCacheBase(CClaimTrie* base, bool fRequireTakeoverHeights = true); explicit CClaimTrieCacheBase(CClaimTrie* base);
virtual ~CClaimTrieCacheBase() = default; virtual ~CClaimTrieCacheBase() = default;
uint256 getMerkleHash(); uint256 getMerkleHash();
bool checkConsistency(int minimumHeight = 1) const;
bool getClaimById(const uint160& claimId, std::string& name, CClaimValue& claim) const;
bool flush(); bool flush();
bool empty() const; bool empty() const;
bool checkConsistency() const;
bool ReadFromDisk(const CBlockIndex* tip); bool ReadFromDisk(const CBlockIndex* tip);
bool haveClaim(const std::string& name, const COutPoint& outPoint) const; bool haveClaim(const std::string& name, const COutPoint& outPoint) const;
bool haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight); bool haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
bool haveSupport(const std::string& name, const COutPoint& outPoint) const; bool haveSupport(const std::string& name, const COutPoint& outPoint) const;
bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight); bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
std::size_t getTotalNamesInTrie() const;
std::size_t getTotalClaimsInTrie() const;
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight); bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight);
bool undoAddClaim(const std::string& name, const COutPoint& outPoint, int nHeight); bool undoAddClaim(const std::string& name, const COutPoint& outPoint, int nHeight);
@ -434,28 +521,26 @@ public:
virtual bool getProofForName(const std::string& name, CClaimTrieProof& proof); virtual bool getProofForName(const std::string& name, CClaimTrieProof& proof);
virtual bool getInfoForName(const std::string& name, CClaimValue& claim) const; virtual bool getInfoForName(const std::string& name, CClaimValue& claim) const;
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo); virtual int expirationTime() const;
virtual CClaimsForNameType getClaimsForName(const std::string& name) const; virtual bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
CAmount getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const; virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
CAmount getEffectiveAmountForClaim(const CClaimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports = nullptr) const;
void setExpirationTime(int time);
int expirationTime();
CClaimTrie::const_iterator begin() const;
CClaimTrie::const_iterator end() const;
CClaimTrie::const_iterator find(const std::string& name) const; CClaimTrie::const_iterator find(const std::string& name) const;
void iterate(std::function<void(const std::string&, const CClaimTrieData&)> callback) const;
void dumpToLog(CClaimTrie::const_iterator it, bool diffFromBase = true) const; void dumpToLog(CClaimTrie::const_iterator it, bool diffFromBase = true) const;
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
protected: protected:
CClaimTrie* base; CClaimTrie* base;
CClaimTrie cache; CClaimTrie nodesToAddOrUpdate; // nodes pulled in from base (and possibly modified thereafter), written to base on flush
std::unordered_set<std::string> namesToCheckForTakeover; std::unordered_set<std::string> nodesAlreadyCached; // set of nodes already pulled into cache from base
std::unordered_set<std::string> namesToCheckForTakeover; // takeover numbers are updated on increment
uint256 recursiveComputeMerkleHash(CClaimTrie::iterator& it); virtual uint256 recursiveComputeMerkleHash(CClaimTrie::iterator& it);
virtual bool recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const;
virtual bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover); virtual bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover);
virtual bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover); virtual bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover);
@ -463,29 +548,19 @@ protected:
virtual bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover); virtual bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover);
virtual bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover); virtual bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover);
virtual bool addClaimToQueues(const std::string& name, const CClaimValue& claim);
virtual bool addSupportToQueues(const std::string& name, const CSupportValue& support);
virtual bool removeSupportFromQueue(const std::string& name, const COutPoint& outPoint, CSupportValue& support);
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
void addToExpirationQueue(int nExpirationHeight, CNameOutPointType& entry);
void removeFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int nHeight);
void addSupportToExpirationQueue(int nExpirationHeight, CNameOutPointType& entry);
void removeSupportFromExpirationQueue(const std::string& name, const COutPoint& outPoint, int nHeight);
supportEntryType getSupportsForName(const std::string& name) const; supportEntryType getSupportsForName(const std::string& name) const;
int getDelayForName(const std::string& name); int getDelayForName(const std::string& name) const;
virtual int getDelayForName(const std::string& name, const uint160& claimId); virtual int getDelayForName(const std::string& name, const uint160& claimId) const;
CClaimTrie::iterator cacheData(const std::string& name, bool create = true); CClaimTrie::iterator cacheData(const std::string& name, bool create = true);
bool getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const; bool getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const;
int getNumBlocksOfContinuousOwnership(const std::string& name); int getNumBlocksOfContinuousOwnership(const std::string& name) const;
void reactivateClaim(const expirationQueueRowType& row, int height, bool increment);
void reactivateSupport(const expirationQueueRowType& row, int height, bool increment);
expirationQueueType expirationQueueCache; expirationQueueType expirationQueueCache;
expirationQueueType supportExpirationQueueCache; expirationQueueType supportExpirationQueueCache;
@ -498,18 +573,15 @@ private:
std::unordered_map<std::string, std::pair<uint160, int>> takeoverCache; std::unordered_map<std::string, std::pair<uint160, int>> takeoverCache;
bool fRequireTakeoverHeights; claimQueueType claimQueueCache; // claims not active yet: to be written to disk on flush
claimQueueType claimQueueCache;
queueNameType claimQueueNameCache; queueNameType claimQueueNameCache;
supportQueueType supportQueueCache; supportQueueType supportQueueCache; // supports not active yet: to be written to disk on flush
queueNameType supportQueueNameCache; queueNameType supportQueueNameCache;
claimIndexElementListType claimsToAdd; claimIndexElementListType claimsToAddToByIdIndex; // written to index on flush
claimIndexClaimListType claimsToDelete; claimIndexClaimListType claimsToDeleteFromByIdIndex;
std::unordered_map<std::string, supportEntryType> cacheSupports; std::unordered_map<std::string, supportEntryType> supportCache; // to be added/updated to base (and disk) on flush
std::unordered_set<std::string> nodesToDelete; std::unordered_set<std::string> nodesToDelete; // to be removed from base (and disk) on flush
std::unordered_set<std::string> alreadyCachedNodes;
std::unordered_map<std::string, bool> takeoverWorkaround; std::unordered_map<std::string, bool> takeoverWorkaround;
std::unordered_set<std::string> removalWorkaround; std::unordered_set<std::string> removalWorkaround;
@ -522,14 +594,60 @@ private:
void markAsDirty(const std::string& name, bool fCheckTakeover); void markAsDirty(const std::string& name, bool fCheckTakeover);
bool removeSupport(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover); bool removeSupport(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover);
bool removeClaim(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover); bool removeClaim(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover);
bool removeClaimFromQueue(const std::string& name, const COutPoint& outPoint, CClaimValue& claim);
typename claimQueueType::value_type* getQueueCacheRow(int nHeight, bool createIfNotExists = false); template <typename T>
typename queueNameType::value_type* getQueueCacheNameRow(const std::string& name, bool createIfNotExists = false); void insertRowsFromQueue(std::vector<T>& result, const std::string& name) const;
typename expirationQueueType::value_type* getExpirationQueueCacheRow(int nHeight, bool createIfNotExists = false);
typename supportQueueType::value_type* getSupportQueueCacheRow(int nHeight, bool createIfNotExists = false); template <typename T>
typename queueNameType::value_type* getSupportQueueCacheNameRow(const std::string& name, bool createIfNotExists = false); std::vector<queueEntryType<T>>* getQueueCacheRow(int nHeight, bool createIfNotExists);
typename expirationQueueType::value_type* getSupportExpirationQueueCacheRow(int nHeight, bool createIfNotExists = false);
template <typename T>
COptional<const std::vector<queueEntryType<T>>> getQueueCacheRow(int nHeight) const;
template <typename T>
queueNameRowType* getQueueCacheNameRow(const std::string& name, bool createIfNotExists);
template <typename T>
COptional<const queueNameRowType> getQueueCacheNameRow(const std::string& name) const;
template <typename T>
expirationQueueRowType* getExpirationQueueCacheRow(int nHeight, bool createIfNotExists);
template <typename T>
bool haveInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
template <typename T>
T add(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight);
template <typename T>
bool remove(T& value, const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover = false);
template <typename T>
bool addToQueue(const std::string& name, const T& value);
template <typename T>
bool removeFromQueue(const std::string& name, const COutPoint& outPoint, T& value);
template <typename T>
bool addToCache(const std::string& name, const T& value, bool fCheckTakeover = false);
template <typename T>
bool removeFromCache(const std::string& name, const COutPoint& outPoint, T& value, bool fCheckTakeover = false);
template <typename T>
bool undoSpend(const std::string& name, const T& value, int nValidAtHeight);
template <typename T>
void undoIncrement(insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo, std::set<T>* deleted = nullptr);
template <typename T>
void undoDecrement(insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo, std::vector<CClaimIndexElement>* added = nullptr, std::set<T>* deleted = nullptr);
template <typename T>
void undoIncrement(const std::string& name, insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo);
template <typename T>
void reactivate(const expirationQueueRowType& row, int height, bool increment);
// for unit test // for unit test
friend struct ClaimTrieChainFixture; friend struct ClaimTrieChainFixture;
@ -539,25 +657,35 @@ private:
class CClaimTrieCacheExpirationFork : public CClaimTrieCacheBase class CClaimTrieCacheExpirationFork : public CClaimTrieCacheBase
{ {
public: public:
explicit CClaimTrieCacheExpirationFork(CClaimTrie* base, bool fRequireTakeoverHeights = true) explicit CClaimTrieCacheExpirationFork(CClaimTrie* base);
: CClaimTrieCacheBase(base, fRequireTakeoverHeights)
{
}
bool forkForExpirationChange(bool increment); void setExpirationTime(int time);
int expirationTime() const override;
// TODO: move the expiration fork code from main.cpp to overrides of increment/decrement block virtual void initializeIncrement();
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
bool incrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo,
std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
bool decrementBlock(insertUndoType& insertUndo,
claimQueueRowType& expireUndo,
insertUndoType& insertSupportUndo,
supportQueueRowType& expireSupportUndo) override;
private: private:
void removeAndAddSupportToExpirationQueue(expirationQueueRowType& row, int height, bool increment); int nExpirationTime;
void removeAndAddToExpirationQueue(expirationQueueRowType& row, int height, bool increment); bool forkForExpirationChange(bool increment);
}; };
class CClaimTrieCacheNormalizationFork : public CClaimTrieCacheExpirationFork class CClaimTrieCacheNormalizationFork : public CClaimTrieCacheExpirationFork
{ {
public: public:
explicit CClaimTrieCacheNormalizationFork(CClaimTrie* base, bool fRequireTakeoverHeights = true) explicit CClaimTrieCacheNormalizationFork(CClaimTrie* base)
: CClaimTrieCacheExpirationFork(base, fRequireTakeoverHeights), overrideInsertNormalization(false), overrideRemoveNormalization(false) : CClaimTrieCacheExpirationFork(base), overrideInsertNormalization(false), overrideRemoveNormalization(false)
{ {
} }
@ -580,21 +708,17 @@ public:
bool getProofForName(const std::string& name, CClaimTrieProof& proof) override; bool getProofForName(const std::string& name, CClaimTrieProof& proof) override;
bool getInfoForName(const std::string& name, CClaimValue& claim) const override; bool getInfoForName(const std::string& name, CClaimValue& claim) const override;
CClaimsForNameType getClaimsForName(const std::string& name) const override; CClaimSupportToName getClaimsForName(const std::string& name) const override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
protected: protected:
bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover = false) override; bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover) override;
bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover = false) override; bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover) override;
bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover) override; bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover) override;
bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover) override; bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover) override;
int getDelayForName(const std::string& name, const uint160& claimId) override; int getDelayForName(const std::string& name, const uint160& claimId) const override;
bool addClaimToQueues(const std::string& name, const CClaimValue& claim) override;
bool addSupportToQueues(const std::string& name, const CSupportValue& support) override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
private: private:
bool overrideInsertNormalization; bool overrideInsertNormalization;
@ -607,6 +731,26 @@ private:
std::vector<std::pair<std::string, int>>& takeoverHeightUndo); std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
}; };
typedef CClaimTrieCacheNormalizationFork CClaimTrieCache; class CClaimTrieCacheHashFork : public CClaimTrieCacheNormalizationFork
{
public:
explicit CClaimTrieCacheHashFork(CClaimTrie* base);
bool getProofForName(const std::string& name, CClaimTrieProof& proof) override;
bool getProofForName(const std::string& name, CClaimTrieProof& proof, const std::function<bool(const CClaimValue&)>& comp);
void initializeIncrement() override;
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
bool allowSupportMetadata() const;
protected:
uint256 recursiveComputeMerkleHash(CClaimTrie::iterator& it) override;
bool recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const override;
private:
void copyAllBaseToCache();
};
typedef CClaimTrieCacheHashFork CClaimTrieCache;
#endif // BITCOIN_CLAIMTRIE_H #endif // BITCOIN_CLAIMTRIE_H

View file

@ -1,34 +1,64 @@
#include "claimtrie.h"
#include <boost/algorithm/string.hpp> #include <consensus/merkle.h>
#include <boost/foreach.hpp> #include <chainparams.h>
#include <claimtrie.h>
#include <hash.h>
#include <boost/locale.hpp> #include <boost/locale.hpp>
#include <boost/locale/conversion.hpp> #include <boost/locale/conversion.hpp>
#include <boost/locale/localization_backend.hpp> #include <boost/locale/localization_backend.hpp>
#include <boost/scope_exit.hpp> #include <boost/scope_exit.hpp>
#include <boost/scoped_ptr.hpp>
void CClaimTrieCacheExpirationFork::removeAndAddToExpirationQueue(expirationQueueRowType& row, int height, bool increment) CClaimTrieCacheExpirationFork::CClaimTrieCacheExpirationFork(CClaimTrie* base)
: CClaimTrieCacheBase(base)
{ {
for (auto e = row.begin(); e != row.end(); ++e) { setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
// remove and insert with new expiration time
removeFromExpirationQueue(e->name, e->outPoint, height);
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration;
CNameOutPointType entry(e->name, e->outPoint);
addToExpirationQueue(new_expiration_height, entry);
}
} }
void CClaimTrieCacheExpirationFork::removeAndAddSupportToExpirationQueue(expirationQueueRowType& row, int height, bool increment) void CClaimTrieCacheExpirationFork::setExpirationTime(int time)
{ {
for (auto e = row.begin(); e != row.end(); ++e) { nExpirationTime = time;
// remove and insert with new expiration time }
removeSupportFromExpirationQueue(e->name, e->outPoint, height);
int extend_expiration = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime; int CClaimTrieCacheExpirationFork::expirationTime() const
int new_expiration_height = increment ? height + extend_expiration : height - extend_expiration; {
CNameOutPointType entry(e->name, e->outPoint); return nExpirationTime;
addSupportToExpirationQueue(new_expiration_height, entry); }
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
{
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
return true;
} }
return false;
}
bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
{
if (CClaimTrieCacheBase::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
return true;
}
return false;
}
void CClaimTrieCacheExpirationFork::initializeIncrement()
{
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if (nNextHeight != Params().GetConsensus().nExtendedClaimExpirationForkHeight)
return;
forkForExpirationChange(true);
}
bool CClaimTrieCacheExpirationFork::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
{
auto ret = CClaimTrieCacheBase::finalizeDecrement(takeoverHeightUndo);
if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
forkForExpirationChange(false);
return ret;
} }
bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment) bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
@ -48,17 +78,17 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
if (!pcursor->GetKey(key)) if (!pcursor->GetKey(key))
continue; continue;
int height = key.second; int height = key.second;
if (key.first == EXP_QUEUE_ROW) { if (key.first == CLAIM_EXP_QUEUE_ROW) {
expirationQueueRowType row; expirationQueueRowType row;
if (pcursor->GetValue(row)) { if (pcursor->GetValue(row)) {
removeAndAddToExpirationQueue(row, height, increment); reactivateClaim(row, height, increment);
} else { } else {
return error("%s(): error reading expiration queue rows from disk", __func__); return error("%s(): error reading expiration queue rows from disk", __func__);
} }
} else if (key.first == SUPPORT_EXP_QUEUE_ROW) { } else if (key.first == SUPPORT_EXP_QUEUE_ROW) {
expirationQueueRowType row; expirationQueueRowType row;
if (pcursor->GetValue(row)) { if (pcursor->GetValue(row)) {
removeAndAddSupportToExpirationQueue(row, height, increment); reactivateSupport(row, height, increment);
} else { } else {
return error("%s(): error reading support expiration queue rows from disk", __func__); return error("%s(): error reading support expiration queue rows from disk", __func__);
} }
@ -142,42 +172,43 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insert
// run the one-time upgrade of all names that need to change // run the one-time upgrade of all names that need to change
// it modifies the (cache) trie as it goes, so we need to grab everything to be modified first // it modifies the (cache) trie as it goes, so we need to grab everything to be modified first
for (auto it = base->begin(); it != base->end(); ++it) { for (auto it = base->cbegin(); it != base->cend(); ++it) {
const std::string normalized = normalizeClaimName(it.key(), true); const std::string normalized = normalizeClaimName(it.key(), true);
if (normalized == it.key()) if (normalized == it.key())
continue; continue;
auto supports = getSupportsForName(it.key()); auto& name = it.key();
for (auto& support : supports) { auto supports = getSupportsForName(name);
for (auto support : supports) {
// if it's already going to expire just skip it // if it's already going to expire just skip it
if (support.nHeight + base->nExpirationTime <= nNextHeight) if (support.nHeight + expirationTime() <= nNextHeight)
continue; continue;
CSupportValue removed; assert(removeSupportFromMap(name, support.outPoint, support, false));
assert(removeSupportFromMap(it.key(), support.outPoint, removed, false)); expireSupportUndo.emplace_back(name, support);
expireSupportUndo.emplace_back(it.key(), removed);
assert(insertSupportIntoMap(normalized, support, false)); assert(insertSupportIntoMap(normalized, support, false));
insertSupportUndo.emplace_back(it.key(), support.outPoint, -1); insertSupportUndo.emplace_back(name, support.outPoint, -1);
} }
namesToCheckForTakeover.insert(normalized); namesToCheckForTakeover.insert(normalized);
auto cached = cacheData(it.key(), false); auto cached = cacheData(name, false);
if (!cached || cached->claims.empty()) if (!cached || cached->empty())
continue; continue;
for (auto& claim : it->claims) { auto claimsCopy = cached->claims;
if (claim.nHeight + base->nExpirationTime <= nNextHeight) auto takeoverHeightCopy = cached->nHeightOfLastTakeover;
for (auto claim : claimsCopy) {
if (claim.nHeight + expirationTime() <= nNextHeight)
continue; continue;
CClaimValue removed; assert(removeClaimFromTrie(name, claim.outPoint, claim, false));
assert(removeClaimFromTrie(it.key(), claim.outPoint, removed, false)); removeUndo.emplace_back(name, claim);
removeUndo.emplace_back(it.key(), removed); assert(insertClaimIntoTrie(normalized, claim, true));
assert(insertClaimIntoTrie(normalized, claim, false)); insertUndo.emplace_back(name, claim.outPoint, -1);
insertUndo.emplace_back(it.key(), claim.outPoint, -1);
} }
takeoverHeightUndo.emplace_back(it.key(), it->nHeightOfLastTakeover); takeoverHeightUndo.emplace_back(name, takeoverHeightCopy);
} }
return true; return true;
} }
@ -208,27 +239,243 @@ bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, C
return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim); return CClaimTrieCacheExpirationFork::getInfoForName(normalizeClaimName(name), claim);
} }
CClaimsForNameType CClaimTrieCacheNormalizationFork::getClaimsForName(const std::string& name) const CClaimSupportToName CClaimTrieCacheNormalizationFork::getClaimsForName(const std::string& name) const
{ {
return CClaimTrieCacheExpirationFork::getClaimsForName(normalizeClaimName(name)); return CClaimTrieCacheExpirationFork::getClaimsForName(normalizeClaimName(name));
} }
int CClaimTrieCacheNormalizationFork::getDelayForName(const std::string& name, const uint160& claimId) int CClaimTrieCacheNormalizationFork::getDelayForName(const std::string& name, const uint160& claimId) const
{ {
return CClaimTrieCacheExpirationFork::getDelayForName(normalizeClaimName(name), claimId); return CClaimTrieCacheExpirationFork::getDelayForName(normalizeClaimName(name), claimId);
} }
bool CClaimTrieCacheNormalizationFork::addClaimToQueues(const std::string& name, const CClaimValue& claim)
{
return CClaimTrieCacheExpirationFork::addClaimToQueues(normalizeClaimName(name, claim.nValidAtHeight > Params().GetConsensus().nNormalizedNameForkHeight), claim);
}
bool CClaimTrieCacheNormalizationFork::addSupportToQueues(const std::string& name, const CSupportValue& support)
{
return CClaimTrieCacheExpirationFork::addSupportToQueues(normalizeClaimName(name, support.nValidAtHeight > Params().GetConsensus().nNormalizedNameForkHeight), support);
}
std::string CClaimTrieCacheNormalizationFork::adjustNameForValidHeight(const std::string& name, int validHeight) const std::string CClaimTrieCacheNormalizationFork::adjustNameForValidHeight(const std::string& name, int validHeight) const
{ {
return normalizeClaimName(name, validHeight > Params().GetConsensus().nNormalizedNameForkHeight); return normalizeClaimName(name, validHeight > Params().GetConsensus().nNormalizedNameForkHeight);
} }
CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieCacheNormalizationFork(base)
{
}
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
std::vector<uint256> getClaimHashes(const CClaimTrieData& data)
{
std::vector<uint256> hashes;
for (auto& claim : data.claims)
hashes.push_back(getValueHash(claim.outPoint, data.nHeightOfLastTakeover));
return hashes;
}
template <typename T>
using iCbType = std::function<uint256(T&)>;
template <typename TIterator>
uint256 recursiveBinaryTreeHash(TIterator& it, const iCbType<TIterator>& process)
{
std::vector<uint256> childHashes;
for (auto& child : it.children())
childHashes.emplace_back(process(child));
std::vector<uint256> claimHashes;
if (!it->empty())
claimHashes = getClaimHashes(it.data());
else if (!it.hasChildren())
return {};
auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
return Hash(left.begin(), left.end(), right.begin(), right.end());
}
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(CClaimTrie::iterator& it)
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(it);
using iterator = CClaimTrie::iterator;
iCbType<iterator> process = [&process](iterator& it) -> uint256 {
if (it->hash.IsNull())
it->hash = recursiveBinaryTreeHash(it, process);
assert(!it->hash.IsNull());
return it->hash;
};
return process(it);
}
bool CClaimTrieCacheHashFork::recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::recursiveCheckConsistency(it, failed);
struct CRecursiveBreak {};
using iterator = CClaimTrie::const_iterator;
iCbType<iterator> process = [&failed, &process](iterator& it) -> uint256 {
if (it->hash.IsNull() || it->hash != recursiveBinaryTreeHash(it, process)) {
failed = it.key();
throw CRecursiveBreak();
}
return it->hash;
};
try {
process(it);
} catch (const CRecursiveBreak&) {
return false;
}
return true;
}
std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint32_t idx)
{
uint32_t count = 0;
int matchlevel = -1;
bool matchh = false;
uint256 inner[32], h;
const uint32_t one = 1;
std::vector<uint256> res;
const auto iterateInner = [&](int& level) {
for (; !(count & (one << level)); level++) {
const auto& ihash = inner[level];
if (matchh) {
res.push_back(ihash);
} else if (matchlevel == level) {
res.push_back(h);
matchh = true;
}
h = Hash(ihash.begin(), ihash.end(), h.begin(), h.end());
}
};
while (count < hashes.size()) {
h = hashes[count];
matchh = count == idx;
count++;
int level = 0;
iterateInner(level);
// Store the resulting hash at inner position level.
inner[level] = h;
if (matchh)
matchlevel = level;
}
int level = 0;
while (!(count & (one << level)))
level++;
h = inner[level];
matchh = matchlevel == level;
while (count != (one << level)) {
// If we reach this point, h is an inner value that is not the top.
if (matchh)
res.push_back(h);
h = Hash(h.begin(), h.end(), h.begin(), h.end());
// Increment count to the value it would have if two entries at this
count += (one << level);
level++;
iterateInner(level);
}
return res;
}
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTrieProof& proof)
{
return getProofForName(name, proof, nullptr);
}
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTrieProof& proof, const std::function<bool(const CClaimValue&)>& comp)
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::getProofForName(name, proof);
auto fillPairs = [&proof](const std::vector<uint256>& hashes, uint32_t idx) {
auto partials = ComputeMerklePath(hashes, idx);
for (int i = partials.size() - 1; i >= 0; --i)
proof.pairs.emplace_back((idx >> i) & 1, partials[i]);
};
// cache the parent nodes
cacheData(name, false);
getMerkleHash();
proof = CClaimTrieProof();
for (auto& it : static_cast<const CClaimTrie&>(nodesToAddOrUpdate).nodes(name)) {
std::vector<uint256> childHashes;
uint32_t nextCurrentIdx = 0;
for (auto& child : it.children()) {
if (name.find(child.key()) == 0)
nextCurrentIdx = uint32_t(childHashes.size());
childHashes.push_back(child->hash);
}
std::vector<uint256> claimHashes;
if (!it->empty())
claimHashes = getClaimHashes(it.data());
// I am on a node; I need a hash(children, claims)
// if I am the last node on the list, it will be hash(children, x)
// else it will be hash(x, claims)
if (it.key() == name) {
uint32_t nClaimIndex = 0;
auto& claims = it->claims;
auto itClaim = !comp ? claims.begin() : std::find_if(claims.begin(), claims.end(), comp);
if (itClaim != claims.end()) {
proof.hasValue = true;
proof.outPoint = itClaim->outPoint;
proof.nHeightOfLastTakeover = it->nHeightOfLastTakeover;
nClaimIndex = std::distance(claims.begin(), itClaim);
}
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
proof.pairs.emplace_back(true, hash);
if (!claimHashes.empty())
fillPairs(claimHashes, nClaimIndex);
} else {
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
proof.pairs.emplace_back(false, hash);
if (!childHashes.empty())
fillPairs(childHashes, nextCurrentIdx);
}
}
std::reverse(proof.pairs.begin(), proof.pairs.end());
return true;
}
void CClaimTrieCacheHashFork::copyAllBaseToCache()
{
for (auto it = base->cbegin(); it != base->cend(); ++it)
if (nodesAlreadyCached.insert(it.key()).second)
nodesToAddOrUpdate.insert(it.key(), it.data());
for (auto it = nodesToAddOrUpdate.begin(); it != nodesToAddOrUpdate.end(); ++it)
it->hash.SetNull();
}
void CClaimTrieCacheHashFork::initializeIncrement()
{
CClaimTrieCacheNormalizationFork::initializeIncrement();
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if (nNextHeight != Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
return;
// if we are forking, we load the entire base trie into the cache trie
// we reset its hash computation so it can be recomputed completely
copyAllBaseToCache();
}
bool CClaimTrieCacheHashFork::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
{
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverHeightUndo);
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
copyAllBaseToCache();
return ret;
}
bool CClaimTrieCacheHashFork::allowSupportMetadata() const
{
return nNextHeight >= Params().GetConsensus().nAllClaimsInMerkleForkHeight;
}

View file

@ -81,6 +81,8 @@ struct Params {
int nMinTakeoverWorkaroundHeight; int nMinTakeoverWorkaroundHeight;
int nMaxTakeoverWorkaroundHeight; int nMaxTakeoverWorkaroundHeight;
int nWitnessForkHeight;
int64_t nPowTargetSpacing; int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan; int64_t nPowTargetTimespan;
/** how long it took claims to expire before the hard fork */ /** how long it took claims to expire before the hard fork */
@ -94,6 +96,8 @@ struct Params {
nOriginalClaimExpirationTime : nOriginalClaimExpirationTime :
nExtendedClaimExpirationTime; nExtendedClaimExpirationTime;
} }
/** blocks before the hard fork that adds all claims into the merkle hash */
int64_t nAllClaimsInMerkleForkHeight;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork; uint256 nMinimumChainWork;
uint256 defaultAssumeValid; uint256 defaultAssumeValid;

View file

@ -154,7 +154,8 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout); const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
assert(!coin.IsSpent()); assert(!coin.IsSpent());
const CTxOut &prevout = coin.out; const CTxOut &prevout = coin.out;
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags); const CScript& scriptPubKey = StripClaimScriptPrefix(prevout.scriptPubKey);
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, scriptPubKey, &tx.vin[i].scriptWitness, flags);
} }
return nSigOps; return nSigOps;
} }

View file

@ -15,6 +15,7 @@
#include <util.h> #include <util.h>
#include <utilmoneystr.h> #include <utilmoneystr.h>
#include <utilstrencodings.h> #include <utilstrencodings.h>
#include <nameclaim.h>
UniValue ValueFromAmount(const CAmount& amount) UniValue ValueFromAmount(const CAmount& amount)
{ {
@ -147,12 +148,20 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
out.pushKV("hex", HexStr(script.begin(), script.end())); out.pushKV("hex", HexStr(script.begin(), script.end()));
std::vector<std::vector<unsigned char>> solns; std::vector<std::vector<unsigned char>> solns;
txnouttype type; txnouttype type; int claimOp;
Solver(script, type, solns); auto stripped = StripClaimScriptPrefix(script, claimOp);
out.pushKV("type", GetTxnOutputType(type)); Solver(stripped, type, solns);
if (claimOp >= 0) {
out.pushKV("isclaim", UniValue(claimOp == OP_CLAIM_NAME || claimOp == OP_UPDATE_CLAIM));
out.pushKV("issupport", UniValue(claimOp == OP_SUPPORT_CLAIM));
out.pushKV("subtype", GetTxnOutputType(type));
out.pushKV("type", GetTxnOutputType(TX_NONSTANDARD)); // trying to keep backwards compatibility
}
else
out.pushKV("type", GetTxnOutputType(type)); // trying to keep backwards compatibility
CTxDestination address; CTxDestination address;
if (include_address && ExtractDestination(script, address)) { if (include_address && ExtractDestination(stripped, address)) {
out.pushKV("address", EncodeDestination(address)); out.pushKV("address", EncodeDestination(address));
} }
} }
@ -168,19 +177,28 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
if (fIncludeHex) if (fIncludeHex)
out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { int claimOp;
auto stripped = StripClaimScriptPrefix(scriptPubKey, claimOp);
auto extracted = ExtractDestinations(stripped, type, addresses, nRequired);
if (extracted)
out.pushKV("reqSigs", nRequired);
if (claimOp >= 0) {
out.pushKV("isclaim", UniValue(claimOp == OP_CLAIM_NAME || claimOp == OP_UPDATE_CLAIM));
out.pushKV("issupport", UniValue(claimOp == OP_SUPPORT_CLAIM));
out.pushKV("subtype", GetTxnOutputType(type));
out.pushKV("type", GetTxnOutputType(TX_NONSTANDARD));
}
else
out.pushKV("type", GetTxnOutputType(type)); out.pushKV("type", GetTxnOutputType(type));
return;
}
out.pushKV("reqSigs", nRequired); if (extracted) {
out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR);
for (const CTxDestination &addr : addresses) {
UniValue a(UniValue::VARR); a.push_back(EncodeDestination(addr));
for (const CTxDestination& addr : addresses) { }
a.push_back(EncodeDestination(addr)); out.pushKV("addresses", a);
} }
out.pushKV("addresses", a);
} }
void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)

View file

@ -80,14 +80,14 @@ static void SetMaxOpenFiles(leveldb::Options *options) {
// implementation that does not use extra file descriptors (the fds are // implementation that does not use extra file descriptors (the fds are
// closed after being mmaped). // closed after being mmaped).
// //
// Increasing the value beyond the default is dangerous because LevelDB will // Increasing the value beyond the nmap count is dangerous because LevelDB will
// fall back to a non-mmap implementation when the file count is too large. // fall back to a non-mmap implementation when the file count is too large (thus contending select()).
// On 32-bit Unix host we should decrease the value because the handles use // On 32-bit Unix host we should decrease the value because the handles use
// up real fds, and we want to avoid fd exhaustion issues. // up real fds, and we want to avoid fd exhaustion issues.
// //
// See PR #12495 for further discussion. // See PR #12495 for further discussion.
int default_open_files = options->max_open_files; int default_open_files = 400;
#ifndef WIN32 #ifndef WIN32
if (sizeof(void*) < 8) { if (sizeof(void*) < 8) {
options->max_open_files = 64; options->max_open_files = 64;
@ -100,10 +100,10 @@ static void SetMaxOpenFiles(leveldb::Options *options) {
static leveldb::Options GetOptions(size_t nCacheSize) static leveldb::Options GetOptions(size_t nCacheSize)
{ {
leveldb::Options options; leveldb::Options options;
auto write_cache = std::min(nCacheSize / 4, size_t(16) << 20U); // cap write_cache at 16MB (4x default) auto write_cache = std::min(nCacheSize / 4, size_t(32 * 1024 * 1024)); // cap write_cache
options.block_cache = leveldb::NewLRUCache(nCacheSize - write_cache * 2); options.block_cache = leveldb::NewLRUCache(nCacheSize - write_cache * 2);
options.write_buffer_size = write_cache; // up to two write buffers may be held in memory simultaneously options.write_buffer_size = write_cache; // up to two write buffers may be held in memory simultaneously
options.filter_policy = leveldb::NewBloomFilterPolicy(10); options.filter_policy = leveldb::NewBloomFilterPolicy(12);
options.compression = leveldb::kNoCompression; options.compression = leveldb::kNoCompression;
options.info_log = new CBitcoinLevelDBLogger(); options.info_log = new CBitcoinLevelDBLogger();
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
@ -116,7 +116,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
} }
CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
: m_name(fs::basename(path)) : m_name(fs::basename(path)), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION)
{ {
penv = nullptr; penv = nullptr;
readoptions.verify_checksums = true; readoptions.verify_checksums = true;
@ -181,8 +181,16 @@ CDBWrapper::~CDBWrapper()
options.env = nullptr; options.env = nullptr;
} }
bool CDBWrapper::Sync() {
CDBBatch batch(*this);
return WriteBatch(batch, true);
}
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
{ {
if (!pdb)
return false;
const bool log_memory = LogAcceptCategory(BCLog::LEVELDB); const bool log_memory = LogAcceptCategory(BCLog::LEVELDB);
double mem_before = 0; double mem_before = 0;
if (log_memory) { if (log_memory) {

View file

@ -16,9 +16,6 @@
#include <leveldb/db.h> #include <leveldb/db.h>
#include <leveldb/write_batch.h> #include <leveldb/write_batch.h>
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
class dbwrapper_error : public std::runtime_error class dbwrapper_error : public std::runtime_error
{ {
public: public:
@ -33,87 +30,16 @@ namespace dbwrapper_private {
/** Handle database error by throwing dbwrapper_error exception. /** Handle database error by throwing dbwrapper_error exception.
*/ */
void HandleError(const leveldb::Status& status); void HandleError(const leveldb::Status& status);
/** Work around circular dependency, as well as for testing in dbwrapper_tests. /** Work around circular dependency, as well as for testing in dbwrapper_tests.
* Database obfuscation should be considered an implementation detail of the * Database obfuscation should be considered an implementation detail of the
* specific database. * specific database.
*/ */
const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w); const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
}; };
/** Batch of changes queued to be written to a CDBWrapper */
class CDBBatch
{
friend class CDBWrapper;
private:
const CDBWrapper &parent;
leveldb::WriteBatch batch;
CDataStream ssKey;
CDataStream ssValue;
size_t size_estimate;
public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
void Clear()
{
batch.Clear();
size_estimate = 0;
}
template <typename K, typename V>
void Write(const K& key, const V& value)
{
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size());
ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
ssValue << value;
ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
leveldb::Slice slValue(ssValue.data(), ssValue.size());
batch.Put(slKey, slValue);
// LevelDB serializes writes as:
// - byte: header
// - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
// - byte[]: key
// - varint: value length
// - byte[]: value
// The formula below assumes the key and value are both less than 16k.
size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
ssKey.clear();
ssValue.clear();
}
template <typename K>
void Erase(const K& key)
{
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size());
batch.Delete(slKey);
// LevelDB serializes erases as:
// - byte: header
// - varint: key length
// - byte[]: key
// The formula below assumes the key is less than 16kB.
size_estimate += 2 + (slKey.size() > 127) + slKey.size();
ssKey.clear();
}
size_t SizeEstimate() const { return size_estimate; }
};
class CDBIterator class CDBIterator
{ {
private: private:
@ -127,7 +53,7 @@ public:
* @param[in] _piter The original leveldb iterator. * @param[in] _piter The original leveldb iterator.
*/ */
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) : CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
parent(_parent), piter(_piter) { }; parent(_parent), piter(_piter) { };
~CDBIterator(); ~CDBIterator();
bool Valid() const; bool Valid() const;
@ -136,7 +62,6 @@ public:
template<typename K> void Seek(const K& key) { template<typename K> void Seek(const K& key) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key; ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size()); leveldb::Slice slKey(ssKey.data(), ssKey.size());
piter->Seek(slKey); piter->Seek(slKey);
@ -173,6 +98,8 @@ public:
}; };
class CDBBatch;
class CDBWrapper class CDBWrapper
{ {
friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
@ -213,6 +140,8 @@ private:
std::vector<unsigned char> CreateObfuscateKey() const; std::vector<unsigned char> CreateObfuscateKey() const;
public: public:
mutable CDataStream ssKey, ssValue;
/** /**
* @param[in] path Location in the filesystem where leveldb data will be stored. * @param[in] path Location in the filesystem where leveldb data will be stored.
* @param[in] nCacheSize Configures various leveldb cache settings. * @param[in] nCacheSize Configures various leveldb cache settings.
@ -222,7 +151,7 @@ public:
* with a zero'd byte array. * with a zero'd byte array.
*/ */
CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false); CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
~CDBWrapper(); virtual ~CDBWrapper();
CDBWrapper(const CDBWrapper&) = delete; CDBWrapper(const CDBWrapper&) = delete;
/* CDBWrapper& operator=(const CDBWrapper&) = delete; */ /* CDBWrapper& operator=(const CDBWrapper&) = delete; */
@ -230,13 +159,13 @@ public:
template <typename K, typename V> template <typename K, typename V>
bool Read(const K& key, V& value) const bool Read(const K& key, V& value) const
{ {
CDataStream ssKey(SER_DISK, CLIENT_VERSION); assert(ssKey.empty());
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key; ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size()); leveldb::Slice slKey(ssKey.data(), ssKey.size());
std::string strValue; std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
ssKey.clear();
if (!status.ok()) { if (!status.ok()) {
if (status.IsNotFound()) if (status.IsNotFound())
return false; return false;
@ -254,23 +183,17 @@ public:
} }
template <typename K, typename V> template <typename K, typename V>
bool Write(const K& key, const V& value, bool fSync = false) bool Write(const K& key, const V& value, bool fSync = false);
{
CDBBatch batch(*this);
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
template <typename K> template <typename K>
bool Exists(const K& key) const bool Exists(const K& key) const
{ {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
ssKey << key; ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size()); leveldb::Slice slKey(ssKey.data(), ssKey.size());
std::string strValue; std::string strValue;
leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
ssKey.clear();
if (!status.ok()) { if (!status.ok()) {
if (status.IsNotFound()) if (status.IsNotFound())
return false; return false;
@ -281,12 +204,7 @@ public:
} }
template <typename K> template <typename K>
bool Erase(const K& key, bool fSync = false) bool Erase(const K& key, bool fSync = false);
{
CDBBatch batch(*this);
batch.Erase(key);
return WriteBatch(batch, fSync);
}
bool WriteBatch(CDBBatch& batch, bool fSync = false); bool WriteBatch(CDBBatch& batch, bool fSync = false);
@ -299,11 +217,7 @@ public:
return true; return true;
} }
bool Sync() bool Sync();
{
CDBBatch batch(*this);
return WriteBatch(batch, true);
}
CDBIterator *NewIterator() CDBIterator *NewIterator()
{ {
@ -319,8 +233,8 @@ public:
size_t EstimateSize(const K& key_begin, const K& key_end) const size_t EstimateSize(const K& key_begin, const K& key_end) const
{ {
CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION); CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey1.reserve(ssKey.capacity());
ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey2.reserve(ssKey.capacity());
ssKey1 << key_begin; ssKey1 << key_begin;
ssKey2 << key_end; ssKey2 << key_end;
leveldb::Slice slKey1(ssKey1.data(), ssKey1.size()); leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
@ -338,8 +252,8 @@ public:
void CompactRange(const K& key_begin, const K& key_end) const void CompactRange(const K& key_begin, const K& key_end) const
{ {
CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION); CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey1.reserve(ssKey.capacity());
ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey2.reserve(ssKey.capacity());
ssKey1 << key_begin; ssKey1 << key_begin;
ssKey2 << key_end; ssKey2 << key_end;
leveldb::Slice slKey1(ssKey1.data(), ssKey1.size()); leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
@ -349,4 +263,88 @@ public:
}; };
/** Batch of changes queued to be written to a CDBWrapper */
class CDBBatch
{
friend class CDBWrapper;
const CDBWrapper &parent;
leveldb::WriteBatch batch;
size_t size_estimate;
CDataStream ssKey, ssValue;
public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), size_estimate(0),
ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION) {
ssKey.reserve(parent.ssKey.capacity());
ssValue.reserve(parent.ssValue.capacity());
};
void Clear()
{
batch.Clear();
size_estimate = 0;
}
template <typename K, typename V>
void Write(const K& key, const V& value)
{
assert(ssKey.empty());
ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size());
assert(ssValue.empty());
ssValue << value;
ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
leveldb::Slice slValue(ssValue.data(), ssValue.size());
batch.Put(slKey, slValue);
// LevelDB serializes writes as:
// - byte: header
// - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
// - byte[]: key
// - varint: value length
// - byte[]: value
// The formula below assumes the key and value are both less than 16k.
size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
ssKey.clear();
ssValue.clear();
}
template <typename K>
void Erase(const K& key)
{
ssKey << key;
leveldb::Slice slKey(ssKey.data(), ssKey.size());
batch.Delete(slKey);
// LevelDB serializes erases as:
// - byte: header
// - varint: key length
// - byte[]: key
// The formula below assumes the key is less than 16kB.
size_estimate += 2 + (slKey.size() > 127) + slKey.size();
ssKey.clear();
}
size_t SizeEstimate() const { return size_estimate; }
};
template<typename K>
bool CDBWrapper::Erase(const K &key, bool fSync) {
CDBBatch batch(*this);
batch.Erase(key);
return WriteBatch(batch, fSync);
}
template<typename K, typename V>
bool CDBWrapper::Write(const K &key, const V &value, bool fSync) {
CDBBatch batch(*this);
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
#endif // BITCOIN_DBWRAPPER_H #endif // BITCOIN_DBWRAPPER_H

View file

@ -28,6 +28,8 @@ protected:
DB(const fs::path& path, size_t n_cache_size, DB(const fs::path& path, size_t n_cache_size,
bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false);
~DB() override {}
/// Read block locator of the chain that the txindex is in sync with. /// Read block locator of the chain that the txindex is in sync with.
bool ReadBestBlock(CBlockLocator& locator) const; bool ReadBestBlock(CBlockLocator& locator) const;

View file

@ -29,6 +29,7 @@ class TxIndex::DB : public BaseIndex::DB
{ {
public: public:
explicit DB(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); explicit DB(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
~DB() override {}
/// Read the disk location of the transaction data with the given hash. Returns false if the /// Read the disk location of the transaction data with the given hash. Returns false if the
/// transaction hash is not indexed. /// transaction hash is not indexed.

View file

@ -22,6 +22,7 @@
#include <httprpc.h> #include <httprpc.h>
#include <index/txindex.h> #include <index/txindex.h>
#include <key.h> #include <key.h>
#include <lbry.h>
#include <validation.h> #include <validation.h>
#include <miner.h> #include <miner.h>
#include <netbase.h> #include <netbase.h>
@ -370,6 +371,7 @@ void SetupServerArgs()
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS); gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-claimtriecache=<n>", strprintf("Set claim trie cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS); gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS); gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS);
gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS);
@ -397,6 +399,7 @@ void SetupServerArgs()
hidden_args.emplace_back("-sysperms"); hidden_args.emplace_back("-sysperms");
#endif #endif
gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), false, OptionsCategory::OPTIONS); gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-memfile=<GiB>", "Use a memory mapped file for the claimtrie allocations (default: use RAM instead)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", false, OptionsCategory::CONNECTION); gArgs.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", false, OptionsCategory::CONNECTION);
gArgs.AddArg("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD), false, OptionsCategory::CONNECTION); gArgs.AddArg("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD), false, OptionsCategory::CONNECTION);
@ -483,7 +486,6 @@ void SetupServerArgs()
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST); CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", false, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", false, OptionsCategory::DEBUG_TEST);
SetupChainParamsBaseOptions(); SetupChainParamsBaseOptions();
@ -1233,11 +1235,6 @@ bool AppInitMain()
CreatePidFile(GetPidFile(), getpid()); CreatePidFile(GetPidFile(), getpid());
#endif #endif
if (g_logger->m_print_to_file) { if (g_logger->m_print_to_file) {
if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) {
// Do this first since it both loads a bunch of debug.log into memory,
// and because this needs to happen before any other debug.log printing
g_logger->ShrinkDebugFile();
}
if (!g_logger->OpenDebugLog()) { if (!g_logger->OpenDebugLog()) {
return InitError(strprintf("Could not open debug log file %s", return InitError(strprintf("Could not open debug log file %s",
g_logger->m_file_path.string())); g_logger->m_file_path.string()));
@ -1440,6 +1437,8 @@ bool AppInitMain()
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
g_memfileSize = gArgs.GetArg("-memfile", 0u);
bool fLoaded = false; bool fLoaded = false;
while (!fLoaded && !ShutdownRequested()) { while (!fLoaded && !ShutdownRequested()) {
bool fReset = fReindex; bool fReset = fReindex;
@ -1461,7 +1460,10 @@ bool AppInitMain()
pblocktree.reset(); pblocktree.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset)); pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
delete pclaimTrie; delete pclaimTrie;
pclaimTrie = new CClaimTrie(false, fReindex); int64_t trieCacheMB = gArgs.GetArg("-claimtriecache", nDefaultDbCache);
trieCacheMB = std::min(trieCacheMB, nMaxDbCache);
trieCacheMB = std::max(trieCacheMB, nMinDbCache);
pclaimTrie = new CClaimTrie(false, fReindex || fReindexChainState, 32, trieCacheMB);
if (fReset) { if (fReset) {
pblocktree->WriteReindexing(true); pblocktree->WriteReindexing(true);
@ -1702,9 +1704,6 @@ bool AppInitMain()
} }
LogPrintf("nBestHeight = %d\n", chain_active_height); LogPrintf("nBestHeight = %d\n", chain_active_height);
const Consensus::Params& consensusParams = Params().GetConsensus();
CClaimTrieCache(pclaimTrie).setExpirationTime(consensusParams.GetExpirationTime(chain_active_height));
if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(); StartTorControl();

View file

@ -3,6 +3,8 @@
#include <cstdio> #include <cstdio>
uint32_t g_memfileSize = 0;
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{ {
if (params.fPowNoRetargeting) if (params.fPowNoRetargeting)

View file

@ -4,6 +4,7 @@
#include <chain.h> #include <chain.h>
#include <chainparams.h> #include <chainparams.h>
extern uint32_t g_memfileSize;
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params); unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params);
#endif #endif

View file

@ -221,6 +221,9 @@ class RandomAccessFile {
// Get a name for the file, only for error reporting // Get a name for the file, only for error reporting
virtual std::string GetName() const = 0; virtual std::string GetName() const = 0;
virtual char* AllocateScratch(std::size_t size) const { return new char[size]; };
virtual void DeallocateScratch(char* pointer) const { delete[] pointer; };
private: private:
// No copying allowed // No copying allowed
RandomAccessFile(const RandomAccessFile&); RandomAccessFile(const RandomAccessFile&);

View file

@ -73,15 +73,15 @@ Status ReadBlock(RandomAccessFile* file,
// Read the block contents as well as the type/crc footer. // Read the block contents as well as the type/crc footer.
// See table_builder.cc for the code that built this structure. // See table_builder.cc for the code that built this structure.
size_t n = static_cast<size_t>(handle.size()); size_t n = static_cast<size_t>(handle.size());
char* buf = new char[n + kBlockTrailerSize]; char* buf = file->AllocateScratch(n + kBlockTrailerSize);
Slice contents; Slice contents;
Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);
if (!s.ok()) { if (!s.ok()) {
delete[] buf; file->DeallocateScratch(buf);
return s; return s;
} }
if (contents.size() != n + kBlockTrailerSize) { if (contents.size() != n + kBlockTrailerSize) {
delete[] buf; file->DeallocateScratch(buf);
return Status::Corruption("truncated block read", file->GetName()); return Status::Corruption("truncated block read", file->GetName());
} }
@ -91,7 +91,7 @@ Status ReadBlock(RandomAccessFile* file,
const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));
const uint32_t actual = crc32c::Value(data, n + 1); const uint32_t actual = crc32c::Value(data, n + 1);
if (actual != crc) { if (actual != crc) {
delete[] buf; file->DeallocateScratch(buf);
s = Status::Corruption("block checksum mismatch", file->GetName()); s = Status::Corruption("block checksum mismatch", file->GetName());
return s; return s;
} }
@ -103,7 +103,7 @@ Status ReadBlock(RandomAccessFile* file,
// File implementation gave us pointer to some other data. // File implementation gave us pointer to some other data.
// Use it directly under the assumption that it will be live // Use it directly under the assumption that it will be live
// while the file is open. // while the file is open.
delete[] buf; file->DeallocateScratch(buf);
result->data = Slice(data, n); result->data = Slice(data, n);
result->heap_allocated = false; result->heap_allocated = false;
result->cachable = false; // Do not double-cache result->cachable = false; // Do not double-cache
@ -118,23 +118,23 @@ Status ReadBlock(RandomAccessFile* file,
case kSnappyCompression: { case kSnappyCompression: {
size_t ulength = 0; size_t ulength = 0;
if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) {
delete[] buf; file->DeallocateScratch(buf);
return Status::Corruption("corrupted compressed block contents", file->GetName()); return Status::Corruption("corrupted compressed block contents", file->GetName());
} }
char* ubuf = new char[ulength]; char* ubuf = new char[ulength];
if (!port::Snappy_Uncompress(data, n, ubuf)) { if (!port::Snappy_Uncompress(data, n, ubuf)) {
delete[] buf; file->DeallocateScratch(buf);
delete[] ubuf; delete[] ubuf;
return Status::Corruption("corrupted compressed block contents", file->GetName()); return Status::Corruption("corrupted compressed block contents", file->GetName());
} }
delete[] buf; file->DeallocateScratch(buf);
result->data = Slice(ubuf, ulength); result->data = Slice(ubuf, ulength);
result->heap_allocated = true; result->heap_allocated = true;
result->cachable = true; result->cachable = true;
break; break;
} }
default: default:
delete[] buf; file->DeallocateScratch(buf);
return Status::Corruption("bad block type", file->GetName()); return Status::Corruption("bad block type", file->GetName());
} }

View file

@ -162,6 +162,7 @@ class PosixRandomAccessFile: public RandomAccessFile {
} }
Status s; Status s;
assert(scratch);
ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset)); ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset));
*result = Slice(scratch, (r < 0) ? 0 : r); *result = Slice(scratch, (r < 0) ? 0 : r);
if (r < 0) { if (r < 0) {
@ -188,19 +189,19 @@ class PosixMmapReadableFile: public RandomAccessFile {
public: public:
// base[0,length-1] contains the mmapped contents of the file. // base[0,length-1] contains the mmapped contents of the file.
PosixMmapReadableFile(const std::string& fname, void* base, size_t length, PosixMmapReadableFile(std::string fname, void* base, size_t length,
Limiter* limiter) Limiter* limiter)
: filename_(fname), mmapped_region_(base), length_(length), : filename_(std::move(fname)), mmapped_region_(base), length_(length),
limiter_(limiter) { limiter_(limiter) {
} }
virtual ~PosixMmapReadableFile() { ~PosixMmapReadableFile() override {
munmap(mmapped_region_, length_); munmap(mmapped_region_, length_);
limiter_->Release(); limiter_->Release();
} }
virtual Status Read(uint64_t offset, size_t n, Slice* result, Status Read(uint64_t offset, size_t n, Slice* result,
char* scratch) const { char* scratch) const override {
Status s; Status s;
if (offset + n > length_) { if (offset + n > length_) {
*result = Slice(); *result = Slice();
@ -211,7 +212,10 @@ class PosixMmapReadableFile: public RandomAccessFile {
return s; return s;
} }
virtual std::string GetName() const { return filename_; } std::string GetName() const override { return filename_; }
char* AllocateScratch(std::size_t size) const override { return nullptr; }
void DeallocateScratch(char* pointer) const override { assert(pointer == nullptr); }
}; };
class PosixWritableFile : public WritableFile { class PosixWritableFile : public WritableFile {
@ -585,8 +589,8 @@ static int MaxMmaps() {
if (mmap_limit >= 0) { if (mmap_limit >= 0) {
return mmap_limit; return mmap_limit;
} }
// Up to 4096 mmaps for 64-bit binaries; none for smaller pointer sizes. // Up to 400 mmaps for 64-bit binaries (800MB); none for smaller pointer sizes.
mmap_limit = sizeof(void*) >= 8 ? 4096 : 0; mmap_limit = sizeof(void*) >= 8 ? 400 : 0;
return mmap_limit; return mmap_limit;
} }

View file

@ -37,6 +37,12 @@ bool BCLog::Logger::OpenDebugLog()
assert(m_fileout == nullptr); assert(m_fileout == nullptr);
assert(!m_file_path.empty()); assert(!m_file_path.empty());
if (fs::exists(m_file_path)) {
fs::path old_file_path(m_file_path);
old_file_path += ".old";
fs::rename(m_file_path, old_file_path);
}
m_fileout = fsbridge::fopen(m_file_path, "a"); m_fileout = fsbridge::fopen(m_file_path, "a");
if (!m_fileout) { if (!m_fileout) {
return false; return false;
@ -83,11 +89,6 @@ bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
return (m_categories.load(std::memory_order_relaxed) & category) != 0; return (m_categories.load(std::memory_order_relaxed) & category) != 0;
} }
bool BCLog::Logger::DefaultShrinkDebugFile() const
{
return m_categories == BCLog::NONE;
}
struct CLogCategoryDesc struct CLogCategoryDesc
{ {
BCLog::LogFlags flag; BCLog::LogFlags flag;
@ -119,6 +120,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::COINDB, "coindb"}, {BCLog::COINDB, "coindb"},
{BCLog::QT, "qt"}, {BCLog::QT, "qt"},
{BCLog::LEVELDB, "leveldb"}, {BCLog::LEVELDB, "leveldb"},
{BCLog::CLAIMS, "claims"},
{BCLog::ALL, "1"}, {BCLog::ALL, "1"},
{BCLog::ALL, "all"}, {BCLog::ALL, "all"},
}; };
@ -230,44 +232,3 @@ void BCLog::Logger::LogPrintStr(const std::string &str)
} }
} }
} }
void BCLog::Logger::ShrinkDebugFile()
{
// Amount of debug.log to save at end when shrinking (must fit in memory)
constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
assert(!m_file_path.empty());
// Scroll debug.log if it's getting too big
FILE* file = fsbridge::fopen(m_file_path, "r");
// Special files (e.g. device nodes) may not have a size.
size_t log_size = 0;
try {
log_size = fs::file_size(m_file_path);
} catch (boost::filesystem::filesystem_error &) {}
// If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
// trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
{
// Restart the file with some of the end
std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
if (fseek(file, -((long)vch.size()), SEEK_END)) {
LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
fclose(file);
return;
}
int nBytes = fread(vch.data(), 1, vch.size(), file);
fclose(file);
file = fsbridge::fopen(m_file_path, "w");
if (file)
{
fwrite(vch.data(), 1, nBytes, file);
fclose(file);
}
}
else if (file != nullptr)
fclose(file);
}

View file

@ -53,6 +53,7 @@ namespace BCLog {
COINDB = (1 << 18), COINDB = (1 << 18),
QT = (1 << 19), QT = (1 << 19),
LEVELDB = (1 << 20), LEVELDB = (1 << 20),
CLAIMS = (1 << 30),
ALL = ~(uint32_t)0, ALL = ~(uint32_t)0,
}; };
@ -92,7 +93,6 @@ namespace BCLog {
bool Enabled() const { return m_print_to_console || m_print_to_file; } bool Enabled() const { return m_print_to_console || m_print_to_file; }
bool OpenDebugLog(); bool OpenDebugLog();
void ShrinkDebugFile();
uint32_t GetCategoryMask() const { return m_categories.load(); } uint32_t GetCategoryMask() const { return m_categories.load(); }
@ -102,8 +102,6 @@ namespace BCLog {
bool DisableCategory(const std::string& str); bool DisableCategory(const std::string& str);
bool WillLogCategory(LogFlags category) const; bool WillLogCategory(LogFlags category) const;
bool DefaultShrinkDebugFile() const;
}; };
} // namespace BCLog } // namespace BCLog

View file

@ -53,6 +53,35 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime; return nNewTime - nOldTime;
} }
void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight)
{
insertUndoType dummyInsertUndo;
claimQueueRowType dummyExpireUndo;
insertUndoType dummyInsertSupportUndo;
supportQueueRowType dummyExpireSupportUndo;
std::vector<std::pair<std::string, int> > dummyTakeoverHeightUndo;
CUpdateCacheCallbacks callbacks = {
.findScriptKey = [&pblock](const COutPoint& point) {
for (auto& tx : pblock->vtx)
if (tx->GetHash() == point.hash && point.n < tx->vout.size())
return tx->vout[point.n].scriptPubKey;
return CScript{};
},
.claimUndoHeights = {}
};
trieCache.initializeIncrement();
CCoinsViewCache view(pcoinsTip.get());
for (auto& tx : pblock->vtx)
if (!tx->IsCoinBase())
UpdateCache(*tx, trieCache, view, nHeight, callbacks);
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo);
}
BlockAssembler::Options::Options() { BlockAssembler::Options::Options() {
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
@ -118,12 +147,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
assert(pindexPrev != nullptr); assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1; nHeight = pindexPrev->nHeight + 1;
if (!pclaimTrie)
{
LogPrintf("CreateNewBlock(): pclaimTrie is invalid");
return NULL;
}
CClaimTrieCache trieCache(pclaimTrie);
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// -regtest only: allow overriding block.nVersion with // -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios // -blockversion=N to test forking scenarios
@ -150,7 +173,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
int nPackagesSelected = 0; int nPackagesSelected = 0;
int nDescendantsUpdated = 0; int nDescendantsUpdated = 0;
addPackageTxs(nPackagesSelected, nDescendantsUpdated, trieCache); addPackageTxs(nPackagesSelected, nDescendantsUpdated);
int64_t nTime1 = GetTimeMicros(); int64_t nTime1 = GetTimeMicros();
@ -178,20 +201,14 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblock->nNonce = 0; pblock->nNonce = 0;
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
insertUndoType dummyInsertUndo; CClaimTrieCache trieCache(pclaimTrie);
claimQueueRowType dummyExpireUndo; blockToCache(pblock, trieCache, nHeight);
insertUndoType dummyInsertSupportUndo;
supportQueueRowType dummyExpireSupportUndo;
std::vector<std::pair<std::string, int> > dummyTakeoverHeightUndo;
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo);
pblock->hashClaimTrie = trieCache.getMerkleHash(); pblock->hashClaimTrie = trieCache.getMerkleHash();
CValidationState state; CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
// if (trieCache.checkConsistency()) // TODO: bring back after prefixtrie merge if (!trieCache.empty())
// trieCache.dumpToLog(trieCache.begin()); trieCache.dumpToLog(trieCache.find({}));
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
} }
int64_t nTime2 = GetTimeMicros(); int64_t nTime2 = GetTimeMicros();
@ -311,42 +328,6 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve
std::sort(sortedEntries.begin(), sortedEntries.end(), CompareTxIterByAncestorCount()); std::sort(sortedEntries.begin(), sortedEntries.end(), CompareTxIterByAncestorCount());
} }
void iterToTrieCache(CTxMemPool::txiter iter, CClaimTrieCache& trieCache, const CTxMemPool::setEntries& entries, int nHeight)
{
spentClaimsType spentClaims;
auto& tx = iter->GetTx();
CCoinsViewCache view(pcoinsTip.get());
for (const CTxIn& txin: tx.vin) {
const Coin& coin = view.AccessCoin(txin.prevout);
CScript scriptPubKey;
int scriptHeight = nHeight;
if (coin.out.IsNull()) {
for (auto entry : entries) {
auto& e = entry->GetTx();
if (e.GetHash() != txin.prevout.hash || txin.prevout.n >= e.vout.size())
continue;
scriptPubKey = e.vout[txin.prevout.n].scriptPubKey;
break;
}
} else {
scriptPubKey = coin.out.scriptPubKey;
scriptHeight = coin.nHeight;
}
if (!scriptPubKey.empty()) {
int throwaway;
SpendClaim(trieCache, scriptPubKey, COutPoint(txin.prevout.hash, txin.prevout.n), scriptHeight, throwaway, spentClaims);
}
}
for (unsigned int i = 0; i < tx.vout.size(); ++i) {
const CTxOut& txout = tx.vout[i];
if (!txout.scriptPubKey.empty())
AddSpendClaim(trieCache, txout.scriptPubKey, COutPoint(tx.GetHash(), i), txout.nValue, nHeight, spentClaims);
}
}
// This transaction selection algorithm orders the mempool based // This transaction selection algorithm orders the mempool based
// on feerate of a transaction including all unconfirmed ancestors. // on feerate of a transaction including all unconfirmed ancestors.
// Since we don't remove transactions from the mempool as we select them // Since we don't remove transactions from the mempool as we select them
@ -357,7 +338,7 @@ void iterToTrieCache(CTxMemPool::txiter iter, CClaimTrieCache& trieCache, const
// Each time through the loop, we compare the best transaction in // Each time through the loop, we compare the best transaction in
// mapModifiedTxs with the next transaction in the mempool to decide what // mapModifiedTxs with the next transaction in the mempool to decide what
// transaction package to work on next. // transaction package to work on next.
void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, CClaimTrieCache& trieCache) void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
{ {
// mapModifiedTx will store sorted packages after they are modified // mapModifiedTx will store sorted packages after they are modified
// because some of their txs are already in the block // because some of their txs are already in the block
@ -474,7 +455,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
SortForBlock(ancestors, sortedEntries); SortForBlock(ancestors, sortedEntries);
for (size_t i=0; i<sortedEntries.size(); ++i) { for (size_t i=0; i<sortedEntries.size(); ++i) {
iterToTrieCache(sortedEntries[i], trieCache, inBlock, nHeight);
AddToBlock(sortedEntries[i]); AddToBlock(sortedEntries[i]);
// Erase from the modified set, if present // Erase from the modified set, if present
mapModifiedTx.erase(sortedEntries[i]); mapModifiedTx.erase(sortedEntries[i]);

View file

@ -170,7 +170,7 @@ private:
/** Add transactions based on feerate including unconfirmed ancestors /** Add transactions based on feerate including unconfirmed ancestors
* Increments nPackagesSelected / nDescendantsUpdated with corresponding * Increments nPackagesSelected / nDescendantsUpdated with corresponding
* statistics from the package selection (for logging statistics). */ * statistics from the package selection (for logging statistics). */
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, CClaimTrieCache& trieCache) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs);
// helper functions for addPackageTxs() // helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */ /** Remove confirmed (inBlock) entries from given set */

View file

@ -1,9 +1,6 @@
#include <boost/foreach.hpp>
#include "nameclaim.h" #include "nameclaim.h"
#include "hash.h" #include "hash.h"
#include "util.h" #include "util.h"
#include "claimtrie.h"
std::vector<unsigned char> uint32_t_to_vch(uint32_t n) std::vector<unsigned char> uint32_t_to_vch(uint32_t n)
{ {
@ -21,25 +18,35 @@ uint32_t vch_to_uint32_t(std::vector<unsigned char>& vchN)
uint32_t n; uint32_t n;
static const size_t uint32Size = sizeof(uint32_t); static const size_t uint32Size = sizeof(uint32_t);
if (vchN.size() != uint32Size) { if (vchN.size() != uint32Size) {
LogPrintf("%s() : a vector<unsigned char> with size other than 4 has been given", __func__); LogPrintf("%s() : a vector<unsigned char> with size other than 4 has been given\n", __func__);
return 0; return 0;
} }
n = vchN[0] << 24 | vchN[1] << 16 | vchN[2] << 8 | vchN[3]; n = vchN[0] << 24 | vchN[1] << 16 | vchN[2] << 8 | vchN[3];
return n; return n;
} }
CScript ClaimNameScript(std::string name, std::string value) CScript ClaimNameScript(std::string name, std::string value, bool fakeSuffix)
{ {
std::vector<unsigned char> vchName(name.begin(), name.end()); std::vector<unsigned char> vchName(name.begin(), name.end());
std::vector<unsigned char> vchValue(value.begin(), value.end()); std::vector<unsigned char> vchValue(value.begin(), value.end());
return CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE; auto ret = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP;
if (fakeSuffix) ret.push_back(OP_TRUE);
return ret;
} }
CScript SupportClaimScript(std::string name, uint160 claimId) CScript SupportClaimScript(std::string name, uint160 claimId, std::string value, bool fakeSuffix)
{ {
std::vector<unsigned char> vchName(name.begin(), name.end()); std::vector<unsigned char> vchName(name.begin(), name.end());
std::vector<unsigned char> vchClaimId(claimId.begin(), claimId.end()); std::vector<unsigned char> vchClaimId(claimId.begin(), claimId.end());
return CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId << OP_2DROP << OP_DROP << OP_TRUE; CScript ret;
if (value.empty())
ret = CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId << OP_2DROP << OP_DROP;
else {
std::vector<unsigned char> vchValue(value.begin(), value.end());
ret = CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP;
}
if (fakeSuffix) ret.push_back(OP_TRUE);
return ret;
} }
CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value) CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value)
@ -50,14 +57,15 @@ CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value)
return CScript() << OP_UPDATE_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP << OP_TRUE; return CScript() << OP_UPDATE_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP << OP_TRUE;
} }
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams) bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, bool allowSupportMetadata)
{ {
CScript::const_iterator pc = scriptIn.begin(); CScript::const_iterator pc = scriptIn.begin();
return DecodeClaimScript(scriptIn, op, vvchParams, pc); return DecodeClaimScript(scriptIn, op, vvchParams, pc, allowSupportMetadata);
} }
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc) bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc, bool allowSupportMetadata)
{ {
op = -1;
opcodetype opcode; opcodetype opcode;
if (!scriptIn.GetOp(pc, opcode)) if (!scriptIn.GetOp(pc, opcode))
{ {
@ -78,6 +86,7 @@ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector
// OP_CLAIM_NAME vchName vchValue OP_2DROP OP_DROP pubkeyscript // OP_CLAIM_NAME vchName vchValue OP_2DROP OP_DROP pubkeyscript
// OP_UPDATE_CLAIM vchName vchClaimId vchValue OP_2DROP OP_2DROP pubkeyscript // OP_UPDATE_CLAIM vchName vchClaimId vchValue OP_2DROP OP_2DROP pubkeyscript
// OP_SUPPORT_CLAIM vchName vchClaimId OP_2DROP OP_DROP pubkeyscript // OP_SUPPORT_CLAIM vchName vchClaimId OP_2DROP OP_DROP pubkeyscript
// OP_SUPPORT_CLAIM vchName vchClaimId vchValue OP_2DROP OP_2DROP pubkeyscript
// All others are invalid. // All others are invalid.
if (!scriptIn.GetOp(pc, opcode, vchParam1) || opcode < 0 || opcode > OP_PUSHDATA4) if (!scriptIn.GetOp(pc, opcode, vchParam1) || opcode < 0 || opcode > OP_PUSHDATA4)
@ -95,35 +104,42 @@ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector
return false; return false;
} }
} }
if (op == OP_UPDATE_CLAIM)
if (!scriptIn.GetOp(pc, opcode, vchParam3))
{ {
if (!scriptIn.GetOp(pc, opcode, vchParam3) || opcode < 0 || opcode > OP_PUSHDATA4) return false;
}
auto last_drop = OP_DROP;
if (opcode >= 0 && opcode <= OP_PUSHDATA4 && op != OP_CLAIM_NAME)
{
if (!scriptIn.GetOp(pc, opcode))
{ {
return false; return false;
} }
last_drop = OP_2DROP;
} }
if (!scriptIn.GetOp(pc, opcode) || opcode != OP_2DROP) else if (op == OP_UPDATE_CLAIM)
{ {
return false; return false;
} }
if (!scriptIn.GetOp(pc, opcode)) if (opcode != OP_2DROP)
{ {
return false; return false;
} }
if ((op == OP_CLAIM_NAME || op == OP_SUPPORT_CLAIM) && opcode != OP_DROP) if (!scriptIn.GetOp(pc, opcode) || opcode != last_drop)
{ {
return false; return false;
} }
else if ((op == OP_UPDATE_CLAIM) && opcode != OP_2DROP) if (op == OP_SUPPORT_CLAIM && last_drop == OP_2DROP && !allowSupportMetadata)
{ {
return false; return false;
} }
vvchParams.push_back(vchParam1); vvchParams.push_back(std::move(vchParam1));
vvchParams.push_back(vchParam2); vvchParams.push_back(std::move(vchParam2));
if (op == OP_UPDATE_CLAIM) if (last_drop == OP_2DROP)
{ {
vvchParams.push_back(vchParam3); vvchParams.push_back(std::move(vchParam3));
} }
return true; return true;
} }
@ -184,7 +200,7 @@ CAmount CalcMinClaimTrieFee(const CTransaction& tx, const CAmount &minFeePerName
} }
CAmount min_fee = 0; CAmount min_fee = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout) for (const CTxOut& txout: tx.vout)
{ {
int op; int op;
std::vector<std::vector<unsigned char> > vvchParams; std::vector<std::vector<unsigned char> > vvchParams;

View file

@ -11,7 +11,7 @@
// This is the minimum claim fee per character in the name of an OP_CLAIM_NAME command that must // This is the minimum claim fee per character in the name of an OP_CLAIM_NAME command that must
// be attached to transactions for it to be accepted into the memory pool. // be attached to transactions for it to be accepted into the memory pool.
// Rationale: current implementation of the claim trie uses more memory for longer name claims // Rationale: current implementation of the claim trie uses more memory for longer name claims
// due to the fact that each chracater is assigned a trie node regardless of whether it contains // due to the fact that each character is assigned a trie node regardless of whether it contains
// any claims or not. In the future, we can switch to a radix tree implementation where // any claims or not. In the future, we can switch to a radix tree implementation where
// empty nodes do not take up any memory and the minimum fee can be priced on a per claim // empty nodes do not take up any memory and the minimum fee can be priced on a per claim
// basis. // basis.
@ -25,11 +25,11 @@
// Scripts exceeding this size are rejected in CheckTransaction in main.cpp // Scripts exceeding this size are rejected in CheckTransaction in main.cpp
#define MAX_CLAIM_NAME_SIZE 255 #define MAX_CLAIM_NAME_SIZE 255
CScript ClaimNameScript(std::string name, std::string value); CScript ClaimNameScript(std::string name, std::string value, bool fakeSuffix=true);
CScript SupportClaimScript(std::string name, uint160 claimId); CScript SupportClaimScript(std::string name, uint160 claimId, std::string value="", bool fakeSuffix=true);
CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value); CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value);
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams); bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, bool allowSupportMetadata=true);
bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc); bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc, bool allowSupportMetadata=true);
CScript StripClaimScriptPrefix(const CScript& scriptIn); CScript StripClaimScriptPrefix(const CScript& scriptIn);
CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op); CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op);
uint160 ClaimIdHash(const uint256& txhash, uint32_t nOut); uint160 ClaimIdHash(const uint256& txhash, uint32_t nOut);

View file

@ -10,11 +10,9 @@
#include <consensus/validation.h> #include <consensus/validation.h>
#include <validation.h> #include <validation.h>
#include <coins.h> #include <coins.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h> #include <utilstrencodings.h>
#include "nameclaim.h" #include <nameclaim.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
@ -117,8 +115,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
unsigned int nDataOut = 0; unsigned int nDataOut = 0;
txnouttype whichType; txnouttype whichType;
for (const CTxOut& txout : tx.vout) { for (const CTxOut& txout : tx.vout) {
const CScript& scriptPubKey = StripClaimScriptPrefix(txout.scriptPubKey); if (!::IsStandard(StripClaimScriptPrefix(txout.scriptPubKey), whichType)) {
if (!::IsStandard(scriptPubKey, whichType)) {
reason = "scriptpubkey"; reason = "scriptpubkey";
return false; return false;
} }
@ -171,8 +168,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
std::vector<std::vector<unsigned char> > vSolutions; std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType; txnouttype whichType;
// get the scriptPubKey corresponding to this input: // get the scriptPubKey corresponding to this input:
const CScript& prevScript = StripClaimScriptPrefix(prev.scriptPubKey); if (!Solver(StripClaimScriptPrefix(prev.scriptPubKey), whichType, vSolutions))
if (!Solver(prevScript, whichType, vSolutions))
return false; return false;
if (whichType == TX_SCRIPTHASH) if (whichType == TX_SCRIPTHASH)
@ -208,7 +204,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CTxOut &prev = mapInputs.AccessCoin(tx.vin[i].prevout).out; const CTxOut &prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
// get the scriptPubKey corresponding to this input: // get the scriptPubKey corresponding to this input:
CScript prevScript = prev.scriptPubKey; CScript prevScript = StripClaimScriptPrefix(prev.scriptPubKey);
if (prevScript.IsPayToScriptHash()) { if (prevScript.IsPayToScriptHash()) {
std::vector <std::vector<unsigned char> > stack; std::vector <std::vector<unsigned char> > stack;

View file

@ -45,7 +45,7 @@ static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
* standard and should be done with care and ideally rarely. It makes sense to * standard and should be done with care and ideally rarely. It makes sense to
* only increase the dust limit after prior releases were already not creating * only increase the dust limit after prior releases were already not creating
* outputs below the new threshold */ * outputs below the new threshold */
static const unsigned int DUST_RELAY_TX_FEE = 3000; static const unsigned int DUST_RELAY_TX_FEE = 1000;
/** /**
* Standard script verification flags that standard transactions will comply * Standard script verification flags that standard transactions will comply
* with. However scripts violating these flags may still be present in valid * with. However scripts violating these flags may still be present in valid

View file

@ -1,6 +1,79 @@
#include "prefixtrie.h" #include <claimtrie.h>
#include "claimtrie.h" #include <fs.h>
#include <lbry.h>
#include <limits>
#include <memory>
#include <prefixtrie.h>
#include <boost/interprocess/allocators/private_node_allocator.hpp>
#include <boost/interprocess/indexes/null_index.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
namespace bip = boost::interprocess;
typedef bip::basic_managed_mapped_file <
char,
bip::rbtree_best_fit<bip::null_mutex_family, bip::offset_ptr<void>>,
bip::null_index
> managed_mapped_file;
template <typename T>
using node_allocator = bip::private_node_allocator<T, managed_mapped_file::segment_manager>;
static managed_mapped_file::segment_manager* segmentManager()
{
struct CSharedMemoryFile
{
CSharedMemoryFile() : file(GetDataDir() / "shared.mem")
{
fs::remove(file);
auto size = (uint64_t)g_memfileSize * 1024ULL * 1024ULL * 1024ULL;
// using string() to remove w_char filename encoding on Windows
menaged_file.reset(new managed_mapped_file(bip::create_only, file.string().c_str(), size));
}
~CSharedMemoryFile()
{
menaged_file.reset();
fs::remove(file);
}
managed_mapped_file::segment_manager* segmentManager()
{
return menaged_file->get_segment_manager();
}
const fs::path file;
std::unique_ptr<managed_mapped_file> menaged_file;
};
static CSharedMemoryFile shem;
return shem.segmentManager();
}
template <typename T>
static node_allocator<T>& nodeAllocator()
{
static node_allocator<T> allocator(segmentManager());
return allocator;
}
template <typename T, class... Args>
static std::shared_ptr<T> nodeAllocate(Args&&... args)
{
return std::allocate_shared<T>(nodeAllocator<T>(), std::forward<Args>(args)...);
}
template <typename T, class... Args>
static std::shared_ptr<T> allocateShared(Args&&... args)
{
static auto allocate = g_memfileSize ? nodeAllocate<T, Args...> : std::make_shared<T, Args...>;
try {
return allocate(std::forward<Args>(args)...);
}
catch (const bip::bad_alloc&) {
allocate = std::make_shared<T, Args...>; // in case we fill up the memfile
LogPrint(BCLog::BENCH, "WARNING: The memfile is full; reverting to the RAM allocator for %s.\n", typeid(T).name());
return allocate(std::forward<Args>(args)...);
}
}
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <bool IsConst> template <bool IsConst>
@ -18,7 +91,7 @@ typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>& CPrefixTrie<TKey,
stack.clear(); stack.clear();
stack.reserve(o.stack.size()); stack.reserve(o.stack.size());
for (auto& i : o.stack) for (auto& i : o.stack)
stack.push_back(Bookmark{i.name, i.parent, i.it, i.end}); stack.push_back(Bookmark{i.name, i.it, i.end});
return *this; return *this;
} }
@ -48,7 +121,7 @@ typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>& CPrefixTrie<TKey,
if (!shared->children.empty()) { if (!shared->children.empty()) {
auto& children = shared->children; auto& children = shared->children;
auto it = children.begin(); auto it = children.begin();
stack.emplace_back(Bookmark{name, shared, it, children.end()}); stack.emplace_back(Bookmark{name, it, children.end()});
auto& postfix = it->first; auto& postfix = it->first;
name.insert(name.end(), postfix.begin(), postfix.end()); name.insert(name.end(), postfix.begin(), postfix.end());
node = it->second; node = it->second;
@ -106,18 +179,30 @@ bool CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator!=(const Iterator& o)
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <bool IsConst> template <bool IsConst>
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator*() const typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator*()
{ {
assert(!node.expired()); return reference{name, data()};
return TPair(name, *(node.lock()->data));
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <bool IsConst> template <bool IsConst>
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::pointer CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator->() const typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::const_reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator*() const
{ {
assert(!node.expired()); return const_reference{name, data()};
return node.lock()->data.get(); }
template <typename TKey, typename TData>
template <bool IsConst>
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::pointer CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator->()
{
return &(data());
}
template <typename TKey, typename TData>
template <bool IsConst>
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::const_pointer CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator->() const
{
return &(data());
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -129,18 +214,20 @@ const TKey& CPrefixTrie<TKey, TData>::Iterator<IsConst>::key() const
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <bool IsConst> template <bool IsConst>
TData& CPrefixTrie<TKey, TData>::Iterator<IsConst>::data() typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::data_reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::data()
{ {
assert(!node.expired()); auto shared = node.lock();
return *(node.lock()->data); assert(shared);
return *(shared->data);
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <bool IsConst> template <bool IsConst>
const TData& CPrefixTrie<TKey, TData>::Iterator<IsConst>::data() const const TData& CPrefixTrie<TKey, TData>::Iterator<IsConst>::data() const
{ {
assert(!node.expired()); auto shared = node.lock();
return *(node.lock()->data); assert(shared);
return *(shared->data);
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -174,21 +261,6 @@ std::vector<typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>> CPref
return ret; return ret;
} }
template <typename TKey>
static std::size_t match(const TKey& a, const TKey& b)
{
std::size_t count = 0;
auto ait = a.cbegin(), aend = a.cend();
auto bit = b.cbegin(), bend = b.cend();
while (ait != aend && bit != bend) {
if (*ait != *bit) break;
++count;
++ait;
++bit;
}
return count;
}
template <typename TKey, typename TData> template <typename TKey, typename TData>
template <typename TIterator, typename TNode> template <typename TIterator, typename TNode>
TIterator CPrefixTrie<TKey, TData>::find(const TKey& key, TNode node, TIterator end) TIterator CPrefixTrie<TKey, TData>::find(const TKey& key, TNode node, TIterator end)
@ -220,6 +292,24 @@ bool CPrefixTrie<TKey, TData>::find(const TKey& key, TNode node, const callback<
return find(TKey(key.begin() + count, key.end()), it->second, cb); return find(TKey(key.begin() + count, key.end()), it->second, cb);
} }
template <typename TKey, typename TData>
template <typename TIterator, typename TNode>
std::vector<TIterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key, TNode root)
{
std::vector<TIterator> ret;
ret.reserve(1 + key.size());
ret.emplace_back(TKey{}, root);
if (key.empty()) return ret;
TKey name;
using CBType = callback<TNode>;
CBType cb = [&name, &ret](const TKey& key, TNode node) {
name.insert(name.end(), key.begin(), key.end());
ret.emplace_back(name, node);
};
find(key, root, cb);
return ret;
}
template <typename TKey, typename TData> template <typename TKey, typename TData>
std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& CPrefixTrie<TKey, TData>::insert(const TKey& key, std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& node) std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& CPrefixTrie<TKey, TData>::insert(const TKey& key, std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& node)
{ {
@ -237,21 +327,20 @@ std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& CPrefixTrie<TKey, TDat
} }
if (count == 0) { if (count == 0) {
++size; ++size;
it = children.emplace(key, std::make_shared<Node>()).first; it = children.emplace(key, allocateShared<Node>()).first;
it->second->data = std::make_shared<TData>();
return it->second; return it->second;
} }
if (count < it->first.size()) { if (count < it->first.size()) {
const TKey prefix(key.begin(), key.begin() + count); TKey prefix(key.begin(), key.begin() + count);
const TKey postfix(it->first.begin() + count, it->first.end()); TKey postfix(it->first.begin() + count, it->first.end());
auto nodes = std::move(it->second); auto nodes = std::move(it->second);
children.erase(it); children.erase(it);
++size; ++size;
it = children.emplace(prefix, std::make_shared<Node>()).first; it = children.emplace(std::move(prefix), allocateShared<Node>()).first;
it->second->children.emplace(postfix, std::move(nodes)); it->second->children.emplace(std::move(postfix), std::move(nodes));
it->second->data = std::make_shared<TData>();
if (key.size() == count) if (key.size() == count)
return it->second; return it->second;
it->second->data = allocateShared<TData>();
} }
return insert(TKey(key.begin() + count, key.end()), it->second); return insert(TKey(key.begin() + count, key.end()), it->second);
} }
@ -268,7 +357,7 @@ void CPrefixTrie<TKey, TData>::erase(const TKey& key, std::shared_ptr<Node>& nod
if (!find(key, node, cb)) if (!find(key, node, cb))
return; return;
nodes.back().second->data = std::make_shared<TData>(); nodes.back().second->data = allocateShared<TData>();
for (; nodes.size() > 1; nodes.pop_back()) { for (; nodes.size() > 1; nodes.pop_back()) {
// if we have only one child and no data ourselves, bring them up to our level // if we have only one child and no data ourselves, bring them up to our level
auto& cNode = nodes.back().second; auto& cNode = nodes.back().second;
@ -281,7 +370,7 @@ void CPrefixTrie<TKey, TData>::erase(const TKey& key, std::shared_ptr<Node>& nod
auto& postfix = child->first; auto& postfix = child->first;
newKey.insert(newKey.end(), postfix.begin(), postfix.end()); newKey.insert(newKey.end(), postfix.begin(), postfix.end());
auto& pNode = nodes[nodes.size() - 2].second; auto& pNode = nodes[nodes.size() - 2].second;
pNode->children.emplace(newKey, std::move(child->second)); pNode->children.emplace(std::move(newKey), std::move(child->second));
pNode->children.erase(prefix); pNode->children.erase(prefix);
--size; --size;
continue; continue;
@ -299,9 +388,9 @@ void CPrefixTrie<TKey, TData>::erase(const TKey& key, std::shared_ptr<Node>& nod
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
CPrefixTrie<TKey, TData>::CPrefixTrie() : size(0), root(std::make_shared<Node>()) CPrefixTrie<TKey, TData>::CPrefixTrie() : size(0), root(allocateShared<Node>())
{ {
root->data = std::make_shared<TData>(); root->data = allocateShared<TData>();
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -309,7 +398,7 @@ template <typename TDataUni>
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::insert(const TKey& key, TDataUni&& data) typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::insert(const TKey& key, TDataUni&& data)
{ {
auto& node = key.empty() ? root : insert(key, root); auto& node = key.empty() ? root : insert(key, root);
node->data = std::make_shared<TData>(std::forward<TDataUni>(data)); node->data = allocateShared<TData>(std::forward<TDataUni>(data));
return key.empty() ? begin() : iterator{key, node}; return key.empty() ? begin() : iterator{key, node};
} }
@ -333,9 +422,9 @@ typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::insert(CPr
auto name = it.key(); auto name = it.key();
name.insert(name.end(), key.begin(), key.end()); name.insert(name.end(), key.begin(), key.end());
auto& node = insert(key, shared); auto& node = insert(key, shared);
copy = iterator{name, node}; copy = iterator{std::move(name), node};
} }
copy.node.lock()->data = std::make_shared<TData>(std::forward<TDataUni>(data)); copy.node.lock()->data = allocateShared<TData>(std::forward<TDataUni>(data));
return copy; return copy;
} }
@ -386,21 +475,17 @@ TData& CPrefixTrie<TKey, TData>::at(const TKey& key)
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
std::vector<typename CPrefixTrie<TKey, TData>::iterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key) const std::vector<typename CPrefixTrie<TKey, TData>::iterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key)
{ {
std::vector<iterator> ret; if (empty()) return {};
if (empty()) return ret; return nodes<iterator>(key, root);
ret.reserve(1 + key.size()); }
ret.emplace_back(TKey{}, root);
if (key.empty()) return ret; template <typename TKey, typename TData>
TKey name; std::vector<typename CPrefixTrie<TKey, TData>::const_iterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key) const
using CBType = callback<std::shared_ptr<Node>>; {
CBType cb = [&name, &ret](const TKey& key, std::shared_ptr<Node> node) { if (empty()) return {};
name.insert(name.end(), key.begin(), key.end()); return nodes<const_iterator>(key, root);
ret.emplace_back(name, node);
};
find(key, root, cb);
return ret;
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -408,7 +493,7 @@ bool CPrefixTrie<TKey, TData>::erase(const TKey& key)
{ {
auto size_was = height(); auto size_was = height();
if (key.empty()) { if (key.empty()) {
root->data = std::make_shared<TData>(); root->data = allocateShared<TData>();
} else { } else {
erase(key, root); erase(key, root);
} }
@ -419,7 +504,7 @@ template <typename TKey, typename TData>
void CPrefixTrie<TKey, TData>::clear() void CPrefixTrie<TKey, TData>::clear()
{ {
size = 0; size = 0;
root->data = std::make_shared<TData>(); root->data = allocateShared<TData>();
root->children.clear(); root->children.clear();
} }
@ -444,7 +529,7 @@ typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::begin()
template <typename TKey, typename TData> template <typename TKey, typename TData>
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::end() typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::end()
{ {
return iterator{TKey(), std::shared_ptr<Node>{}}; return {};
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -456,7 +541,7 @@ typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::cbeg
template <typename TKey, typename TData> template <typename TKey, typename TData>
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::cend() typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::cend()
{ {
return const_iterator{TKey(), std::shared_ptr<Node>{}}; return {};
} }
template <typename TKey, typename TData> template <typename TKey, typename TData>
@ -468,7 +553,7 @@ typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::begi
template <typename TKey, typename TData> template <typename TKey, typename TData>
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::end() const typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::end() const
{ {
return const_iterator{TKey(), std::shared_ptr<Node>{}}; return {};
} }
using Key = std::string; using Key = std::string;

View file

@ -9,6 +9,10 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <boost/container/flat_map.hpp>
namespace bc = boost::container;
template <typename TKey, typename TData> template <typename TKey, typename TData>
class CPrefixTrie class CPrefixTrie
{ {
@ -17,13 +21,13 @@ class CPrefixTrie
template <bool> template <bool>
friend class Iterator; friend class Iterator;
friend class CPrefixTrie<TKey, TData>; friend class CPrefixTrie<TKey, TData>;
std::map<TKey, std::shared_ptr<Node>> children; bc::flat_map<TKey, std::shared_ptr<Node>> children;
public: public:
Node() = default; Node() = default;
Node(const Node&) = delete; Node(const Node&) = delete;
Node(Node&& o) noexcept = default; Node(Node&& o) noexcept = default;
Node& operator=(Node&& o) noexcept = default; Node& operator=(Node&&) noexcept = default;
Node& operator=(const Node&) = delete; Node& operator=(const Node&) = delete;
std::shared_ptr<TData> data; std::shared_ptr<TData> data;
}; };
@ -38,15 +42,15 @@ class CPrefixTrie
friend class CPrefixTrie<TKey, TData>; friend class CPrefixTrie<TKey, TData>;
using TKeyRef = std::reference_wrapper<const TKey>; using TKeyRef = std::reference_wrapper<const TKey>;
using TDataRef = std::reference_wrapper<TData>; using TDataRef = std::reference_wrapper<typename std::conditional<IsConst, const TData, TData>::type>;
using TPair = std::pair<TKeyRef, TDataRef>; using TPair = std::pair<TKeyRef, TDataRef>;
using ConstTPair = std::pair<TKeyRef, const TData>;
TKey name; TKey name;
std::weak_ptr<Node> node; std::weak_ptr<Node> node;
struct Bookmark { struct Bookmark {
TKey name; TKey name;
std::weak_ptr<Node> parent;
typename TChildren::iterator it; typename TChildren::iterator it;
typename TChildren::iterator end; typename TChildren::iterator end;
}; };
@ -56,12 +60,15 @@ class CPrefixTrie
public: public:
// Iterator traits // Iterator traits
using value_type = TPair; using value_type = TPair;
using const_pointer = const TData* const;
using const_reference = ConstTPair;
using data_reference = typename std::conditional<IsConst, const TData&, TData&>::type;
using pointer = typename std::conditional<IsConst, const TData* const, TData* const>::type; using pointer = typename std::conditional<IsConst, const TData* const, TData* const>::type;
using reference = typename std::conditional<IsConst, const TPair, TPair>::type; using reference = typename std::conditional<IsConst, ConstTPair, TPair>::type;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag; using iterator_category = std::forward_iterator_tag;
Iterator() = delete; Iterator() = default;
Iterator(const Iterator&) = default; Iterator(const Iterator&) = default;
Iterator(Iterator&& o) noexcept = default; Iterator(Iterator&& o) noexcept = default;
Iterator(const TKey& name, const std::shared_ptr<Node>& node) noexcept; Iterator(const TKey& name, const std::shared_ptr<Node>& node) noexcept;
@ -85,12 +92,15 @@ class CPrefixTrie
bool operator==(const Iterator& o) const; bool operator==(const Iterator& o) const;
bool operator!=(const Iterator& o) const; bool operator!=(const Iterator& o) const;
reference operator*() const; reference operator*();
pointer operator->() const; const_reference operator*() const;
pointer operator->();
const_pointer operator->() const;
const TKey& key() const; const TKey& key() const;
TData& data(); data_reference data();
const TData& data() const; const TData& data() const;
std::size_t depth() const; std::size_t depth() const;
@ -111,6 +121,9 @@ class CPrefixTrie
template <typename TNode> template <typename TNode>
static bool find(const TKey& key, TNode node, const callback<TNode>& cb); static bool find(const TKey& key, TNode node, const callback<TNode>& cb);
template <typename TIterator, typename TNode>
static std::vector<TIterator> nodes(const TKey& key, TNode root);
std::shared_ptr<Node>& insert(const TKey& key, std::shared_ptr<Node>& node); std::shared_ptr<Node>& insert(const TKey& key, std::shared_ptr<Node>& node);
void erase(const TKey& key, std::shared_ptr<Node>& node); void erase(const TKey& key, std::shared_ptr<Node>& node);
@ -136,7 +149,8 @@ public:
TData& at(const TKey& key); TData& at(const TKey& key);
std::vector<iterator> nodes(const TKey& key) const; std::vector<iterator> nodes(const TKey& key);
std::vector<const_iterator> nodes(const TKey& key) const;
bool erase(const TKey& key); bool erase(const TKey& key);
@ -193,4 +207,19 @@ inline bool operator!=(const std::reference_wrapper<std::unique_ptr<T>>& ref, co
return !(ref == obj); return !(ref == obj);
} }
template <typename TKey>
static std::size_t match(const TKey& a, const TKey& b)
{
std::size_t count = 0;
auto ait = a.cbegin(), aend = a.cend();
auto bit = b.cbegin(), bend = b.cend();
while (ait != aend && bit != bend) {
if (*ait != *bit) break;
++count;
++ait;
++bit;
}
return count;
}
#endif // BITCOIN_PREFIXTRIE_H #endif // BITCOIN_PREFIXTRIE_H

View file

@ -17,7 +17,7 @@ static const struct {
} network_styles[] = { } network_styles[] = {
{"lbrycrd", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, {"lbrycrd", QAPP_APP_NAME_DEFAULT, 0, 0, ""},
{"lbrycrdtest", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, {"lbrycrdtest", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")},
{"regtest", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"} {"lbrycrdreg", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"}
}; };
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);

View file

@ -228,11 +228,11 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char*
PaymentRequestPlus request; PaymentRequestPlus request;
if (readPaymentRequestFromFile(arg, request)) if (readPaymentRequestFromFile(arg, request))
{ {
if (request.getDetails().network() == "lbrycrd") if (request.getDetails().network() == CBaseChainParams::MAIN)
{ {
node.selectParams(CBaseChainParams::MAIN); node.selectParams(CBaseChainParams::MAIN);
} }
else if (request.getDetails().network() == "lbrycrdtest") else if (request.getDetails().network() == CBaseChainParams::TESTNET)
{ {
node.selectParams(CBaseChainParams::TESTNET); node.selectParams(CBaseChainParams::TESTNET);
} }

View file

@ -1310,16 +1310,18 @@ static UniValue getchaintips(const JSONRPCRequest& request)
"\nResult:\n" "\nResult:\n"
"[\n" "[\n"
" {\n" " {\n"
" \"height\": xxxx, (numeric) height of the chain tip\n" " \"height\": xxxx, (numeric) height of the chain tip\n"
" \"hash\": \"xxxx\", (string) block hash of the tip\n" " \"hash\": \"xxxx\", (string) block hash of the tip\n"
" \"branchlen\": 0 (numeric) zero for main chain\n" " \"branchlen\": 0 (numeric) zero for main chain\n"
" \"status\": \"active\" (string) \"active\" for the main chain\n" " \"status\": \"active\" (string) \"active\" for the main chain\n"
" },\n" " },\n"
" {\n" " {\n"
" \"height\": xxxx,\n" " \"height\": xxxx,\n"
" \"hash\": \"xxxx\",\n" " \"hash\": \"xxxx\",\n"
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n" " \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n" " \"branchhash\": \"xxxx\", (string) hash of the historical block where we branched\n"
" \"branchhashNext\": \"xxxx\", (string) block hash of the first block down this chain\n"
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" }\n" " }\n"
"]\n" "]\n"
"Possible values for status:\n" "Possible values for status:\n"
@ -1372,8 +1374,19 @@ static UniValue getchaintips(const JSONRPCRequest& request)
obj.pushKV("height", block->nHeight); obj.pushKV("height", block->nHeight);
obj.pushKV("hash", block->phashBlock->GetHex()); obj.pushKV("hash", block->phashBlock->GetHex());
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; // not use ForkAt method because we need the previous one as well
const CBlockIndex *forkAt = block, *forkPrev = block;
while (forkAt && !chainActive.Contains(forkAt)) {
forkPrev = forkAt;
forkAt = forkAt->pprev;
}
const int branchLen = block->nHeight - forkAt->nHeight;
obj.pushKV("branchlen", branchLen); obj.pushKV("branchlen", branchLen);
if (forkAt != forkPrev) {
obj.pushKV("branchhash", forkAt->phashBlock->GetHex());
obj.pushKV("branchhashNext", forkPrev->phashBlock->GetHex());
}
std::string status; std::string status;
if (chainActive.Contains(block)) { if (chainActive.Contains(block)) {

345
src/rpc/claimrpchelp.h Normal file
View file

@ -0,0 +1,345 @@
#ifndef CLAIMRPCHELP_H
#define CLAIMRPCHELP_H
// always keep defines T_ + value in upper case
#define T_NORMALIZEDNAME "normalizedName"
#define T_BLOCKHASH "blockhash"
#define T_CLAIMS "claims"
#define T_CLAIMID "claimId"
#define T_TXID "txId"
#define T_N "n"
#define T_AMOUNT "amount"
#define T_HEIGHT "height"
#define T_VALUE "value"
#define T_NAME "name"
#define T_VALIDATHEIGHT "validAtHeight"
#define T_NAMES "names"
#define T_EFFECTIVEAMOUNT "effectiveAmount"
#define T_LASTTAKEOVERHEIGHT "lastTakeoverHeight"
#define T_SUPPORTS "supports"
#define T_SUPPORTSWITHOUTCLAIM "supportsWithoutClaim"
#define T_TOTALNAMES "totalNames"
#define T_TOTALCLAIMS "totalClaims"
#define T_TOTALVALUE "totalValue"
#define T_CONTROLLINGONLY "controllingOnly"
#define T_CLAIMTYPE "claimType"
#define T_DEPTH "depth"
#define T_INCLAIMTRIE "inClaimTrie"
#define T_ISCONTROLLING "isControlling"
#define T_INSUPPORTMAP "inSupportMap"
#define T_INQUEUE "inQueue"
#define T_BLOCKSTOVALID "blocksToValid"
#define T_NODES "nodes"
#define T_CHILDREN "children"
#define T_CHARACTER "character"
#define T_NODEHASH "nodeHash"
#define T_VALUEHASH "valueHash"
#define T_PAIRS "pairs"
#define T_ODD "odd"
#define T_HASH "hash"
#define T_BID "bid"
#define T_SEQUENCE "sequence"
#define T_CLAIMSADDEDORUPDATED "claimsAddedOrUpdated"
#define T_SUPPORTSADDEDORUPDATED "supportsAddedOrUpdated"
#define T_CLAIMSREMOVED "claimsRemoved"
#define T_SUPPORTSREMOVED "supportsRemoved"
#define T_ADDRESS "address"
#define T_PENDINGAMOUNT "pendingAmount"
enum {
GETCLAIMSINTRIE = 0,
GETNAMESINTRIE,
GETVALUEFORNAME,
GETCLAIMSFORNAME,
GETCLAIMBYID,
GETTOTALCLAIMEDNAMES,
GETTOTALCLAIMS,
GETTOTALVALUEOFCLAIMS,
GETCLAIMSFORTX,
GETNAMEPROOF,
CHECKNORMALIZATION,
GETCLAIMBYBID,
GETCLAIMBYSEQ,
GETCLAIMPROOFBYBID,
GETCLAIMPROOFBYSEQ,
GETCHANGESINBLOCK,
};
#define S3_(pre, name, def) pre "\"" name "\"" def "\n"
#define S3(pre, name, def) S3_(pre, name, def)
#define S1(str) str "\n"
#define NAME_TEXT " (string) the name to look up"
#define BLOCKHASH_TEXT " (string, optional) get claims in the trie\n" \
" at the block specified\n" \
" by this block hash.\n" \
" If none is given,\n" \
" the latest active\n" \
" block will be used."
#define CLAIM_OUTPUT \
S3(" ", T_NORMALIZEDNAME, " (string) the name of the claim (after normalization)") \
S3(" ", T_NAME, " (string) the original name of this claim (before normalization)") \
S3(" ", T_VALUE, " (string) the value of this claim") \
S3(" ", T_ADDRESS, " (string) the destination address of this claim") \
S3(" ", T_CLAIMID, " (string) the claimId of the claim") \
S3(" ", T_TXID, " (string) the txid of the claim") \
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs") \
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located") \
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support became/becomes valid") \
S3(" ", T_AMOUNT, " (numeric) the amount of the claim") \
S3(" ", T_EFFECTIVEAMOUNT, " (numeric) the amount plus amount from all supports associated with the claim") \
S3(" ", T_PENDINGAMOUNT, " (numeric) expected amount when claim and its supports are all valid") \
S3(" ", T_SUPPORTS, ": [ (array of object) supports for this claim") \
S3(" ", T_VALUE, " (string) the metadata of the support if any") \
S3(" ", T_ADDRESS, " (string) the destination address of the support") \
S3(" ", T_TXID, " (string) the txid of the support") \
S3(" ", T_N, " (numeric) the index of the support in the transaction's list of outputs") \
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located") \
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support became/becomes valid") \
S3(" ", T_AMOUNT, " (numeric) the amount of the support") \
S1(" ]") \
S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which ownership of the name changed") \
S3(" ", T_BID, " (numeric) lower value means a higher bid rate, ordered by effective amount") \
S3(" ", T_SEQUENCE, " (numeric) lower value means an older one in sequence, ordered by height of insertion")
#define PROOF_OUTPUT \
S3(" ", T_NODES, ": [ (array of object, pre-fork) full nodes\n" \
" (i.e. those which lead to the requested name)") \
S3(" ", T_CHILDREN, ": [ (array of object) the children of the node") \
S3(" ", T_CHARACTER, " (string) the character which leads from the parent to this child node") \
S3(" ", T_NODEHASH, " (string, if exists) the hash of the node if this is a leaf node") \
S1(" ]") \
S3(" ", T_VALUEHASH, " (string, if exists) the hash of this node's value, if" \
" it has one. If this is the requested name this\n" \
" will not exist whether the node has a value or not") \
S1(" ]") \
S3(" ", T_PAIRS, ": [ (array of pairs, post-fork) hash can be validated by" \
" hashing claim from the bottom up") \
S3(" ", T_ODD, " (boolean) this value goes on the right of hash") \
S3(" ", T_HASH, " (string) the hash to be mixed in") \
S1(" ]") \
S3(" ", T_TXID, " (string, if exists) the txid of the claim which controls" \
" this name, if there is one.") \
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs") \
S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which ownership of the name changed")
static const char* const rpc_help[] = {
// GETCLAIMSINTRIE
S1("getclaimsintrie ( \"" T_BLOCKHASH R"(" )
Return all claims in the name trie. Deprecated
Arguments:)")
S3("1. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
S3(" ", T_NORMALIZEDNAME, " (string) the name of the claim(s) (after normalization)")
S3(" ", T_CLAIMS, ": [ (array of object) the claims for this name")
S3(" ", T_NAME, " (string) the original name of this claim (before normalization)")
S3(" ", T_VALUE, " (string) the value of this claim")
S3(" ", T_ADDRESS, " (string) the destination address of this claim")
S3(" ", T_CLAIMID, " (string) the claimId of the claim")
S3(" ", T_TXID, " (string) the txid of the claim")
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs")
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located")
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the claim became/becomes valid")
S3(" ", T_AMOUNT, " (numeric) the amount of the claim")
S1(" ]")
"]",
// GETNAMESINTRIE
S1("getnamesintrie ( \"" T_BLOCKHASH R"(" )
Return all claim names in the trie.
Arguments:)")
S3("1. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
S3(" ", T_NAMES, " all names in the trie that have claims")
"]",
// GETVALUEFORNAME
S1("getvalueforname \"" T_NAME "\" ( \"" T_BLOCKHASH "\" \"" T_CLAIMID R"(" )
Return the winning or specified by claimId value associated with a name
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S3("3. ", T_CLAIMID, " (string, optional) can be partial one")
S1("Result: [")
CLAIM_OUTPUT
"]",
// GETCLAIMSFORNAME
S1("getclaimsforname \"" T_NAME "\" ( \"" T_BLOCKHASH R"(" )
Return all claims and supports for a name
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
S3(" ", T_NORMALIZEDNAME, " (string) the name of the claim(s) (after normalization)")
S3(" ", T_CLAIMS, ": [ (array of object) the claims for this name")
S3(" ", T_NAME, " (string) the original name of this claim (before normalization)")
S3(" ", T_VALUE, " (string) the value of this claim")
S3(" ", T_ADDRESS, " (string) the destination address of this claim")
S3(" ", T_CLAIMID, " (string) the claimId of the claim")
S3(" ", T_TXID, " (string) the txid of the claim")
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs")
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located")
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the claim became/becomes valid")
S3(" ", T_AMOUNT, " (numeric) the amount of the claim")
S3(" ", T_EFFECTIVEAMOUNT, " (numeric) the amount plus amount from all supports associated with the claim")
S3(" ", T_PENDINGAMOUNT, " (numeric) expected amount when claim and its support got valid")
S3(" ", T_SUPPORTS, ": [ (array of object) supports for this claim")
S3(" ", T_VALUE, " (string) the metadata of the support if any")
S3(" ", T_ADDRESS, " (string) the destination address of the support")
S3(" ", T_TXID, " (string) the txid of the support")
S3(" ", T_N, " (numeric) the index of the support in the transaction's list of outputs")
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located")
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support became/becomes valid")
S3(" ", T_AMOUNT, " (numeric) the amount of the support")
S1(" ]")
S3(" ", T_BID, " (numeric) lower value means a higher bid rate, ordered by effective amount")
S3(" ", T_SEQUENCE, " (numeric) lower value means an older one in sequence, ordered by height of insertion")
S1(" ]")
S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which ownership of the name changed")
S3(" ", T_SUPPORTSWITHOUTCLAIM, ": [")
S3(" ", T_TXID, " (string) the txid of the support")
S3(" ", T_N, " (numeric) the index of the support in the transaction's list of outputs")
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located")
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the support became/becomes valid")
S3(" ", T_AMOUNT, " (numeric) the amount of the support")
S1(" ]")
"]",
// GETCLAIMBYID
S1("getclaimbyid \"" T_CLAIMID R"("
Get a claim by claim id
Arguments:)")
S3("1. ", T_CLAIMID, " (string) the claimId of this claim or patial id (at least 3 chars)")
S1("Result: [")
CLAIM_OUTPUT
"]",
// GETTOTALCLAIMEDNAMES
S1(R"(gettotalclaimednames
Return the total number of names that have been
Arguments:)")
S1("Result:")
S3(" ", T_TOTALNAMES, " (numeric) the total number of names in the trie")
,
// GETTOTALCLAIMS
S1(R"(gettotalclaims
Return the total number of active claims in the trie
Arguments:)")
S1("Result:")
S3(" ", T_TOTALCLAIMS, " (numeric) the total number of active claims")
,
// GETTOTALVALUEOFCLAIMS
S1("gettotalvalueofclaims ( " T_CONTROLLINGONLY R"( )
Return the total value of the claims in the trie
Arguments:)")
S3("1. ", T_CONTROLLINGONLY, " (boolean) only include the value of controlling claims")
S1("Result:")
S3(" ", T_TOTALVALUE, " (numeric) the total value of the claims in the trie")
,
// GETCLAIMSFORTX
S1("getclaimsfortx \"" T_TXID R"("
Return any claims or supports found in a transaction
Arguments:)")
S3("1. ", T_TXID, " (string) the txid of the transaction to check for unspent claims")
S1("Result: [")
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs")
S3(" ", T_CLAIMTYPE, " (string) claim or support")
S3(" ", T_NAME, " (string) the name claimed or supported")
S3(" ", T_CLAIMID, " (string) if a claim, its ID")
S3(" ", T_VALUE, " (string) if a claim, its value")
S3(" ", T_DEPTH, " (numeric) the depth of the transaction in the main chain")
S3(" ", T_INCLAIMTRIE, " (boolean) if a name claim, whether the claim is active, i.e. has made it into the trie")
S3(" ", T_ISCONTROLLING, " (boolean) if a name claim, whether the claim is the current controlling claim for the name")
S3(" ", T_INSUPPORTMAP, " (boolean) if a support, whether the support is active, i.e. has made it into the support map")
S3(" ", T_INQUEUE, " (boolean) whether the claim is in a queue waiting to be inserted into the trie or support map")
S3(" ", T_BLOCKSTOVALID, " (numeric) if in a queue, the number of blocks until it's inserted into the trie or support map")
"]",
// GETNAMEPROOF
S1("getnameproof \"" T_NAME "\" ( \"" T_BLOCKHASH "\" \"" T_CLAIMID R"(" )
Return the cryptographic proof that a name maps to a value or doesn't.
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S3("3. ", T_CLAIMID, R"( (string, optional, post-fork) for validating a specific claim
can be partial one)")
S1("Result: [")
PROOF_OUTPUT
"]",
// CHECKNORMALIZATION
S1("checknormalization \"" T_NAME R"("
Given an unnormalized name of a claim, return normalized version of it
Arguments:)")
S3("1. ", T_NAME, " (string) the name to normalize")
S1("Result:")
S3(" ", T_NORMALIZEDNAME, " (string) normalized name")
,
// GETCLAIMBYBID
S1("getclaimbybid \"" T_NAME "\" ( " T_BID " \"" T_BLOCKHASH R"(" )
Get a claim by bid
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_BID, " (numeric, optional) bid number")
S3("3. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
CLAIM_OUTPUT
"]",
// GETCLAIMBYSEQ
S1("getclaimbyseq \"" T_NAME "\" ( " T_SEQUENCE " \"" T_BLOCKHASH R"(" )
Get a claim by sequence
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_SEQUENCE, " (numeric, optional) sequence number")
S3("3. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
CLAIM_OUTPUT
"]",
// GETCLAIMPROOFBYBID
S1("getclaimproofbyid \"" T_NAME "\" ( " T_BID " \"" T_BLOCKHASH R"(" )
Return the cryptographic proof that a name maps to a value or doesn't by a bid.
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_BID, " (numeric, optional) bid number")
S3("3. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
PROOF_OUTPUT
"]",
// GETCLAIMPROOFBYSEQ
S1("getclaimproofbyseq \"" T_NAME "\" ( " T_SEQUENCE " \"" T_BLOCKHASH R"(" )
Return the cryptographic proof that a name maps to a value or doesn't by a sequence.
Arguments:)")
S3("1. ", T_NAME, NAME_TEXT)
S3("2. ", T_SEQUENCE, " (numeric, optional) sequence number")
S3("3. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
PROOF_OUTPUT
"]",
// GETCHANGESINBLOCK
S1("getchangesinblock ( \"" T_BLOCKHASH R"(" )
Return the list of claims added, updated, and removed as pulled from the queued work for that block."
Use this method to determine which claims or supports went live on a given block."
Arguments:)")
S3("1. ", T_BLOCKHASH, BLOCKHASH_TEXT)
S1("Result: [")
S3(" ", T_CLAIMSADDEDORUPDATED, " (array of string) claimIDs added or updated in the trie")
S3(" ", T_CLAIMSREMOVED, " (array of string) claimIDs that were removed from the trie")
S3(" ", T_SUPPORTSADDEDORUPDATED, " (array of string) IDs of supports added or updated")
S3(" ", T_SUPPORTSREMOVED, " (array of string) IDs that were removed from the trie")
"]",
};
#endif // CLAIMRPCHELP_H

File diff suppressed because it is too large Load diff

View file

@ -80,6 +80,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "scantxoutset", 1, "scanobjects" }, { "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" }, { "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" }, { "addmultisigaddress", 1, "keys" },
{ "addtimelockedaddress", 0, "timelock" },
{ "createmultisig", 0, "nrequired" }, { "createmultisig", 0, "nrequired" },
{ "createmultisig", 1, "keys" }, { "createmultisig", 1, "keys" },
{ "listunspent", 0, "minconf" }, { "listunspent", 0, "minconf" },
@ -171,6 +172,15 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "rescanblockchain", 0, "start_height"}, { "rescanblockchain", 0, "start_height"},
{ "rescanblockchain", 1, "stop_height"}, { "rescanblockchain", 1, "stop_height"},
{ "createwallet", 1, "disable_private_keys"}, { "createwallet", 1, "disable_private_keys"},
{ "listnameclaims", 0, "includesupports"},
{ "listnameclaims", 1, "activeonly"},
{ "listnameclaims", 2, "minconf"},
{ "getclaimbybid", 1, "bid"},
{ "getclaimbyseq", 1, "sequence"},
{ "getclaimproofbybid", 1, "bid"},
{ "getclaimproofbyseq", 1, "sequence"},
{ "supportclaim", 4, "isTip"},
{ "gettotalvalueofclaims", 0, "controlling_only"},
}; };
class CRPCConvertTable class CRPCConvertTable

View file

@ -451,7 +451,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
if (strMode != "template") if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
if (Params().NetworkIDString() != "lbrycrdreg") // who should own this constant? if (Params().NetworkIDString() == CBaseChainParams::MAIN)
{ {
if (!g_connman) if (!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@ -567,6 +567,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
const bool fPreSegWit = (ThresholdState::ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); const bool fPreSegWit = (ThresholdState::ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache));
if (!fPreSegWit && !fSupportsSegwit)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Segwit support is now required. Please include \"segwit\" in the client's rules.");
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
@ -621,7 +623,6 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
aMutable.push_back("time"); aMutable.push_back("time");
aMutable.push_back("transactions"); aMutable.push_back("transactions");
aMutable.push_back("prevblock"); aMutable.push_back("prevblock");
aMutable.push_back("submit/coinbase");
result.pushKV("capabilities", aCaps); result.pushKV("capabilities", aCaps);

View file

@ -549,14 +549,15 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
" ],\n" " ],\n"
" \"vout\" : [ (array of json objects)\n" " \"vout\" : [ (array of json objects)\n"
" {\n" " {\n"
" \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n" " \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n" " \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n" " \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n" " \"asm\" : \"asm\", (string) the asm\n"
" \"hex\" : \"hex\", (string) the hex\n" " \"hex\" : \"hex\", (string) the hex\n"
" \"reqSigs\" : n, (numeric) The required sigs\n" " \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"subtype\" : \"pubkeyhash\", (numeric) For claims and supports, this represents the type of suffix\n"
" \"addresses\" : [ (json array of string)\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) lbry address\n" " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) lbry address\n"
" ,...\n" " ,...\n"
" ]\n" " ]\n"
@ -1757,7 +1758,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n" "createpsbt and walletcreatefundedpsbt should be used for new applications.\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of a raw transaction\n" "1. \"hexstring\" (string, required) The hex string of a raw transaction\n"
"2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarded and conversion.\n" "2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarded and conversion\n"
" will continue. If false, RPC will fail if any signatures are present.\n" " will continue. If false, RPC will fail if any signatures are present.\n"
"3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n" "3. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction.\n"
" If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n" " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"

View file

@ -64,8 +64,20 @@ void CScheduler::serviceQueue()
// Explicitly use a template here to avoid hitting that overload. // Explicitly use a template here to avoid hitting that overload.
while (!shouldStop() && !taskQueue.empty()) { while (!shouldStop() && !taskQueue.empty()) {
boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first;
if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) try {
break; // Exit loop after timeout, it means we reached the time of the event if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) {
break; // Exit loop after timeout, it means we reached the time of the event
}
} catch (boost::thread_interrupted) {
// We need to make sure we don't ignore this, or the thread won't end
throw;
} catch (...) {
// Some boost versions have a bug that can cause a time prior to system boot (or wake from sleep) to throw an exception instead of return timeout
// See https://github.com/boostorg/thread/issues/308
// Check if the time has passed and, if so, break gracefully
if (timeToWaitFor <= boost::chrono::system_clock::now()) break;
throw;
}
} }
#endif #endif
// If there are multiple threads, the queue can empty while we're waiting (another // If there are multiple threads, the queue can empty while we're waiting (another

View file

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <script/interpreter.h> #include <script/interpreter.h>
#include <nameclaim.h>
#include <crypto/ripemd160.h> #include <crypto/ripemd160.h>
#include <crypto/sha1.h> #include <crypto/sha1.h>
@ -1490,6 +1491,11 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
} }
int claimOp;
const CScript& strippedScriptPubKey = StripClaimScriptPrefix(scriptPubKey, claimOp);
if (claimOp >= 0) // lbryum used to violate this rule with an off-by-1 at len == 255 (and its not very important)
flags &= ~SCRIPT_VERIFY_MINIMALDATA;
std::vector<std::vector<unsigned char> > stack, stackCopy; std::vector<std::vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror)) if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror))
// serror is set // serror is set
@ -1505,10 +1511,11 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return set_error(serror, SCRIPT_ERR_EVAL_FALSE); return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
// Bare witness programs // Bare witness programs
int witnessversion; int witnessversion;
std::vector<unsigned char> witnessprogram; std::vector<unsigned char> witnessprogram;
if (flags & SCRIPT_VERIFY_WITNESS) { if (flags & SCRIPT_VERIFY_WITNESS) {
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (strippedScriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
hadWitness = true; hadWitness = true;
if (scriptSig.size() != 0) { if (scriptSig.size() != 0) {
// The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability. // The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.
@ -1524,7 +1531,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
} }
// Additional validation for spend-to-script-hash transactions: // Additional validation for spend-to-script-hash transactions:
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) if ((flags & SCRIPT_VERIFY_P2SH) && strippedScriptPubKey.IsPayToScriptHash())
{ {
// scriptSig must be literals-only or validation fails // scriptSig must be literals-only or validation fails
if (!scriptSig.IsPushOnly()) if (!scriptSig.IsPushOnly())

View file

@ -40,8 +40,6 @@ enum class IsMineResult
WATCH_ONLY = 1, //! Included in watch-only balance WATCH_ONLY = 1, //! Included in watch-only balance
SPENDABLE = 2, //! Included in all balances SPENDABLE = 2, //! Included in all balances
INVALID = 3, //! Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness) INVALID = 3, //! Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
CLAIM = 4,
SUPPORT = 5,
}; };
bool PermitsUncompressed(IsMineSigVersion sigversion) bool PermitsUncompressed(IsMineSigVersion sigversion)
@ -60,17 +58,11 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion) IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
{ {
int op = 0;
IsMineResult ret = IsMineResult::NO; IsMineResult ret = IsMineResult::NO;
CScript strippedScriptPubKey = StripClaimScriptPrefix(scriptPubKey, op);
IsMineResult claim_ret = ((op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) ? IsMineResult::CLAIM :
((op == OP_SUPPORT_CLAIM) ? IsMineResult::SUPPORT :
IsMineResult::NO));
std::vector<valtype> vSolutions; std::vector<valtype> vSolutions;
txnouttype whichType; txnouttype whichType;
Solver(strippedScriptPubKey, whichType, vSolutions); Solver(scriptPubKey, whichType, vSolutions);
CKeyID keyID; CKeyID keyID;
switch (whichType) switch (whichType)
@ -85,7 +77,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
return IsMineResult::INVALID; return IsMineResult::INVALID;
} }
if (keystore.HaveKey(keyID)) { if (keystore.HaveKey(keyID)) {
ret = std::max(claim_ret, IsMineResult::SPENDABLE); ret = std::max(ret, IsMineResult::SPENDABLE);
} }
break; break;
case TX_WITNESS_V0_KEYHASH: case TX_WITNESS_V0_KEYHASH:
@ -100,10 +92,6 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
// This also applies to the P2WSH case. // This also applies to the P2WSH case.
break; break;
} }
// Claims are not explicitly supported on Witness v0
// Transactions, and instead of supporting the wrapped inner
// tx, we are ignoring this type at this time (consistent with
// previous releases).
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
break; break;
} }
@ -116,7 +104,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
} }
} }
if (keystore.HaveKey(keyID)) { if (keystore.HaveKey(keyID)) {
ret = std::max(claim_ret, IsMineResult::SPENDABLE); ret = std::max(ret, IsMineResult::SPENDABLE);
} }
break; break;
case TX_SCRIPTHASH: case TX_SCRIPTHASH:
@ -128,7 +116,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript; CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) { if (keystore.GetCScript(scriptID, subscript)) {
ret = std::max(claim_ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH)); ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::P2SH));
} }
break; break;
} }
@ -146,10 +134,6 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
CScriptID scriptID = CScriptID(hash); CScriptID scriptID = CScriptID(hash);
CScript subscript; CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) { if (keystore.GetCScript(scriptID, subscript)) {
// Claims are not explicitly supported on Witness v0
// Transactions, and instead of supporting the wrapped inner
// tx, we are ignoring this type at this time (consistent with
// previous releases).
ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0)); ret = std::max(ret, IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0));
} }
break; break;
@ -176,14 +160,14 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
} }
} }
if (HaveKeys(keys, keystore)) { if (HaveKeys(keys, keystore)) {
ret = std::max(claim_ret, IsMineResult::SPENDABLE); ret = std::max(ret, IsMineResult::SPENDABLE);
} }
break; break;
} }
} }
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) { if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
ret = std::max(claim_ret, IsMineResult::WATCH_ONLY); ret = std::max(ret, IsMineResult::WATCH_ONLY);
} }
return ret; return ret;
} }
@ -192,18 +176,22 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
{ {
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) { isminetype flags = ISMINE_NO;
int op;
CScript strippedScriptPubKey = StripClaimScriptPrefix(scriptPubKey, op);
if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM)
flags = ISMINE_CLAIM;
else if (op == OP_SUPPORT_CLAIM)
flags = ISMINE_SUPPORT;
switch (IsMineInner(keystore, strippedScriptPubKey, IsMineSigVersion::TOP)) {
case IsMineResult::INVALID: case IsMineResult::INVALID:
case IsMineResult::NO: case IsMineResult::NO:
return ISMINE_NO; return ISMINE_NO;
case IsMineResult::WATCH_ONLY: case IsMineResult::WATCH_ONLY:
return ISMINE_WATCH_ONLY; return ISMINE_WATCH_ONLY; // addresses we're watching are never considered our claim or support -- but should they be?
case IsMineResult::SPENDABLE: case IsMineResult::SPENDABLE:
return ISMINE_SPENDABLE; return isminetype(ISMINE_SPENDABLE | flags);
case IsMineResult::CLAIM:
return ISMINE_CLAIM;
case IsMineResult::SUPPORT:
return ISMINE_SUPPORT;
} }
assert(false); assert(false);
} }

View file

@ -21,7 +21,9 @@ enum isminetype
ISMINE_SPENDABLE = 2, ISMINE_SPENDABLE = 2,
ISMINE_CLAIM = 4, ISMINE_CLAIM = 4,
ISMINE_SUPPORT = 8, ISMINE_SUPPORT = 8,
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
ISMINE_STAKE = ISMINE_CLAIM | ISMINE_SUPPORT,
ISMINE_SPENDABLE_OR_STAKE = ISMINE_SPENDABLE | ISMINE_STAKE
}; };
/** used for bitflags of isminetype */ /** used for bitflags of isminetype */
typedef uint8_t isminefilter; typedef uint8_t isminefilter;

View file

@ -133,9 +133,9 @@ const char* GetOpName(opcodetype opcode)
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY"; case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
case OP_NOP4 : return "OP_NOP4"; case OP_NOP4 : return "OP_NOP4";
case OP_NOP5 : return "OP_NOP5"; case OP_NOP5 : return "OP_NOP5";
case OP_NOP6 : return "OP_NOP6"; case OP_NOP6 : return "OP_CLAIM_NAME";
case OP_NOP7 : return "OP_NOP7"; case OP_NOP7 : return "OP_SUPPORT_CLAIM";
case OP_NOP8 : return "OP_NOP8"; case OP_NOP8 : return "OP_UPDATE_CLAIM";
case OP_NOP9 : return "OP_NOP9"; case OP_NOP9 : return "OP_NOP9";
case OP_NOP10 : return "OP_NOP10"; case OP_NOP10 : return "OP_NOP10";

View file

@ -6,13 +6,12 @@
#include <script/sign.h> #include <script/sign.h>
#include <key.h> #include <key.h>
#include <nameclaim.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <script/standard.h> #include <script/standard.h>
#include <uint256.h> #include <uint256.h>
#include "nameclaim.h"
typedef std::vector<unsigned char> valtype; typedef std::vector<unsigned char> valtype;
MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
@ -88,6 +87,21 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
return false; return false;
} }
static CScript StripTimelockPrefix(const CScript& script) {
auto it = script.begin();
opcodetype op;
if (!script.GetOp(it, op))
return script;
if (!script.GetOp(it, op) || (op != OP_CHECKLOCKTIMEVERIFY && op != OP_CHECKSEQUENCEVERIFY))
return script;
if (!script.GetOp(it, op) || op != OP_DROP)
return script;
return CScript(it, script.end());
}
/** /**
* Sign scriptPubKey using signature made with creator. * Sign scriptPubKey using signature made with creator.
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
@ -102,10 +116,10 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
ret.clear(); ret.clear();
std::vector<unsigned char> sig; std::vector<unsigned char> sig;
const CScript& strippedScriptPubKey = StripClaimScriptPrefix(scriptPubKey);
std::vector<valtype> vSolutions; std::vector<valtype> vSolutions;
if (!Solver(strippedScriptPubKey, whichTypeRet, vSolutions)) auto stripped = StripClaimScriptPrefix(scriptPubKey);
stripped = StripTimelockPrefix(stripped);
if (!Solver(stripped, whichTypeRet, vSolutions))
return false; return false;
switch (whichTypeRet) switch (whichTypeRet)
@ -353,7 +367,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
// Get scripts // Get scripts
txnouttype script_type; txnouttype script_type;
std::vector<std::vector<unsigned char>> solutions; std::vector<std::vector<unsigned char>> solutions;
Solver(txout.scriptPubKey, script_type, solutions); Solver(StripClaimScriptPrefix(txout.scriptPubKey), script_type, solutions);
SigVersion sigversion = SigVersion::BASE; SigVersion sigversion = SigVersion::BASE;
CScript next_script = txout.scriptPubKey; CScript next_script = txout.scriptPubKey;

View file

@ -6,9 +6,9 @@
#include <script/standard.h> #include <script/standard.h>
#include <crypto/sha256.h> #include <crypto/sha256.h>
#include <nameclaim.h>
#include <pubkey.h> #include <pubkey.h>
#include <script/script.h> #include <script/script.h>
#include <util.h>
#include <utilstrencodings.h> #include <utilstrencodings.h>
@ -166,7 +166,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{ {
std::vector<valtype> vSolutions; std::vector<valtype> vSolutions;
txnouttype whichType; txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) if (!Solver(StripClaimScriptPrefix(scriptPubKey), whichType, vSolutions))
return false; return false;
if (whichType == TX_PUBKEY) if (whichType == TX_PUBKEY)
@ -214,9 +214,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
addressRet.clear(); addressRet.clear();
typeRet = TX_NONSTANDARD; typeRet = TX_NONSTANDARD;
std::vector<valtype> vSolutions; std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, typeRet, vSolutions)) auto solved = Solver(scriptPubKey, typeRet, vSolutions);
return false; if (!solved || typeRet == TX_NULL_DATA){
if (typeRet == TX_NULL_DATA){
// This is data, not addresses // This is data, not addresses
return false; return false;
} }

View file

@ -559,8 +559,8 @@ template<typename Stream, typename K, typename T> void Unserialize(Stream& is, s
/** /**
* map * map
*/ */
template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m); template<typename Stream, typename K, typename T, typename ... Z> void Serialize(Stream& os, const std::map<K, T, Z...>& m);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m); template<typename Stream, typename K, typename T, typename ... Z> void Unserialize(Stream& is, std::map<K, T, Z...>& m);
/** /**
* set * set
@ -781,20 +781,20 @@ void Unserialize(Stream& is, std::pair<K, T>& item)
/** /**
* map * map
*/ */
template<typename Stream, typename K, typename T, typename Pred, typename A> template<typename Stream, typename K, typename T, typename ... Z>
void Serialize(Stream& os, const std::map<K, T, Pred, A>& m) void Serialize(Stream& os, const std::map<K, T, Z...>& m)
{ {
WriteCompactSize(os, m.size()); WriteCompactSize(os, m.size());
for (const auto& entry : m) for (const auto& entry : m)
Serialize(os, entry); Serialize(os, entry);
} }
template<typename Stream, typename K, typename T, typename Pred, typename A> template<typename Stream, typename K, typename T, typename ... Z>
void Unserialize(Stream& is, std::map<K, T, Pred, A>& m) void Unserialize(Stream& is, std::map<K, T, Z...>& m)
{ {
m.clear(); m.clear();
unsigned int nSize = ReadCompactSize(is); unsigned int nSize = ReadCompactSize(is);
typename std::map<K, T, Pred, A>::iterator mi = m.begin(); typename std::map<K, T, Z...>::iterator mi = m.begin();
for (unsigned int i = 0; i < nSize; i++) for (unsigned int i = 0; i < nSize; i++)
{ {
std::pair<K, T> item; std::pair<K, T> item;

View file

@ -227,6 +227,10 @@ public:
return (std::string(begin(), end())); return (std::string(begin(), end()));
} }
std::size_t capacity() const
{
return vch.capacity();
}
// //
// Vector subset // Vector subset

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
#include <uint256.h> #include <uint256.h>
#include <validation.h> #include <validation.h>
#include <test/claimtriefixture.h>
#include <test/test_bitcoin.h> #include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/scope_exit.hpp> #include <boost/scope_exit.hpp>
@ -12,7 +13,7 @@ using namespace std;
class CClaimTrieCacheTest : public CClaimTrieCacheBase class CClaimTrieCacheTest : public CClaimTrieCacheBase
{ {
public: public:
explicit CClaimTrieCacheTest(CClaimTrie* base): CClaimTrieCacheBase(base, false) explicit CClaimTrieCacheTest(CClaimTrie* base): CClaimTrieCacheBase(base)
{ {
} }
@ -23,42 +24,25 @@ public:
void insert(const std::string& key, CClaimTrieData&& data) void insert(const std::string& key, CClaimTrieData&& data)
{ {
cache.insert(key, std::move(data)); nodesToAddOrUpdate.insert(key, std::move(data));
} }
bool erase(const std::string& key) bool erase(const std::string& key)
{ {
return cache.erase(key); return nodesToAddOrUpdate.erase(key);
} }
int cacheSize() int cacheSize()
{ {
return cache.height(); return nodesToAddOrUpdate.height();
} }
CClaimTrie::iterator getCache(const std::string& key) CClaimTrie::iterator getCache(const std::string& key)
{ {
return cache.find(key); return nodesToAddOrUpdate.find(key);
} }
}; };
CMutableTransaction BuildTransaction(const uint256& prevhash)
{
CMutableTransaction tx;
tx.nVersion = 1;
tx.nLockTime = 0;
tx.vin.resize(1);
tx.vout.resize(1);
tx.vin[0].prevout.hash = prevhash;
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript();
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
tx.vout[0].scriptPubKey = CScript();
tx.vout[0].nValue = 0;
return tx;
}
BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup) BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(merkle_hash_single_test) BOOST_AUTO_TEST_CASE(merkle_hash_single_test)
@ -124,7 +108,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2); BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2);
BOOST_CHECK(ntState.checkConsistency(0)); BOOST_CHECK(ntState.checkConsistency());
CClaimTrieCacheTest ntState1(pclaimTrie); CClaimTrieCacheTest ntState1(pclaimTrie);
ntState1.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused, true); ntState1.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused, true);
@ -144,7 +128,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3); BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3);
BOOST_CHECK(ntState2.checkConsistency(0)); BOOST_CHECK(ntState2.checkConsistency());
CClaimTrieCacheTest ntState3(pclaimTrie); CClaimTrieCacheTest ntState3(pclaimTrie);
ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200), true); ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200), true);
@ -152,7 +136,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState3.flush(); ntState3.flush();
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4); BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4);
BOOST_CHECK(ntState3.checkConsistency(0)); BOOST_CHECK(ntState3.checkConsistency());
CClaimTrieCacheTest ntState4(pclaimTrie); CClaimTrieCacheTest ntState4(pclaimTrie);
ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint, unused, true); ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint, unused, true);
@ -160,7 +144,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState4.flush(); ntState4.flush();
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2); BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2);
BOOST_CHECK(ntState4.checkConsistency(0)); BOOST_CHECK(ntState4.checkConsistency());
CClaimTrieCacheTest ntState5(pclaimTrie); CClaimTrieCacheTest ntState5(pclaimTrie);
ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true); ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true);
@ -169,7 +153,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState5.flush(); ntState5.flush();
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2); BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2);
BOOST_CHECK(ntState5.checkConsistency(0)); BOOST_CHECK(ntState5.checkConsistency());
CClaimTrieCacheTest ntState6(pclaimTrie); CClaimTrieCacheTest ntState6(pclaimTrie);
ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201), true); ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201), true);
@ -178,7 +162,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState6.flush(); ntState6.flush();
BOOST_CHECK(!pclaimTrie->empty()); BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2); BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2);
BOOST_CHECK(ntState6.checkConsistency(0)); BOOST_CHECK(ntState6.checkConsistency());
CClaimTrieCacheTest ntState7(pclaimTrie); CClaimTrieCacheTest ntState7(pclaimTrie);
ntState7.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true); ntState7.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true);
@ -190,7 +174,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
ntState7.flush(); ntState7.flush();
BOOST_CHECK(pclaimTrie->empty()); BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0); BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0);
BOOST_CHECK(ntState7.checkConsistency(0)); BOOST_CHECK(ntState7.checkConsistency());
} }
BOOST_AUTO_TEST_CASE(basic_insertion_info_test) BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
@ -200,7 +184,6 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
CClaimTrieCacheTest ctc(pclaimTrie); CClaimTrieCacheTest ctc(pclaimTrie);
// create and insert claim // create and insert claim
CClaimValue unused;
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
CMutableTransaction tx1 = BuildTransaction(hash0); CMutableTransaction tx1 = BuildTransaction(hash0);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0); uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
@ -211,13 +194,13 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
CClaimValue claimVal(claimOutPoint, claimId, amount, height, validHeight); CClaimValue claimVal(claimOutPoint, claimId, amount, height, validHeight);
ctc.insertClaimIntoTrie("test", claimVal, true); ctc.insertClaimIntoTrie("test", claimVal, true);
// try getClaimsForName, getEffectiveAmountForClaim, getInfoForName // try getClaimsForName, effectiveAmount, getInfoForName
auto res = ctc.getClaimsForName("test"); auto res = ctc.getClaimsForName("test");
BOOST_CHECK_EQUAL(res.claims.size(), 1); BOOST_CHECK_EQUAL(res.claimsNsupports.size(), 1);
BOOST_CHECK_EQUAL(res.claims[0], claimVal); BOOST_CHECK_EQUAL(res.claimsNsupports[0].claim, claimVal);
BOOST_CHECK_EQUAL(res.supports.size(), 0); BOOST_CHECK_EQUAL(res.claimsNsupports[0].supports.size(), 0);
BOOST_CHECK_EQUAL(10, ctc.getEffectiveAmountForClaim("test", claimId)); BOOST_CHECK_EQUAL(10, res.claimsNsupports[0].effectiveAmount);
CClaimValue claim; CClaimValue claim;
BOOST_CHECK(ctc.getInfoForName("test", claim)); BOOST_CHECK(ctc.getInfoForName("test", claim));
@ -232,12 +215,12 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
CSupportValue support(supportOutPoint, claimId, supportAmount, height, validHeight); CSupportValue support(supportOutPoint, claimId, supportAmount, height, validHeight);
ctc.insertSupportIntoMap("test", support, false); ctc.insertSupportIntoMap("test", support, false);
res = ctc.getClaimsForName("test"); auto res1 = ctc.getClaimsForName("test");
BOOST_CHECK_EQUAL(res.claims.size(), 1); BOOST_CHECK_EQUAL(res1.claimsNsupports.size(), 1);
BOOST_CHECK_EQUAL(res.supports.size(), 1); BOOST_CHECK_EQUAL(res1.claimsNsupports[0].supports.size(), 1);
// try getEffectiveAmount // try getEffectiveAmount
BOOST_CHECK_EQUAL(20, ctc.getEffectiveAmountForClaim("test", claimId)); BOOST_CHECK_EQUAL(20, res1.claimsNsupports[0].effectiveAmount);
} }
BOOST_AUTO_TEST_CASE(recursive_prune_test) BOOST_AUTO_TEST_CASE(recursive_prune_test)
@ -298,29 +281,12 @@ BOOST_AUTO_TEST_CASE(iteratetrie_test)
ctc.insertClaimIntoTrie("test", claimVal, true); ctc.insertClaimIntoTrie("test", claimVal, true);
BOOST_CHECK(ctc.flush()); BOOST_CHECK(ctc.flush());
std::size_t count = 0; auto hit = pclaimTrie->find("");
for (auto it = pclaimTrie->begin(); it != pclaimTrie->end(); ++it) { BOOST_CHECK(hit);
++count; BOOST_CHECK_EQUAL(hit.children().size(), 1U);
if (it.key() == "test") { BOOST_CHECK(hit = pclaimTrie->find("test"));
BOOST_CHECK_EQUAL(it->claims.size(), 1); BOOST_CHECK_EQUAL(hit.children().size(), 0U);
} BOOST_CHECK_EQUAL(hit.data().claims.size(), 1);
}
BOOST_CHECK_EQUAL(count, 2);
count = 0;
for (const auto& it: *pclaimTrie) {
++count;
if (it.first == "test") {
const CClaimTrieData& data = it.second;
BOOST_CHECK_EQUAL(data.claims.size(), 1);
}
}
BOOST_CHECK_EQUAL(count, 2);
auto it = pclaimTrie->find("test");
BOOST_CHECK(it != pclaimTrie->end());
BOOST_CHECK_EQUAL(it->claims.size(), 1);
BOOST_CHECK_EQUAL(pclaimTrie->height(), 1);
} }
BOOST_AUTO_TEST_CASE(trie_stays_consistent_test) BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
@ -337,15 +303,15 @@ BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
BOOST_CHECK(cache.insertClaimIntoTrie(name, value, false)); BOOST_CHECK(cache.insertClaimIntoTrie(name, value, false));
cache.flush(); cache.flush();
BOOST_CHECK(cache.checkConsistency(0)); BOOST_CHECK(cache.checkConsistency());
for (auto& name: names) { for (auto& name: names) {
CClaimValue temp; CClaimValue temp;
BOOST_CHECK(cache.removeClaimFromTrie(name, COutPoint(), temp, false)); BOOST_CHECK(cache.removeClaimFromTrie(name, COutPoint(), temp, false));
cache.flush(); cache.flush();
BOOST_CHECK(cache.checkConsistency(0)); BOOST_CHECK(cache.checkConsistency());
} }
BOOST_CHECK_EQUAL(trie.height(), 0); BOOST_CHECK(trie.empty());
} }
BOOST_AUTO_TEST_CASE(takeover_workaround_triggers) BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
@ -394,9 +360,91 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu)); BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
BOOST_CHECK_EQUAL(3, cache.find("aa")->nHeightOfLastTakeover); BOOST_CHECK_EQUAL(3, cache.getCache("aa")->nHeightOfLastTakeover);
BOOST_CHECK_EQUAL(3, cache.find("bb")->nHeightOfLastTakeover); BOOST_CHECK_EQUAL(3, cache.getCache("bb")->nHeightOfLastTakeover);
BOOST_CHECK_EQUAL(1, cache.find("cc")->nHeightOfLastTakeover); BOOST_CHECK_EQUAL(1, cache.getCache("cc")->nHeightOfLastTakeover);
}
BOOST_AUTO_TEST_CASE(verify_basic_serialization)
{
CClaimValue cv;
cv.outPoint = COutPoint(uint256S("123"), 2);
cv.nHeight = 3;
cv.claimId.SetHex("4567");
cv.nEffectiveAmount = 4;
cv.nAmount = 5;
cv.nValidAtHeight = 6;
CDataStream ssData(SER_NETWORK, PROTOCOL_VERSION);
ssData << cv;
CClaimValue cv2;
ssData >> cv2;
BOOST_CHECK_EQUAL(cv, cv2);
}
BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize)
{
CDataStream ss(SER_DISK, 0);
uint160 hash160;
CClaimTrieData n1;
CClaimTrieData n2;
CClaimValue throwaway;
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
n1.insertClaim(v1);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.insertClaim(v2);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.removeClaim(v1.outPoint, throwaway);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
n1.removeClaim(v2.outPoint, throwaway);
BOOST_CHECK(n1 != n2);
ss << n1;
ss >> n2;
BOOST_CHECK_EQUAL(n1, n2);
}
BOOST_AUTO_TEST_CASE(claimtrienode_remove_invalid_claim)
{
uint160 hash160;
CClaimTrieData n1;
CClaimTrieData n2;
CClaimValue throwaway;
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
n1.insertClaim(v1);
n2.insertClaim(v2);
bool invalidClaim = n2.removeClaim(v1.outPoint, throwaway);
BOOST_CHECK_EQUAL(invalidClaim, false);
invalidClaim = n1.removeClaim(v2.outPoint, throwaway);
BOOST_CHECK_EQUAL(invalidClaim, false);
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,803 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtrieexpirationfork_tests, RegTestingSetup)
/*
expiration
check claims expire and loses claim
check claims expire and is not updateable (may be changed in future soft fork)
check supports expire and can cause supported bid to lose claim
*/
BOOST_AUTO_TEST_CASE(claimtrie_expire_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(1000000, 5, 1000000);
// check claims expire and loses claim
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2);
fixture.IncrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx1));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx2));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
fixture.DecrementBlocks(fixture.expirationTime());
// check claims expire and is not updateable (may be changed in future soft fork)
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test", "one", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx3));
fixture.IncrementBlocks(fixture.expirationTime());
CMutableTransaction u1 = fixture.MakeUpdate(tx3, "test", "two", ClaimIdHash(tx3.GetHash(), 0), 2);
BOOST_CHECK(!fixture.is_best_claim("test",u1));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx3));
fixture.DecrementBlocks(1);
// check supports expire and can cause supported bid to lose claim
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "test", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx4));
CMutableTransaction u2 = fixture.MakeUpdate(tx4, "test", "two", ClaimIdHash(tx4.GetHash(),0), 1);
CMutableTransaction u3 = fixture.MakeUpdate(tx5, "test", "two", ClaimIdHash(tx5.GetHash(),0), 2);
fixture.IncrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", u3));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx4));
fixture.DecrementBlocks(1);
// check updated claims will extend expiration
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", tx6));
CMutableTransaction u4 = fixture.MakeUpdate(tx6, "test", "two", ClaimIdHash(tx6.GetHash(), 0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.IncrementBlocks(fixture.expirationTime()-1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("test", u4));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test", u4));
fixture.DecrementBlocks(fixture.expirationTime());
BOOST_CHECK(fixture.is_best_claim("test", tx6));
}
/*
claim expiration for hard fork
check claims do not expire post ExpirationForkHeight
check supports work post ExpirationForkHeight
*/
BOOST_AUTO_TEST_CASE(hardfork_claim_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(7, 3, 6);
// First create a claim and make sure it expires pre-fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",3);
fixture.IncrementBlocks(4);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
// Create a claim 1 block before the fork height that will expire after the fork height
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
// Disable future expirations and fast-forward past the fork height
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// make sure decrementing to before the fork height will apppropriately set back the
// expiration time to the original expiraiton time
fixture.DecrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// make sure that claim created 1 block before the fork expires as expected
// at the extended expiration times
BOOST_CHECK(fixture.is_best_claim("test2", tx2));
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.is_best_claim("test2", tx2));
fixture.DecrementBlocks(5);
BOOST_CHECK(fixture.is_best_claim("test2", tx2));
// This first claim is still expired since it's pre-fork, even
// after fork activation
BOOST_CHECK(!fixture.is_best_claim("test", tx1));
// This new claim created at the fork height cannot expire at original expiration
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",1);
fixture.IncrementBlocks(1);
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test",tx3));
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
// but it expires at the extended expiration, and not a single block below
fixture.IncrementBlocks(6);
BOOST_CHECK(!fixture.is_best_claim("test",tx3));
fixture.DecrementBlocks(6);
fixture.IncrementBlocks(5);
BOOST_CHECK(fixture.is_best_claim("test",tx3));
fixture.DecrementBlocks(5);
// Ensure that we cannot update the original pre-fork expired claim
CMutableTransaction u1 = fixture.MakeUpdate(tx1,"test","two",ClaimIdHash(tx1.GetHash(),0), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("test",u1));
// Ensure that supports for the expired claim don't support it
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(),u1,"test",10);
BOOST_CHECK(!fixture.is_best_claim("test",u1));
// Ensure that we can update the new post-fork claim
CMutableTransaction u2 = fixture.MakeUpdate(tx3,"test","two",ClaimIdHash(tx3.GetHash(),0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",u2));
// Ensure that supports for the new post-fork claim
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),u2,"test",3);
BOOST_CHECK(fixture.is_best_claim("test",u2));
}
/*
support expiration for hard fork
*/
BOOST_AUTO_TEST_CASE(hardfork_support_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(2, 2, 4);
// Create claim and support it before the fork height
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 2);
// this claim will win without the support
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test","one",2);
fixture.IncrementBlocks(2);
// check that the claim expires as expected at the extended time, as does the support
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(2);
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.is_best_claim("test",tx1));
fixture.DecrementBlocks(3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("test",tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
fixture.DecrementBlocks(1);
// update the claims at fork
fixture.DecrementBlocks(1);
CMutableTransaction u1 = fixture.MakeUpdate(tx1, "test", "two", ClaimIdHash(tx1.GetHash(),0), 1);
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test", "two", ClaimIdHash(tx2.GetHash(),0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(Params().GetConsensus().nExtendedClaimExpirationForkHeight, chainActive.Height());
BOOST_CHECK(fixture.is_best_claim("test", u1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
BOOST_CHECK(!fixture.is_claim_in_queue("test", tx1));
BOOST_CHECK(!fixture.is_claim_in_queue("test", tx2));
// check that the support expires as expected
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("test", u2));
fixture.DecrementBlocks(3);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test",u1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",3));
}
/*
activation_fall_through and supports_fall_through
Tests for where claims/supports in queues would be undone properly in a decrement.
See https://github.com/lbryio/lbrycrd/issues/243 for more details
*/
BOOST_AUTO_TEST_CASE(activations_fall_through)
{
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.IncrementBlocks(3);
BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(3);
fixture.Spend(tx1); // this will trigger early activation on tx2 claim
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(1); //reorg the early activation
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.Spend(tx1);
fixture.IncrementBlocks(1); // this should not cause tx2 to activate again and crash
BOOST_CHECK(fixture.is_best_claim("A", tx2));
}
BOOST_AUTO_TEST_CASE(supports_fall_through)
{
ClaimTrieChainFixture fixture;
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 3);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "3", 2);
fixture.IncrementBlocks(3);
BOOST_CHECK_EQUAL(fixture.proportionalDelayFactor(), 1);
CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "A", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(3);
fixture.Spend(tx1); // this will trigger early activation
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.DecrementBlocks(1); // reorg the early activation
BOOST_CHECK(fixture.is_best_claim("A", tx1));
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx1)); //tx2 support should not be active
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2)); //tx2 support should be active now
}
/*
claim/support expiration for hard fork, but with checks for disk procedures
*/
BOOST_AUTO_TEST_CASE(hardfork_disk_test)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(7, 3, 6);
// Check that incrementing to fork height, reseting to disk will get proper expiration time
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(7, true);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
fixture.ReadFromDisk(chainActive.Tip());
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// Create a claim and support 1 block before the fork height that will expire after the fork height.
// Reset to disk, increment past the fork height and make sure we get
// proper behavior
fixture.DecrementBlocks(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1);
fixture.IncrementBlocks(1);
fixture.ReadFromDisk(chainActive.Tip());
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2));
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test",2));
fixture.DecrementBlocks(2);
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.is_best_claim("test", tx1));
// Create a claim and support before the fork height, reset to disk, update the claim
// increment past the fork height and make sure we get proper behavior
fixture.DecrementBlocks();
fixture.setExpirationForkHeight(3, 5, 6);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1);
fixture.IncrementBlocks(1);
fixture.ReadFromDisk(chainActive.Tip());
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1);
// increment to fork
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2",2));
// increment to original expiration, should not be expired
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 2));
fixture.DecrementBlocks(2);
// increment to extended expiration, should be expired and not one block before
fixture.IncrementBlocks(5);
BOOST_CHECK(!fixture.is_best_claim("test2", u2));
fixture.DecrementBlocks(5);
fixture.IncrementBlocks(4);
BOOST_CHECK(fixture.is_best_claim("test2", u2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("test2", 1)); // the support expires one block before
}
BOOST_AUTO_TEST_CASE(claim_expiration_test)
{
ClaimTrieChainFixture fixture;
std::string sName("atest");
std::string sValue("testa");
int nThrowaway;
// set expiration time to 80 blocks after the block is created
fixture.setExpirationForkHeight(1000000, 80, 1000000);
// create a claim. verify the expiration event has been scheduled.
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10);
COutPoint tx1OutPoint(tx1.GetHash(), 0);
fixture.IncrementBlocks(1, true);
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(79); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll forward a bit and then roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
fixture.IncrementBlocks(20); // 101
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
fixture.DecrementBlocks(21); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
fixture.DecrementBlocks(2); // 79
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// roll back some more.
fixture.DecrementBlocks(39); // 40
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// spend the claim. verify the expiration event is removed.
CMutableTransaction tx2 = fixture.Spend(tx1);
fixture.IncrementBlocks(1); // 41
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back the spend. verify the expiration event is returned.
fixture.DecrementBlocks(1); // 40
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until the expiration event occurs. verify the event occurs on time.
fixture.IncrementBlocks(40); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// spend the expired claim
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// undo the spend. verify everything remains empty.
fixture.DecrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify the claim is reinserted. verify the expiration event is scheduled again.
fixture.DecrementBlocks(1); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// verify the expiration event happens at the right time again
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// roll back to before the expiration event. verify it gets reinserted and expiration gets scheduled.
fixture.DecrementBlocks(1); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// roll all the way back. verify the claim is removed and the expiration event is removed.
fixture.DecrementBlocks(); // 0
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
// Make sure that when a claim expires, a lesser claim for the same name takes over
CClaimValue val;
// create one claim for the name
fixture.CommitTx(tx1);
fixture.IncrementBlocks(1, true); // 1
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance a little while and insert the second claim
fixture.IncrementBlocks(4); // 5
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 5);
COutPoint tx3OutPoint(tx3.GetHash(), 0);
fixture.IncrementBlocks(1); // 6
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
// advance until tx3 is valid, ensure tx1 is winning
fixture.IncrementBlocks(4); // 10
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(fixture.haveClaimInQueue(sName, tx3OutPoint, nThrowaway));
fixture.IncrementBlocks(1); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
uint256 tx1MerkleHash = fixture.getMerkleHash();
// roll back to before tx3 is valid
fixture.DecrementBlocks(1); // 10
// advance again until tx is valid
fixture.IncrementBlocks(1); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash());
// advance until the expiration event occurs. verify the expiration event occurs on time.
fixture.IncrementBlocks(69, true); // 80
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
fixture.IncrementBlocks(1); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint);
BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash());
// spend tx1
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1); // 82
// roll back to when tx1 and tx3 are in the trie and tx1 is winning
fixture.DecrementBlocks(); // 11
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK_EQUAL(tx1MerkleHash, fixture.getMerkleHash());
// roll all the way back
fixture.DecrementBlocks();
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.expirationQueueEmpty());
}
BOOST_AUTO_TEST_CASE(expiring_supports_test)
{
ClaimTrieChainFixture fixture;
std::string sName("atest");
std::string sValue1("testa");
std::string sValue2("testb");
CClaimValue val;
std::vector<uint256> blocks_to_invalidate;
fixture.setExpirationForkHeight(1000000, 80, 1000000);
// to be active bid must have: a higher block number and current block >= (current height - block number) / 32
// Verify that supports expire
// Create a 1 LBC claim (tx1)
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1);
fixture.IncrementBlocks(1); // 1, expires at 81
BOOST_CHECK(pcoinsTip->HaveCoin(COutPoint(tx1.GetHash(), 0)));
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
// Create a 5 LBC support (tx3)
CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName, 5);
fixture.IncrementBlocks(1); // 2, expires at 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
// Advance some, then insert 5 LBC claim (tx2)
fixture.IncrementBlocks(19); // 21
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue2, 5);
fixture.IncrementBlocks(1); // 22, activating in (22 - 2) / 1 = 20block (but not then active because support still holds tx1 up)
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
uint256 rootMerkleHash = fixture.getMerkleHash();
// Advance until tx2 is valid
fixture.IncrementBlocks(20); // 42
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK_EQUAL(rootMerkleHash, fixture.getMerkleHash());
fixture.IncrementBlocks(1); // 43
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash());
rootMerkleHash = fixture.getMerkleHash();
// Update tx1 so that it expires after tx3 expires
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
CMutableTransaction tx4 = fixture.MakeUpdate(tx1, sName, sValue1, claimId, tx1.vout[0].nValue);
fixture.IncrementBlocks(1); // 104
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
// Advance until the support expires
fixture.IncrementBlocks(37); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
rootMerkleHash = fixture.getMerkleHash();
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
rootMerkleHash = fixture.getMerkleHash();
// undo the block, make sure control goes back
fixture.DecrementBlocks(1); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
// redo the block, make sure it expires again
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
rootMerkleHash = fixture.getMerkleHash();
// roll back some, spend the support, and make sure nothing unexpected
// happens at the time the support should have expired
fixture.DecrementBlocks(19); // 63
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
BOOST_CHECK(rootMerkleHash != fixture.getMerkleHash());
fixture.Spend(tx3);
fixture.IncrementBlocks(1); // 64
blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash());
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
fixture.IncrementBlocks(20); // 84
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
//undo the spend, and make sure it still expires on time
fixture.DecrementBlocks(21); // 63
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
fixture.IncrementBlocks(18); // 81
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx4.GetHash());
fixture.IncrementBlocks(1); // 82
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx2.GetHash());
// roll all the way back
fixture.DecrementBlocks(82);
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
}
BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
{
ClaimTrieChainFixture fixture;
fixture.setExpirationForkHeight(1000000, 5, 1000000);
const std::string name = "test";
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
fixture.IncrementBlocks(1);
CClaimValue claimValue;
std::string claimName;
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
// make second claim with activation delay 1
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 2);
uint160 claimId2 = ClaimIdHash(tx2.GetHash(), 0);
fixture.IncrementBlocks(1);
// second claim is not activated yet, but can still access by claim id
BOOST_CHECK(fixture.is_best_claim(name, tx1));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.IncrementBlocks(1);
// second claim has activated
BOOST_CHECK(fixture.is_best_claim(name, tx2));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.DecrementBlocks(1);
// second claim has been deactivated via decrement
// should still be accesible via claim id
BOOST_CHECK(fixture.is_best_claim(name, tx1));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
fixture.IncrementBlocks(1);
// second claim should have been re activated via increment
BOOST_CHECK(fixture.is_best_claim(name, tx2));
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
BOOST_CHECK_EQUAL(claimName, name);
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,419 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <functional>
#include <test/claimtriefixture.h>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtriefixture_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(claimtriefixture_noop)
{
BOOST_REQUIRE(true);
}
BOOST_AUTO_TEST_SUITE_END()
CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout, unsigned int numOutputs, int locktime)
{
CMutableTransaction tx;
tx.nVersion = CTransaction::CURRENT_VERSION;
tx.vin.resize(1);
tx.vout.resize(numOutputs);
tx.vin[0].prevout.hash = prev.GetHash();
tx.vin[0].prevout.n = prevout;
tx.vin[0].scriptSig = CScript();
if (locktime != 0) {
// Use a relative locktime for validity X blocks in the future
tx.nLockTime = chainActive.Height() + locktime;
tx.vin[0].nSequence = 0xffffffff - 1;
} else {
tx.nLockTime = 1 << 31; // Disable BIP68
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
}
CAmount valuePerOutput = prev.vout[prevout].nValue;
unsigned int numOutputsCopy = numOutputs;
while ((numOutputsCopy = numOutputsCopy >> 1) > 0)
valuePerOutput = valuePerOutput >> 1;
for (unsigned int i = 0; i < numOutputs; ++i) {
tx.vout[i].scriptPubKey = CScript();
tx.vout[i].nValue = valuePerOutput;
}
return tx;
}
CMutableTransaction BuildTransaction(const uint256& prevhash)
{
CMutableTransaction tx;
tx.nVersion = 1;
tx.nLockTime = 0;
tx.vin.resize(1);
tx.vout.resize(1);
tx.vin[0].prevout.hash = prevhash;
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript();
tx.vin[0].nSequence = std::numeric_limits<unsigned int>::max();
tx.vout[0].scriptPubKey = CScript();
tx.vout[0].nValue = 0;
return tx;
}
BlockAssembler AssemblerForTest()
{
BlockAssembler::Options options;
options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
options.blockMinFeeRate = CFeeRate(0);
return BlockAssembler(Params(), options);
}
ClaimTrieChainFixture::ClaimTrieChainFixture() : CClaimTrieCache(pclaimTrie),
unique_block_counter(0), normalization_original(-1), expirationForkHeight(-1), forkhash_original(-1)
{
fRequireStandard = false;
BOOST_CHECK_EQUAL(nNextHeight, chainActive.Height() + 1);
setNormalizationForkHeight(1000000);
gArgs.ForceSetArg("-limitancestorcount", "1000000");
gArgs.ForceSetArg("-limitancestorsize", "1000000");
gArgs.ForceSetArg("-limitdescendantcount", "1000000");
gArgs.ForceSetArg("-limitdescendantsize", "1000000");
num_txs_for_next_block = 0;
coinbase_txs_used = 0;
unique_block_counter = 0;
added_unchecked = false;
// generate coinbases to spend
CreateCoinbases(40, coinbase_txs);
}
ClaimTrieChainFixture::~ClaimTrieChainFixture()
{
added_unchecked = false;
DecrementBlocks(chainActive.Height());
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (normalization_original >= 0)
consensus.nNormalizedNameForkHeight = normalization_original;
if (expirationForkHeight >= 0) {
consensus.nExtendedClaimExpirationForkHeight = expirationForkHeight;
consensus.nExtendedClaimExpirationTime = extendedExpiration;
consensus.nOriginalClaimExpirationTime = originalExpiration;
}
if (forkhash_original >= 0)
consensus.nAllClaimsInMerkleForkHeight = forkhash_original;
}
void ClaimTrieChainFixture::setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (expirationForkHeight < 0) {
expirationForkHeight = consensus.nExtendedClaimExpirationForkHeight;
originalExpiration = consensus.nOriginalClaimExpirationTime;
extendedExpiration = consensus.nExtendedClaimExpirationTime;
}
consensus.nExtendedClaimExpirationForkHeight = target;
consensus.nExtendedClaimExpirationTime = postForkExpirationTime;
consensus.nOriginalClaimExpirationTime = preForkExpirationTime;
setExpirationTime(targetMinusCurrent >= 0 ? preForkExpirationTime : postForkExpirationTime);
}
void ClaimTrieChainFixture::setNormalizationForkHeight(int targetMinusCurrent)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (normalization_original < 0)
normalization_original = consensus.nNormalizedNameForkHeight;
consensus.nNormalizedNameForkHeight = target;
}
void ClaimTrieChainFixture::setHashForkHeight(int targetMinusCurrent)
{
int target = chainActive.Height() + targetMinusCurrent;
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (forkhash_original < 0)
forkhash_original = consensus.nAllClaimsInMerkleForkHeight;
consensus.nAllClaimsInMerkleForkHeight = target;
}
bool ClaimTrieChainFixture::CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate)
{
CBlock* pblock = &pblocktemplate->block;
{
LOCK(cs_main);
pblock->nVersion = 5;
pblock->hashPrevBlock = chainActive.Tip()->GetBlockHash();
pblock->nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << int(++unique_block_counter);
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus());
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
for (uint32_t i = 0;; ++i) {
pblock->nNonce = i;
if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus()))
break;
}
}
auto success = ProcessNewBlock(Params(), std::make_shared<const CBlock>(*pblock), true, nullptr);
return success && pblock->GetHash() == chainActive.Tip()->GetBlockHash();
}
bool ClaimTrieChainFixture::CreateCoinbases(unsigned int num_coinbases, std::vector<CTransaction>& coinbases)
{
std::unique_ptr<CBlockTemplate> pblocktemplate;
coinbases.clear();
BOOST_CHECK(pblocktemplate = AssemblerForTest().CreateNewBlock(CScript() << OP_TRUE));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1);
for (unsigned int i = 0; i < 100 + num_coinbases; ++i) {
BOOST_CHECK(CreateBlock(pblocktemplate));
if (coinbases.size() < num_coinbases)
coinbases.push_back(std::move(*pblocktemplate->block.vtx[0]));
}
return true;
}
void ClaimTrieChainFixture::CommitTx(const CMutableTransaction &tx, bool has_locktime)
{
num_txs_for_next_block++;
if (has_locktime) {
added_unchecked = true;
TestMemPoolEntryHelper entry;
LOCK(mempool.cs);
mempool.addUnchecked(tx.GetHash(), entry.Fee(0).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
} else {
CValidationState state;
CAmount txFeeRate = CAmount(0);
LOCK(cs_main);
BOOST_CHECK_EQUAL(AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr, nullptr, false, txFeeRate, false), true);
}
}
// spend a bid into some non claimtrie related unspent
CMutableTransaction ClaimTrieChainFixture::Spend(const CTransaction &prev)
{
CMutableTransaction tx = BuildTransaction(prev, 0);
tx.vout[0].scriptPubKey = CScript() << OP_TRUE;
tx.vout[0].nValue = prev.vout[0].nValue;
CommitTx(tx);
return tx;
}
// make claim at the current block
CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime)
{
uint32_t prevout = prev.vout.size() - 1;
while (prevout > 0 && prev.vout[prevout].nValue < quantity)
--prevout;
CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1, locktime);
tx.vout[0].scriptPubKey = ClaimNameScript(name, value);
tx.vout[0].nValue = quantity;
if (tx.vout.size() > 1) {
tx.vout[1].scriptPubKey = CScript() << OP_TRUE;
tx.vout[1].nValue = prev.vout[prevout].nValue - quantity;
}
CommitTx(tx, locktime != 0);
return tx;
}
CMutableTransaction ClaimTrieChainFixture::MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value)
{
return MakeClaim(prev, name, value, prev.vout[0].nValue, 0);
}
// make support at the current block
CMutableTransaction ClaimTrieChainFixture::MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity)
{
uint32_t prevout = prev.vout.size() - 1;
while (prevout > 0 && prev.vout[prevout].nValue < quantity)
--prevout;
CMutableTransaction tx = BuildTransaction(prev, prevout, prev.vout[prevout].nValue > quantity ? 2 : 1);
tx.vout[0].scriptPubKey = SupportClaimScript(name, ClaimIdHash(claimtx.GetHash(), 0));
tx.vout[0].nValue = quantity;
if (tx.vout.size() > 1) {
tx.vout[1].scriptPubKey = CScript() << OP_TRUE;
tx.vout[1].nValue = prev.vout[prevout].nValue - quantity;
}
CommitTx(tx);
return tx;
}
// make update at the current block
CMutableTransaction ClaimTrieChainFixture::MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity)
{
CMutableTransaction tx = BuildTransaction(prev, 0);
tx.vout[0].scriptPubKey = UpdateClaimScript(name, claimId, value);
tx.vout[0].nValue = quantity;
CommitTx(tx);
return tx;
}
CTransaction ClaimTrieChainFixture::GetCoinbase()
{
return coinbase_txs.at(coinbase_txs_used++);
}
// create i blocks
void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
{
if (mark)
marks.push_back(chainActive.Height());
clear(); // clears the internal cache
for (int i = 0; i < num_blocks; ++i) {
CScript coinbase_scriptpubkey;
coinbase_scriptpubkey << CScriptNum(chainActive.Height());
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest().CreateNewBlock(coinbase_scriptpubkey);
BOOST_CHECK(pblocktemplate != nullptr);
if (!added_unchecked)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1);
BOOST_CHECK_EQUAL(CreateBlock(pblocktemplate), true);
num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1;
}
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// disconnect i blocks from tip
void ClaimTrieChainFixture::DecrementBlocks(int num_blocks)
{
clear(); // clears the internal cache
CValidationState state;
{
LOCK(cs_main);
CBlockIndex* pblockindex = chainActive[chainActive.Height() - num_blocks + 1];
BOOST_CHECK_EQUAL(InvalidateBlock(state, Params(), pblockindex), true);
}
BOOST_CHECK_EQUAL(state.IsValid(), true);
BOOST_CHECK_EQUAL(ActivateBestChain(state, Params()), true);
mempool.clear();
num_txs_for_next_block = 0;
nNextHeight = chainActive.Height() + 1;
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// decrement back to last mark
void ClaimTrieChainFixture::DecrementBlocks()
{
int mark = marks.back();
marks.pop_back();
DecrementBlocks(chainActive.Height() - mark);
}
template <typename K>
bool ClaimTrieChainFixture::keyTypeEmpty(uint8_t keyType)
{
boost::scoped_ptr<CDBIterator> pcursor(base->db->NewIterator());
pcursor->SeekToFirst();
while (pcursor->Valid()) {
std::pair<uint8_t, K> key;
if (pcursor->GetKey(key))
if (key.first == keyType)
return false;
pcursor->Next();
}
return true;
}
bool ClaimTrieChainFixture::queueEmpty()
{
for (const auto& claimQueue: claimQueueCache)
if (!claimQueue.second.empty())
return false;
return keyTypeEmpty<int>(CLAIM_QUEUE_ROW);
}
bool ClaimTrieChainFixture::expirationQueueEmpty()
{
for (const auto& expirationQueue: expirationQueueCache)
if (!expirationQueue.second.empty())
return false;
return keyTypeEmpty<int>(CLAIM_EXP_QUEUE_ROW);
}
bool ClaimTrieChainFixture::supportEmpty()
{
for (const auto& entry: supportCache)
if (!entry.second.empty())
return false;
return supportCache.empty() && keyTypeEmpty<std::string>(SUPPORT);
}
bool ClaimTrieChainFixture::supportQueueEmpty()
{
for (const auto& support: supportQueueCache)
if (!support.second.empty())
return false;
return keyTypeEmpty<int>(SUPPORT_QUEUE_ROW);
}
int ClaimTrieChainFixture::proportionalDelayFactor()
{
return base->nProportionalDelayFactor;
}
boost::test_tools::predicate_result negativeResult(const std::function<void(boost::wrap_stringstream&)>& callback)
{
boost::test_tools::predicate_result res(false);
callback(res.message());
return res;
}
boost::test_tools::predicate_result negativeResult(const std::string& message)
{
return negativeResult([&message](boost::wrap_stringstream& stream) {
stream << message;
});
}
// is a claim in queue
boost::test_tools::predicate_result ClaimTrieChainFixture::is_claim_in_queue(const std::string& name, const CTransaction &tx)
{
COutPoint outPoint(tx.GetHash(), 0);
int validAtHeight;
if (haveClaimInQueue(name, outPoint, validAtHeight))
return true;
return negativeResult("Is not a claim in queue");
}
// check if tx is best claim based on outpoint
boost::test_tools::predicate_result ClaimTrieChainFixture::is_best_claim(const std::string& name, const CTransaction &tx)
{
CClaimValue val;
COutPoint outPoint(tx.GetHash(), 0);
bool have_claim = haveClaim(name, outPoint);
bool have_info = getInfoForName(name, val);
if (have_claim && have_info && val.outPoint == outPoint)
return true;
return negativeResult("Is not best claim");
}
// check effective quantity of best claim
boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_amount_equals(const std::string& name, CAmount amount)
{
CClaimValue val;
bool have_info = getInfoForName(name, val);
if (!have_info)
return negativeResult("No claim found");
CAmount effective_amount = getClaimsForName(name).find(val.claimId).effectiveAmount;
if (effective_amount != amount)
return negativeResult([amount, effective_amount](boost::wrap_stringstream& stream) {
stream << amount << " != " << effective_amount;
});
return true;
}
std::size_t ClaimTrieChainFixture::getTotalNamesInTrie() const
{
return base->getTotalNamesInTrie();
}

124
src/test/claimtriefixture.h Normal file
View file

@ -0,0 +1,124 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#ifndef _CLAIMTRIEFIXTURE_H_
#define _CLAIMTRIEFIXTURE_H_
#include <chainparams.h>
#include <claimtrie.h>
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <miner.h>
#include <nameclaim.h>
#include <policy/policy.h>
#include <pow.h>
#include <primitives/transaction.h>
#include <random.h>
#include <rpc/claimrpchelp.h>
#include <rpc/server.h>
#include <streams.h>
#include <test/test_bitcoin.h>
#include <txmempool.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
#include <iostream>
extern ::CChainState g_chainstate;
extern ::ArgsManager gArgs;
extern std::vector<std::string> random_strings(std::size_t count);
extern bool getClaimById(const uint160&, std::string&, CClaimValue*);
CMutableTransaction BuildTransaction(const uint256& prevhash);
CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1, int locktime=0);
BlockAssembler AssemblerForTest();
// Test Fixtures
struct ClaimTrieChainFixture: public CClaimTrieCache
{
std::vector<CTransaction> coinbase_txs;
std::vector<int> marks;
int coinbase_txs_used;
int unique_block_counter;
int normalization_original;
unsigned int num_txs_for_next_block;
bool added_unchecked;
int64_t expirationForkHeight;
int64_t originalExpiration;
int64_t extendedExpiration;
int64_t forkhash_original;
using CClaimTrieCache::getSupportsForName;
ClaimTrieChainFixture();
~ClaimTrieChainFixture();
void setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime);
void setNormalizationForkHeight(int targetMinusCurrent);
void setHashForkHeight(int targetMinusCurrent);
bool CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate);
bool CreateCoinbases(unsigned int num_coinbases, std::vector<CTransaction>& coinbases);
void CommitTx(const CMutableTransaction &tx, bool has_locktime=false);
// spend a bid into some non claimtrie related unspent
CMutableTransaction Spend(const CTransaction &prev);
// make claim at the current block
CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value, CAmount quantity, int locktime=0);
CMutableTransaction MakeClaim(const CTransaction& prev, const std::string& name, const std::string& value);
// make support at the current block
CMutableTransaction MakeSupport(const CTransaction &prev, const CTransaction &claimtx, const std::string& name, CAmount quantity);
// make update at the current block
CMutableTransaction MakeUpdate(const CTransaction &prev, const std::string& name, const std::string& value, const uint160& claimId, CAmount quantity);
CTransaction GetCoinbase();
// create i blocks
void IncrementBlocks(int num_blocks, bool mark = false);
// disconnect i blocks from tip
void DecrementBlocks(int num_blocks);
// decrement back to last mark
void DecrementBlocks();
bool queueEmpty();
bool expirationQueueEmpty();
bool supportEmpty();
bool supportQueueEmpty();
int proportionalDelayFactor();
// is a claim in queue
boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx);
// check if tx is best claim based on outpoint
boost::test_tools::predicate_result is_best_claim(const std::string& name, const CTransaction &tx);
// check effective quantity of best claim
boost::test_tools::predicate_result best_claim_effective_amount_equals(const std::string& name, CAmount amount);
std::size_t getTotalNamesInTrie() const;
private:
template <typename K>
bool keyTypeEmpty(uint8_t keyType);
};
#endif // _CLAIMTRIEFIXTURE_H_

View file

@ -0,0 +1,390 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash)
{
for (auto& pair : pairs)
if (pair.first) // we're on the right because we were an odd index number
claimHash = Hash(pair.second.begin(), pair.second.end(), claimHash.begin(), claimHash.end());
else
claimHash = Hash(claimHash.begin(), claimHash.end(), pair.second.begin(), pair.second.end());
BOOST_CHECK_EQUAL(cache.getMerkleHash(), claimHash);
}
BOOST_FIXTURE_TEST_SUITE(claimtriehashfork_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_rollback_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
fixture.IncrementBlocks(1);
uint256 currentRoot = fixture.getMerkleHash();
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash());
fixture.IncrementBlocks(3);
BOOST_CHECK_NE(currentRoot, fixture.getMerkleHash());
fixture.DecrementBlocks(3);
BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash());
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
fixture.IncrementBlocks(1);
COutPoint outPoint(tx1.GetHash(), 0);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
CClaimTrieProof proof;
BOOST_CHECK(fixture.getProofForName("test", proof, [&claimId](const CClaimValue& claim) {
return claim.claimId == claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, outPoint);
auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string names[] = {"test", "tester", "tester2"};
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "one", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "two", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "thr", 3);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "for", 4);
CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), names[0], "fiv", 5);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "two", 2);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), names[1], "thr", 3);
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), names[2], "one", 1);
fixture.IncrementBlocks(1);
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string names[] = {"test", "toast", "tot", "top", "toa", "toad"};
for (const auto& name : names)
fixture.MakeClaim(fixture.GetCoinbase(), name, "one", 1);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "two", 2);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "tre", 3);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "qua", 4);
fixture.MakeClaim(fixture.GetCoinbase(), "toa", "cin", 5);
fixture.IncrementBlocks(1);
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::size_t i = 0;
auto names = random_strings(300);
auto lastTx = MakeTransactionRef(fixture.GetCoinbase());
for (const auto& name : names) {
auto tx = fixture.MakeClaim(*lastTx, name, "one", 1);
lastTx = MakeTransactionRef(std::move(tx));
if (++i % 5 == 0)
for (std::size_t j = 0; j < (i / 5); ++j) {
auto tx = fixture.MakeClaim(*lastTx, name, "one", 1);
lastTx = MakeTransactionRef(std::move(tx));
}
fixture.IncrementBlocks(1);
}
for (const auto& name : names) {
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
CClaimTrieProof proof;
auto& claim = claimSupports.claim;
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
return claim.claimId == value.claimId;
}));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name)
{
uint256 previousComputedHash;
std::string computedReverseName;
bool verifiedValue = false;
for (auto itNodes = proof.nodes.rbegin(); itNodes != proof.nodes.rend(); ++itNodes) {
bool foundChildInChain = false;
std::vector<unsigned char> vchToHash;
for (auto itChildren = itNodes->children.begin(); itChildren != itNodes->children.end(); ++itChildren) {
vchToHash.push_back(itChildren->first);
uint256 childHash;
if (itChildren->second.IsNull()) {
if (previousComputedHash.IsNull()) {
return false;
}
if (foundChildInChain) {
return false;
}
foundChildInChain = true;
computedReverseName += itChildren->first;
childHash = previousComputedHash;
} else {
childHash = itChildren->second;
}
vchToHash.insert(vchToHash.end(), childHash.begin(), childHash.end());
}
if (itNodes != proof.nodes.rbegin() && !foundChildInChain) {
return false;
}
if (itNodes->hasValue) {
uint256 valHash;
if (itNodes->valHash.IsNull()) {
if (itNodes != proof.nodes.rbegin()) {
return false;
}
if (!proof.hasValue) {
return false;
}
valHash = getValueHash(proof.outPoint,
proof.nHeightOfLastTakeover);
verifiedValue = true;
} else {
valHash = itNodes->valHash;
}
vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end());
} else if (proof.hasValue && itNodes == proof.nodes.rbegin()) {
return false;
}
CHash256 hasher;
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
hasher.Write(vchToHash.data(), vchToHash.size());
hasher.Finalize(&(vchHash[0]));
uint256 calculatedHash(vchHash);
previousComputedHash = calculatedHash;
}
if (previousComputedHash != rootHash) {
return false;
}
if (proof.hasValue && !verifiedValue) {
return false;
}
std::string::reverse_iterator itComputedName = computedReverseName.rbegin();
std::string::const_iterator itName = name.begin();
for (; itName != name.end() && itComputedName != computedReverseName.rend(); ++itName, ++itComputedName) {
if (*itName != *itComputedName) {
return false;
}
}
return (!proof.hasValue || itName == name.end());
}
BOOST_AUTO_TEST_CASE(value_proof_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("a");
std::string sValue1("testa");
std::string sName2("abc");
std::string sValue2("testabc");
std::string sName3("abd");
std::string sValue3("testabd");
std::string sName4("zyx");
std::string sValue4("testzyx");
std::string sName5("zyxa");
std::string sName6("omg");
std::string sName7("");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1);
COutPoint tx1OutPoint(tx1.GetHash(), 0);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName2, sValue2);
COutPoint tx2OutPoint(tx2.GetHash(), 0);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), sName3, sValue3);
COutPoint tx3OutPoint(tx3.GetHash(), 0);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), sName4, sValue4);
COutPoint tx4OutPoint(tx4.GetHash(), 0);
CClaimValue val;
// create a claim. verify the expiration event has been scheduled.
fixture.IncrementBlocks(5, true);
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName1, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName2, val));
BOOST_CHECK_EQUAL(val.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName3, val));
BOOST_CHECK_EQUAL(val.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getInfoForName(sName4, val));
BOOST_CHECK_EQUAL(val.outPoint, tx4OutPoint);
CClaimTrieProof proof;
BOOST_CHECK(fixture.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
BOOST_CHECK(fixture.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK_EQUAL(proof.hasValue, false);
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), sName7, sValue4);
COutPoint tx5OutPoint(tx5.GetHash(), 0);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.getInfoForName(sName7, val));
BOOST_CHECK_EQUAL(val.outPoint, tx5OutPoint);
BOOST_CHECK(fixture.getProofForName(sName1, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
BOOST_CHECK(fixture.getProofForName(sName2, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
BOOST_CHECK(fixture.getProofForName(sName3, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
BOOST_CHECK(fixture.getProofForName(sName4, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
BOOST_CHECK(fixture.getProofForName(sName5, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName6, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName7, proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK_EQUAL(proof.outPoint, tx5OutPoint);
fixture.DecrementBlocks();
BOOST_CHECK(pclaimTrie->empty());
BOOST_CHECK(fixture.queueEmpty());
}
// Check that blocks with bogus calimtrie hash is rejected
BOOST_AUTO_TEST_CASE(bogus_claimtrie_hash_test)
{
ClaimTrieChainFixture fixture;
std::string sName("test");
std::string sValue1("test");
int orig_chain_height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue1, 1);
std::unique_ptr<CBlockTemplate> pblockTemp;
BOOST_CHECK(pblockTemp = AssemblerForTest().CreateNewBlock(tx1.vout[0].scriptPubKey));
pblockTemp->block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
pblockTemp->block.nVersion = 5;
pblockTemp->block.nTime = chainActive.Tip()->GetBlockTime() + Params().GetConsensus().nPowTargetSpacing;
CMutableTransaction txCoinbase(*pblockTemp->block.vtx[0]);
txCoinbase.vin[0].scriptSig = CScript() << int(chainActive.Height() + 1) << 1;
txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, Params().GetConsensus());
pblockTemp->block.vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblockTemp->block.hashMerkleRoot = BlockMerkleRoot(pblockTemp->block);
//create bogus hash
uint256 bogusHashClaimTrie;
bogusHashClaimTrie.SetHex("aaa");
pblockTemp->block.hashClaimTrie = bogusHashClaimTrie;
for (uint32_t i = 0;; ++i) {
pblockTemp->block.nNonce = i;
if (CheckProofOfWork(pblockTemp->block.GetPoWHash(), pblockTemp->block.nBits, Params().GetConsensus())) {
break;
}
}
bool success = ProcessNewBlock(Params(), std::make_shared<const CBlock>(pblockTemp->block), true, nullptr);
// will process , but will not be connected
BOOST_CHECK(success);
BOOST_CHECK(pblockTemp->block.GetHash() != chainActive.Tip()->GetBlockHash());
BOOST_CHECK_EQUAL(orig_chain_height, chainActive.Height());
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,494 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
BOOST_FIXTURE_TEST_SUITE(claimtrienormalization_tests, RegTestingSetup)
/*
normalization
test normalization function indpendent from rest of the code
*/
BOOST_AUTO_TEST_CASE(normalization_only)
{
CClaimTrieCache ccache(pclaimTrie);
// basic ASCII casing tests
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TESt", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("tesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("TesT", true));
BOOST_CHECK_EQUAL("test", ccache.normalizeClaimName("test", true));
BOOST_CHECK_EQUAL("test this", ccache.normalizeClaimName("Test This", true));
// test invalid utf8 bytes are returned as is
BOOST_CHECK_EQUAL("\xFF", ccache.normalizeClaimName("\xFF", true));
BOOST_CHECK_EQUAL("\xC3\x28", ccache.normalizeClaimName("\xC3\x28", true));
// ohm sign unicode code point \x2126 should be transformed to equivalent
// unicode code point \x03C9 , greek small letter omega
BOOST_CHECK_EQUAL("\xCF\x89", ccache.normalizeClaimName("\xE2\x84\xA6", true));
// cyrillic capital ef code point \x0424 should be transformed to lower case
// \x0444
BOOST_CHECK_EQUAL("\xD1\x84", ccache.normalizeClaimName("\xD0\xA4", true));
// armenian capital ben code point \x0532 should be transformed to lower case
// \x0562
BOOST_CHECK_EQUAL("\xD5\xA2", ccache.normalizeClaimName("\xD4\xB2", true));
// japanese pbu code point \x3076 should be transformed by NFD decomposition
// into \x3075 and \x3099
BOOST_CHECK_EQUAL("\xE3\x81\xB5\xE3\x82\x99",
ccache.normalizeClaimName("\xE3\x81\xB6", true));
// hangul ggwalg unicode code point \xAF51 should be transformed by NFD
// decomposition into unicode code points \x1101 \x116A \x11B0
// source: http://unicode.org/L2/L2009/09052-tr47.html
BOOST_CHECK_EQUAL("\xE1\x84\x81\xE1\x85\xAA\xE1\x86\xB0",
ccache.normalizeClaimName("\xEA\xBD\x91", true));
}
/*
normalization
check claim name normalization before the fork
check claim name normalization after the fork
*/
BOOST_AUTO_TEST_CASE(claimtriebranching_normalization)
{
ClaimTrieChainFixture fixture;
// check claim names are not normalized
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "normalizeTest", "one", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.getTotalNamesInTrie() == 0);
fixture.CommitTx(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
CMutableTransaction tx2a = fixture.MakeClaim(fixture.GetCoinbase(), "Normalizetest", "one_a", 2);
CMutableTransaction tx2 = fixture.MakeUpdate(tx2a, "Normalizetest", "one", ClaimIdHash(tx2a.GetHash(), 0), 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
fixture.IncrementBlocks(1, true);
// Post-fork, tx1 (the previous winning claim) assumes all name
// variants of what it originally was ...
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 3));
BOOST_CHECK(!pclaimTrie->find("normalizeTest"));
// Check equivalence of normalized claim names
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
fixture.IncrementBlocks(1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "NORMALIZETEST", "one", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("normalizetest", tx3));
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "NoRmAlIzEtEsT", 2);
fixture.IncrementBlocks(1);
// Ensure that supports work for normalized claim names
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // effective amount is 5
BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 5));
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "foo", "bar", 1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx4, "Foo", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("foo", tx4));
CMutableTransaction u1 = fixture.MakeUpdate(tx4, "foo", "baz", ClaimIdHash(tx4.GetHash(), 0), 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("foo", u1));
CMutableTransaction u2 = fixture.MakeUpdate(tx1, "nOrmalIzEtEst", "two", ClaimIdHash(tx1.GetHash(), 0), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("normalizetest", u2));
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "Ame\u0301lie", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue nval1;
fixture.getInfoForName("amélie", nval1);
BOOST_CHECK(nval1.claimId == ClaimIdHash(tx5.GetHash(), 0));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("amélie", 2));
// Check equivalence of normalized claim names
BOOST_CHECK(fixture.is_best_claim("amélie", tx5));
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "あてはまる", "jn1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("あてはまる", tx7));
CMutableTransaction tx8 = fixture.MakeClaim(fixture.GetCoinbase(), "AÑEJO", "es1", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("añejo", tx8));
// Rewind to 1 block before the fork and be sure that the fork is no longer active
fixture.DecrementBlocks();
// Now check that our old (non-normalized) claims are 'alive' again
BOOST_CHECK(fixture.is_best_claim("normalizeTest", tx1));
BOOST_CHECK(!fixture.is_best_claim("Normalizetest", tx1)); // no longer equivalent
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Create new claim
CMutableTransaction tx9 = fixture.MakeClaim(fixture.GetCoinbase(), "blah", "blah", 1);
std::string invalidUtf8("\xFF\xFF");
CMutableTransaction tx10 = fixture.MakeClaim(fixture.GetCoinbase(), invalidUtf8, "blah", 1); // invalid UTF8
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
BOOST_CHECK(fixture.is_best_claim(invalidUtf8, tx10));
// Rewind to 1 block before the fork and be sure that the fork is
// no longer active
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("Normalizetest", tx2));
// Roll forward to fork height again and check again that we're normalized
fixture.IncrementBlocks(1);
BOOST_CHECK(chainActive.Height() == Params().GetConsensus().nNormalizedNameForkHeight);
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
}
BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
{
ClaimTrieChainFixture fixture;
std::string name = "Ame\u0301lie";
std::string name_upper = "Amélie";
std::string name_normd = "amélie"; // this accented e is not actually the same as the one above; this has been "normalized"
BOOST_CHECK(name != name_upper);
// Add another set of unicode claims that will collapse after the fork
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, "amilie", 2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), name_upper, "amelie", 2);
fixture.MakeClaim(fixture.GetCoinbase(), "amelie1", "amelie", 2);
fixture.IncrementBlocks(1);
CClaimValue lookupClaim;
std::string lookupName;
BOOST_CHECK(getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, &lookupClaim));
CClaimValue nval1;
BOOST_CHECK(fixture.getInfoForName("amelie1", nval1));
// amélie is not found cause normalization still not appear
BOOST_CHECK(!fixture.getInfoForName(name_normd, nval1));
// Activate the fork (which rebuilds the existing claimtrie and
// cache), flattening all previously existing name clashes due to
// the normalization
fixture.setNormalizationForkHeight(1);
int currentHeight = chainActive.Height();
fixture.IncrementBlocks(1);
// Ok normalization fix the name problem
BOOST_CHECK(fixture.getInfoForName(name_normd, nval1));
BOOST_CHECK(nval1.nHeight == currentHeight);
BOOST_CHECK(lookupClaim == nval1);
CCoinsViewCache coins(pcoinsTip.get());
CClaimTrieCache trieCache(pclaimTrie);
CBlockIndex* pindex = chainActive.Tip();
CBlock block;
int amelieValidHeight;
BOOST_CHECK(trieCache.shouldNormalize());
BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus()));
BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK);
BOOST_CHECK(!trieCache.shouldNormalize());
BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
BOOST_CHECK(!pclaimTrie->find(name));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1));
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(trieCache.shouldNormalize());
// we cannot use getXXXForName cause they will normalized name
for (auto it = pclaimTrie->cbegin(); it != pclaimTrie->cend(); ++it)
BOOST_CHECK(it.key() != name);
}
BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
fixture.IncrementBlocks(3, true);
BOOST_CHECK(fixture.is_best_claim("a", tx3));
fixture.DecrementBlocks();
BOOST_CHECK(fixture.is_best_claim("A", tx2));
}
BOOST_AUTO_TEST_CASE(normalized_activations_fall_through)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(5);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.proportionalDelayFactor() == 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 4);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "2", 3);
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "ab", "2", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("AB", tx1));
fixture.IncrementBlocks(3);
BOOST_CHECK(fixture.is_best_claim("ab", tx2));
BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 4U);
fixture.DecrementBlocks(3);
fixture.Spend(tx1);
fixture.Spend(tx2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("ab", tx3));
BOOST_CHECK(fixture.getClaimsForName("ab").claimsNsupports.size() == 2U);
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("AB", tx1));
fixture.Spend(tx1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("ab", tx2));
for (int i = 0; i < 7; ++i) {
fixture.IncrementBlocks(i, true); // well into normalized teritory
CMutableTransaction tx5 = fixture.MakeClaim(fixture.GetCoinbase(), "CD", "a", 1 + i);
fixture.IncrementBlocks(3);
CMutableTransaction tx6 = fixture.MakeClaim(fixture.GetCoinbase(), "Cd", "b", 2 + i);
CMutableTransaction tx7 = fixture.MakeClaim(fixture.GetCoinbase(), "cD", "c", 3 + i);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("cd", tx5));
fixture.Spend(tx5);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("cd", tx7));
fixture.DecrementBlocks();
}
}
BOOST_AUTO_TEST_CASE(normalization_removal_test)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
fixture.IncrementBlocks(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "AB", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "Ab", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "aB", "3", 3);
CMutableTransaction sx1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "AB", 1);
CMutableTransaction sx2 = fixture.MakeSupport(fixture.GetCoinbase(), tx2, "Ab", 1);
CClaimTrieCache cache(pclaimTrie);
int height = chainActive.Height() + 1;
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height);
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height);
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height);
insertUndoType insertUndo;
claimQueueRowType expireUndo;
insertUndoType insertSupportUndo;
supportQueueRowType expireSupportUndo;
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U);
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo));
BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), height));
BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), height));
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U);
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_supports)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(3);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4));
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 5));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 4));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 3));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
fixture.IncrementBlocks(5);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("a", 3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_fail_on_spend)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
std::string sName1("testN");
std::string sName2("testn");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "1", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim(sName1, tx1));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, "2", 2);
CMutableTransaction tx1s = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 2);
fixture.IncrementBlocks(2, true);
BOOST_CHECK(fixture.is_best_claim(sName2, tx1));
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
CMutableTransaction tx3s = fixture.Spend(tx1s);
fixture.IncrementBlocks(2);
BOOST_CHECK(fixture.is_best_claim(sName2, tx2));
fixture.DecrementBlocks();
BOOST_CHECK(fixture.is_best_claim(sName1, tx1));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_sort_order)
{
ClaimTrieChainFixture fixture;
fixture.setNormalizationForkHeight(2);
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "2", 2);
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "a", "3", 3);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
BOOST_CHECK(fixture.getClaimsForName("a").claimsNsupports.size() == 3U);
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("A", tx2));
BOOST_CHECK(fixture.is_best_claim("a", tx3));
}
BOOST_AUTO_TEST_CASE(normalization_does_not_kill_expirations)
{
ClaimTrieChainFixture fixture;
auto& consensus = Params().GetConsensus();
fixture.setExpirationForkHeight(consensus.nExtendedClaimExpirationForkHeight, 3, consensus.nExtendedClaimExpirationTime);
fixture.setNormalizationForkHeight(4);
// need to see that claims expiring on the frame when we normalize aren't kept
// need to see that supports expiring on the frame when we normalize aren't kept
// need to see that claims & supports carried through the normalization fork do expire
// and that they come back correctly when we roll backwards
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "A", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx1, "A", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "B", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx2, "B", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
CMutableTransaction tx3 = fixture.MakeClaim(fixture.GetCoinbase(), "C", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx3, "C", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2));
CMutableTransaction tx4 = fixture.MakeClaim(fixture.GetCoinbase(), "D", "1", 1);
fixture.MakeSupport(fixture.GetCoinbase(), tx4, "D", 1);
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(2);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("d", 2));
fixture.DecrementBlocks(1);
BOOST_CHECK(fixture.best_claim_effective_amount_equals("A", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("B", 2));
BOOST_CHECK(fixture.best_claim_effective_amount_equals("C", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2));
fixture.IncrementBlocks(3);
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("a", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("b", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("c", 2));
BOOST_CHECK(!fixture.best_claim_effective_amount_equals("d", 2)); // (not re-added)
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -0,0 +1,407 @@
// Copyright (c) 2015-2019 The LBRY Foundation
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://opensource.org/licenses/mit-license.php
#include <test/claimtriefixture.h>
using namespace std;
extern void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash);
BOOST_FIXTURE_TEST_SUITE(claimtrierpc_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(getnamesintrie_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test");
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 42);
fixture.IncrementBlocks(1);
rpcfn_type getnamesintrie = tableRPC["getnamesintrie"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
UniValue results = getnamesintrie(req);
BOOST_CHECK_EQUAL(results.size(), 1U);
req.params.push_back(blockHash.GetHex());
results = getnamesintrie(req);
BOOST_CHECK_EQUAL(results.size(), 0U);
}
BOOST_AUTO_TEST_CASE(getvalueforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("testV");
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
fixture.MakeSupport(fixture.GetCoinbase(), tx1, sName1, 3);
fixture.IncrementBlocks(10);
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
UniValue results = getvalueforname(req);
BOOST_CHECK_EQUAL(results[T_VALUE].get_str(), HexStr(sValue1));
BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 5);
req.params.push_back(blockHash.GetHex());
results = getvalueforname(req);
BOOST_CHECK_EQUAL(results[T_AMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(results[T_EFFECTIVEAMOUNT].get_int(), 2);
}
BOOST_AUTO_TEST_CASE(getclaimsforname_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 2);
fixture.IncrementBlocks(1);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
UniValue results = getclaimsforname(req);
UniValue claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
fixture.IncrementBlocks(1);
results = getclaimsforname(req);
claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 3);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
BOOST_CHECK_EQUAL(claims[1][T_SUPPORTS].size(), 0U);
req.params.push_back(blockHash.GetHex());
results = getclaimsforname(req);
claims = results[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 1U);
BOOST_CHECK_EQUAL(results[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[0][T_SUPPORTS].size(), 0U);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback2_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1);
fixture.IncrementBlocks(2);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(3);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, sValue1, 3);
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
req.params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(req);
BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 5);
BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][0][T_SUPPORTS].size(), 0U);
BOOST_CHECK_EQUAL(claimsResults[T_CLAIMS][1][T_SUPPORTS].size(), 0U);
UniValue valueResults = getvalueforname(req);
BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue2));
BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 2);
}
BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("testN");
std::string sValue1("test1");
std::string sValue2("test2");
int height = chainActive.Height();
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 3);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(2);
uint256 blockHash = chainActive.Tip()->GetBlockHash();
CMutableTransaction tx3 = fixture.Spend(tx1); // abandon the claim
fixture.IncrementBlocks(1);
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
rpcfn_type getvalueforname = tableRPC["getvalueforname"]->actor;
rpcfn_type getblocktemplate = tableRPC["getblocktemplate"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
UniValue templateResults = getblocktemplate(req);
BOOST_CHECK_EQUAL(templateResults["claimtrie"].get_str(), chainActive.Tip()->hashClaimTrie.GetHex());
req.params.push_back(UniValue(sName1));
req.params.push_back(blockHash.GetHex());
UniValue claimsResults = getclaimsforname(req);
BOOST_CHECK_EQUAL(claimsResults[T_LASTTAKEOVERHEIGHT].get_int(), height + 1);
UniValue valueResults = getvalueforname(req);
BOOST_CHECK_EQUAL(valueResults[T_VALUE].get_str(), HexStr(sValue1));
BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 3);
}
std::vector<std::pair<bool, uint256>> jsonToPairs(const UniValue& jsonPair)
{
std::vector<std::pair<bool, uint256>> pairs;
for (std::size_t i = 0; i < jsonPair.size(); ++i) {
auto& jpair = jsonPair[i];
pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str()));
}
return pairs;
}
BOOST_AUTO_TEST_CASE(hash_bid_seq_claim_changes_test)
{
ClaimTrieChainFixture fixture;
fixture.setHashForkHeight(2);
fixture.IncrementBlocks(4);
std::string name = "toa";
std::string value1 = "one", value2 = "two", value3 = "tre", value4 = "for";
auto tx1 = fixture.MakeClaim(fixture.GetCoinbase(), name, value1, 1);
fixture.IncrementBlocks(1);
CMutableTransaction tx2 = BuildTransaction(fixture.GetCoinbase(), 0, 2);
tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME
<< std::vector<unsigned char>(name.begin(), name.end())
<< std::vector<unsigned char>(value2.begin(), value2.end()) << OP_2DROP << OP_DROP << OP_TRUE;
tx2.vout[0].nValue = 3;
tx2.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME
<< std::vector<unsigned char>(name.begin(), name.end())
<< std::vector<unsigned char>(value3.begin(), value3.end()) << OP_2DROP << OP_DROP << OP_TRUE;
tx2.vout[1].nValue = 2;
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1);
auto tx3 = fixture.MakeClaim(fixture.GetCoinbase(), name, value4, 4);
fixture.IncrementBlocks(1);
int height = chainActive.Height();
auto claimId1 = ClaimIdHash(tx1.GetHash(), 0);
auto claimId2 = ClaimIdHash(tx2.GetHash(), 0);
auto claimId3 = ClaimIdHash(tx2.GetHash(), 1);
auto claimId4 = ClaimIdHash(tx3.GetHash(), 0);
int claim1bid = 3, claim1seq = 0;
int claim2bid = 1, claim2seq = 1;
int claim3bid = 2, claim3seq = 2;
int claim4bid = 0, claim4seq = 3;
auto getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
auto result = getclaimsforname(req);
auto claims = result[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 4U);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 4);
BOOST_CHECK_EQUAL(claims[0][T_BID].get_int(), claim4bid);
BOOST_CHECK_EQUAL(claims[0][T_SEQUENCE].get_int(), claim4seq);
BOOST_CHECK_EQUAL(claims[0][T_CLAIMID].get_str(), claimId4.GetHex());
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(claims[1][T_BID].get_int(), claim2bid);
BOOST_CHECK_EQUAL(claims[1][T_SEQUENCE].get_int(), claim2seq);
BOOST_CHECK_EQUAL(claims[1][T_CLAIMID].get_str(), claimId2.GetHex());
BOOST_CHECK_EQUAL(claims[2][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(claims[2][T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(claims[2][T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(claims[2][T_CLAIMID].get_str(), claimId3.GetHex());
BOOST_CHECK_EQUAL(claims[3][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK_EQUAL(claims[3][T_BID].get_int(), claim1bid);
BOOST_CHECK_EQUAL(claims[3][T_SEQUENCE].get_int(), claim1seq);
BOOST_CHECK_EQUAL(claims[3][T_CLAIMID].get_str(), claimId1.GetHex());
auto getclaimbybid = tableRPC["getclaimbybid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim3bid));
result = getclaimbybid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex());
auto getclaimbyseq = tableRPC["getclaimbyseq"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim2seq));
result = getclaimbyseq(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 3);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim2bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim2seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId2.GetHex());
auto getclaimbyid = tableRPC["getclaimbyid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(claimId1.GetHex()));
result = getclaimbyid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim1bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim1seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId1.GetHex());
// check by partial id (at least 3 chars)
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(claimId3.GetHex().substr(0, 3)));
result = getclaimbyid(req);
BOOST_CHECK_EQUAL(result[T_LASTTAKEOVERHEIGHT].get_int(), height);
BOOST_CHECK_EQUAL(result[T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK_EQUAL(result[T_BID].get_int(), claim3bid);
BOOST_CHECK_EQUAL(result[T_SEQUENCE].get_int(), claim3seq);
BOOST_CHECK_EQUAL(result[T_CLAIMID].get_str(), claimId3.GetHex());
auto blockhash = chainActive.Tip()->GetBlockHash();
auto getnameproof = tableRPC["getnameproof"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(blockhash.GetHex()));
req.params.push_back(UniValue(claimId3.GetHex()));
result = getnameproof(req);
auto claimHash = getValueHash(COutPoint(tx2.GetHash(), 1), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
// check by partial id (can be even 1 char)
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(blockhash.GetHex()));
req.params.push_back(UniValue(claimId2.GetHex().substr(0, 2)));
result = getnameproof(req);
claimHash = getValueHash(COutPoint(tx2.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getclaimproofbybid = tableRPC["getclaimproofbybid"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim1bid));
result = getclaimproofbybid(req);
claimHash = getValueHash(COutPoint(tx1.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getclaimproofbyseq = tableRPC["getclaimproofbyseq"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(name));
req.params.push_back(UniValue(claim4seq));
result = getclaimproofbyseq(req);
claimHash = getValueHash(COutPoint(tx3.GetHash(), 0), result[T_LASTTAKEOVERHEIGHT].get_int());
ValidatePairs(fixture, jsonToPairs(result[T_PAIRS]), claimHash);
auto getchangesinblock = tableRPC["getchangesinblock"]->actor;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(blockhash.GetHex()));
result = getchangesinblock(req);
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED].size(), 3);
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][0].get_str(), claimId2.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][1].get_str(), claimId3.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSADDEDORUPDATED][2].get_str(), claimId4.GetHex());
BOOST_CHECK_EQUAL(result[T_CLAIMSREMOVED].size(), 0);
BOOST_CHECK_EQUAL(result[T_SUPPORTSADDEDORUPDATED].size(), 0);
BOOST_CHECK_EQUAL(result[T_SUPPORTSREMOVED].size(), 0);
}
BOOST_AUTO_TEST_CASE(claim_rpc_pending_amount_test)
{
ClaimTrieChainFixture fixture;
std::string sName1("test");
std::string sValue1("test1");
std::string sValue2("test2");
rpcfn_type getclaimsforname = tableRPC["getclaimsforname"]->actor;
JSONRPCRequest req;
req.params = UniValue(UniValue::VARR);
req.params.push_back(UniValue(sName1));
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue1, 1);
fixture.IncrementBlocks(1);
fixture.MakeClaim(fixture.GetCoinbase(), sName1, sValue2, 2);
fixture.IncrementBlocks(1);
auto claims = getclaimsforname(req)[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 0);
BOOST_CHECK(claims[1].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_PENDINGAMOUNT].get_int(), 2);
fixture.IncrementBlocks(1);
claims = getclaimsforname(req)[T_CLAIMS];
BOOST_CHECK_EQUAL(claims.size(), 2U);
BOOST_CHECK_EQUAL(claims[0][T_EFFECTIVEAMOUNT].get_int(), 2);
BOOST_CHECK(!claims[0].exists(T_PENDINGAMOUNT));
BOOST_CHECK_EQUAL(claims[1][T_EFFECTIVEAMOUNT].get_int(), 1);
BOOST_CHECK(!claims[1].exists(T_PENDINGAMOUNT));
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -28,7 +28,7 @@
"76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac", "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
{ {
"isPrivkey": false, "isPrivkey": false,
"chain": "regtest" "chain": "lbrycrdreg"
} }
], ],
[ [
@ -72,7 +72,7 @@
{ {
"isCompressed": false, "isCompressed": false,
"isPrivkey": true, "isPrivkey": true,
"chain": "regtest" "chain": "lbrycrdreg"
} }
], ],
[ [
@ -90,7 +90,7 @@
{ {
"isCompressed": true, "isCompressed": true,
"isPrivkey": true, "isPrivkey": true,
"chain": "regtest" "chain": "lbrycrdreg"
} }
], ],
[ [
@ -294,7 +294,7 @@
{ {
"isCompressed": false, "isCompressed": false,
"isPrivkey": true, "isPrivkey": true,
"chain": "regtest" "chain": "lbrycrdreg"
} }
], ],
[ [
@ -481,7 +481,7 @@
"001428e40f9a66993a8d50b2604af71b17e1606842d8", "001428e40f9a66993a8d50b2604af71b17e1606842d8",
{ {
"isPrivkey": false, "isPrivkey": false,
"chain": "regtest", "chain": "lbrycrdreg",
"tryCaseFlip": true "tryCaseFlip": true
} }
] ]

View file

@ -458,9 +458,6 @@
["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"], ["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP6 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP7 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP8 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP9 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP9 1", "P2SH,STRICTENC", "OK"],
["NOP", "NOP10 1", "P2SH,STRICTENC", "OK"], ["NOP", "NOP10 1", "P2SH,STRICTENC", "OK"],
@ -869,8 +866,8 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
["Ensure 100% coverage of discouraged NOPS"], ["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"], ["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
@ -1793,7 +1790,7 @@
"2-of-2 with two identical keys and sigs pushed using OP_DUP" "2-of-2 with two identical keys and sigs pushed using OP_DUP"
], ],
[ [
"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL",
"", "",
"OK", "OK",
@ -1807,14 +1804,14 @@
"P2PK with non-push scriptSig but with P2SH validation" "P2PK with non-push scriptSig but with P2SH validation"
], ],
[ [
"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL",
"P2SH", "P2SH",
"SIG_PUSHONLY", "SIG_PUSHONLY",
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"
], ],
[ [
"0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP9 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
"HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL", "HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL",
"SIGPUSHONLY", "SIGPUSHONLY",
"SIG_PUSHONLY", "SIG_PUSHONLY",

View file

@ -8,7 +8,6 @@ BOOST_FIXTURE_TEST_SUITE(nameclaim_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(calc_min_claimtrie_fee) BOOST_AUTO_TEST_CASE(calc_min_claimtrie_fee)
{ {
CMutableTransaction tx; CMutableTransaction tx;
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].scriptPubKey = ClaimNameScript("A","test"); tx.vout[0].scriptPubKey = ClaimNameScript("A","test");
@ -31,7 +30,18 @@ BOOST_AUTO_TEST_CASE(calc_min_claimtrie_fee)
CMutableTransaction tx4; CMutableTransaction tx4;
tx4.vout.resize(1); tx4.vout.resize(1);
BOOST_CHECK_EQUAL(CalcMinClaimTrieFee(tx4,MIN_FEE_PER_NAMECLAIM_CHAR), 0); BOOST_CHECK_EQUAL(CalcMinClaimTrieFee(tx4,MIN_FEE_PER_NAMECLAIM_CHAR), 0);
}
BOOST_AUTO_TEST_CASE(support_handles_value)
{
auto script = SupportClaimScript("s1", uint160(), "me value");
int op = 0;
std::vector<std::vector<unsigned char>> params;
BOOST_CHECK(!DecodeClaimScript(script, op, params, false));
params.clear();
BOOST_CHECK(DecodeClaimScript(script, op, params));
BOOST_CHECK(params[0][0] == 's');
BOOST_CHECK(std::string(params[2].begin(), params[2].end()) == "me value");
} }
BOOST_AUTO_TEST_CASE(scriptToAsmStr_output) BOOST_AUTO_TEST_CASE(scriptToAsmStr_output)

View file

@ -3,6 +3,7 @@
#include <random.h> #include <random.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <test/claimtriefixture.h>
#include <test/test_bitcoin.h> #include <test/test_bitcoin.h>
#include <chrono> #include <chrono>
@ -37,7 +38,79 @@ std::vector<std::string> random_strings(std::size_t count)
using namespace std; using namespace std;
BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, RegTestingSetup)
#ifndef MAC_OSX // can't find a random number generator that produces the same sequence on OSX
BOOST_AUTO_TEST_CASE(triehash_fuzzer_test)
{
ClaimTrieChainFixture fixture;
auto envClaims = std::getenv("TRIEHASH_FUZZER_CLAIMS");
auto envBlocks = std::getenv("TRIEHASH_FUZZER_BLOCKS");
const int claimsPerBlock = envClaims ? std::atoi(envClaims) : 100;
const int blocks = envBlocks ? std::atoi(envBlocks) : 13;
auto names = random_strings(blocks * claimsPerBlock);
FastRandomContext frc(true);
std::unordered_map<std::string, std::vector<CMutableTransaction>> existingClaims;
std::vector<CMutableTransaction> existingSupports;
std::string value(1024, 'c');
std::vector<CTransaction> cb {fixture.GetCoinbase()};
for (int i = 0; i < blocks; ++i) {
for (int j = 0; j < claimsPerBlock; ++j) {
auto name = names[i * claimsPerBlock + j];
auto supportFront = frc.randrange(4) == 0;
auto supportBack = frc.randrange(4) == 0;
auto removeClaim = frc.randrange(4) == 0;
auto removeSupport = frc.randrange(4) == 0;
auto hit = existingClaims.find(name);
if (supportFront && hit != existingClaims.end() && hit->second.size()) {
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
existingSupports.push_back(tx);
cb.emplace_back(std::move(tx));
}
if (removeClaim && hit != existingClaims.end() && hit->second.size()) {
auto idx = frc.rand64() % hit->second.size();
fixture.Spend(hit->second[idx]);
hit->second.erase(hit->second.begin() + idx);
} else {
auto tx = fixture.MakeClaim(cb.back(), name, value, 2);
existingClaims[name].push_back(tx);
hit = existingClaims.find(name);
cb.emplace_back(std::move(tx));
}
if (supportBack && hit != existingClaims.end() && hit->second.size()) {
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
existingSupports.push_back(tx);
cb.emplace_back(std::move(tx));
}
if (removeSupport && (i & 7) == 7 && !existingSupports.empty()) {
const auto tidx = frc.rand64() % existingSupports.size();
const auto tx = existingSupports[tidx];
fixture.Spend(tx);
existingSupports.erase(existingSupports.begin() + tidx);
}
if (cb.back().GetValueOut() < 10 || cb.size() > 40000) {
cb.clear();
cb.push_back(fixture.GetCoinbase());
}
}
fixture.IncrementBlocks(1);
if (blocks > 13 && i % 50 == 0) // travisCI needs some periodic output
std::cerr << "In triehash_fuzzer_test with " << fixture.getTotalNamesInTrie() << " names at block " << i << std::endl;
}
if (blocks == 1000 && claimsPerBlock == 100)
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "28825257a129eef69cab87d6255c8359fc6dc083ca7f09222526e3a7971f382d");
else if (blocks == 13 && claimsPerBlock == 100)
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "4e5984d6984f5f05d50e821e6228d56bcfbd16ca2093cd0308f6ff1c2bc8689a");
else
std::cerr << "Hash: " << fixture.getMerkleHash().GetHex() << std::endl;
}
#endif
BOOST_AUTO_TEST_CASE(insert_erase_test) BOOST_AUTO_TEST_CASE(insert_erase_test)
{ {

View file

@ -719,16 +719,16 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true
).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem()); ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem());
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with non-push scriptSig but with P2SH validation", 0 "P2PK with non-push scriptSig but with P2SH validation", 0
).PushSig(keys.key2).Add(CScript() << OP_NOP9)); ).PushSig(keys.key2).Add(CScript() << OP_NOP9));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true
).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); ).PushSig(keys.key2).Add(CScript() << OP_NOP9).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY));
tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).PushSig(keys.key1)); ).Num(0).PushSig(keys.key1).PushSig(keys.key1));

View file

@ -20,6 +20,8 @@
#include <script/sigcache.h> #include <script/sigcache.h>
#include "claimtrie.h" #include "claimtrie.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_parameters.hpp>
void CConnmanTest::AddNode(CNode& node) void CConnmanTest::AddNode(CNode& node)
{ {
@ -39,7 +41,6 @@ void CConnmanTest::ClearNodes()
uint256 insecure_rand_seed = GetRandHash(); uint256 insecure_rand_seed = GetRandHash();
FastRandomContext insecure_rand_ctx(insecure_rand_seed); FastRandomContext insecure_rand_ctx(insecure_rand_seed);
extern bool fPrintToConsole;
extern void noui_connect(); extern void noui_connect();
std::ostream& operator<<(std::ostream& os, const uint256& num) std::ostream& operator<<(std::ostream& os, const uint256& num)
@ -80,16 +81,24 @@ std::ostream& operator<<(std::ostream& os, const CClaimValue& claim)
std::ostream& operator<<(std::ostream& os, const CSupportValue& support) std::ostream& operator<<(std::ostream& os, const CSupportValue& support)
{ {
os << "support(" << support.outPoint.ToString() os << "support(" << support.outPoint.ToString()
<< ", " << support.supportedClaimId.ToString() << ", " << support.supportedClaimId.ToString()
<< ", " << support.nAmount << ", " << support.nAmount
<< ", " << support.nHeight << ", " << support.nHeight
<< ", " << support.nValidAtHeight << ')'; << ", " << support.nValidAtHeight << ')';
return os; return os;
} }
BasicTestingSetup::BasicTestingSetup(const std::string& chainName) BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
: m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30)))) : m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{ {
// for debugging:
if (boost::unit_test::runtime_config::get<boost::unit_test::log_level>(boost::unit_test::runtime_config::btrt_log_level)
<= boost::unit_test::log_level::log_messages) {
g_logger->m_print_to_console = true;
g_logger->m_log_time_micros = true;
g_logger->EnableCategory(BCLog::ALL);
}
SHA256AutoDetect(); SHA256AutoDetect();
RandomInit(); RandomInit();
ECC_Start(); ECC_Start();

View file

@ -44,7 +44,7 @@ struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle; ECCVerifyHandle globalVerifyHandle;
explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup(); virtual ~BasicTestingSetup();
fs::path SetDataDir(const std::string& name); fs::path SetDataDir(const std::string& name);
@ -70,7 +70,7 @@ struct TestingSetup: public BasicTestingSetup {
std::unique_ptr<PeerLogicValidation> peerLogic; std::unique_ptr<PeerLogicValidation> peerLogic;
explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN); explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup(); ~TestingSetup() override;
}; };
class CBlock; class CBlock;
@ -89,7 +89,7 @@ struct TestChain100Setup : public TestingSetup {
CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
const CScript& scriptPubKey); const CScript& scriptPubKey);
~TestChain100Setup(); ~TestChain100Setup() override;
std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
CKey coinbaseKey; // private/public key needed to spend coinbase transactions CKey coinbaseKey; // private/public key needed to spend coinbase transactions
@ -97,7 +97,7 @@ struct TestChain100Setup : public TestingSetup {
struct RegTestingSetup: public TestingSetup { struct RegTestingSetup: public TestingSetup {
RegTestingSetup(); RegTestingSetup();
~RegTestingSetup(); ~RegTestingSetup() override;
}; };
class CTxMemPoolEntry; class CTxMemPoolEntry;

View file

@ -701,7 +701,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// Check dust with default relay fee: // Check dust with default relay fee:
CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000; CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000;
BOOST_CHECK_EQUAL(nDustThreshold, 546); BOOST_CHECK_EQUAL(nDustThreshold, 182);
// dust: // dust:
t.vout[0].nValue = nDustThreshold - 1; t.vout[0].nValue = nDustThreshold - 1;
BOOST_CHECK(!IsStandardTx(t, reason)); BOOST_CHECK(!IsStandardTx(t, reason));

View file

@ -4,6 +4,7 @@
#include <util.h> #include <util.h>
#include <chainparamsbase.h>
#include <clientversion.h> #include <clientversion.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <sync.h> #include <sync.h>
@ -558,27 +559,27 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
std::string error; std::string error;
test_args.ParseParameters(0, (char**)argv_testnet, error); test_args.ParseParameters(0, (char**)argv_testnet, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrd"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::MAIN);
test_args.ParseParameters(2, (char**)argv_testnet, error); test_args.ParseParameters(2, (char**)argv_testnet, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(2, (char**)argv_regtest, error); test_args.ParseParameters(2, (char**)argv_regtest, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::REGTEST);
test_args.ParseParameters(3, (char**)argv_test_no_reg, error); test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(3, (char**)argv_both, error); test_args.ParseParameters(3, (char**)argv_both, error);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
test_args.ParseParameters(0, (char**)argv_testnet, error); test_args.ParseParameters(0, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(2, (char**)argv_testnet, error); test_args.ParseParameters(2, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(2, (char**)argv_regtest, error); test_args.ParseParameters(2, (char**)argv_regtest, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
@ -586,7 +587,7 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
test_args.ParseParameters(3, (char**)argv_test_no_reg, error); test_args.ParseParameters(3, (char**)argv_test_no_reg, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(3, (char**)argv_both, error); test_args.ParseParameters(3, (char**)argv_both, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
@ -598,11 +599,11 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
test_args.ParseParameters(0, (char**)argv_testnet, error); test_args.ParseParameters(0, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(2, (char**)argv_testnet, error); test_args.ParseParameters(2, (char**)argv_testnet, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(2, (char**)argv_regtest, error); test_args.ParseParameters(2, (char**)argv_regtest, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
@ -610,7 +611,7 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
test_args.ParseParameters(2, (char**)argv_test_no_reg, error); test_args.ParseParameters(2, (char**)argv_test_no_reg, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "lbrycrdtest"); BOOST_CHECK_EQUAL(test_args.GetChainName(), CBaseChainParams::TESTNET);
test_args.ParseParameters(3, (char**)argv_both, error); test_args.ParseParameters(3, (char**)argv_both, error);
test_args.ReadConfigString(testnetconf); test_args.ReadConfigString(testnetconf);

View file

@ -26,7 +26,7 @@ struct CDiskTxPos;
//! No need to periodic flush if at least this much space still available. //! No need to periodic flush if at least this much space still available.
static constexpr int MAX_BLOCK_COINSDB_USAGE = 10; static constexpr int MAX_BLOCK_COINSDB_USAGE = 10;
//! -dbcache default (MiB) //! -dbcache default (MiB)
static const int64_t nDefaultDbCache = sizeof(void*) > 4 ? 700 : 450; static const int64_t nDefaultDbCache = 560;
//! -dbbatchsize default (bytes) //! -dbbatchsize default (bytes)
static const int64_t nDefaultDbBatchSize = 16 << 20; static const int64_t nDefaultDbBatchSize = 16 << 20;
//! max. -dbcache (MiB) //! max. -dbcache (MiB)
@ -34,13 +34,13 @@ static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache (MiB) //! min. -dbcache (MiB)
static const int64_t nMinDbCache = 4; static const int64_t nMinDbCache = 4;
//! Max memory allocated to block tree DB specific cache, if no -txindex (MiB) //! Max memory allocated to block tree DB specific cache, if no -txindex (MiB)
static const int64_t nMaxBlockDBCache = 8; static const int64_t nMaxBlockDBCache = 16;
//! Max memory allocated to block tree DB specific cache, if -txindex (MiB) //! Max memory allocated to block tree DB specific cache, if -txindex (MiB)
// Unlike for the UTXO database, for the txindex scenario the leveldb cache make // Unlike for the UTXO database, for the txindex scenario the leveldb cache make
// a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991 // a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991
static const int64_t nMaxTxIndexCache = 1024; static const int64_t nMaxTxIndexCache = 1024;
//! Max memory allocated to coin DB specific cache (MiB) //! Max memory allocated to coin DB specific cache (MiB)
static const int64_t nMaxCoinsDBCache = 8; static const int64_t nMaxCoinsDBCache = 32;
/** CCoinsView backed by the coin database (chainstate/) */ /** CCoinsView backed by the coin database (chainstate/) */
class CCoinsViewDB final : public CCoinsView class CCoinsViewDB final : public CCoinsView

View file

@ -2,7 +2,7 @@
set -e set -e
srcdir="$(dirname $0)" srcdir="$(dirname $0)"
cd "$srcdir" cd "$srcdir"
if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="$(which glibtoolize 2>/dev/null)"; then
LIBTOOLIZE="${GLIBTOOLIZE}" LIBTOOLIZE="${GLIBTOOLIZE}"
export LIBTOOLIZE export LIBTOOLIZE
fi fi

View file

@ -1351,36 +1351,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
return true; return true;
} }
namespace { bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: OpenUndoFile failed", __func__);
// Write index header
unsigned int nSize = GetSerializeSize(fileout, blockundo);
fileout << messageStart << nSize;
// Write undo data
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("%s: ftell failed", __func__);
pos.nPos = (unsigned int)fileOutPos;
fileout << blockundo;
// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
return true;
}
static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
{ {
CDiskBlockPos pos = pindex->GetUndoPos(); CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull()) { if (pos.IsNull()) {
@ -1411,6 +1382,35 @@ static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
return true; return true;
} }
namespace {
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: OpenUndoFile failed", __func__);
// Write index header
unsigned int nSize = GetSerializeSize(fileout, blockundo);
fileout << messageStart << nSize;
// Write undo data
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("%s: ftell failed", __func__);
pos.nPos = (unsigned int)fileOutPos;
fileout << blockundo;
// calculate & write checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
return true;
}
/** Abort with a message */ /** Abort with a message */
static bool AbortNode(const std::string& strMessage, const std::string& userMessage="") static bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
{ {
@ -1546,7 +1546,6 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
} }
for (unsigned int j = tx.vin.size(); j-- > 0;) { for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout; const COutPoint &out = tx.vin[j].prevout;
/* int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), txundo, view, trieCache, out); */
int res = ApplyTxInUndo(j, txundo, view, trieCache, out); int res = ApplyTxInUndo(j, txundo, view, trieCache, out);
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
fClean = fClean && res != DISCONNECT_UNCLEAN; fClean = fClean && res != DISCONNECT_UNCLEAN;
@ -1563,25 +1562,12 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
assert(trieCache.finalizeDecrement(blockUndo.takeoverHeightUndo)); assert(trieCache.finalizeDecrement(blockUndo.takeoverHeightUndo));
auto merkleHash = trieCache.getMerkleHash(); auto merkleHash = trieCache.getMerkleHash();
if (merkleHash != pindex->pprev->hashClaimTrie) { if (merkleHash != pindex->pprev->hashClaimTrie) {
if (trieCache.checkConsistency()) { if (!trieCache.empty())
for (auto cit = trieCache.begin(); cit != trieCache.end(); ++cit) { trieCache.dumpToLog(trieCache.find({}));
if (cit->claims.size() && cit->nHeightOfLastTakeover <= 0)
LogPrintf("Invalid takeover height discovered in cache for %s\n", cit.key());
if (cit->hash.IsNull())
LogPrintf("Invalid hash discovered in cache for %s\n", cit.key());
}
}
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight); LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
assert(merkleHash == pindex->pprev->hashClaimTrie); assert(merkleHash == pindex->pprev->hashClaimTrie);
} }
if (pindex->nHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
{
LogPrintf("Decremented past the extended claim expiration hard fork height\n");
trieCache.setExpirationTime(Params().GetConsensus().GetExpirationTime(pindex->nHeight-1));
trieCache.forkForExpirationChange(false);
}
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
} }
@ -1908,7 +1894,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// post BIP34 before approximately height 486,000,000 and presumably will // post BIP34 before approximately height 486,000,000 and presumably will
// be reset before it reaches block 1,983,702 and starts doing unnecessary // be reset before it reaches block 1,983,702 and starts doing unnecessary
// BIP30 checking again. // BIP30 checking again.
/* assert(pindex->pprev); */
if (pindex->pprev) if (pindex->pprev)
{ {
CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
@ -1939,14 +1925,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// Get the script flags for this block // Get the script flags for this block
unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus()); unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus());
// v 13 LBRYcrd hard fork to extend expiration time
if (pindex->nHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
{
LogPrintf("Incremented past the extended claim expiration hard fork height\n");
trieCache.setExpirationTime(chainparams.GetConsensus().GetExpirationTime(pindex->nHeight));
trieCache.forkForExpirationChange(true);
}
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal); LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
@ -1954,6 +1932,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : nullptr); CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : nullptr);
trieCache.initializeIncrement();
std::vector<int> prevheights; std::vector<int> prevheights;
CAmount nFees = 0; CAmount nFees = 0;
int nInputs = 0; int nInputs = 0;
@ -2015,35 +1995,13 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
return error("ConnectBlock(): CheckInputs on %s failed with %s", return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state)); tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks); control.Add(vChecks);
CUpdateCacheCallbacks callbacks = {
// To handle claim updates, stick all claims found in the inputs into a map of .findScriptKey = {},
// name: (txhash, nOut). When running through the outputs, if any claim's .claimUndoHeights = [&mClaimUndoHeights](int index, int nValidAtHeight) {
// name is found in the map, send the name's txhash and nOut to the trie cache, mClaimUndoHeights.emplace(index, nValidAtHeight);
// and then remove the name: (txhash, nOut) mapping from the map. }
// If there are two or more claims in the inputs with the same name, only };
// use the first. UpdateCache(tx, trieCache, view, pindex->nHeight, callbacks);
spentClaimsType spentClaims;
for (unsigned int j = 0; j < tx.vin.size(); j++)
{
const CTxIn& txin = tx.vin[j];
const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.out.scriptPubKey.empty())
continue;
int nValidAtHeight;
if (SpendClaim(trieCache, coin.out.scriptPubKey, COutPoint(txin.prevout.hash, txin.prevout.n), coin.nHeight, nValidAtHeight, spentClaims))
mClaimUndoHeights[j] = nValidAtHeight;
}
for (unsigned int j = 0; j < tx.vout.size(); j++) {
const CTxOut& txout = tx.vout[j];
if (!txout.scriptPubKey.empty())
AddSpendClaim(trieCache, txout.scriptPubKey, COutPoint(tx.GetHash(), j), txout.nValue, pindex->nHeight, spentClaims);
}
} }
CTxUndo undoDummy; CTxUndo undoDummy;
@ -2082,8 +2040,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (trieCache.getMerkleHash() != block.hashClaimTrie) if (trieCache.getMerkleHash() != block.hashClaimTrie)
{ {
if (trieCache.checkConsistency()) if (!trieCache.empty()) // we could run checkConsistency here, but it would take a while
trieCache.dumpToLog(trieCache.begin()); trieCache.dumpToLog(trieCache.find({}));
return state.DoS(100, error("ConnectBlock() : the merkle root of the claim trie does not match " return state.DoS(100, error("ConnectBlock() : the merkle root of the claim trie does not match "
"(actual=%s vs block=%s on height=%d)", trieCache.getMerkleHash().GetHex(), "(actual=%s vs block=%s on height=%d)", trieCache.getMerkleHash().GetHex(),
block.hashClaimTrie.GetHex(), pindex->nHeight), REJECT_INVALID, "bad-claim-merkle-hash"); block.hashClaimTrie.GetHex(), pindex->nHeight), REJECT_INVALID, "bad-claim-merkle-hash");
@ -2226,7 +2184,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
// overwrite one. Still, use a conservative safety factor of 2. // overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(48 * 2 * 2 * pcoinsTip->GetCacheSize())) if (!CheckDiskSpace(48 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error("out of disk space"); return state.Error("out of disk space");
if (!pclaimTrie->SyncToDisk()) if (mode == FlushStateMode::ALWAYS && !pclaimTrie->SyncToDisk())
return state.Error("Failed to write to claim trie database"); return state.Error("Failed to write to claim trie database");
// Flush the chainstate (which may refer to block index entries). // Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush()) if (!pcoinsTip->Flush())
@ -2238,6 +2196,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
if (full_flush_completed) { if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets). // Update best block in wallet (so we can detect restored wallets).
GetMainSignals().ChainStateFlushed(chainActive.GetLocator()); GetMainSignals().ChainStateFlushed(chainActive.GetLocator());
LogPrint(BCLog::BENCH, "Finished full disk flush in %.2fms\n", (GetTimeMicros() - nLastFlush) * MILLI);
} }
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error while flushing: ") + e.what()); return AbortNode(state, std::string("System error while flushing: ") + e.what());
@ -2291,7 +2250,8 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
} }
std::string warningMessages; std::string warningMessages;
if (!IsInitialBlockDownload()) auto isInitialBlockDownload = IsInitialBlockDownload();
if (!isInitialBlockDownload)
{ {
int nUpgraded = 0; int nUpgraded = 0;
const CBlockIndex* pindex = pindexNew; const CBlockIndex* pindex = pindexNew;
@ -2324,15 +2284,21 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
DoWarning(strWarning); DoWarning(strWarning);
} }
} }
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__, /* Continued */ static int64_t lastBlockPrintTime = 0;
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, auto currentTime = GetAdjustedTime();
log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, if (!warningMessages.empty() || !isInitialBlockDownload || lastBlockPrintTime < currentTime - 15 || LogAcceptCategory(BCLog::CLAIMS)) {
FormatISO8601DateTime(pindexNew->GetBlockTime()), lastBlockPrintTime = currentTime;
GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g txb=%lu tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s",
if (!warningMessages.empty()) __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
LogPrintf(" warning='%s'", warningMessages); /* Continued */ log(pindexNew->nChainWork.getdouble()) / log(2.0), (unsigned long) pindexNew->nTx,
LogPrintf("\n"); (unsigned long) pindexNew->nChainTx, FormatISO8601DateTime(pindexNew->GetBlockTime()),
GuessVerificationProgress(chainParams.TxData(), pindexNew),
pcoinsTip->DynamicMemoryUsage() * (1.0 / (1U << 20U)), pcoinsTip->GetCacheSize(),
isInitialBlockDownload ? " IBD" : "");
if (!warningMessages.empty())
LogPrintf(" warning='%s'", warningMessages); /* Continued */
LogPrintf("\n");
}
} }
/** Disconnect chainActive's tip. /** Disconnect chainActive's tip.
@ -2806,14 +2772,18 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
if (ShutdownRequested()) if (ShutdownRequested())
break; break;
} while (pindexNewTip != pindexMostWork); } while (pindexNewTip != pindexMostWork);
CheckBlockIndex(chainparams.GetConsensus());
// Write changes periodically to disk, after relay. auto& consensus = chainparams.GetConsensus();
if (!FlushStateToDisk(chainparams, state, FlushStateMode::PERIODIC)) { CheckBlockIndex(consensus);
return false;
auto flushMode = FlushStateMode::PERIODIC;
if (pindexNewTip && chainparams.NetworkIDString() != CBaseChainParams::REGTEST
&& pindexNewTip->nTime + consensus.nPowTargetSpacing > GetAdjustedTime()) {
// trying to ensure that we flush to disk after new blocks when we're caught up to the chain
// they're technically allowed to be two hours late, but experience says one minute is more likely
flushMode = FlushStateMode::ALWAYS;
} }
return FlushStateToDisk(chainparams, state, flushMode);
return true;
} }
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) { bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
@ -3083,7 +3053,7 @@ static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int
if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos, true)) { if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos, true)) {
FILE *file = OpenBlockFile(pos); FILE *file = OpenBlockFile(pos);
if (file) { if (file) {
LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); LogPrint(BCLog::BENCH, "Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);
fclose(file); fclose(file);
} }
@ -3116,7 +3086,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos,
if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos, true)) { if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos, true)) {
FILE *file = OpenUndoFile(pos); FILE *file = OpenUndoFile(pos);
if (file) { if (file) {
LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); LogPrint(BCLog::BENCH, "Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);
fclose(file); fclose(file);
} }

View file

@ -57,7 +57,7 @@ static const bool DEFAULT_WHITELISTFORCERELAY = true;
/** Default for -minrelaytxfee, minimum relay fee for transactions */ /** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
//! -maxtxfee default //! -maxtxfee default
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.5 * COIN;
//! Discourage users to set fees higher than this amount (in satoshis) per kB //! Discourage users to set fees higher than this amount (in satoshis) per kB
static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN; static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) //! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
@ -200,7 +200,7 @@ static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */ /** Minimum blocks required to signal NODE_NETWORK_LIMITED */
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 288 * 3; // 36 hours static const signed int DEFAULT_CHECKBLOCKS = 144; // 6 hours
static const unsigned int DEFAULT_CHECKLEVEL = 3; static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) // Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)

View file

@ -203,6 +203,12 @@ public:
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache) ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
{ {
// Check if we've past a hardfork state for segwit.
if (pos == Consensus::DEPLOYMENT_SEGWIT) {
return pindexPrev != nullptr && pindexPrev->nHeight + 1 >= params.nWitnessForkHeight ?
ThresholdState::ACTIVE : ThresholdState::FAILED;
}
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]); return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
} }

Some files were not shown because too many files have changed in this diff Show more