From 5cb8025dddef2ecdb6cce0da8beaa0a63c7cb35d Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Mon, 1 Apr 2019 11:47:48 +0100 Subject: [PATCH] [1.1.0] Merge master into 1.1.0 (#2720) * cleanup legacy "3 dot" check (#2625) * Allow to peers behind NAT to get up to preferred_max connections (#2543) Allow to peers behind NAT to get up to preffered_max connections If peer has only outbound connections it's mot likely behind NAT and we should not stop it from getting more outbound connections * Reduce usage of unwrap in p2p crate (#2627) Also change store crate a bit * Simplify (and fix) output_pos cleanup during chain compaction (#2609) * expose leaf pos iterator use it for various things in txhashset when iterating over outputs * fix * cleanup * rebuild output_pos index (and clear it out first) when compacting the chain * fixup tests * refactor to match on (output, proof) tuple * add comments to compact() to explain what is going on. * get rid of some boxing around the leaf_set iterator * cleanup * [docs] Add switch commitment documentation (#2526) * remove references to no-longer existing switch commitment hash (as switch commitments were removed in ca8447f3bd49e80578770da841e5fbbac2c23cde and moved into the blinding factor of the Pedersen Commitment) * some rewording (points vs curves) and fix of small formatting issues * Add switch commitment documentation * [docs] Documents in grin repo had translated in Korean. (#2604) * Start to M/W intro translate in Korean * translate in Korean * add korean translation on intro * table_of_content.md translate in Korean. * table_of_content_KR.md finish translate in Korean, start to translate State_KR.md * add state_KR.md & commit some translation in State_KR.md * WIP stat_KR.md translation * add build_KR.md && stratum_KR.md * finish translate stratum_KR.md & table_of_content_KR.md * rename intro.KR.md to intro_KR.md * add intro_KR.md file path each language's intro.md * add Korean translation file path to stratum.md & table_of_contents.md * fix difference with grin/master * Fix TxHashSet file filter for Windows. (#2641) * Fix TxHashSet file filter for Windows. * rustfmt * Updating regexp * Adding in test case * Display the current download rate rather than the average when syncing the chain (#2633) * When syncing the chain, calculate the displayed download speed using the current rate from the most recent iteration, rather than the average download speed from the entire syncing process. * Replace the explicitly ignored variables in the pattern with an implicit ignore * remove root = true from editorconfig (#2655) * Add Medium post to intro (#2654) Spoke to @yeastplume who agreed it makes sense to add the "Grin Transactions Explained, Step-by-Step" Medium post to intro.md Open for suggestions on a better location. * add a new configure item for log_max_files (#2601) * add a new configure item for log_max_files * rustfmt * use a constant instead of multiple 32 * rustfmt * Fix the build warning of deprecated trim_right_matches (#2662) * [DOC] state.md, build.md and chain directory documents translate in Korean. (#2649) * add md files for translation. * start to translation fast-sync, code_structure. add file build_KR.md, states_KR.md * add dandelion_KR.md && simulation_KR.md for Korean translation. * add md files for translation. * start to translation fast-sync, code_structure. add file build_KR.md, states_KR.md * add dandelion_KR.md && simulation_KR.md for Korean translation. * remove some useless md files for translation. this is rearrange set up translation order. * add dot end of sentence & translate build.md in korean * remove fast-sync_KR.md * finish build_KR.md translation * finish build_KR.md translation * finish translation state_KR.md & add phrase in state.md to move other language md file * translate blocks_and_headers.md && chain_sync.md in Korean * add . in chain_sync.md , translation finished in doc/chain dir. * fix some miss typos * Api documentation fixes (#2646) * Fix the API documentation for Chain Validate (v1/chain/validate). It was documented as a POST, but it is actually a GET request, which can be seen in its handler ChainValidationHandler * Update the API V1 route list response to include the headers and merkleproof routes. Also clarify that for the chain/outputs route you must specify either byids or byheight to select outputs. * refactor(ci): reorganize CI related code (#2658) Break-down the CI related code into smaller more maintainable pieces. * Specify grin or nanogrins in API docs where applicable (#2642) * Set Content-Type in API client (#2680) * Reduce number of unwraps in chain crate (#2679) * fix: the restart of state sync doesn't work sometimes (#2687) * let check_txhashset_needed return true on abnormal case (#2684) * Reduce number of unwwaps in api crate (#2681) * Reduce number of unwwaps in api crate * Format use section * Small QoL improvements for wallet developers (#2651) * Small changes for wallet devs * Move create_nonce into Keychain trait * Replace match by map_err * Add flag to Slate to skip fee check * Fix secp dependency * Remove check_fee flag in Slate * Add Japanese edition of build.md (#2697) * catch the panic to avoid peer thread quit early (#2686) * catch the panic to avoid peer thread quit before taking the chance to ban * move catch wrapper logic down into the util crate * log the panic info * keep txhashset.rs untouched * remove a warning * [DOC] dandelion.md, simulation.md ,fast-sync.md and pruning.md documents translate in Korean. (#2678) * Show response code in API client error message (#2683) It's hard to investigate what happens when an API client error is printed out * Add some better logging for get_outputs_by_id failure states (#2705) * Switch commitment doc fixes (#2645) Fix some typos and remove the use of parentheses in a couple of places to make the reading flow a bit better. * docs: update/add new README.md badges (#2708) Replace existing badges with SVG counterparts and add a bunch of new ones. * Update intro.md (#2702) Add mention of censoring attack prevented by range proofs * use sandbox folder for txhashset validation on state sync (#2685) * use sandbox folder for txhashset validation on state sync * rustfmt * use temp directory as the sandbox instead actual db_root txhashset dir * rustfmt * move txhashset overwrite to the end of full validation * fix travis-ci test * rustfmt * fix: hashset have 2 folders including txhashset and header * rustfmt * (1)switch to rebuild_header_mmr instead of copy the sandbox header mmr (2)lock txhashset when overwriting and opening and rebuild * minor improve on sandbox_dir * add Japanese edition of state.md (#2703) * Attempt to fix broken TUI locale (#2713) Can confirm that on the same machine 1.0.2 TUI looks great and is broken on the current master. Bump of `cursive` version fixed it for me. Fixes #2676 * clean the header folder in sandbox (#2716) * forgot to clean the header folder in sandbox in #2685 * Reduce number of unwraps in servers crate (#2707) It doesn't include stratum server which is sufficiently changed in 1.1 branch and adapters, which is big enough for a separate PR. * rustfmt * change version to beta --- .auto-release.sh | 81 -- .ci/general-jobs | 28 + .ci/release-jobs | 122 +++ .editorconfig | 3 - .travis.yml | 82 +- Cargo.lock | 772 ++++++++---------- Cargo.toml | 22 +- README.md | 11 +- api/Cargo.toml | 14 +- api/src/auth.rs | 25 +- api/src/client.rs | 19 +- api/src/handlers.rs | 43 +- api/src/handlers/blocks_api.rs | 23 +- api/src/handlers/chain_api.rs | 27 +- api/src/handlers/peers_api.rs | 12 +- api/src/handlers/pool_api.rs | 10 +- api/src/handlers/server_api.rs | 4 +- api/src/handlers/transactions_api.rs | 47 +- api/src/handlers/utils.rs | 13 +- api/src/lib.rs | 2 +- api/src/rest.rs | 8 +- api/src/types.rs | 59 +- api/src/web.rs | 9 + api/tests/rest.rs | 7 +- chain/Cargo.toml | 10 +- chain/src/chain.rs | 178 ++-- chain/src/error.rs | 8 +- chain/src/pipe.rs | 26 +- chain/src/store.rs | 46 +- chain/src/txhashset/txhashset.rs | 275 ++++--- chain/tests/data_file_integrity.rs | 2 +- chain/tests/mine_simple_chain.rs | 6 +- chain/tests/test_coinbase_maturity.rs | 8 +- chain/tests/test_txhashset.rs | 27 +- config/Cargo.toml | 10 +- config/src/comments.rs | 8 + core/Cargo.toml | 6 +- core/src/core.rs | 4 +- core/src/core/pmmr/backend.rs | 3 + core/src/core/pmmr/pmmr.rs | 5 + core/src/core/transaction.rs | 5 +- core/src/libtx/build.rs | 3 +- core/src/libtx/proof.rs | 25 +- core/tests/vec_backend.rs | 4 + doc/api/node_api.md | 8 +- doc/api/wallet_owner_api.md | 4 +- doc/build.md | 4 +- doc/build_JP.md | 129 +++ doc/build_KR.md | 131 +++ doc/chain/blocks_and_headers.md | 2 + doc/chain/blocks_and_headers_KR.md | 38 + doc/chain/chain_sync.md | 4 +- doc/chain/chain_sync_KR.md | 79 ++ doc/coinbase_maturity.md | 4 +- doc/dandelion/dandelion.md | 1 + doc/dandelion/dandelion_KR.md | 89 ++ doc/dandelion/simulation.md | 2 + doc/dandelion/simulation_KR.md | 73 ++ doc/fast-sync.md | 2 +- doc/fast-sync_KR.md | 16 + doc/intro.md | 59 +- doc/intro_DE.md | 2 +- doc/intro_ES.md | 2 +- doc/intro_JP.md | 2 +- doc/intro_KR.md | 318 ++++++++ doc/intro_NL.md | 2 +- doc/intro_PT-BR.md | 2 +- doc/intro_RU.md | 2 +- doc/intro_SE.md | 2 +- doc/intro_ZH-CN.md | 2 +- doc/pruning.md | 5 +- doc/pruning_KR.md | 62 ++ doc/release_instruction.md | 6 +- doc/state.md | 2 + doc/state_JP.md | 48 ++ doc/state_KR.md | 46 ++ doc/stratum.md | 2 + doc/stratum_KR.md | 536 ++++++++++++ doc/switch_commitment.md | 292 +++++++ ...e_of_contents.md => table_of_contents_.md} | 2 + doc/table_of_contents_KR.md | 35 + keychain/Cargo.toml | 4 +- keychain/src/keychain.rs | 9 + keychain/src/types.rs | 1 + p2p/Cargo.toml | 10 +- p2p/src/conn.rs | 13 +- p2p/src/msg.rs | 38 +- p2p/src/peer.rs | 105 +-- p2p/src/peers.rs | 41 +- p2p/src/protocol.rs | 19 +- p2p/src/store.rs | 30 +- p2p/src/types.rs | 1 + pool/Cargo.toml | 12 +- servers/Cargo.toml | 18 +- servers/src/common/adapters.rs | 23 +- servers/src/common/types.rs | 26 +- servers/src/grin/dandelion_monitor.rs | 1 - servers/src/grin/seed.rs | 6 +- servers/src/grin/server.rs | 27 +- servers/src/grin/sync/body_sync.rs | 58 +- servers/src/grin/sync/header_sync.rs | 18 +- servers/src/grin/sync/state_sync.rs | 25 +- servers/src/grin/sync/syncer.rs | 70 +- servers/src/mining/mine_block.rs | 4 +- src/bin/tui/status.rs | 7 +- store/Cargo.toml | 6 +- store/src/leaf_set.rs | 5 + store/src/lmdb.rs | 32 +- store/src/pmmr.rs | 35 +- store/src/types.rs | 21 +- store/tests/pmmr.rs | 49 +- util/Cargo.toml | 2 +- util/src/logger.rs | 7 +- util/src/types.rs | 6 + util/src/zip.rs | 111 ++- 115 files changed, 3590 insertions(+), 1367 deletions(-) delete mode 100755 .auto-release.sh create mode 100755 .ci/general-jobs create mode 100755 .ci/release-jobs create mode 100644 doc/build_JP.md create mode 100644 doc/build_KR.md create mode 100644 doc/chain/blocks_and_headers_KR.md create mode 100644 doc/chain/chain_sync_KR.md create mode 100644 doc/dandelion/dandelion_KR.md create mode 100644 doc/dandelion/simulation_KR.md create mode 100644 doc/fast-sync_KR.md create mode 100644 doc/intro_KR.md create mode 100644 doc/pruning_KR.md create mode 100644 doc/state_JP.md create mode 100644 doc/state_KR.md create mode 100644 doc/stratum_KR.md create mode 100644 doc/switch_commitment.md rename doc/{table_of_contents.md => table_of_contents_.md} (96%) create mode 100644 doc/table_of_contents_KR.md diff --git a/.auto-release.sh b/.auto-release.sh deleted file mode 100755 index d75a297ca3..0000000000 --- a/.auto-release.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -repo_slug="mimblewimble/grin" -token="$GITHUB_TOKEN" -export CHANGELOG_GITHUB_TOKEN="$token" - -tagname=`git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD` - -echo 'package the release binary...\n' - -if [[ $TRAVIS_OS_NAME == 'osx' ]]; then - - # Do some custom requirements on OS X - cd target/release ; rm -f *.tgz; tar zcf "grin-$tagname-$TRAVIS_JOB_ID-osx.tgz" grin - /bin/ls -ls *.tgz | awk '{print $6,$7,$8,$9,$10}' - md5 "grin-$tagname-$TRAVIS_JOB_ID-osx.tgz" > "grin-$tagname-$TRAVIS_JOB_ID-osx.tgz"-md5sum.txt - /bin/ls -ls *-md5sum.txt | awk '{print $6,$7,$8,$9,$10}' - cd - > /dev/null; - echo "osx tarball generated\n" - - # Only generate changelog on Linux platform, to avoid duplication - exit 0 -elif [[ $TRAVIS_OS_NAME == 'windows' ]]; then - - # Custom requirements on windows - cd target/release ; rm -f *.zip ; 7z a -tzip "grin-$tagname-$TRAVIS_JOB_ID-win-x64.zip" grin.exe - /bin/ls -ls *.zip | awk '{print $6,$7,$8,$9,$10}' - md5sum "grin-$tagname-$TRAVIS_JOB_ID-win-x64.zip" > "grin-$tagname-$TRAVIS_JOB_ID-win-x64.zip"-md5sum.txt - /bin/ls -ls *-md5sum.txt | awk '{print $6,$7,$8,$9,$10}' - cd - > /dev/null; - echo "win x64 zip file generated\n" - - # Only generate changelog on Linux platform, to avoid duplication - exit 0 -else - # Do some custom requirements on Linux - cd target/release ; rm -f *.tgz; tar zcf "grin-$tagname-$TRAVIS_JOB_ID-linux-amd64.tgz" grin - /bin/ls -ls *.tgz | awk '{print $6,$7,$8,$9,$10}' - md5sum "grin-$tagname-$TRAVIS_JOB_ID-linux-amd64.tgz" > "grin-$tagname-$TRAVIS_JOB_ID-linux-amd64.tgz"-md5sum.txt - /bin/ls -ls *-md5sum.txt | awk '{print $6,$7,$8,$9,$10}' - cd - > /dev/null; - echo "linux tarball generated\n" -fi - -version="$tagname" -branch="`git symbolic-ref -q --short HEAD`" - -# automatic changelog generator -gem install github_changelog_generator - -LAST_REVISION=$(git rev-list --tags --skip=1 --max-count=1) -LAST_RELEASE_TAG=$(git describe --abbrev=0 --tags ${LAST_REVISION}) - -# Generate CHANGELOG.md -github_changelog_generator \ - -u $(cut -d "/" -f1 <<< $repo_slug) \ - -p $(cut -d "/" -f2 <<< $repo_slug) \ - --since-tag ${LAST_RELEASE_TAG} - -body="$(cat CHANGELOG.md)" - -# Overwrite CHANGELOG.md with JSON data for GitHub API -jq -n \ - --arg body "$body" \ - --arg name "$version" \ - --arg tag_name "$version" \ - --arg target_commitish "$branch" \ - '{ - body: $body, - name: $name, - tag_name: $tag_name, - target_commitish: $target_commitish, - draft: false, - prerelease: false - }' > CHANGELOG.md - -release_id="$(curl -0 -XGET -H "Authorization: token $token" https://api.github.com/repos/$repo_slug/releases/tags/$tagname 2>/dev/null | grep id | head -n 1 | sed 's/ *"id": *\(.*\),/\1/')" -echo "Updating release $version for repo: $repo_slug, branch: $branch. release id: $release_id" -curl -H "Authorization: token $token" --request PATCH --data @CHANGELOG.md "https://api.github.com/repos/$repo_slug/releases/$release_id" -echo "auto changelog uploaded.\n" - diff --git a/.ci/general-jobs b/.ci/general-jobs new file mode 100755 index 0000000000..e9612d1c83 --- /dev/null +++ b/.ci/general-jobs @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Copyright 2019 The Grin Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script contains general jobs. + +case "${CI_JOB}" in + "test") + for dir in ${CI_JOB_ARGS}; do + printf "executing tests in directory \`%s\`...\n" "${dir}" + cd "${dir}" && \ + cargo test --release && \ + cd - > /dev/null || exit 1 + done + ;; +esac diff --git a/.ci/release-jobs b/.ci/release-jobs new file mode 100755 index 0000000000..8c899716e8 --- /dev/null +++ b/.ci/release-jobs @@ -0,0 +1,122 @@ +#!/usr/bin/env bash + +# Copyright 2019 The Grin Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script contains release-related jobs. + +# Redeclare CI and VCP specific environment variables +# to make future migration to other providers easier. +readonly JOB_ID="${TRAVIS_JOB_ID}" +readonly OS_NAME="${TRAVIS_OS_NAME}" +readonly TEST_RESULT="${TRAVIS_TEST_RESULT}" +readonly VCP_AUTH_TOKEN="${GITHUB_TOKEN}" + +case "${CI_JOB}" in + "release") + # The release can only be triggered after successful completion of all tests. + [[ "${TEST_RESULT}" != 0 ]] && exit 1 + + readonly REPO_TAG="$(git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD)" + + case "${OS_NAME}" in + "linux") + cargo clean && \ + cargo build --release + readonly ARCHIVE_CMD="tar zcf" + readonly BIN_SUFFIX="" + readonly PKG_NAME="grin-${REPO_TAG}-${JOB_ID}-linux-amd64" + readonly PKG_SUFFIX=".tgz" + ;; + + "osx") + brew update + cargo clean && \ + cargo build --release + readonly ARCHIVE_CMD="tar zcf" + readonly BIN_SUFFIX="" + readonly PKG_NAME="grin-${REPO_TAG}-${JOB_ID}-osx" + readonly PKG_SUFFIX=".tgz" + ;; + + "windows") + cargo clean && \ + cargo build --release + readonly ARCHIVE_CMD="7z a -tzip" + readonly BIN_SUFFIX=".exe" + readonly PKG_NAME="grin-${REPO_TAG}-${JOB_ID}-win-x64" + readonly PKG_SUFFIX=".zip" + ;; + + *) + printf "Error! Unknown \$OS_NAME: \`%s\`" "${OS_NAME}" + exit 1 + esac + + printf "creating package \`%s\` for the release binary...\n" "${PKG_NAME}${PKG_SUFFIX}" + + cd ./target/release/ || exit 1 + rm -f -- *"${PKG_SUFFIX}" + ${ARCHIVE_CMD} "${PKG_NAME}${PKG_SUFFIX}" "grin${BIN_SUFFIX}" + ls -ls -- *.tgz | cut -d' ' -f6- + openssl md5 "${PKG_NAME}${PKG_SUFFIX}" > "${PKG_NAME}${PKG_SUFFIX}-md5sum.txt" + ls -ls -- *-md5sum.txt | cut -d' ' -f6- + cd - > /dev/null || exit 1 + + printf "%s package \`%s\` generated\n" "${OS_NAME}" "${PKG_NAME}${PKG_SUFFIX}" + + # Generate changelog only on the Linux platform to avoid duplication. + [[ "${OS_NAME}" != "linux" ]] && exit 0 + + # Generate CHANGELOG.md + readonly REPO_SLUG="mimblewimble/grin" + readonly REPO_BRANCH="$(git symbolic-ref -q --short HEAD)" + readonly REPO_PREV_RELEASE_TAG="$(git describe --abbrev=0 --tags "$(git rev-list --tags --skip=0 --max-count=1)")" + + gem install github_changelog_generator + + # Needed by github_changelog_generator. + export CHANGELOG_GITHUB_TOKEN="${VCP_AUTH_TOKEN}" + + github_changelog_generator \ + --user "$(cut -d "/" -f1 <<< ${REPO_SLUG})" \ + --project "$(cut -d "/" -f2 <<< ${REPO_SLUG})" \ + --since-tag "${REPO_PREV_RELEASE_TAG}" + + readonly CHANGELOG_CONTENT="$( CHANGELOG.md + + readonly HEADERS="Authorization: token ${VCP_AUTH_TOKEN}" + readonly RELEASE_URL="https://api.github.com/repos/${REPO_SLUG}/releases" + readonly RELEASE_ID="$(curl -0 --request GET -H "${HEADERS}" "${RELEASE_URL}/tags/${REPO_TAG}" 2> /dev/null | grep id | head -n 1 | sed 's/ *"id": *\(.*\),/\1/')" + + printf "updating release changelog %s for repo: %s, branch: %s, release id: %s\n" "${REPO_TAG}" "${REPO_SLUG}" "${REPO_BRANCH}" "${RELEASE_ID}" + curl -H "${HEADERS}" --request PATCH --data @CHANGELOG.md "${RELEASE_URL}/${RELEASE_ID}" + printf "changelog uploaded.\n" + ;; +esac \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 65356d3a4a..da2cf4f86b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,3 @@ -# top-most .editorconfig file -root = true - # use hard tabs for rust source files [*.rs] indent_style = tab diff --git a/.travis.yml b/.travis.yml index 99e66efb5a..911de6a5af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,28 @@ -language: rust - -git: - depth: false +# Copyright 2019 The Grin Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. dist: trusty sudo: required -cache: - cargo: true - timeout: 240 - directories: - - $HOME/.cargo - - $TRAVIS_BUILD_DIR/target - -before_cache: - - rm -rf $TRAVIS_BUILD_DIR/target/tmp +language: rust rust: - stable +git: + depth: false + addons: apt: sources: @@ -33,6 +37,13 @@ addons: - gcc - binutils-dev +cache: + cargo: true + timeout: 240 + directories: + - $HOME/.cargo + - $TRAVIS_BUILD_DIR/target + env: global: - RUST_BACKTRACE="1" @@ -41,46 +52,29 @@ env: matrix: include: - os: linux - env: TEST_SUITE=servers + env: CI_JOB="test" CI_JOB_ARGS="servers" + - os: linux + env: CI_JOB="test" CI_JOB_ARGS="chain core" - os: linux - env: TEST_SUITE=chain-core + env: CI_JOB="test" CI_JOB_ARGS="pool p2p src" - os: linux - env: TEST_SUITE=pool-p2p-src + env: CI_JOB="test" CI_JOB_ARGS="keychain" - os: linux - env: TEST_SUITE=keychain + env: CI_JOB="test" CI_JOB_ARGS="api util store" - os: linux - env: TEST_SUITE=api-util-store + env: CI_JOB="release" CI_JOB_ARGS= - os: osx - env: TEST_SUITE=release + env: CI_JOB="release" CI_JOB_ARGS= # - os: windows -# env: TEST_SUITE=release +# env: CI_JOB="release" CI_JOB_ARGS= -script: - - IFS='-' read -r -a DIRS <<< "$TEST_SUITE"; DIR=${DIRS[0]}; - echo "start testing on folder $DIR..."; - if [[ -n "$DIR" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cd $DIR && cargo test --release && cd - > /dev/null; fi; - - IFS='-' read -r -a DIRS <<< "$TEST_SUITE"; DIR=${DIRS[1]}; - if [[ -n "$DIR" ]]; then - echo "start testing on folder $DIR..."; - cd $DIR && cargo test --release && cd - > /dev/null; - fi; - - IFS='-' read -r -a DIRS <<< "$TEST_SUITE"; DIR=${DIRS[2]}; - if [[ -n "$DIR" ]]; then - echo "start testing on folder $DIR..."; - cd $DIR && cargo test --release && cd - > /dev/null; - fi; +script: .ci/general-jobs + +before_cache: + - rm -rf $TRAVIS_BUILD_DIR/target/tmp before_deploy: - - if [[ "$TEST_SUITE" == "pool-p2p-src" ]]; then - cargo clean && cargo build --release && ./.auto-release.sh; - fi - - if [[ "$TEST_SUITE" == "release" ]] && [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update; - cargo clean && cargo build --release && ./.auto-release.sh; - fi - - if [[ "$TEST_SUITE" == "release" ]] && [[ "$TRAVIS_OS_NAME" == "windows" ]]; then - cargo clean && cargo build --release && ./.auto-release.sh; - fi + - bash .ci/release-jobs deploy: provider: releases diff --git a/Cargo.lock b/Cargo.lock index a3a89f370b..fe45c2a230 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "aho-corasick" -version = "0.6.10" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -26,7 +26,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arc-swap" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -70,7 +70,7 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -87,8 +87,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -98,8 +98,8 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -117,16 +117,16 @@ version = "0.37.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -186,7 +186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -195,7 +195,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -208,7 +208,7 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -218,7 +218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -228,7 +228,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -270,10 +270,10 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -282,7 +282,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "croaring-sys 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -291,8 +291,8 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -300,33 +300,6 @@ name = "crossbeam" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "crossbeam" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-channel" version = "0.3.8" @@ -338,7 +311,7 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -347,42 +320,32 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-epoch" -version = "0.7.1" +name = "crossbeam-queue" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -411,28 +374,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cursive" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "enum-map 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "enumset 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cursive" version = "0.10.0" @@ -440,14 +381,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "enum-map 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "enumset 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "enumset 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -470,11 +412,11 @@ dependencies = [ [[package]] name = "dirs" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -518,21 +460,21 @@ dependencies = [ [[package]] name = "enumset" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "enumset_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "enumset_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "enumset_derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -543,7 +485,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -563,7 +505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -577,18 +519,18 @@ name = "filetime" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "flate2" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -603,7 +545,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -659,7 +601,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -672,7 +614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "grin" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "built 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -680,51 +622,50 @@ dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cursive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cursive 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_api 1.1.0", - "grin_chain 1.1.0", - "grin_config 1.1.0", - "grin_core 1.1.0", - "grin_keychain 1.1.0", - "grin_p2p 1.1.0", - "grin_servers 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", + "grin_api 1.1.0-beta.1", + "grin_chain 1.1.0-beta.1", + "grin_config 1.1.0-beta.1", + "grin_core 1.1.0-beta.1", + "grin_keychain 1.1.0-beta.1", + "grin_p2p 1.1.0-beta.1", + "grin_servers 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_api" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_chain 1.1.0", - "grin_core 1.1.0", - "grin_p2p 1.1.0", - "grin_pool 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", + "grin_chain 1.1.0-beta.1", + "grin_core 1.1.0-beta.1", + "grin_p2p 1.1.0-beta.1", + "grin_pool 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -733,7 +674,7 @@ dependencies = [ [[package]] name = "grin_chain" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -742,38 +683,38 @@ dependencies = [ "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_core 1.1.0", - "grin_keychain 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "grin_core 1.1.0-beta.1", + "grin_keychain 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_config" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ - "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_core 1.1.0", - "grin_p2p 1.1.0", - "grin_servers 1.1.0", - "grin_util 1.1.0", + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "grin_core 1.1.0-beta.1", + "grin_p2p 1.1.0-beta.1", + "grin_servers 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_core" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -782,79 +723,79 @@ dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_keychain 1.1.0", - "grin_util 1.1.0", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "grin_keychain 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_keychain" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_util 1.1.0", + "grin_util 1.1.0-beta.1", "hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "ripemd160 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_p2p" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_core 1.1.0", - "grin_pool 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", + "grin_core 1.1.0-beta.1", + "grin_pool 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_pool" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_chain 1.1.0", - "grin_core 1.1.0", - "grin_keychain 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", + "grin_chain 1.1.0-beta.1", + "grin_core 1.1.0-beta.1", + "grin_keychain 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -864,44 +805,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_servers" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_api 1.1.0", - "grin_chain 1.1.0", - "grin_core 1.1.0", - "grin_keychain 1.1.0", - "grin_p2p 1.1.0", - "grin_pool 1.1.0", - "grin_store 1.1.0", - "grin_util 1.1.0", + "grin_api 1.1.0-beta.1", + "grin_chain 1.1.0-beta.1", + "grin_core 1.1.0-beta.1", + "grin_keychain 1.1.0-beta.1", + "grin_p2p 1.1.0-beta.1", + "grin_pool 1.1.0-beta.1", + "grin_store 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_store" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -910,32 +851,32 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "grin_core 1.1.0", - "grin_util 1.1.0", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "grin_core 1.1.0-beta.1", + "grin_util 1.1.0-beta.1", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grin_util" -version = "1.1.0" +version = "1.1.0-beta.1" dependencies = [ "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "grin_secp256k1zkp 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -943,11 +884,11 @@ dependencies = [ [[package]] name = "h2" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -955,7 +896,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -972,7 +913,7 @@ name = "http" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -997,26 +938,27 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.24" +version = "0.12.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1029,10 +971,10 @@ dependencies = [ "ct-logs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1059,7 +1001,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1087,7 +1029,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1097,7 +1039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.49" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1105,8 +1047,8 @@ name = "libgit2-sys" version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1117,7 +1059,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1125,7 +1067,7 @@ name = "libloading" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1134,20 +1076,15 @@ name = "libz-sys" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "linked-hash-map" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "linked-hash-map" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1156,7 +1093,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "liblmdb-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "supercow 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1175,8 +1112,8 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1192,16 +1129,16 @@ dependencies = [ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1210,10 +1147,10 @@ dependencies = [ [[package]] name = "lru-cache" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1231,7 +1168,7 @@ name = "memchr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1244,7 +1181,7 @@ name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1258,8 +1195,8 @@ name = "miniz-sys" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1275,9 +1212,9 @@ name = "miniz_oxide_c_api" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1291,7 +1228,7 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1305,7 +1242,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1334,8 +1271,8 @@ name = "ncurses" version = "5.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1344,8 +1281,8 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1355,9 +1292,9 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1493,7 +1430,7 @@ name = "num_cpus" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1503,7 +1440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ordered-float" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1522,10 +1459,10 @@ name = "pancurses" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ncurses 5.99.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pdcurses-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pdcurses-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1552,7 +1489,7 @@ name = "parking_lot_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1564,7 +1501,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1588,11 +1525,11 @@ dependencies = [ [[package]] name = "pdcurses-sys" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1667,7 +1604,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1680,7 +1617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1691,13 +1628,13 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1746,19 +1683,19 @@ name = "rand_jitter" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1791,7 +1728,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1799,18 +1736,18 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_users" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1820,19 +1757,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.1.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1843,9 +1780,9 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1947,10 +1884,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1958,28 +1895,28 @@ name = "serde-value" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1988,9 +1925,9 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2006,11 +1943,11 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2060,7 +1997,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.26" +version = "0.15.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2075,16 +2012,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "term" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2094,7 +2032,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2111,8 +2049,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2129,8 +2067,8 @@ name = "thread-id" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2139,7 +2077,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2147,30 +2085,31 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2180,9 +2119,9 @@ name = "tokio-codec" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2190,31 +2129,31 @@ name = "tokio-core" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-current-thread" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2223,39 +2162,40 @@ dependencies = [ [[package]] name = "tokio-fs" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2264,15 +2204,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-sync" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2281,29 +2222,28 @@ name = "tokio-tcp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2314,7 +2254,15 @@ dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-trace-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2322,13 +2270,13 @@ name = "tokio-udp" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2336,16 +2284,16 @@ name = "tokio-uds" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2353,7 +2301,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2448,9 +2396,9 @@ name = "uuid" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2511,7 +2459,7 @@ name = "which" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2589,10 +2537,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yaml-rust" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2612,10 +2560,10 @@ dependencies = [ [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" -"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" +"checksum arc-swap 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c79e383ce3e5b88b123589fe774221be2240a9936866f4f2286cbfe555ef36e8" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum array-macro 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4ff37a25fb442a1fecfd399be0dde685558bca30fb998420532889a36852d2" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" @@ -2635,49 +2583,45 @@ dependencies = [ "checksum built 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61f5aae2fa15b68fbcf0cbab64e659a55d10e9bacc55d3470ef77ae73030d755" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7f7c04e52c35222fffcc3a115b5daf5f7e2bfb71c13c4e2321afe1fc71859c2" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum croaring 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b350ece8a9ba71eeb9c068a98a86dc420ca5c1d6bd4e1627a4581e9c843c38" "checksum croaring-sys 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "546b00f33bdf591bce6410a8dca65047d126b1d5a9189190d085aa8c493d43a7" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" -"checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" "checksum ct-logs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95a4bf5107667e12bf6ce31a3a5066d67acc88942b6742117a41198734aaccaa" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" "checksum cursive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad36e47ece323d806b1daa3c87c7eb2aae54ef15e6554e27fe3dbdacf6b515fc" -"checksum cursive 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1df013f020cf1e66c456c9af584ae660590b8147186fd66b941604f85145b880" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a" +"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" "checksum enum-map 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "caa1769f019df7ccd8f9a741d2d608309688d0f1bd8a8747c14ac993660c761c" "checksum enum-map-derive 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "153f6e8a8b2868e2fedf921b165f30229edcccb74d6a9bb1ccf0480ef61cd07e" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" -"checksum enumset 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "55da7777fd68a7213fa1d8f56ec3063141e44650c7fe7ae329ab69a0e77ecf00" -"checksum enumset_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24300e54ac8ddea74e337f0309c71df4a8c1d7a7fd48a287ef0af8354fadb788" +"checksum enumset 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67547bfa69f4ca1c960f151d502f3b6db7cbb523ae2b20c6da7333c69fa24c" +"checksum enumset_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f90b5cdb387bc97d281c59fffebe335cf0a01e1734e1fc0e92d731fdbb9ceb36" "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" -"checksum flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4" +"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" @@ -2690,13 +2634,13 @@ dependencies = [ "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum grin_secp256k1zkp 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "75e9a265f3eeea4c204470f7262e2c6fe18f3d8ddf5fb24340cb550ac4f909c5" -"checksum h2 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb2b25a33e231484694267af28fec74ac63b5ccf51ee2065a5e313b834d836e" +"checksum h2 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "910a5e7be6283a9c91b3982fa5188368c8719cce2a3cf3b86048673bf9d9c36b" "checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a" "checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum hyper 0.12.24 (registry+https://github.com/rust-lang/crates.io-index)" = "fdfa9b401ef6c4229745bb6e9b2529192d07b920eed624cdee2a82348cd550af" +"checksum hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896" "checksum hyper-rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68f2aa6b1681795bf4da8063f718cd23145aa0c9a5143d9787b345aa60d38ee4" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" @@ -2704,21 +2648,20 @@ dependencies = [ "checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" "checksum libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" "checksum liblmdb-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "feed38a3a580f60bf61aaa067b0ff4123395966839adeaf67258a9e50c4d2e49" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" -"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" -"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" +"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "13416eee745b087c22934f35f1f24da22da41ba2a5ce197143d168ce055cc58d" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" "checksum log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25e0fc8737a634116a2deb38d821e4400ed16ce9dcb0d628a978d399260f5902" -"checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" +"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" @@ -2751,7 +2694,7 @@ dependencies = [ "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum odds 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "4eae0151b9dacf24fcc170d9995e511669a082856a91f958a2fe380bfab3fb22" -"checksum ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0015e9e8e28ee20c581cfbfe47c650cedeb9ed0721090e0b7ebb10b9cdbcc2" +"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d3058bc37c433096b2ac7afef1c5cdfae49ede0a4ffec3dfc1df1df0959d0ff0" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" @@ -2759,7 +2702,7 @@ dependencies = [ "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c09cddfbfc98de7f76931acf44460972edb4023eb14d0c6d4018800e552d8e0" -"checksum pdcurses-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90e12bfe55b7080fdfa0742f7a22ce7d5d1da250ca064ae6b81c843a2084fa2a" +"checksum pdcurses-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "084dd22796ff60f1225d4eb6329f33afaf4c85419d51d440ab6b8c6f4529166b" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" @@ -2779,16 +2722,16 @@ dependencies = [ "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" -"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)" = "d32b3053e5ced86e4bc0411fec997389532bf56b000e66cb4884eeeb41413d69" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26" +"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828" "checksum reexport-proc-macro 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b90ec417f693152463d468b6d06ccc45ae3833f0538ef9e1cc154cf09eb1f575" -"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" -"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum regex 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2cf47563eeec4ae0b6f5b0e0306024ccef91e779342705bbaa4b6ffc75ad825d" +"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum ripemd160 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "482aa56cc68aaeccdaaff1cc5a72c247da8bbad3beb174ca5741f274c22883fb" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" @@ -2804,13 +2747,13 @@ dependencies = [ "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850" +"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" "checksum serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f" -"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4" -"checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9" +"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0887a8e097a69559b56aa2526bf7aff7c3048cf627dff781f0b56a6001534593" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" -"checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" +"checksum signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97a47ae722318beceb0294e6f3d601205a1e6abaa4437d9d33e3a212233e3021" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" @@ -2819,9 +2762,9 @@ dependencies = [ "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum supercow 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" +"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" @@ -2829,19 +2772,20 @@ dependencies = [ "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "e0500b88064f08bebddd0c0bed39e19f5c567a5f30975bee52b0c0d3e2eeb38c" +"checksum tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "65641e515a437b308ab131a82ce3042ff9795bef5d6c5a9be4eb24195c417fd9" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" -"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" -"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" -"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" -"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" +"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" +"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" +"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" +"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" "checksum tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "208d62fa3e015426e3c64039d9d20adf054a3c9b4d9445560f1c41c75bef3eab" -"checksum tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c73850a5ad497d73ccfcfc0ffb494a4502d93f35cb475cfeef4fcf2916d26040" +"checksum tokio-sync 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fda385df506bf7546e70872767f71e81640f1f251bdf2fd8eb81a0eaec5fe022" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb" +"checksum tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ec5759cf26cf9659555f36c431b515e3d05f66831741c85b4b5d5dfb9cf1323c" "checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" +"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" @@ -2879,6 +2823,6 @@ dependencies = [ "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" -"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" +"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" "checksum zeroize 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddfeb6eee2fb3b262ef6e0898a52b7563bb8e0d5955a313b3cf2f808246ea14" "checksum zip 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "36b9e08fb518a65cf7e08a1e482573eb87a2f4f8c6619316612a3c1f162fe822" diff --git a/Cargo.toml b/Cargo.toml index 44daed9316..5c65192716 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -32,13 +32,13 @@ term = "0.5" failure = "0.1" failure_derive = "0.1" -grin_api = { path = "./api", version = "1.1.0" } -grin_config = { path = "./config", version = "1.1.0" } -grin_core = { path = "./core", version = "1.1.0" } -grin_keychain = { path = "./keychain", version = "1.1.0" } -grin_p2p = { path = "./p2p", version = "1.1.0" } -grin_servers = { path = "./servers", version = "1.1.0" } -grin_util = { path = "./util", version = "1.1.0" } +grin_api = { path = "./api", version = "1.1.0-beta.1" } +grin_config = { path = "./config", version = "1.1.0-beta.1" } +grin_core = { path = "./core", version = "1.1.0-beta.1" } +grin_keychain = { path = "./keychain", version = "1.1.0-beta.1" } +grin_p2p = { path = "./p2p", version = "1.1.0-beta.1" } +grin_servers = { path = "./servers", version = "1.1.0-beta.1" } +grin_util = { path = "./util", version = "1.1.0-beta.1" } [target.'cfg(windows)'.dependencies] cursive = { version = "0.10.0", default-features = false, features = ["pancurses-backend"] } @@ -46,11 +46,11 @@ cursive = { version = "0.10.0", default-features = false, features = ["pancurses version = "0.16.0" features = ["win32"] [target.'cfg(unix)'.dependencies] -cursive = "0.9.0" +cursive = "0.10.0" [build-dependencies] built = "0.3" [dev-dependencies] -grin_chain = { path = "./chain", version = "1.1.0" } -grin_store = { path = "./store", version = "1.1.0" } +grin_chain = { path = "./chain", version = "1.1.0-beta.1" } +grin_store = { path = "./store", version = "1.1.0-beta.1" } diff --git a/README.md b/README.md index 0d029a017a..b0e1efcf73 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -[![Build Status](https://travis-ci.org/mimblewimble/grin.svg?branch=master)](https://travis-ci.org/mimblewimble/grin) -[![Gitter chat](https://badges.gitter.im/grin_community/Lobby.png)](https://gitter.im/grin_community/Lobby) -[![Support chat](https://badges.gitter.im/grin_community/Lobby.png)](https://gitter.im/grin_community/support) -[![Codecov coverage status](https://codecov.io/gh/mimblewimble/grin/branch/master/graph/badge.svg)](https://codecov.io/gh/mimblewimble/grin) +[![Build Status](https://img.shields.io/travis/mimblewimble/grin/master.svg)](https://travis-ci.org/mimblewimble/grin) +[![Coverage Status](https://img.shields.io/codecov/c/github/mimblewimble/grin/master.svg)](https://codecov.io/gh/mimblewimble/grin) +[![Chat](https://img.shields.io/gitter/room/grin_community/Lobby.svg)](https://gitter.im/grin_community/Lobby) +[![Support](https://img.shields.io/badge/support-on%20gitter-brightgreen.svg)](https://gitter.im/grin_community/support) +[![Documentation Wiki](https://img.shields.io/badge/doc-wiki-blue.svg)](https://github.com/mimblewimble/docs/wiki) +[![Release Version](https://img.shields.io/github/release/mimblewimble/grin.svg)](https://github.com/mimblewimble/grin/releases) +[![License](https://img.shields.io/github/license/mimblewimble/grin.svg)](https://github.com/mimblewimble/grin/blob/master/LICENSE) # Grin diff --git a/api/Cargo.toml b/api/Cargo.toml index d728945a88..c8df75f0dd 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_api" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "APIs for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -30,9 +30,9 @@ futures = "0.1.21" rustls = "0.13" url = "1.7.0" -grin_core = { path = "../core", version = "1.1.0" } -grin_chain = { path = "../chain", version = "1.1.0" } -grin_p2p = { path = "../p2p", version = "1.1.0" } -grin_pool = { path = "../pool", version = "1.1.0" } -grin_store = { path = "../store", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_chain = { path = "../chain", version = "1.1.0-beta.1" } +grin_p2p = { path = "../p2p", version = "1.1.0-beta.1" } +grin_pool = { path = "../pool", version = "1.1.0-beta.1" } +grin_store = { path = "../store", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } diff --git a/api/src/auth.rs b/api/src/auth.rs index 3b00fa7015..073c9374ca 100644 --- a/api/src/auth.rs +++ b/api/src/auth.rs @@ -13,19 +13,25 @@ // limitations under the License. use crate::router::{Handler, HandlerObj, ResponseFuture}; +use crate::web::response; use futures::future::ok; use hyper::header::{HeaderValue, AUTHORIZATION, WWW_AUTHENTICATE}; use hyper::{Body, Request, Response, StatusCode}; use ring::constant_time::verify_slices_are_equal; +lazy_static! { + pub static ref GRIN_BASIC_REALM: HeaderValue = + HeaderValue::from_str("Basic realm=GrinAPI").unwrap(); +} + // Basic Authentication Middleware pub struct BasicAuthMiddleware { api_basic_auth: String, - basic_realm: String, + basic_realm: &'static HeaderValue, } impl BasicAuthMiddleware { - pub fn new(api_basic_auth: String, basic_realm: String) -> BasicAuthMiddleware { + pub fn new(api_basic_auth: String, basic_realm: &'static HeaderValue) -> BasicAuthMiddleware { BasicAuthMiddleware { api_basic_auth, basic_realm, @@ -39,8 +45,12 @@ impl Handler for BasicAuthMiddleware { req: Request, mut handlers: Box>, ) -> ResponseFuture { + let next_handler = match handlers.next() { + Some(h) => h, + None => return response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + }; if req.method().as_str() == "OPTIONS" { - return handlers.next().unwrap().call(req, handlers); + return next_handler.call(req, handlers); } if req.headers().contains_key(AUTHORIZATION) && verify_slices_are_equal( @@ -49,7 +59,7 @@ impl Handler for BasicAuthMiddleware { ) .is_ok() { - handlers.next().unwrap().call(req, handlers) + next_handler.call(req, handlers) } else { // Unauthorized 401 unauthorized_response(&self.basic_realm) @@ -57,13 +67,10 @@ impl Handler for BasicAuthMiddleware { } } -fn unauthorized_response(basic_realm: &str) -> ResponseFuture { +fn unauthorized_response(basic_realm: &HeaderValue) -> ResponseFuture { let response = Response::builder() .status(StatusCode::UNAUTHORIZED) - .header( - WWW_AUTHENTICATE, - HeaderValue::from_str(basic_realm).unwrap(), - ) + .header(WWW_AUTHENTICATE, basic_realm) .body(Body::empty()) .unwrap(); Box::new(ok(response)) diff --git a/api/src/client.rs b/api/src/client.rs index 98636ce0be..fb3b6b4769 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -19,7 +19,7 @@ use crate::util::to_base64; use failure::{Fail, ResultExt}; use futures::future::{err, ok, Either}; use http::uri::{InvalidUri, Uri}; -use hyper::header::{ACCEPT, AUTHORIZATION, USER_AGENT}; +use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, USER_AGENT}; use hyper::rt::{Future, Stream}; use hyper::{Body, Client, Request}; use hyper_rustls; @@ -136,9 +136,8 @@ fn build_request<'a>( .into() })?; let mut builder = Request::builder(); - if api_secret.is_some() { - let basic_auth = - "Basic ".to_string() + &to_base64(&("grin:".to_string() + &api_secret.unwrap())); + if let Some(api_secret) = api_secret { + let basic_auth = format!("Basic {}", to_base64(&format!("grin:{}", api_secret))); builder.header(AUTHORIZATION, basic_auth); } @@ -147,6 +146,7 @@ fn build_request<'a>( .uri(uri) .header(USER_AGENT, "grin-client") .header(ACCEPT, "application/json") + .header(CONTENT_TYPE, "application/json") .body(match body { None => Body::empty(), Some(json) => json.into(), @@ -202,9 +202,11 @@ fn send_request_async(req: Request) -> Box) -> Box) -> Result { let task = send_request_async(req); - let mut rt = Runtime::new().unwrap(); + let mut rt = + Runtime::new().context(ErrorKind::Internal("can't create Tokio runtime".to_owned()))?; Ok(rt.block_on(task)?) } diff --git a/api/src/handlers.rs b/api/src/handlers.rs index 9afd229c51..feb65e3438 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -20,39 +20,26 @@ mod server_api; mod transactions_api; mod utils; -use crate::router::{Router, RouterError}; - -// Server -use self::server_api::IndexHandler; -use self::server_api::StatusHandler; - -// Blocks use self::blocks_api::BlockHandler; use self::blocks_api::HeaderHandler; - -// TX Set -use self::transactions_api::TxHashSetHandler; - -// Chain use self::chain_api::ChainCompactHandler; use self::chain_api::ChainHandler; use self::chain_api::ChainValidationHandler; use self::chain_api::OutputHandler; - -// Pool Handlers -use self::pool_api::PoolInfoHandler; -use self::pool_api::PoolPushHandler; - -// Peers use self::peers_api::PeerHandler; use self::peers_api::PeersAllHandler; use self::peers_api::PeersConnectedHandler; - -use crate::auth::BasicAuthMiddleware; +use self::pool_api::PoolInfoHandler; +use self::pool_api::PoolPushHandler; +use self::server_api::IndexHandler; +use self::server_api::StatusHandler; +use self::transactions_api::TxHashSetHandler; +use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM}; use crate::chain; use crate::p2p; use crate::pool; use crate::rest::*; +use crate::router::{Router, RouterError}; use crate::util; use crate::util::RwLock; use std::net::SocketAddr; @@ -76,11 +63,10 @@ pub fn start_rest_apis( ) -> bool { let mut apis = ApiServer::new(); let mut router = build_router(chain, tx_pool, peers).expect("unable to build API router"); - if api_secret.is_some() { - let api_basic_auth = - "Basic ".to_string() + &util::to_base64(&("grin:".to_string() + &api_secret.unwrap())); - let basic_realm = "Basic realm=GrinAPI".to_string(); - let basic_auth_middleware = Arc::new(BasicAuthMiddleware::new(api_basic_auth, basic_realm)); + if let Some(api_secret) = api_secret { + let api_basic_auth = format!("Basic {}", util::to_base64(&format!("grin:{}", api_secret))); + let basic_auth_middleware = + Arc::new(BasicAuthMiddleware::new(api_basic_auth, &GRIN_BASIC_REALM)); router.add_middleware(basic_auth_middleware); } @@ -103,16 +89,19 @@ pub fn build_router( ) -> Result { let route_list = vec![ "get blocks".to_string(), + "get headers".to_string(), "get chain".to_string(), "post chain/compact".to_string(), - "post chain/validate".to_string(), - "get chain/outputs".to_string(), + "get chain/validate".to_string(), + "get chain/outputs/byids?id=xxx,yyy,zzz".to_string(), + "get chain/outputs/byheight?start_height=101&end_height=200".to_string(), "get status".to_string(), "get txhashset/roots".to_string(), "get txhashset/lastoutputs?n=10".to_string(), "get txhashset/lastrangeproofs".to_string(), "get txhashset/lastkernels".to_string(), "get txhashset/outputs?start_index=1&max=100".to_string(), + "get txhashset/merkleproof?n=1".to_string(), "get pool".to_string(), "post pool/push".to_string(), "post peers/a.b.c.d:p/ban".to_string(), diff --git a/api/src/handlers/blocks_api.rs b/api/src/handlers/blocks_api.rs index 9da0a1c875..4cea007a5f 100644 --- a/api/src/handlers/blocks_api.rs +++ b/api/src/handlers/blocks_api.rs @@ -41,7 +41,7 @@ impl HeaderHandler { return Ok(h); } if let Ok(height) = input.parse() { - match w(&self.chain).get_header_by_height(height) { + match w(&self.chain)?.get_header_by_height(height) { Ok(header) => return Ok(BlockHeaderPrintable::from_header(&header)), Err(_) => return Err(ErrorKind::NotFound)?, } @@ -50,7 +50,7 @@ impl HeaderHandler { let vec = util::from_hex(input) .map_err(|e| ErrorKind::Argument(format!("invalid input: {}", e)))?; let h = Hash::from_vec(&vec); - let header = w(&self.chain) + let header = w(&self.chain)? .get_block_header(&h) .context(ErrorKind::NotFound)?; Ok(BlockHeaderPrintable::from_header(&header)) @@ -58,7 +58,7 @@ impl HeaderHandler { fn get_header_for_output(&self, commit_id: String) -> Result { let oid = get_output(&self.chain, &commit_id)?.1; - match w(&self.chain).get_header_for_output(&oid) { + match w(&self.chain)?.get_header_for_output(&oid) { Ok(header) => Ok(BlockHeaderPrintable::from_header(&header)), Err(_) => Err(ErrorKind::NotFound)?, } @@ -85,22 +85,23 @@ pub struct BlockHandler { impl BlockHandler { fn get_block(&self, h: &Hash) -> Result { - let block = w(&self.chain).get_block(h).context(ErrorKind::NotFound)?; - Ok(BlockPrintable::from_block(&block, w(&self.chain), false)) + let chain = w(&self.chain)?; + let block = chain.get_block(h).context(ErrorKind::NotFound)?; + BlockPrintable::from_block(&block, chain, false) + .map_err(|_| ErrorKind::Internal("chain error".to_owned()).into()) } fn get_compact_block(&self, h: &Hash) -> Result { - let block = w(&self.chain).get_block(h).context(ErrorKind::NotFound)?; - Ok(CompactBlockPrintable::from_compact_block( - &block.into(), - w(&self.chain), - )) + let chain = w(&self.chain)?; + let block = chain.get_block(h).context(ErrorKind::NotFound)?; + CompactBlockPrintable::from_compact_block(&block.into(), chain) + .map_err(|_| ErrorKind::Internal("chain error".to_owned()).into()) } // Try to decode the string as a height or a hash. fn parse_input(&self, input: String) -> Result { if let Ok(height) = input.parse() { - match w(&self.chain).get_header_by_height(height) { + match w(&self.chain)?.get_header_by_height(height) { Ok(header) => return Ok(header.hash()), Err(_) => return Err(ErrorKind::NotFound)?, } diff --git a/api/src/handlers/chain_api.rs b/api/src/handlers/chain_api.rs index d0df2aa4fd..66bedcca77 100644 --- a/api/src/handlers/chain_api.rs +++ b/api/src/handlers/chain_api.rs @@ -21,6 +21,7 @@ use crate::types::*; use crate::util; use crate::util::secp::pedersen::Commitment; use crate::web::*; +use failure::ResultExt; use hyper::{Body, Request, StatusCode}; use std::sync::Weak; @@ -32,7 +33,7 @@ pub struct ChainHandler { impl ChainHandler { fn get_tip(&self) -> Result { - let head = w(&self.chain) + let head = w(&self.chain)? .head() .map_err(|e| ErrorKind::Internal(format!("can't get head: {}", e)))?; Ok(Tip::from_tip(head)) @@ -53,7 +54,7 @@ pub struct ChainValidationHandler { impl Handler for ChainValidationHandler { fn get(&self, _req: Request) -> ResponseFuture { - match w(&self.chain).validate(true) { + match w_fut!(&self.chain).validate(true) { Ok(_) => response(StatusCode::OK, "{}"), Err(e) => response( StatusCode::INTERNAL_SERVER_ERROR, @@ -72,7 +73,7 @@ pub struct ChainCompactHandler { impl Handler for ChainCompactHandler { fn post(&self, _req: Request) -> ResponseFuture { - match w(&self.chain).compact() { + match w_fut!(&self.chain).compact() { Ok(_) => response(StatusCode::OK, "{}"), Err(e) => response( StatusCode::INTERNAL_SERVER_ERROR, @@ -105,9 +106,13 @@ impl OutputHandler { let mut outputs: Vec = vec![]; for x in commitments { - if let Ok(output) = self.get_output(&x) { - outputs.push(output); - } + match self.get_output(&x) { + Ok(output) => outputs.push(output), + Err(e) => error!( + "Failure to get output for commitment {} with error {}", + x, e + ), + }; } Ok(outputs) } @@ -118,13 +123,14 @@ impl OutputHandler { commitments: Vec, include_proof: bool, ) -> Result { - let header = w(&self.chain) + let header = w(&self.chain)? .get_header_by_height(block_height) .map_err(|_| ErrorKind::NotFound)?; // TODO - possible to compact away blocks we care about // in the period between accepting the block and refreshing the wallet - let block = w(&self.chain) + let chain = w(&self.chain)?; + let block = chain .get_block(&header.hash()) .map_err(|_| ErrorKind::NotFound)?; let outputs = block @@ -132,9 +138,10 @@ impl OutputHandler { .iter() .filter(|output| commitments.is_empty() || commitments.contains(&output.commit)) .map(|output| { - OutputPrintable::from_output(output, w(&self.chain), Some(&header), include_proof) + OutputPrintable::from_output(output, chain.clone(), Some(&header), include_proof) }) - .collect(); + .collect::, _>>() + .context(ErrorKind::Internal("cain error".to_owned()))?; Ok(BlockOutputs { header: BlockHeaderInfo::from_header(&header), diff --git a/api/src/handlers/peers_api.rs b/api/src/handlers/peers_api.rs index 6453432fb3..a36813cb1f 100644 --- a/api/src/handlers/peers_api.rs +++ b/api/src/handlers/peers_api.rs @@ -26,7 +26,7 @@ pub struct PeersAllHandler { impl Handler for PeersAllHandler { fn get(&self, _req: Request) -> ResponseFuture { - let peers = &w(&self.peers).all_peers(); + let peers = &w_fut!(&self.peers).all_peers(); json_response_pretty(&peers) } } @@ -37,7 +37,7 @@ pub struct PeersConnectedHandler { impl Handler for PeersConnectedHandler { fn get(&self, _req: Request) -> ResponseFuture { - let peers: Vec = w(&self.peers) + let peers: Vec = w_fut!(&self.peers) .connected_peers() .iter() .map(|p| p.info.clone().into()) @@ -73,13 +73,13 @@ impl Handler for PeerHandler { ); } - match w(&self.peers).get_peer(peer_addr) { + match w_fut!(&self.peers).get_peer(peer_addr) { Ok(peer) => json_response(&peer), Err(_) => response(StatusCode::NOT_FOUND, "peer not found"), } } fn post(&self, req: Request) -> ResponseFuture { - let mut path_elems = req.uri().path().trim_right_matches('/').rsplit('/'); + let mut path_elems = req.uri().path().trim_end_matches('/').rsplit('/'); let command = match path_elems.next() { None => return response(StatusCode::BAD_REQUEST, "invalid url"), Some(c) => c, @@ -101,8 +101,8 @@ impl Handler for PeerHandler { }; match command { - "ban" => w(&self.peers).ban_peer(addr, ReasonForBan::ManualBan), - "unban" => w(&self.peers).unban_peer(addr), + "ban" => w_fut!(&self.peers).ban_peer(addr, ReasonForBan::ManualBan), + "unban" => w_fut!(&self.peers).unban_peer(addr), _ => return response(StatusCode::BAD_REQUEST, "invalid command"), }; diff --git a/api/src/handlers/pool_api.rs b/api/src/handlers/pool_api.rs index 299b79a287..cf9278cef6 100644 --- a/api/src/handlers/pool_api.rs +++ b/api/src/handlers/pool_api.rs @@ -24,7 +24,7 @@ use crate::util; use crate::util::RwLock; use crate::web::*; use failure::ResultExt; -use futures::future::ok; +use futures::future::{err, ok}; use futures::Future; use hyper::{Body, Request, StatusCode}; use std::sync::Weak; @@ -37,7 +37,7 @@ pub struct PoolInfoHandler { impl Handler for PoolInfoHandler { fn get(&self, _req: Request) -> ResponseFuture { - let pool_arc = w(&self.tx_pool); + let pool_arc = w_fut!(&self.tx_pool); let pool = pool_arc.read(); json_response(&PoolInfo { @@ -63,7 +63,11 @@ impl PoolPushHandler { let params = QueryParams::from(req.uri().query()); let fluff = params.get("fluff").is_some(); - let pool_arc = w(&self.tx_pool).clone(); + let pool_arc = match w(&self.tx_pool) { + //w(&self.tx_pool).clone(); + Ok(p) => p, + Err(e) => return Box::new(err(e)), + }; Box::new( parse_body(req) diff --git a/api/src/handlers/server_api.rs b/api/src/handlers/server_api.rs index 42a829a658..d5092b0547 100644 --- a/api/src/handlers/server_api.rs +++ b/api/src/handlers/server_api.rs @@ -45,12 +45,12 @@ pub struct StatusHandler { impl StatusHandler { fn get_status(&self) -> Result { - let head = w(&self.chain) + let head = w(&self.chain)? .head() .map_err(|e| ErrorKind::Internal(format!("can't get head: {}", e)))?; Ok(Status::from_tip_and_peers( head, - w(&self.peers).peer_count(), + w(&self.peers)?.peer_count(), )) } } diff --git a/api/src/handlers/transactions_api.rs b/api/src/handlers/transactions_api.rs index 42723e71de..a65047624d 100644 --- a/api/src/handlers/transactions_api.rs +++ b/api/src/handlers/transactions_api.rs @@ -45,23 +45,26 @@ pub struct TxHashSetHandler { impl TxHashSetHandler { // gets roots - fn get_roots(&self) -> TxHashSet { - TxHashSet::from_head(w(&self.chain)) + fn get_roots(&self) -> Result { + Ok(TxHashSet::from_head(w(&self.chain)?)) } // gets last n outputs inserted in to the tree - fn get_last_n_output(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_output(w(&self.chain), distance) + fn get_last_n_output(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_output(w(&self.chain)?, distance)) } // gets last n outputs inserted in to the tree - fn get_last_n_rangeproof(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_rangeproof(w(&self.chain), distance) + fn get_last_n_rangeproof(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_rangeproof( + w(&self.chain)?, + distance, + )) } // gets last n outputs inserted in to the tree - fn get_last_n_kernel(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_kernel(w(&self.chain), distance) + fn get_last_n_kernel(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_kernel(w(&self.chain)?, distance)) } // allows traversal of utxo set @@ -70,18 +73,21 @@ impl TxHashSetHandler { if max > 1000 { max = 1000; } - let outputs = w(&self.chain) + let chain = w(&self.chain)?; + let outputs = chain .unspent_outputs_by_insertion_index(start_index, max) .context(ErrorKind::NotFound)?; - Ok(OutputListing { + let out = OutputListing { last_retrieved_index: outputs.0, highest_index: outputs.1, outputs: outputs .2 .iter() - .map(|x| OutputPrintable::from_output(x, w(&self.chain), None, true)) - .collect(), - }) + .map(|x| OutputPrintable::from_output(x, chain.clone(), None, true)) + .collect::, _>>() + .context(ErrorKind::Internal("cain error".to_owned()))?, + }; + Ok(out) } // return a dummy output with merkle proof for position filled out @@ -92,10 +98,9 @@ impl TxHashSetHandler { id )))?; let commit = Commitment::from_vec(c); - let output_pos = w(&self.chain) - .get_output_pos(&commit) - .context(ErrorKind::NotFound)?; - let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&w(&self.chain), commit) + let chain = w(&self.chain)?; + let output_pos = chain.get_output_pos(&commit).context(ErrorKind::NotFound)?; + let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&chain, commit) .map_err(|_| ErrorKind::NotFound)?; Ok(OutputPrintable { output_type: OutputType::Coinbase, @@ -120,10 +125,10 @@ impl Handler for TxHashSetHandler { let id = parse_param_no_err!(params, "id", "".to_owned()); match right_path_element!(req) { - "roots" => json_response_pretty(&self.get_roots()), - "lastoutputs" => json_response_pretty(&self.get_last_n_output(last_n)), - "lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)), - "lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)), + "roots" => result_to_response(self.get_roots()), + "lastoutputs" => result_to_response(self.get_last_n_output(last_n)), + "lastrangeproofs" => result_to_response(self.get_last_n_rangeproof(last_n)), + "lastkernels" => result_to_response(self.get_last_n_kernel(last_n)), "outputs" => result_to_response(self.outputs(start_index, max)), "merkleproof" => result_to_response(self.get_merkle_proof_for_output(&id)), _ => response(StatusCode::BAD_REQUEST, ""), diff --git a/api/src/handlers/utils.rs b/api/src/handlers/utils.rs index bedaf09046..1aa309e981 100644 --- a/api/src/handlers/utils.rs +++ b/api/src/handlers/utils.rs @@ -24,8 +24,9 @@ use std::sync::{Arc, Weak}; // All handlers use `Weak` references instead of `Arc` to avoid cycles that // can never be destroyed. These 2 functions are simple helpers to reduce the // boilerplate of dealing with `Weak`. -pub fn w(weak: &Weak) -> Arc { - weak.upgrade().unwrap() +pub fn w(weak: &Weak) -> Result, Error> { + weak.upgrade() + .ok_or_else(|| ErrorKind::Internal("failed to upgrade weak refernce".to_owned()).into()) } /// Retrieves an output from the chain given a commit id (a tiny bit iteratively) @@ -48,14 +49,16 @@ pub fn get_output( OutputIdentifier::new(OutputFeatures::Coinbase, &commit), ]; - for x in outputs.iter().filter(|x| w(chain).is_unspent(x).is_ok()) { - let block_height = w(chain) + let chain = w(chain)?; + + for x in outputs.iter().filter(|x| chain.is_unspent(x).is_ok()) { + let block_height = chain .get_header_for_output(&x) .context(ErrorKind::Internal( "Can't get header for output".to_owned(), ))? .height; - let output_pos = w(chain).get_output_pos(&x.commit).unwrap_or(0); + let output_pos = chain.get_output_pos(&x.commit).unwrap_or(0); return Ok((Output::new(&commit, block_height, output_pos), x.clone())); } Err(ErrorKind::NotFound)? diff --git a/api/src/lib.rs b/api/src/lib.rs index 282a290092..d9a566e195 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -39,7 +39,7 @@ mod rest; mod router; mod types; -pub use crate::auth::BasicAuthMiddleware; +pub use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM}; pub use crate::handlers::start_rest_apis; pub use crate::rest::*; pub use crate::router::*; diff --git a/api/src/rest.rs b/api/src/rest.rs index fa26ef64ad..98c1b13144 100644 --- a/api/src/rest.rs +++ b/api/src/rest.rs @@ -19,11 +19,12 @@ //! register them on a ApiServer. use crate::router::{Handler, HandlerObj, ResponseFuture, Router}; +use crate::web::response; use failure::{Backtrace, Context, Fail, ResultExt}; use futures::sync::oneshot; use futures::Stream; use hyper::rt::Future; -use hyper::{rt, Body, Request, Server}; +use hyper::{rt, Body, Request, Server, StatusCode}; use rustls; use rustls::internal::pemfile; use std::fmt::{self, Display}; @@ -264,6 +265,9 @@ impl Handler for LoggingMiddleware { mut handlers: Box>, ) -> ResponseFuture { debug!("REST call: {} {}", req.method(), req.uri().path()); - handlers.next().unwrap().call(req, handlers) + match handlers.next() { + Some(handler) => handler.call(req, handlers), + None => response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + } } } diff --git a/api/src/types.rs b/api/src/types.rs index c069ac0148..4ae8371775 100644 --- a/api/src/types.rs +++ b/api/src/types.rs @@ -222,7 +222,9 @@ impl<'de> serde::de::Visitor<'de> for PrintableCommitmentVisitor { E: serde::de::Error, { Ok(PrintableCommitment { - commit: pedersen::Commitment::from_vec(util::from_hex(String::from(v)).unwrap()), + commit: pedersen::Commitment::from_vec( + util::from_hex(String::from(v)).map_err(serde::de::Error::custom)?, + ), }) } } @@ -255,7 +257,7 @@ impl OutputPrintable { chain: Arc, block_header: Option<&core::BlockHeader>, include_proof: bool, - ) -> OutputPrintable { + ) -> Result { let output_type = if output.is_coinbase() { OutputType::Coinbase } else { @@ -266,7 +268,7 @@ impl OutputPrintable { let spent = chain.is_unspent(&out_id).is_err(); let block_height = match spent { true => None, - false => Some(chain.get_header_for_output(&out_id).unwrap().height), + false => Some(chain.get_header_for_output(&out_id)?.height), }; let proof = if include_proof { @@ -280,13 +282,15 @@ impl OutputPrintable { // We require the rewind() to be stable even after the PMMR is pruned and // compacted so we can still recreate the necessary proof. let mut merkle_proof = None; - if output.is_coinbase() && !spent && block_header.is_some() { - merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok() + if output.is_coinbase() && !spent { + if let Some(block_header) = block_header { + merkle_proof = chain.get_merkle_proof(&out_id, &block_header).ok(); + } }; let output_pos = chain.get_output_pos(&output.commit).unwrap_or(0); - OutputPrintable { + Ok(OutputPrintable { output_type, commit: output.commit, spent, @@ -295,7 +299,7 @@ impl OutputPrintable { block_height, merkle_proof, mmr_index: output_pos, - } + }) } pub fn commit(&self) -> Result { @@ -303,12 +307,13 @@ impl OutputPrintable { } pub fn range_proof(&self) -> Result { - let proof_str = self - .proof - .clone() - .ok_or_else(|| ser::Error::HexError(format!("output range_proof missing"))) - .unwrap(); - let p_vec = util::from_hex(proof_str).unwrap(); + let proof_str = match self.proof.clone() { + Some(p) => p, + None => return Err(ser::Error::HexError(format!("output range_proof missing"))), + }; + + let p_vec = util::from_hex(proof_str) + .map_err(|_| ser::Error::HexError(format!("invalud output range_proof")))?; let mut p_bytes = [0; util::secp::constants::MAX_PROOF_SIZE]; for i in 0..p_bytes.len() { p_bytes[i] = p_vec[i]; @@ -428,6 +433,15 @@ impl<'de> serde::de::Deserialize<'de> for OutputPrintable { } } + if output_type.is_none() + || commit.is_none() + || spent.is_none() + || proof_hash.is_none() + || mmr_index.is_none() + { + return Err(serde::de::Error::custom("invalid output")); + } + Ok(OutputPrintable { output_type: output_type.unwrap(), commit: commit.unwrap(), @@ -570,7 +584,7 @@ impl BlockPrintable { block: &core::Block, chain: Arc, include_proof: bool, - ) -> BlockPrintable { + ) -> Result { let inputs = block .inputs() .iter() @@ -587,18 +601,19 @@ impl BlockPrintable { include_proof, ) }) - .collect(); + .collect::, _>>()?; + let kernels = block .kernels() .iter() .map(|kernel| TxKernelPrintable::from_txkernel(kernel)) .collect(); - BlockPrintable { + Ok(BlockPrintable { header: BlockHeaderPrintable::from_header(&block.header), inputs: inputs, outputs: outputs, kernels: kernels, - } + }) } } @@ -620,24 +635,24 @@ impl CompactBlockPrintable { pub fn from_compact_block( cb: &core::CompactBlock, chain: Arc, - ) -> CompactBlockPrintable { - let block = chain.get_block(&cb.hash()).unwrap(); + ) -> Result { + let block = chain.get_block(&cb.hash())?; let out_full = cb .out_full() .iter() .map(|x| OutputPrintable::from_output(x, chain.clone(), Some(&block.header), false)) - .collect(); + .collect::, _>>()?; let kern_full = cb .kern_full() .iter() .map(|x| TxKernelPrintable::from_txkernel(x)) .collect(); - CompactBlockPrintable { + Ok(CompactBlockPrintable { header: BlockHeaderPrintable::from_header(&cb.header), out_full, kern_full, kern_ids: cb.kern_ids().iter().map(|x| x.to_hex()).collect(), - } + }) } } diff --git a/api/src/web.rs b/api/src/web.rs index 1bd2962375..eb525bb8ea 100644 --- a/api/src/web.rs +++ b/api/src/web.rs @@ -180,3 +180,12 @@ macro_rules! parse_param_no_err( } } )); + +#[macro_export] +macro_rules! w_fut( + ($p: expr) =>( + match w($p) { + Ok(p) => p, + Err(_) => return response(StatusCode::INTERNAL_SERVER_ERROR, "weak reference upgrade failed" ), + } + )); diff --git a/api/tests/rest.rs b/api/tests/rest.rs index 641ce3d2e5..3651bf7172 100644 --- a/api/tests/rest.rs +++ b/api/tests/rest.rs @@ -2,7 +2,7 @@ use grin_api as api; use grin_util as util; use crate::api::*; -use hyper::{Body, Request}; +use hyper::{Body, Request, StatusCode}; use std::net::SocketAddr; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use std::sync::Arc; @@ -43,7 +43,10 @@ impl Handler for CounterMiddleware { mut handlers: Box>, ) -> ResponseFuture { self.counter.fetch_add(1, Ordering::SeqCst); - handlers.next().unwrap().call(req, handlers) + match handlers.next() { + Some(h) => h.call(req, handlers), + None => return response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + } } } diff --git a/chain/Cargo.toml b/chain/Cargo.toml index 5f36d7b0b4..a68e768b5b 100644 --- a/chain/Cargo.toml +++ b/chain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_chain" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -23,10 +23,10 @@ lru-cache = "0.1" lazy_static = "1" regex = "1" -grin_core = { path = "../core", version = "1.1.0" } -grin_keychain = { path = "../keychain", version = "1.1.0" } -grin_store = { path = "../store", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_keychain = { path = "../keychain", version = "1.1.0-beta.1" } +grin_store = { path = "../store", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] env_logger = "0.5" diff --git a/chain/src/chain.rs b/chain/src/chain.rs index fd0148d09f..d11162f3c3 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -35,7 +35,9 @@ use crate::util::secp::pedersen::{Commitment, RangeProof}; use crate::util::{Mutex, RwLock, StopState}; use grin_store::Error::NotFoundErr; use std::collections::HashMap; +use std::env; use std::fs::File; +use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -688,7 +690,7 @@ impl Chain { } // prepares the zip and return the corresponding Read - let txhashset_reader = txhashset::zip_read(self.db_root.clone(), &header)?; + let txhashset_reader = txhashset::zip_read(self.db_root.clone(), &header, None)?; Ok(( header.output_mmr_size, header.kernel_mmr_size, @@ -763,11 +765,15 @@ impl Chain { } /// Check chain status whether a txhashset downloading is needed - pub fn check_txhashset_needed(&self, caller: String, hashes: &mut Option>) -> bool { + pub fn check_txhashset_needed( + &self, + caller: String, + hashes: &mut Option>, + ) -> Result { let horizon = global::cut_through_horizon() as u64; - let body_head = self.head().unwrap(); - let header_head = self.header_head().unwrap(); - let sync_head = self.get_sync_head().unwrap(); + let body_head = self.head()?; + let header_head = self.header_head()?; + let sync_head = self.get_sync_head()?; debug!( "{}: body_head - {}, {}, header_head - {}, {}, sync_head - {}, {}", @@ -785,7 +791,7 @@ impl Chain { "{}: no need txhashset. header_head.total_difficulty: {} <= body_head.total_difficulty: {}", caller, header_head.total_difficulty, body_head.total_difficulty, ); - return false; + return Ok(false); } let mut oldest_height = 0; @@ -797,6 +803,7 @@ impl Chain { "{}: header_head not found in chain db: {} at {}", caller, header_head.last_block_h, header_head.height, ); + return Ok(false); } // @@ -822,17 +829,30 @@ impl Chain { if oldest_height < header_head.height.saturating_sub(horizon) { if oldest_height > 0 { + // this is the normal case. for example: + // body head height is 1 (and not a fork), oldest_height will be 2 + // body head height is 0 (a typical fresh node), oldest_height will be 1 + // body head height is 10,001 (but at a fork), oldest_height will be 10,001 + // body head height is 10,005 (but at a fork with depth 5), oldest_height will be 10,001 debug!( "{}: need a state sync for txhashset. oldest block which is not on local chain: {} at {}", caller, oldest_hash, oldest_height, ); - return true; } else { - error!("{}: something is wrong! oldest_height is 0", caller); - return false; - }; + // this is the abnormal case, when is_on_current_chain() already return Err, and even for genesis block. + error!("{}: corrupted storage? oldest_height is 0 when check_txhashset_needed. state sync is needed", caller); + } + Ok(true) + } else { + Ok(false) } - return false; + } + + /// Clean the temporary sandbox folder + pub fn clean_txhashset_sandbox(&self) { + let sandbox_dir = env::temp_dir(); + txhashset::clean_txhashset_folder(&sandbox_dir); + txhashset::clean_header_folder(&sandbox_dir); } /// Writes a reading view on a txhashset state that's been provided to us. @@ -849,24 +869,27 @@ impl Chain { // Initial check whether this txhashset is needed or not let mut hashes: Option> = None; - if !self.check_txhashset_needed("txhashset_write".to_owned(), &mut hashes) { + if !self.check_txhashset_needed("txhashset_write".to_owned(), &mut hashes)? { warn!("txhashset_write: txhashset received but it's not needed! ignored."); return Err(ErrorKind::InvalidTxHashSet("not needed".to_owned()).into()); } let header = self.get_block_header(&h)?; - { - let mut txhashset_ref = self.txhashset.write(); - // Drop file handles in underlying txhashset - txhashset_ref.release_backend_files(); - } - - // Rewrite hashset - txhashset::zip_write(self.db_root.clone(), txhashset_data, &header)?; - - let mut txhashset = - txhashset::TxHashSet::open(self.db_root.clone(), self.store.clone(), Some(&header))?; + // Write txhashset to sandbox (in the os temporary directory) + let sandbox_dir = env::temp_dir(); + txhashset::clean_txhashset_folder(&sandbox_dir); + txhashset::clean_header_folder(&sandbox_dir); + txhashset::zip_write(sandbox_dir.clone(), txhashset_data.try_clone()?, &header)?; + + let mut txhashset = txhashset::TxHashSet::open( + sandbox_dir + .to_str() + .expect("invalid sandbox folder") + .to_owned(), + self.store.clone(), + Some(&header), + )?; // The txhashset.zip contains the output, rangeproof and kernel MMRs. // We must rebuild the header MMR ourselves based on the headers in our db. @@ -918,9 +941,28 @@ impl Chain { debug!("txhashset_write: finished committing the batch (head etc.)"); - // Replace the chain txhashset with the newly built one. + // Sandbox full validation ok, go to overwrite txhashset on db root { let mut txhashset_ref = self.txhashset.write(); + + // Before overwriting, drop file handlers in underlying txhashset + txhashset_ref.release_backend_files(); + + // Move sandbox to overwrite + txhashset.release_backend_files(); + txhashset::txhashset_replace(sandbox_dir.clone(), PathBuf::from(self.db_root.clone()))?; + + // Re-open on db root dir + txhashset = txhashset::TxHashSet::open( + self.db_root.clone(), + self.store.clone(), + Some(&header), + )?; + + self.rebuild_header_mmr(&Tip::from_header(&header), &mut txhashset)?; + txhashset::clean_header_folder(&sandbox_dir); + + // Replace the chain txhashset with the newly built one. *txhashset_ref = txhashset; } @@ -933,35 +975,22 @@ impl Chain { Ok(()) } - fn compact_txhashset(&self) -> Result<(), Error> { - debug!("Starting txhashset compaction..."); - { - // Note: We take a lock on the stop_state here and do not release it until - // we have finished processing this chain compaction operation. - let stop_lock = self.stop_state.lock(); - if stop_lock.is_stopped() { - return Err(ErrorKind::Stopped.into()); - } - - let mut txhashset = self.txhashset.write(); - txhashset.compact()?; - } - debug!("... finished txhashset compaction."); - Ok(()) - } - /// Cleanup old blocks from the db. /// Determine the cutoff height from the horizon and the current block height. /// *Only* runs if we are not in archive mode. - fn compact_blocks_db(&self) -> Result<(), Error> { + fn remove_historical_blocks( + &self, + txhashset: &txhashset::TxHashSet, + batch: &mut store::Batch<'_>, + ) -> Result<(), Error> { if self.archive_mode { return Ok(()); } let horizon = global::cut_through_horizon() as u64; - let head = self.head()?; + let head = batch.head()?; - let tail = match self.tail() { + let tail = match batch.tail() { Ok(tail) => tail, Err(_) => Tip::from_header(&self.genesis), }; @@ -969,7 +998,7 @@ impl Chain { let cutoff = head.height.saturating_sub(horizon); debug!( - "compact_blocks_db: head height: {}, tail height: {}, horizon: {}, cutoff: {}", + "remove_historical_blocks: head height: {}, tail height: {}, horizon: {}, cutoff: {}", head.height, tail.height, horizon, cutoff, ); @@ -979,10 +1008,11 @@ impl Chain { let mut count = 0; - let tail = self.get_header_by_height(head.height - horizon)?; - let mut current = self.get_header_by_height(head.height - horizon - 1)?; + let tail_hash = txhashset.get_header_hash_by_height(head.height - horizon)?; + let tail = batch.get_block_header(&tail_hash)?; - let batch = self.store.batch()?; + let current_hash = txhashset.get_header_hash_by_height(head.height - horizon - 1)?; + let mut current = batch.get_block_header(¤t_hash)?; loop { // Go to the store directly so we can handle NotFoundErr robustly. @@ -1010,11 +1040,12 @@ impl Chain { } } batch.save_body_tail(&Tip::from_header(&tail))?; - batch.commit()?; + debug!( - "compact_blocks_db: removed {} blocks. tail height: {}", + "remove_historical_blocks: removed {} blocks. tail height: {}", count, tail.height ); + Ok(()) } @@ -1024,12 +1055,35 @@ impl Chain { /// * removes historical blocks and associated data from the db (unless archive mode) /// pub fn compact(&self) -> Result<(), Error> { - self.compact_txhashset()?; + // Note: We take a lock on the stop_state here and do not release it until + // we have finished processing this chain compaction operation. + // We want to avoid shutting the node down in the middle of compacting the data. + let stop_lock = self.stop_state.lock(); + if stop_lock.is_stopped() { + return Err(ErrorKind::Stopped.into()); + } + // Take a write lock on the txhashet and start a new writeable db batch. + let mut txhashset = self.txhashset.write(); + let mut batch = self.store.batch()?; + + // Compact the txhashset itself (rewriting the pruned backend files). + txhashset.compact(&mut batch)?; + + // Rebuild our output_pos index in the db based on current UTXO set. + txhashset::extending(&mut txhashset, &mut batch, |extension| { + extension.rebuild_index()?; + Ok(()) + })?; + + // If we are not in archival mode remove historical blocks from the db. if !self.archive_mode { - self.compact_blocks_db()?; + self.remove_historical_blocks(&txhashset, &mut batch)?; } + // Commit all the above db changes. + batch.commit()?; + Ok(()) } @@ -1142,12 +1196,20 @@ impl Chain { } /// Gets the block header at the provided height. - /// Note: This takes a read lock on the txhashset. + /// Note: Takes a read lock on the txhashset. /// Take care not to call this repeatedly in a tight loop. pub fn get_header_by_height(&self, height: u64) -> Result { + let hash = self.get_header_hash_by_height(height)?; + self.get_block_header(&hash) + } + + /// Gets the header hash at the provided height. + /// Note: Takes a read lock on the txhashset. + /// Take care not to call this repeatedly in a tight loop. + fn get_header_hash_by_height(&self, height: u64) -> Result { let txhashset = self.txhashset.read(); - let header = txhashset.get_header_by_height(height)?; - Ok(header) + let hash = txhashset.get_header_hash_by_height(height)?; + Ok(hash) } /// Gets the block header in which a given output appears in the txhashset. @@ -1208,10 +1270,10 @@ impl Chain { /// Builds an iterator on blocks starting from the current chain head and /// running backward. Specialized to return information pertaining to block /// difficulty calculation (timestamp and previous difficulties). - pub fn difficulty_iter(&self) -> store::DifficultyIter<'_> { - let head = self.head().unwrap(); + pub fn difficulty_iter(&self) -> Result, Error> { + let head = self.head()?; let store = self.store.clone(); - store::DifficultyIter::from(head.last_block_h, store) + Ok(store::DifficultyIter::from(head.last_block_h, store)) } /// Check whether we have a block without reading it diff --git a/chain/src/error.rs b/chain/src/error.rs index b394044235..4ba115269e 100644 --- a/chain/src/error.rs +++ b/chain/src/error.rs @@ -89,9 +89,15 @@ pub enum ErrorKind { /// Error validating a Merkle proof (coinbase output) #[fail(display = "Error validating merkle proof")] MerkleProof, - /// output not found + /// Output not found #[fail(display = "Output not found")] OutputNotFound, + /// Rangeproof not found + #[fail(display = "Rangeproof not found")] + RangeproofNotFound, + /// Tx kernel not found + #[fail(display = "Tx kernel not found")] + TxKernelNotFound, /// output spent #[fail(display = "Output is spent")] OutputSpent, diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index 3fcc558386..a6db8fbaec 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -183,16 +183,21 @@ pub fn sync_block_headers( headers: &[BlockHeader], ctx: &mut BlockContext<'_>, ) -> Result, Error> { - if let Some(header) = headers.first() { - debug!( - "pipe: sync_block_headers: {} headers from {} at {}", - headers.len(), - header.hash(), - header.height, - ); - } else { - return Ok(None); - } + let first_header = match headers.first() { + Some(header) => { + debug!( + "pipe: sync_block_headers: {} headers from {} at {}", + headers.len(), + header.hash(), + header.height, + ); + header + } + None => { + error!("failed to get the first header"); + return Ok(None); + } + }; let all_known = if let Some(last_header) = headers.last() { ctx.batch.get_block_header(&last_header.hash()).is_ok() @@ -201,7 +206,6 @@ pub fn sync_block_headers( }; if !all_known { - let first_header = headers.first().unwrap(); let prev_header = ctx.batch.get_previous_header(&first_header)?; txhashset::sync_extending(&mut ctx.txhashset, &mut ctx.batch, |extension| { extension.rewind(&prev_header)?; diff --git a/chain/src/store.rs b/chain/src/store.rs index 972f4e56c0..fe75bbfd5f 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -50,12 +50,13 @@ impl ChainStore { } } -#[allow(missing_docs)] impl ChainStore { + /// The current chain head. pub fn head(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX]), "HEAD") } + /// The current chain "tail" (earliest block in the store). pub fn tail(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![TAIL_PREFIX]), "TAIL") } @@ -70,10 +71,12 @@ impl ChainStore { option_to_not_found(self.db.get_ser(&vec![HEADER_HEAD_PREFIX]), "HEADER_HEAD") } + /// The "sync" head. pub fn get_sync_head(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![SYNC_HEAD_PREFIX]), "SYNC_HEAD") } + /// Get full block. pub fn get_block(&self, h: &Hash) -> Result { option_to_not_found( self.db.get_ser(&to_key(BLOCK_PREFIX, &mut h.to_vec())), @@ -81,10 +84,12 @@ impl ChainStore { ) } + /// Does this full block exist? pub fn block_exists(&self, h: &Hash) -> Result { self.db.exists(&to_key(BLOCK_PREFIX, &mut h.to_vec())) } + /// Get block_sums for the block hash. pub fn get_block_sums(&self, h: &Hash) -> Result { option_to_not_found( self.db.get_ser(&to_key(BLOCK_SUMS_PREFIX, &mut h.to_vec())), @@ -92,10 +97,12 @@ impl ChainStore { ) } + /// Get previous header. pub fn get_previous_header(&self, header: &BlockHeader) -> Result { self.get_block_header(&header.prev_hash) } + /// Get block header. pub fn get_block_header(&self, h: &Hash) -> Result { option_to_not_found( self.db @@ -104,6 +111,7 @@ impl ChainStore { ) } + /// Get PMMR pos for the given output commitment. pub fn get_output_pos(&self, commit: &Commitment) -> Result { option_to_not_found( self.db @@ -126,12 +134,13 @@ pub struct Batch<'a> { db: store::Batch<'a>, } -#[allow(missing_docs)] impl<'a> Batch<'a> { + /// The head. pub fn head(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![HEAD_PREFIX]), "HEAD") } + /// The tail. pub fn tail(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![TAIL_PREFIX]), "TAIL") } @@ -146,27 +155,33 @@ impl<'a> Batch<'a> { option_to_not_found(self.db.get_ser(&vec![HEADER_HEAD_PREFIX]), "HEADER_HEAD") } + /// Get "sync" head. pub fn get_sync_head(&self) -> Result { option_to_not_found(self.db.get_ser(&vec![SYNC_HEAD_PREFIX]), "SYNC_HEAD") } + /// Save head to db. pub fn save_head(&self, t: &Tip) -> Result<(), Error> { self.db.put_ser(&vec![HEAD_PREFIX], t)?; self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t) } + /// Save body head to db. pub fn save_body_head(&self, t: &Tip) -> Result<(), Error> { self.db.put_ser(&vec![HEAD_PREFIX], t) } + /// Save body "tail" to db. pub fn save_body_tail(&self, t: &Tip) -> Result<(), Error> { self.db.put_ser(&vec![TAIL_PREFIX], t) } + /// Save header_head to db. pub fn save_header_head(&self, t: &Tip) -> Result<(), Error> { self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t) } + /// Save "sync" head to db. pub fn save_sync_head(&self, t: &Tip) -> Result<(), Error> { self.db.put_ser(&vec![SYNC_HEAD_PREFIX], t) } @@ -191,6 +206,7 @@ impl<'a> Batch<'a> { ) } + /// Does the block exist? pub fn block_exists(&self, h: &Hash) -> Result { self.db.exists(&to_key(BLOCK_PREFIX, &mut h.to_vec())) } @@ -224,6 +240,7 @@ impl<'a> Batch<'a> { Ok(()) } + /// Save block header to db. pub fn save_block_header(&self, header: &BlockHeader) -> Result<(), Error> { let hash = header.hash(); @@ -234,6 +251,7 @@ impl<'a> Batch<'a> { Ok(()) } + /// Save output_pos to index. pub fn save_output_pos(&self, commit: &Commitment, pos: u64) -> Result<(), Error> { self.db.put_ser( &to_key(COMMIT_POS_PREFIX, &mut commit.as_ref().to_vec())[..], @@ -241,6 +259,7 @@ impl<'a> Batch<'a> { ) } + /// Get output_pos from index. pub fn get_output_pos(&self, commit: &Commitment) -> Result { option_to_not_found( self.db @@ -249,15 +268,21 @@ impl<'a> Batch<'a> { ) } - pub fn delete_output_pos(&self, commit: &[u8]) -> Result<(), Error> { - self.db - .delete(&to_key(COMMIT_POS_PREFIX, &mut commit.to_vec())) + /// Clear all entries from the output_pos index (must be rebuilt after). + pub fn clear_output_pos(&self) -> Result<(), Error> { + let key = to_key(COMMIT_POS_PREFIX, &mut "".to_string().into_bytes()); + for (k, _) in self.db.iter::(&key)? { + self.db.delete(&k)?; + } + Ok(()) } + /// Get the previous header. pub fn get_previous_header(&self, header: &BlockHeader) -> Result { self.get_block_header(&header.prev_hash) } + /// Get block header. pub fn get_block_header(&self, h: &Hash) -> Result { option_to_not_found( self.db @@ -266,6 +291,7 @@ impl<'a> Batch<'a> { ) } + /// Save the input bitmap for the block. fn save_block_input_bitmap(&self, bh: &Hash, bm: &Bitmap) -> Result<(), Error> { self.db.put( &to_key(BLOCK_INPUT_BITMAP_PREFIX, &mut bh.to_vec())[..], @@ -273,16 +299,19 @@ impl<'a> Batch<'a> { ) } + /// Delete the block input bitmap. fn delete_block_input_bitmap(&self, bh: &Hash) -> Result<(), Error> { self.db .delete(&to_key(BLOCK_INPUT_BITMAP_PREFIX, &mut bh.to_vec())) } + /// Save block_sums for the block. pub fn save_block_sums(&self, h: &Hash, sums: &BlockSums) -> Result<(), Error> { self.db .put_ser(&to_key(BLOCK_SUMS_PREFIX, &mut h.to_vec())[..], &sums) } + /// Get block_sums for the block. pub fn get_block_sums(&self, h: &Hash) -> Result { option_to_not_found( self.db.get_ser(&to_key(BLOCK_SUMS_PREFIX, &mut h.to_vec())), @@ -290,10 +319,12 @@ impl<'a> Batch<'a> { ) } + /// Delete the block_sums for the block. fn delete_block_sums(&self, bh: &Hash) -> Result<(), Error> { self.db.delete(&to_key(BLOCK_SUMS_PREFIX, &mut bh.to_vec())) } + /// Build the input bitmap for the given block. fn build_block_input_bitmap(&self, block: &Block) -> Result { let bitmap = block .inputs() @@ -304,6 +335,7 @@ impl<'a> Batch<'a> { Ok(bitmap) } + /// Build and store the input bitmap for the given block. fn build_and_store_block_input_bitmap(&self, block: &Block) -> Result { // Build the bitmap. let bitmap = self.build_block_input_bitmap(block)?; @@ -314,8 +346,8 @@ impl<'a> Batch<'a> { Ok(bitmap) } - // Get the block input bitmap from the db or build the bitmap from - // the full block from the db (if the block is found). + /// Get the block input bitmap from the db or build the bitmap from + /// the full block from the db (if the block is found). pub fn get_block_input_bitmap(&self, bh: &Hash) -> Result { if let Ok(Some(bytes)) = self .db diff --git a/chain/src/txhashset/txhashset.rs b/chain/src/txhashset/txhashset.rs index 6d547ee62d..fc66479080 100644 --- a/chain/src/txhashset/txhashset.rs +++ b/chain/src/txhashset/txhashset.rs @@ -32,13 +32,12 @@ use crate::util::secp::pedersen::{Commitment, RangeProof}; use crate::util::{file, secp_static, zip}; use croaring::Bitmap; use grin_store; -use grin_store::pmmr::{clean_files_by_prefix, PMMRBackend, PMMR_FILES}; -use grin_store::types::prune_noop; +use grin_store::pmmr::{PMMRBackend, PMMR_FILES}; use std::collections::HashSet; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use std::time::Instant; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; const HEADERHASHSET_SUBDIR: &'static str = "header"; const TXHASHSET_SUBDIR: &'static str = "txhashset"; @@ -67,7 +66,10 @@ impl PMMRHandle { ) -> Result, Error> { let path = Path::new(root_dir).join(sub_dir).join(file_name); fs::create_dir_all(path.clone())?; - let backend = PMMRBackend::new(path.to_str().unwrap().to_string(), prunable, header)?; + let path_str = path.to_str().ok_or(Error::from(ErrorKind::Other( + "invalid file path".to_owned(), + )))?; + let backend = PMMRBackend::new(path_str.to_string(), prunable, header)?; let last_pos = backend.unpruned_size(); Ok(PMMRHandle { backend, last_pos }) } @@ -206,21 +208,27 @@ impl TxHashSet { .get_last_n_insertions(distance) } - /// Get the header at the specified height based on the current state of the txhashset. - /// Derives the MMR pos from the height (insertion index) and retrieves the header hash. - /// Looks the header up in the db by hash. - pub fn get_header_by_height(&self, height: u64) -> Result { + /// Get the header hash at the specified height based on the current state of the txhashset. + pub fn get_header_hash_by_height(&self, height: u64) -> Result { let pos = pmmr::insertion_to_pmmr_index(height + 1); let header_pmmr = ReadonlyPMMR::at(&self.header_pmmr_h.backend, self.header_pmmr_h.last_pos); if let Some(entry) = header_pmmr.get_data(pos) { - let header = self.commit_index.get_block_header(&entry.hash())?; - Ok(header) + Ok(entry.hash()) } else { - Err(ErrorKind::Other(format!("get header by height")).into()) + Err(ErrorKind::Other(format!("get header hash by height")).into()) } } + /// Get the header at the specified height based on the current state of the txhashset. + /// Derives the MMR pos from the height (insertion index) and retrieves the header hash. + /// Looks the header up in the db by hash. + pub fn get_header_by_height(&self, height: u64) -> Result { + let hash = self.get_header_hash_by_height(height)?; + let header = self.commit_index.get_block_header(&hash)?; + Ok(header) + } + /// returns outputs from the given insertion (leaf) index up to the /// specified limit. Also returns the last index actually populated pub fn outputs_by_insertion_index( @@ -280,39 +288,30 @@ impl TxHashSet { } /// Compact the MMR data files and flush the rm logs - pub fn compact(&mut self) -> Result<(), Error> { - let commit_index = self.commit_index.clone(); - let head_header = commit_index.head_header()?; + pub fn compact(&mut self, batch: &mut Batch<'_>) -> Result<(), Error> { + debug!("txhashset: starting compaction..."); + + let head_header = batch.head_header()?; let current_height = head_header.height; // horizon for compacting is based on current_height - let horizon = current_height.saturating_sub(global::cut_through_horizon().into()); - let horizon_header = self.get_header_by_height(horizon)?; + let horizon_height = current_height.saturating_sub(global::cut_through_horizon().into()); + let horizon_hash = self.get_header_hash_by_height(horizon_height)?; + let horizon_header = batch.get_block_header(&horizon_hash)?; - let batch = self.commit_index.batch()?; + let rewind_rm_pos = input_pos_to_rewind(&horizon_header, &head_header, batch)?; - let rewind_rm_pos = input_pos_to_rewind(&horizon_header, &head_header, &batch)?; + debug!("txhashset: check_compact output mmr backend..."); + self.output_pmmr_h + .backend + .check_compact(horizon_header.output_mmr_size, &rewind_rm_pos)?; - { - let clean_output_index = |commit: &[u8]| { - let _ = batch.delete_output_pos(commit); - }; - - self.output_pmmr_h.backend.check_compact( - horizon_header.output_mmr_size, - &rewind_rm_pos, - clean_output_index, - )?; - - self.rproof_pmmr_h.backend.check_compact( - horizon_header.output_mmr_size, - &rewind_rm_pos, - &prune_noop, - )?; - } + debug!("txhashset: check_compact rangeproof mmr backend..."); + self.rproof_pmmr_h + .backend + .check_compact(horizon_header.output_mmr_size, &rewind_rm_pos)?; - // Finally commit the batch, saving everything to the db. - batch.commit()?; + debug!("txhashset: ... compaction finished"); Ok(()) } @@ -797,11 +796,9 @@ impl<'a> Committed for Extension<'a> { fn outputs_committed(&self) -> Vec { let mut commitments = vec![]; - for n in 1..self.output_pmmr.unpruned_size() + 1 { - if pmmr::is_leaf(n) { - if let Some(out) = self.output_pmmr.get_data(n) { - commitments.push(out.commit); - } + for pos in self.output_pmmr.leaf_pos_iter() { + if let Some(out) = self.output_pmmr.get_data(pos) { + commitments.push(out.commit); } } commitments @@ -1259,20 +1256,18 @@ impl<'a> Extension<'a> { pub fn rebuild_index(&self) -> Result<(), Error> { let now = Instant::now(); - let mut count = 0; + self.batch.clear_output_pos()?; - for n in 1..self.output_pmmr.unpruned_size() + 1 { - // non-pruned leaves only - if pmmr::bintree_postorder_height(n) == 0 { - if let Some(out) = self.output_pmmr.get_data(n) { - self.batch.save_output_pos(&out.commit, n)?; - count += 1; - } + let mut count = 0; + for pos in self.output_pmmr.leaf_pos_iter() { + if let Some(out) = self.output_pmmr.get_data(pos) { + self.batch.save_output_pos(&out.commit, pos)?; + count += 1; } } debug!( - "txhashset: rebuild_index ({} UTXOs), took {}s", + "txhashset: rebuild_index: {} UTXOs, took {}s", count, now.elapsed().as_secs(), ); @@ -1325,13 +1320,23 @@ impl<'a> Extension<'a> { let total_kernels = pmmr::n_leaves(self.kernel_pmmr.unpruned_size()); for n in 1..self.kernel_pmmr.unpruned_size() + 1 { if pmmr::is_leaf(n) { - if let Some(kernel) = self.kernel_pmmr.get_data(n) { - kernel.verify()?; - kern_count += 1; + let kernel = self + .kernel_pmmr + .get_data(n) + .ok_or::(ErrorKind::TxKernelNotFound.into())?; + + kernel.verify()?; + kern_count += 1; + + if kern_count % 20 == 0 { + status.on_validation(kern_count, total_kernels, 0, 0); + } + if kern_count % 1_000 == 0 { + debug!( + "txhashset: verify_kernel_signatures: verified {} signatures", + kern_count, + ); } - } - if n % 20 == 0 { - status.on_validation(kern_count, total_kernels, 0, 0); } } @@ -1353,30 +1358,34 @@ impl<'a> Extension<'a> { let mut proof_count = 0; let total_rproofs = pmmr::n_leaves(self.output_pmmr.unpruned_size()); - for n in 1..self.output_pmmr.unpruned_size() + 1 { - if pmmr::is_leaf(n) { - if let Some(out) = self.output_pmmr.get_data(n) { - if let Some(rp) = self.rproof_pmmr.get_data(n) { - commits.push(out.commit); - proofs.push(rp); - } else { - // TODO - rangeproof not found - return Err(ErrorKind::OutputNotFound.into()); - } - proof_count += 1; - - if proofs.len() >= 1000 { - Output::batch_verify_proofs(&commits, &proofs)?; - commits.clear(); - proofs.clear(); - debug!( - "txhashset: verify_rangeproofs: verified {} rangeproofs", - proof_count, - ); - } + for pos in self.output_pmmr.leaf_pos_iter() { + let output = self.output_pmmr.get_data(pos); + let proof = self.rproof_pmmr.get_data(pos); + + // Output and corresponding rangeproof *must* exist. + // It is invalid for either to be missing and we fail immediately in this case. + match (output, proof) { + (None, _) => return Err(ErrorKind::OutputNotFound.into()), + (_, None) => return Err(ErrorKind::RangeproofNotFound.into()), + (Some(output), Some(proof)) => { + commits.push(output.commit); + proofs.push(proof); } } - if n % 20 == 0 { + + proof_count += 1; + + if proofs.len() >= 1_000 { + Output::batch_verify_proofs(&commits, &proofs)?; + commits.clear(); + proofs.clear(); + debug!( + "txhashset: verify_rangeproofs: verified {} rangeproofs", + proof_count, + ); + } + + if proof_count % 20 == 0 { status.on_validation(0, 0, proof_count, total_rproofs); } } @@ -1404,38 +1413,22 @@ impl<'a> Extension<'a> { /// Packages the txhashset data files into a zip and returns a Read to the /// resulting file -pub fn zip_read(root_dir: String, header: &BlockHeader) -> Result { - let txhashset_zip = format!("{}_{}.zip", TXHASHSET_ZIP, header.hash().to_string()); +pub fn zip_read(root_dir: String, header: &BlockHeader, rand: Option) -> Result { + let ts = if let None = rand { + let now = SystemTime::now(); + now.duration_since(UNIX_EPOCH).unwrap().subsec_micros() + } else { + rand.unwrap() + }; + let txhashset_zip = format!("{}_{}.zip", TXHASHSET_ZIP, ts); let txhashset_path = Path::new(&root_dir).join(TXHASHSET_SUBDIR); let zip_path = Path::new(&root_dir).join(txhashset_zip); - - // if file exist, just re-use it - let zip_file = File::open(zip_path.clone()); - if let Ok(zip) = zip_file { - return Ok(zip); - } else { - // clean up old zips. - // Theoretically, we only need clean-up those zip files older than STATE_SYNC_THRESHOLD. - // But practically, these zip files are not small ones, we just keep the zips in last one hour - let data_dir = Path::new(&root_dir); - let pattern = format!("{}_", TXHASHSET_ZIP); - if let Ok(n) = clean_files_by_prefix(data_dir.clone(), &pattern, 60 * 60) { - debug!( - "{} zip files have been clean up in folder: {:?}", - n, data_dir - ); - } - } - - // otherwise, create the zip archive - let path_to_be_cleanup = { + // create the zip archive + { // Temp txhashset directory - let temp_txhashset_path = Path::new(&root_dir).join(format!( - "{}_zip_{}", - TXHASHSET_SUBDIR, - header.hash().to_string() - )); + let temp_txhashset_path = + Path::new(&root_dir).join(format!("{}_zip_{}", TXHASHSET_SUBDIR, ts)); // Remove temp dir if it exist if temp_txhashset_path.exists() { fs::remove_dir_all(&temp_txhashset_path)?; @@ -1447,38 +1440,70 @@ pub fn zip_read(root_dir: String, header: &BlockHeader) -> Result { // Compress zip zip::compress(&temp_txhashset_path, &File::create(zip_path.clone())?) .map_err(|ze| ErrorKind::Other(ze.to_string()))?; - - temp_txhashset_path - }; + } // open it again to read it back - let zip_file = File::open(zip_path.clone())?; - - // clean-up temp txhashset directory. - if let Err(e) = fs::remove_dir_all(&path_to_be_cleanup) { - warn!( - "txhashset zip file: {:?} fail to remove, err: {}", - zip_path.to_str(), - e - ); - } + let zip_file = File::open(zip_path)?; Ok(zip_file) } /// Extract the txhashset data from a zip file and writes the content into the /// txhashset storage dir pub fn zip_write( - root_dir: String, + root_dir: PathBuf, txhashset_data: File, header: &BlockHeader, ) -> Result<(), Error> { - let txhashset_path = Path::new(&root_dir).join(TXHASHSET_SUBDIR); + debug!("zip_write on path: {:?}", root_dir); + let txhashset_path = root_dir.clone().join(TXHASHSET_SUBDIR); fs::create_dir_all(txhashset_path.clone())?; zip::decompress(txhashset_data, &txhashset_path, expected_file) .map_err(|ze| ErrorKind::Other(ze.to_string()))?; check_and_remove_files(&txhashset_path, header) } +/// Overwrite txhashset folders in "to" folder with "from" folder +pub fn txhashset_replace(from: PathBuf, to: PathBuf) -> Result<(), Error> { + debug!("txhashset_replace: move from {:?} to {:?}", from, to); + + // clean the 'to' folder firstly + clean_txhashset_folder(&to); + + // rename the 'from' folder as the 'to' folder + if let Err(e) = fs::rename( + from.clone().join(TXHASHSET_SUBDIR), + to.clone().join(TXHASHSET_SUBDIR), + ) { + error!("hashset_replace fail on {}. err: {}", TXHASHSET_SUBDIR, e); + Err(ErrorKind::TxHashSetErr(format!("txhashset replacing fail")).into()) + } else { + Ok(()) + } +} + +/// Clean the txhashset folder +pub fn clean_txhashset_folder(root_dir: &PathBuf) { + let txhashset_path = root_dir.clone().join(TXHASHSET_SUBDIR); + if txhashset_path.exists() { + if let Err(e) = fs::remove_dir_all(txhashset_path.clone()) { + warn!( + "clean_txhashset_folder: fail on {:?}. err: {}", + txhashset_path, e + ); + } + } +} + +/// Clean the header folder +pub fn clean_header_folder(root_dir: &PathBuf) { + let header_path = root_dir.clone().join(HEADERHASHSET_SUBDIR); + if header_path.exists() { + if let Err(e) = fs::remove_dir_all(header_path.clone()) { + warn!("clean_header_folder: fail on {:?}. err: {}", header_path, e); + } + } +} + fn expected_file(path: &Path) -> bool { use lazy_static::lazy_static; use regex::Regex; @@ -1491,7 +1516,7 @@ fn expected_file(path: &Path) -> bool { ) .as_str() ) - .unwrap(); + .expect("invalid txhashset regular expression"); } RE.is_match(&s_path) } @@ -1530,7 +1555,7 @@ fn check_and_remove_files(txhashset_path: &PathBuf, header: &BlockHeader) -> Res } // Then compare the files found in the subdirectories - let mut pmmr_files_expected: HashSet<_> = PMMR_FILES + let pmmr_files_expected: HashSet<_> = PMMR_FILES .iter() .cloned() .map(|s| { @@ -1541,8 +1566,6 @@ fn check_and_remove_files(txhashset_path: &PathBuf, header: &BlockHeader) -> Res } }) .collect(); - // prevent checker from deleting 3 dot file, could be removed after mainnet - pmmr_files_expected.insert(format!("pmmr_leaf.bin.{}...", header.hash())); let subdirectories = fs::read_dir(txhashset_path)?; for subdirectory in subdirectories { diff --git a/chain/tests/data_file_integrity.rs b/chain/tests/data_file_integrity.rs index 7b384a2c85..49eb6e5a08 100644 --- a/chain/tests/data_file_integrity.rs +++ b/chain/tests/data_file_integrity.rs @@ -76,7 +76,7 @@ fn data_files() { for n in 1..4 { let prev = chain.head_header().unwrap(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap(); let mut b = diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index fa448e7d6b..2d090d7a7b 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -98,7 +98,7 @@ where for n in 1..4 { let prev = chain.head_header().unwrap(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let reward = libtx::reward::output(keychain, &pk, 0, false).unwrap(); let mut b = @@ -406,7 +406,7 @@ fn output_header_mappings() { for n in 1..15 { let prev = chain.head_header().unwrap(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier(); let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap(); reward_outputs.push(reward.0.clone()); @@ -540,7 +540,7 @@ fn actual_diff_iter_output() { Arc::new(Mutex::new(StopState::new())), ) .unwrap(); - let iter = chain.difficulty_iter(); + let iter = chain.difficulty_iter().unwrap(); let mut last_time = 0; let mut first = true; for elem in iter.into_iter() { diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index 5eb047d666..a74bf40856 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -63,7 +63,7 @@ fn test_coinbase_maturity() { let key_id3 = ExtKeychainPath::new(1, 3, 0, 0, 0).to_identifier(); let key_id4 = ExtKeychainPath::new(1, 4, 0, 0, 0).to_identifier(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let reward = libtx::reward::output(&keychain, &key_id1, 0, false).unwrap(); let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap(); block.header.timestamp = prev.timestamp + Duration::seconds(60); @@ -110,7 +110,7 @@ fn test_coinbase_maturity() { let fees = txs.iter().map(|tx| tx.fee()).sum(); let reward = libtx::reward::output(&keychain, &key_id3, fees, false).unwrap(); let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.pow.secondary_scaling = next_header_info.secondary_scaling; @@ -144,7 +144,7 @@ fn test_coinbase_maturity() { let reward = libtx::reward::output(&keychain, &pk, 0, false).unwrap(); let mut block = core::core::Block::new(&prev, vec![], Difficulty::min(), reward).unwrap(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); block.header.timestamp = prev.timestamp + Duration::seconds(60); block.header.pow.secondary_scaling = next_header_info.secondary_scaling; @@ -169,7 +169,7 @@ fn test_coinbase_maturity() { let txs = vec![coinbase_txn]; let fees = txs.iter().map(|tx| tx.fee()).sum(); - let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()); + let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let reward = libtx::reward::output(&keychain, &key_id4, fees, false).unwrap(); let mut block = core::core::Block::new(&prev, txs, Difficulty::min(), reward).unwrap(); diff --git a/chain/tests/test_txhashset.rs b/chain/tests/test_txhashset.rs index 6d81a18b84..441d1d9f45 100644 --- a/chain/tests/test_txhashset.rs +++ b/chain/tests/test_txhashset.rs @@ -22,6 +22,7 @@ use std::fs::{self, File, OpenOptions}; use std::iter::FromIterator; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; use crate::chain::store::ChainStore; use crate::chain::txhashset; @@ -35,6 +36,9 @@ fn clean_output_dir(dir_name: &str) { #[test] fn test_unexpected_zip() { + let now = SystemTime::now(); + let rand = now.duration_since(UNIX_EPOCH).unwrap().subsec_micros(); + let db_root = format!(".grin_txhashset_zip"); clean_output_dir(&db_root); let chain_store = ChainStore::new(&db_root).unwrap(); @@ -42,13 +46,15 @@ fn test_unexpected_zip() { txhashset::TxHashSet::open(db_root.clone(), store.clone(), None).unwrap(); let head = BlockHeader::default(); // First check if everything works out of the box - assert!(txhashset::zip_read(db_root.clone(), &head).is_ok()); - let zip_path = Path::new(&db_root).join(format!( - "txhashset_snapshot_{}.zip", - head.hash().to_string() - )); + assert!(txhashset::zip_read(db_root.clone(), &head, Some(rand)).is_ok()); + let zip_path = Path::new(&db_root).join(format!("txhashset_snapshot_{}.zip", rand)); let zip_file = File::open(&zip_path).unwrap(); - assert!(txhashset::zip_write(db_root.clone(), zip_file, &head).is_ok()); + assert!(txhashset::zip_write( + PathBuf::from(db_root.clone()), + zip_file, + &BlockHeader::default() + ) + .is_ok()); // Remove temp txhashset dir assert!(fs::remove_dir_all( Path::new(&db_root).join(format!("txhashset_zip_{}", head.hash().to_string())) @@ -56,7 +62,7 @@ fn test_unexpected_zip() { .is_err()); // Then add strange files in the original txhashset folder write_file(db_root.clone()); - assert!(txhashset::zip_read(db_root.clone(), &head).is_ok()); + assert!(txhashset::zip_read(db_root.clone(), &head, Some(rand)).is_ok()); // Check that the temp dir dos not contains the strange files let txhashset_zip_path = Path::new(&db_root).join(format!("txhashset_zip_{}", head.hash().to_string())); @@ -70,7 +76,12 @@ fn test_unexpected_zip() { .is_err()); let zip_file = File::open(zip_path).unwrap(); - assert!(txhashset::zip_write(db_root.clone(), zip_file, &head).is_ok()); + assert!(txhashset::zip_write( + PathBuf::from(db_root.clone()), + zip_file, + &BlockHeader::default() + ) + .is_ok()); // Check that the txhashset dir dos not contains the strange files let txhashset_path = Path::new(&db_root).join("txhashset"); assert!(txhashset_contains_expected_files( diff --git a/config/Cargo.toml b/config/Cargo.toml index 601801178d..37aebf201a 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_config" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Configuration for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -16,10 +16,10 @@ serde_derive = "1" toml = "0.4" dirs = "1.0.3" -grin_core = { path = "../core", version = "1.1.0" } -grin_servers = { path = "../servers", version = "1.1.0" } -grin_p2p = { path = "../p2p", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_servers = { path = "../servers", version = "1.1.0-beta.1" } +grin_p2p = { path = "../p2p", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] pretty_assertions = "0.5.1" diff --git a/config/src/comments.rs b/config/src/comments.rs index b5e3f6d970..3409dbcaf2 100644 --- a/config/src/comments.rs +++ b/config/src/comments.rs @@ -413,6 +413,14 @@ fn comments() -> HashMap { .to_string(), ); + retval.insert( + "log_max_files".to_string(), + " +#maximum count of the log files to rotate over +" + .to_string(), + ); + retval } diff --git a/core/Cargo.toml b/core/Cargo.toml index 29079b7511..304c01d748 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_core" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -28,8 +28,8 @@ uuid = { version = "0.6", features = ["serde", "v4"] } log = "0.4" chrono = { version = "0.4.4", features = ["serde"] } -grin_keychain = { path = "../keychain", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_keychain = { path = "../keychain", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] serde_json = "1" diff --git a/core/src/core.rs b/core/src/core.rs index d761bb7517..009236ea68 100644 --- a/core/src/core.rs +++ b/core/src/core.rs @@ -95,9 +95,9 @@ pub fn amount_to_hr_string(amount: u64, truncate: bool) -> String { if truncate { let nzeros = hr.chars().rev().take_while(|x| x == &'0').count(); if nzeros < *WIDTH { - return hr.trim_right_matches('0').to_string(); + return hr.trim_end_matches('0').to_string(); } else { - return format!("{}0", hr.trim_right_matches('0')); + return format!("{}0", hr.trim_end_matches('0')); } } hr diff --git a/core/src/core/pmmr/backend.rs b/core/src/core/pmmr/backend.rs index e4e0e9d270..c92dd7f317 100644 --- a/core/src/core/pmmr/backend.rs +++ b/core/src/core/pmmr/backend.rs @@ -51,6 +51,9 @@ pub trait Backend { /// (ignoring the remove log). fn get_data_from_file(&self, position: u64) -> Option; + /// Iterator over current (unpruned, unremoved) leaf positions. + fn leaf_pos_iter(&self) -> Box + '_>; + /// Remove Hash by insertion position. An index is also provided so the /// underlying backend can implement some rollback of positions up to a /// given index (practically the index is the height of a block that diff --git a/core/src/core/pmmr/pmmr.rs b/core/src/core/pmmr/pmmr.rs index 6df1a46f66..7367f0eef2 100644 --- a/core/src/core/pmmr/pmmr.rs +++ b/core/src/core/pmmr/pmmr.rs @@ -75,6 +75,11 @@ where ReadonlyPMMR::at(&self.backend, self.last_pos) } + /// Iterator over current (unpruned, unremoved) leaf positions. + pub fn leaf_pos_iter(&self) -> impl Iterator + '_ { + self.backend.leaf_pos_iter() + } + /// Returns a vec of the peaks of this MMR. pub fn peaks(&self) -> Vec { let peaks_pos = peaks(self.last_pos); diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 95c5cc7abe..0ff9779bf9 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -1242,10 +1242,7 @@ impl Readable for OutputFeatures { /// Output for a transaction, defining the new ownership of coins that are being /// transferred. The commitment is a blinded value for the output while the /// range proof guarantees the commitment includes a positive value without -/// overflow and the ownership of the private key. The switch commitment hash -/// provides future-proofing against quantum-based attacks, as well as providing -/// wallet implementations with a way to identify their outputs for wallet -/// reconstruction. +/// overflow and the ownership of the private key. #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct Output { /// Options for an output's structure or use diff --git a/core/src/libtx/build.rs b/core/src/libtx/build.rs index 7ed3b2ec81..0930623fc9 100644 --- a/core/src/libtx/build.rs +++ b/core/src/libtx/build.rs @@ -34,7 +34,8 @@ pub struct Context<'a, K> where K: Keychain, { - keychain: &'a K, + /// The keychain used for key derivation + pub keychain: &'a K, } /// Function type returned by the transaction combinators. Transforms a diff --git a/core/src/libtx/proof.rs b/core/src/libtx/proof.rs index 8a523dd634..cc0a6bb503 100644 --- a/core/src/libtx/proof.rs +++ b/core/src/libtx/proof.rs @@ -14,29 +14,12 @@ //! Rangeproof library functions -use crate::blake2; use crate::keychain::{Identifier, Keychain}; use crate::libtx::error::{Error, ErrorKind}; use crate::util::secp::key::SecretKey; use crate::util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof}; use crate::util::secp::{self, Secp256k1}; -fn create_nonce(k: &K, commit: &Commitment) -> Result -where - K: Keychain, -{ - // hash(commit|wallet root secret key (m)) as nonce - let root_key = k.derive_key(0, &K::root_key_id())?; - let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.0[..]); - let res = res.as_bytes(); - match SecretKey::from_slice(k.secp(), &res) { - Ok(sk) => Ok(sk), - Err(e) => Err(ErrorKind::RangeProof( - format!("Unable to create nonce: {:?}", e).to_string(), - ))?, - } -} - /// Create a bulletproof pub fn create( k: &K, @@ -50,7 +33,9 @@ where { let commit = k.commit(amount, key_id)?; let skey = k.derive_key(amount, key_id)?; - let nonce = create_nonce(k, &commit)?; + let nonce = k + .create_nonce(&commit) + .map_err(|e| ErrorKind::RangeProof(e.to_string()))?; let message = ProofMessage::from_bytes(&key_id.serialize_path()); Ok(k.secp() .bullet_proof(amount, skey, nonce, extra_data, Some(message))) @@ -80,7 +65,9 @@ pub fn rewind( where K: Keychain, { - let nonce = create_nonce(k, &commit)?; + let nonce = k + .create_nonce(&commit) + .map_err(|e| ErrorKind::RangeProof(e.to_string()))?; let proof_message = k .secp() .rewind_bullet_proof(commit, nonce, extra_data, proof); diff --git a/core/tests/vec_backend.rs b/core/tests/vec_backend.rs index e7bae7cba8..73f5e3a7e4 100644 --- a/core/tests/vec_backend.rs +++ b/core/tests/vec_backend.rs @@ -104,6 +104,10 @@ impl Backend for VecBackend { Some(data.as_elmt()) } + fn leaf_pos_iter(&self) -> Box + '_> { + unimplemented!() + } + fn remove(&mut self, position: u64) -> Result<(), String> { self.remove_list.push(position); Ok(()) diff --git a/doc/api/node_api.md b/doc/api/node_api.md index 1071ddc77a..8529038a0a 100644 --- a/doc/api/node_api.md +++ b/doc/api/node_api.md @@ -9,7 +9,7 @@ 1. [Chain Endpoint](#chain-endpoint) 1. [GET Chain](#get-chain) 1. [POST Chain Compact](#post-chain-compact) - 1. [POST Chain Validate](#post-chain-validate) + 1. [GET Chain Validate](#get-chain-validate) 1. [GET Chain Outputs by IDs](#get-chain-outputs-by-ids) 1. [GET Chain Outputs by Height](#get-chain-outputs-by-height) 1. [Status Endpoint](#status-endpoint) @@ -282,7 +282,7 @@ Trigger a compaction of the chain state to regain storage space. }); ``` -### POST Chain Validate +### GET Chain Validate Trigger a validation of the chain state. @@ -292,7 +292,7 @@ Trigger a validation of the chain state. * **Method:** - `POST` + `GET` * **URL Params** @@ -316,7 +316,7 @@ Trigger a validation of the chain state. $.ajax({ url: "/v1/chain/validate", dataType: "json", - type : "POST", + type : "GET", success : function(r) { console.log(r); } diff --git a/doc/api/wallet_owner_api.md b/doc/api/wallet_owner_api.md index 70562de089..25c26f5802 100644 --- a/doc/api/wallet_owner_api.md +++ b/doc/api/wallet_owner_api.md @@ -108,7 +108,7 @@ Attempt to update and retrieve outputs. * **Success Response:** * **Code:** 200 - * **Content:** Array of + * **Content:** All listed amounts in nanogrin. Array of | Field | Type | Description | |:----------------------------------|:---------|:----------------------------------------| @@ -341,7 +341,7 @@ Send a transaction either directly by http or file (then display the slate) | Field | Type | Description | |:------------------------------|:---------|:-------------------------------------| - | amount | number | Amount to send | + | amount | number | Amount to send (in nanogrin) | | minimum_confirmations | number | Minimum confirmations | | method | string | Payment method | | dest | string | Destination url | diff --git a/doc/build.md b/doc/build.md index e658c4aa15..1cea9b9793 100644 --- a/doc/build.md +++ b/doc/build.md @@ -1,6 +1,6 @@ # Grin - Build, Configuration, and Running -*Read this in other languages: [Español](build_ES.md).* +*Read this in other languages: [Español](build_ES.md), [Korean](build_KR.md), [日本語](build_JP.md).* ## Supported Platforms @@ -115,7 +115,7 @@ You can bind-mount your grin cache to run inside the container. docker run -it -d -v $HOME/.grin:/root/.grin grin ``` If you prefer to use a docker named volume, you can pass `-v dotgrin:/root/.grin` instead. -Using a named volume copies default configurations upon volume creation +Using a named volume copies default configurations upon volume creation. ## Cross-platform builds diff --git a/doc/build_JP.md b/doc/build_JP.md new file mode 100644 index 0000000000..9b9db1066e --- /dev/null +++ b/doc/build_JP.md @@ -0,0 +1,129 @@ +# grin - ビルド、設定、動作確認 + +*Read this in other languages: [Español](build_ES.md), [Korean](build_KR.md), [日本語](build_JP.md).* + +## 動作環境 + +grinのプログラミング言語である`rust`はほぼ全ての環境に対応している。 + +現在の動作環境 + +* Linux x86\_64とmacOS [grin、マイニング、開発] +* Windows 10は未対応 [一部のビルドはできるがマイニングがまだ。助けを募集中!] + +## 要件 + +* rust 1.31+ ([rustup]((https://www.rustup.rs/))を使えば`curl https://sh.rustup.rs -sSf | sh; source $HOME/.cargo/env`でインストール可) + * rustをインストール済みの場合は`rustup update`を実行 +* clang +* ncursesとそのライブラリ (ncurses, ncursesw5) +* zlibとそのライブラリ (zlib1g-dev または zlib-devel) +* pkg-config +* libssl-dev +* linux-headers (Alpine linuxでは必要) +* llvm + +Debianベースのディストリビューション(Debian、Ubuntu、Mintなど)ではrustを除き1コマンドでインストールできる: + +```sh +apt install build-essential cmake git libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config libssl-dev llvm +``` + +Mac: + +```sh +xcode-select --install +brew install --with-toolchain llvm +brew install pkg-config +brew install openssl +``` + +## ビルド手順 + +```sh +git clone https://github.com/mimblewimble/grin.git +cd grin +cargo build --release +``` + +grinはデバッグモードでもビルド可能(`--release`を付けない状態で、`--debug`か`--verbose`を付ける)。 +しかし暗号の計算のオーバーヘッドが大きく、高速同期が著しく遅くなる。 + +## ビルドエラー + +[Troubleshooting](https://github.com/mimblewimble/docs/wiki/Troubleshooting) + +## 何がビルドされるか + +ビルドの成果物 + +* `target/release/grin` - grinの実行ファイル + +grinのデータ、設定ファイル、ログファイルはデフォルトでは(ホームディレクトリ配下の)`~/.grin`のディレクトリに格納されている。 +全ての設定値は`~/.grin/main/grin-server.toml`を編集することで変更可能。 + +データファイルをカレントディレクトリに出力することも可能。 +そのためには以下のコマンドを実行。 + +```sh +grin server config +``` + +カレントディレクトリに`grin-server.toml`がある場合、カレントディレクトリにデータが出力される。 +grinを`grin-server.toml`を含むディレクトリで起動する場合、デフォルトである`~/.grin/main/grin-server.toml`よりも優先される。 + +テスト中はgrinのバイナリにpathを通す: + +```sh +export PATH=`pwd`/target/release:$PATH +``` + +ただし、grinをインストールしたルートディレクトリから実行することを想定している。 + +これにより`grin`が直接実行可能になる(オプションは`grin help`で調べられる)。 + +## 設定 + +grinは気の利いたデフォルト設定で起動するようになっており、さらに`grin-server.toml`のファイルを通じて設定可能。 +このファイルはgrinの初回起動で作成され、利用可能なオプションに関するドキュメントを含んでいる。 + +`grin-server.toml`を通じて設定することが推奨されるが、全ての設定はコマンドラインで上書きすることも可能。 + +コマンドライン関連のヘルプについてはこちらを実行: + +```sh +grin help +grin wallet help +grin client help +``` + +## Docker + +```sh +docker build -t grin -f etc/Dockerfile . +``` +floonetを使用する場合、代わりに`etc/Dockerfile.floonet`を指定。 + +コンテナ内で実行する場合、grinのキャッシュをバインドマウントすることも可能。 + +```sh +docker run -it -d -v $HOME/.grin:/root/.grin grin +``` +dockerの名前付きボリュームを使用する場合、代わりに`-v dotgrin:/root/.grin`を指定。 +ボリュームが作成される前に、名前付きボリュームがコピーされる。 + +## クロスプラットフォームビルド + +rust(cargo)はあらゆるプラットフォームでビルド可能なので、`grin`をバリデーションノードとして省電力なデバイスで実行することも可能である。 +x86のLinux上で`grin`をクロスコンパイルしARMバイナリを作成し、Raspberry Piで実行することも可能。 + +## grinの使用 + +機能やトラブルシューティングなどに関するより多くの情報については[Wallet User Guide](https://github.com/mimblewimble/docs/wiki/Wallet-User-Guide)。 + + +## grinのマイニング + +grinのマイニングに関する全ての機能は[grin-miner](https://github.com/mimblewimble/grin-miner)と呼ばれるスタンドアローンなパッケージに分離されていることに注意。 + +grin-minerをgrinノードと通信させるためには、`grin-server.toml`の設定ファイルで`enable_stratum_server = true`と設定し、ウォレットリスナーを起動(`grin wallet listen`)しておく必要がある。 diff --git a/doc/build_KR.md b/doc/build_KR.md new file mode 100644 index 0000000000..18360aa6e9 --- /dev/null +++ b/doc/build_KR.md @@ -0,0 +1,131 @@ +# Grin - Build, Configuration, and Running + +*다른 언어로 되어있는 문서를 읽으려면:[에스파냐어](build_ES.md). + +## 지원하는 플랫폼들에 대해서 + +장기적으로는 대부분의 플랫폼에서 어느정도 지원하게 될 것입니다. +Grin 프로그래밍 언어는 `rust`로 대부분의 플랫폼들에서 빌드 할 수 있습니다. + +지금까지 작동하는 플랫폼은 무엇인가요? + +* Linux x86_64 그리고 macOS [grin + mining + development] +* Windows 10은 아직 지원하지 않습니다 [grin kind-of builds, mining은 아직 지원하지 않음 . 도움이 필요해요!] + +## 요구사항 + +* rust 1.31 버전 이상 (다음 명령어를 사용하세요. [rustup]((https://www.rustup.rs/))- 예.) `curl https://sh.rustup.rs -sSf | sh; source $HOME/.cargo/env`) + + * 만약 rust 가 설치되어 있다면, 다음 명령어를 사용해서 업데이트 할 수 있습니다. + `rustup update` +* clang +* ncurses 과 libs (ncurses, ncursesw5) +* zlib libs (zlib1g-dev or zlib-devel) +* pkg-config +* libssl-dev +* linux-headers (reported needed on Alpine linux) +* llvm + +Debian 기반의 배포들은 (Debian, Ubuntu, Mint, 등등) 다음 명령어 한 줄로 설치 됩니다. + +```sh +apt install build-essential cmake git libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config libssl-dev llvm +``` + +Mac 사용자: + +```sh +xcode-select --install +brew install --with-toolchain llvm +brew install pkg-config +brew install openssl +``` + +## 빌드 순서 + +```sh +git clone https://github.com/mimblewimble/grin.git +cd grin +cargo build --release +``` + +Grin은 Debug 모드로 Build 할 수 있습니다. (`--release` 플래그가 사용하지 않고, `--debug` 또는 `--verbose` 플래그를 사용하세요.) 그러나 이 명령어는 암호 오퍼레이션으로 인해 큰 오버헤드를 가지므로 fast sync 가 어려울 정도로 느려집니다. + +## Build 에러들 + +[트러블 슈팅 관련해서는 이 링크를 클릭하세요.](https://github.com/mimblewimble/docs/wiki/Troubleshooting) + +## 무엇을 Build 해야 되나요? + +성공적으로 빌드한다면: + +* `target/release/grin` - 메인 grin 바이너리 디렉토리가 생성됩니다. + +모든 데이터, 설정, 로그 파일들은 기본적으로 숨겨진 `~/.grin` 디렉토리에 생성되고 사용됩니다. (user home 디렉토리 안에 있습니다.) +`~/.grin/main/grin-server.toml` 을 수정해서 모든 설정값들을 바꿀 수 있습니다. + +Grin은 현재 디렉토리 내에서도 데이터 파일들을 만들 수 있습니다. 밑에 있는 Bash 명령어를 작동하세요. + +```sh +grin server config +``` + +이 명령어는 `grin-server.toml`를 현재 디렉토리에서 생성합니다. +이 파일은 현재 디렉토리 내의 모든 데이터에 대해서 사용하도록 미리 구성되어 있습니다. +`grin-server.toml` 파일이 있는 디렉토리에서 grin을 실행하면 기본값`~ / .grin / main / grin-server.toml` 대신 그 파일의 값을 사용하게됩니다. + +Testing 중에서는 Grin 바이너리를 이렇게 path 에 삽입 할 수도 있습니다. + +```sh +export PATH=`pwd`/target/release:$PATH +``` + +만약 Grin을 root 디렉토리에서 실행한다고 가정하면, `grin` 명령어를 바로 실행할 수 있습니다. (`grin help` 명령어를 통해서 좀 더 많은 옵션을 알아보세요.) + +## 설정하기 + +Grin 은 기본적으로 설정되어 있는 올바른 값으로 실행하고 `grin-server.toml`를 통해 추가로 설정하는 것이 가능합니다. +Grin이 처음 실행될때 설정파일이 생성되고 각 사용가능한 옵션에 대한 매뉴얼을 포함하고 있습니다. + +`grin-server.toml` 파일을 통해 모든 Grin 서버 구성을 수행하는 것이 좋지만, +커맨드 라인 명령어를 사용하면 `grin-server.toml` 파일의 모든설정을 덮어쓰는 것이 가능합니다. + +Grin을 작동시키는 명령어에 대한 도움말은 다음 명령어를 실행하세요. + +```sh +grin help +grin wallet help +grin client help +``` + +## Docker 사용하기 + +```sh +docker build -t grin -f etc/Dockerfile . +``` + +floonet을 사용하려면 `etc/Dockerfile.floonet` 을 사용하세요. +container 안에서 grin cache를 bind-mount로 사용 할 수 있습니다. + +```sh +docker run -it -d -v $HOME/.grin:/root/.grin grin +``` + +Docker를 named volume으로 사용하는 것을 선호한다면 `-v dotgrin:/root/.grin` 명령어를 대신 사용할 수 있습니다. +named volume샤용시 volume 생성시 기본 설정을 복사합니다. + +## 크로스 플랫폼 빌드 + +Rust(Cargo)는 여러 플랫폼에서 Grin을 빌드 할 수 있습니다. 그래서 이론적으로 낮은 성능의 디바이스 에서도 인증받은 노드로 grin을 아마도 작동 시킬 수 있을것 입니다. +예를 들자면 라즈베리 파이 같은 x96 리눅스플랫폼 위에서 `grin` 크로스 컴파일을 하고 ARM 바이너릐를 만듭니다. + +## Grin 사용하기 + +[지갑 유저 가이드](https://github.com/mimblewimble/docs/wiki/Wallet-User-Guide) 위키페이지와 링크된 페이지들은 어떤 Feature 를 가지고 있는지 , 트러블 슈팅 등등에 대한 좀 더 많은 정보를 가지고 있습니다. + +## Grin 채굴하기 + +Grin의 모든 마이닝 기능은 분리된 독랍형 패키지인 [grin-miner](https://github.com/mimblewimble/grin-miner)로 옮겨졌습니다. +일단 Grin 노드가 실행되면 실행중인 노드에 대해 grin-miner를 빌드하고 실행하여 마이닝을 시작할 수 있습니다. + +grin-miner가 grin 노드와 통신 할 수 있게 하려면, `grin-server.toml` 설정 파일에서`enable_stratum_server = true`가 설정되어 있는지 확인하세요. 그 다음 Wallet listener인 `grin wallet listen` 명령어를 실행하세요 . \ No newline at end of file diff --git a/doc/chain/blocks_and_headers.md b/doc/chain/blocks_and_headers.md index aeee03df7c..818a158829 100644 --- a/doc/chain/blocks_and_headers.md +++ b/doc/chain/blocks_and_headers.md @@ -1,5 +1,7 @@ # Blocks and Block headers +*Read this in other languages: [Korean](blocks_and_headers_KR.md).* + ## Node receives block from peer (normal operation) During normal operation the Grin node will receive blocks from connected peers via the gossip protocol. diff --git a/doc/chain/blocks_and_headers_KR.md b/doc/chain/blocks_and_headers_KR.md new file mode 100644 index 0000000000..94d4933143 --- /dev/null +++ b/doc/chain/blocks_and_headers_KR.md @@ -0,0 +1,38 @@ +# Blocks and Block headers + +## 정상 운영시 노드가 피어로부터 블록을 받는것에 대해서 + +정상 동작 중에 Grin 노드는 가십 프로토콜을 통해 연결된 피어로부터 블록을 받습니다. +블록과 블록 헤더의 유효성이 성공적으로 확인되면 둘 다 저장됩니다. 헤더 헤드가 최신 블록 헤더를 가리키도록 업데이트되고 블록 헤드가 최신 블록을 가리키도록 업데이트됩니다. + +![Simple Block](images/simple_block.png) + +## 노드가 처음 동기화 될때 + +[tbd] + +## 노드가 블록의 상태를 따라잡기 위해 피어와 동기화 하는것에 대해서 + +노드는 주기적으로 현재의`total_difficulty`와 연결된 모든 피어들의 `total_difficulty`를 비교할 것입니다. total_difficulty가 더 높은 피어가 표시되면이 가장 많이 일한 피어(most_work_peer)와 동기화를 시도합니다. most_work_peers가 여러 개 있으면 그 중 하나가 무작위로 선택됩니다. +동기화 프로세스는 현재 알려진 체인 상태 (locator에 대한 자세한 정보는 [tbd] 참고하세요.)를 기반으로 "locator"를 빌드하고 그 다음 피어에게서 헤더 목록을 요청하고 해당 헤더를 선택하는 데 도움이되는 locator를 전달하면서 시작됩니다. +헤더 목록을 수신하면 노드는 노드의 유효성을 확인한 다음 저장합니다. 각 헤더에 대해 가장 최근 헤더를 반영하도록 헤더 헤드가 업데이트 됩니다. +그러면 노드는 헤더체인 (헤더 헤드에서 부터 역순으로)과 현재 블록체인 (블록 헤드에서부터 역순으로)을 비교하여 각 "누락한" 블록을 요청합니다. 블록은 노드보다 total_difficulty가 큰 피어에게 요청됩니다. 이 프로세스는 (노드보다) 더 높은 total_difficulty를 가진 피어가 보이지 않고 두 헤드(헤더헤드 & 블록헤드) 가 일치한 상태 (동일한 헤드 / 블록을 가리키고 있음)에 있을 때까지 반복됩니다. + +![Simple sync](images/simple_sync.png) + +## 새로운 피어가 이전에 알려지지 않은 가장 긴 fork 와 연결된 경우 + +![Sync on fork](images/sync_on_fork.png) + +## 노드가 매우 뒤떨어져 있을때에 대해서 ( 500 블록 이상 ) + +현재 헤더 검색은 약 500 헤더 (512?)의 배치로 제한됩니다. 500개 헤더의 첫 배치를 받은 이후에 새로운 헤더 체인이 되지만 새로운 체인의 total_difficulty가 기존 체인을 추월하기에 충분하지 않을 때 어떤 일이 발생하는지 정확히 설명해야합니다. +여기서 어떻게될까요? + +## 노드가 블록을 성공적으로 마이닝 했을때에 대해서 + +[tbd] + +## 두 블록이 같이 채굴 되었을때 ( 일시적인 포크)에 대해서 + +[tbd] diff --git a/doc/chain/chain_sync.md b/doc/chain/chain_sync.md index 70fe4ce6f7..5ca400f272 100644 --- a/doc/chain/chain_sync.md +++ b/doc/chain/chain_sync.md @@ -1,5 +1,7 @@ # Blockchain Syncing +*Read this in other languages: [Korean](chain_sync_KR.md).* + We describe here the different methods used by a new node when joining the network to catch up with the latest chain state. We start with reminding the reader of the following assumptions, which are all characteristics of Grin or MimbleWimble: @@ -110,7 +112,7 @@ that block. If a hard fork occurs, the network may become split, forcing new nodes to always push their horizon back to when the hard fork occurred. While this is not a problem -for short-term hard forks, it may become an issue for long-term or permanent forks +for short-term hard forks, it may become an issue for long-term or permanent forks. To prevent this situation, peers should always be checked for hard fork related capabilities (a bitmask of features a peer exposes) on connection. diff --git a/doc/chain/chain_sync_KR.md b/doc/chain/chain_sync_KR.md new file mode 100644 index 0000000000..c5d25b4c53 --- /dev/null +++ b/doc/chain/chain_sync_KR.md @@ -0,0 +1,79 @@ +# 블록체인의 동기화 + +최신 노드 상태를 따라 가기 위해 네트워크에 참여할 때 새 노드가 사용하는 여러 가지 방법을 설명합니다. +먼저, 독자에게 다음과 같은 Grin 또는 MimbleWimble의 특성을 먼저 전제 하고 설명하겠습니다. + +* 해당 블록 안의 모든 블록 헤더는 체인 안에 사용하지 않는 출력값의 모든 루트해시를 가지고 있습니다. +* 입력 또는 출력은 전체 블록 상태를 무효화하지 않고선 변조되거나 위조 될 수 없습니다 + +오직 보안 모델에 영향을 줄 수있는 주요 노드 유형과 고급 알고리즘에만 의도적으로 초점을 두고 있습니다. 예를 들어 헤더 우선 같은 몇몇 추가 개선점들을 줄 수 있는 휴리스틱은 유용하지만 이 섹션에서는 언급하지 않을것입니다. + +## Full 히스토리 동기화 + +### 설명 + +이 모델은 대부분의 메이저 퍼블릭 블록체인 에서 "풀 노드"가 사용하는 모델입니다. 새로운 노드는 제네시스 블록에 대한 사전 정보를 가지고 있습니다. 노드는 네트워크의 다른 피어와 연결되어 피어에게 알려진 최신 블록(호라이즌 블록)에 도달 할 때까지 블록을 요청하기 시작합니다. + +보안 모델은 비트 코인과 비슷합니다. 전체 체인, 총 작업, 각 블록의 유효성, 전체 내용 등을 검증 할 수 있습니다. 또한 MimbleWimble 및 전체 UTXO 세트 실행들을 통해 훨씬 더 무결성 검증이 잘 수행될 수 있습니다. + +이 모드에서는 저장공간 최적화 또는 대역폭 최적화를 시도하지 않습니다 (예를 들자면 유효성 검증 후 Range proof 가 삭제 될 수 있습니다). 여기서 중요한 것은 기록 아카이브를 제공하고 나중에 확인 및 증명을 하게 하는 것입니다. + +### 무엇이 잘못 될 수 있나요? + +다른 블록체인과 동일하게 아래와 같은 문제가 생길 수 있습니다. + +* 연결된 모든 노드가 부정직하다면 (sybil 공격 또는 그와 비슷한 상태를 말합니다.), 전체 체인 상태에 대해 거짓말을 할 수 있습니다. +* 엄청난 마이닝 파워를 가진 누군가가 전체 블록체인 기록을 다시 쓸 수 있습니다. +* Etc. + +## 부분 블록체인 히스토리 동기화 + +이 모델에서는 보안에 대해서 가능한 한 적게 ​​타협하면서 매우 빠른 동기화를 위힌 최적화를 하려고 합니다. 사실 보안 모델은 다운로드 할 데이터의 양이 훨씬 적음에도 불구하고 풀 노드와 거의 동일합니다. + +새로 네트워크에 참여하는 노드는 블록헤드에서 블록 수만큼 떨어진 값인 `Z`로 미리 구성됩니다. ( 원문에서는 horizon `Z` 로 표현되었습니다. 블록헤드 - 블록 = `Z`라고 할 수 있습니다. - 역자 주 ) 예를 들어 `Z = 5000` 이고 헤드가 높이 `H = 23000` 에 있으면, 가장 높은 블록은 가장 긴 체인에서 높이가 `h = 18000`인 블록입니다. + +또한 새로운 노드에는 제네시스 블록에 대한 사전 정보가 있습니다. 노드는 다른 피어들과 연결하고 가장 긴 체인의 헤드에 대해 알게 됩니다. 가장 높은 블록의 블록 헤더(horizon block 이라고 원문에 표시되어 있음 - 역자 주 )를 요청하며 다른 피어의 동의가 필요하게 됩니다. 컨센서스가 `h = H - Z`에 이르지 않으면 노드는 `Z`값( horizon Z 라고 원문에 표시되어 있음 - 역자 주 )을 점차 증가시켜 컨센서스가 이루어질 때까지`h`를 뒤로 이동시킵니다. 그런 다음 가장 긴 블록에서의 전체 UTXO 정보를 얻습니다. 이 정보를 통해 다음을 증명할 수 있습니다. + +* 모든 블록헤더안에 있는 해당 체인의 전체 난이도 +* 예상되는 코인 공급량과 같은 모든 UTXO 실행값의 합. +* 블록헤더에 있는 루트 해시와 매치되는 모든 UTXO의 루트해시 + +블록의 유효성 검사가 완료되면 피어는 블록 콘텐츠를 `Z`값에서 (from the horizon 이라고 원문에 표시되어 있음 - 역자 주) 헤드까지 다운로드하고 유효성을 검사 할 수 있습니다. + +이 알고리즘은 `Z`의 매우 낮은 값 (또는 `Z = 1`인 극단적인 경우에도)에서도 작동합니다. 그러나 어느 블록체인에서도 발생할 수있는 정상적인 포크 때문에 낮은 값이 문제가 될 수 있습니다. 이러한 문제를 방지하고 로컬 검증된 을 늘리려면 최소한 며칠 분량의 `Z`값에서 최대 몇 주간의 `Z`값을 사용하는 것을 권장합니다. + +### 무엇이 잘못 될 수 있나요? + +이 동기화 모드는 간단하게 설명 할 수 있지만 어떻게 보안을 유지 할 것인가에 대해선 불분명해 보일 수 있습니다. +여기서는 몇몇 가능 할 수 있는 공격 유형과 퇴치 방식 및 기타 가능한 실패 시나리오에 대해 설명합니다. + +### 공격자가 가장 긴 블록에서 부터 상태를 위조하려고 할때 + +이 공격은 노드가 네트워크와 올바르게 동기화되었다고 노드가 인식하도록 하나 실제로 노드가 위조 상태에 있게 합니다. +이에 대해 아래와 같은 여러 전략을 시도 할 수 있습니다. + +* 완전히 가짜지만 유효한 최신 블록상태 (horizon state 라고 원문에 표시되 어있음 - 역자 주) 일때 (헤더 및 작업 증명 포함), 최소한 하나의 정직한 피어가 있다고 가정하면, UTXO 세트의 루트 해시와 블록 해시도 다른 피어의 수평 상태와 일치하지 않습니다. +* 유효한 블록 헤더이지만 가짜 UTXO 세트일때, 헤더의 UTXO 세트의 루트 해시는 노드가 수신 한 UTXO 세트 자체에서 계산 한 것과 일치하지 않습니다. +* 가짜 총 난이도를 가진 완전히 유효한 블록으로 노드를 가짜 포크로 유도할 경우, 전체 난이도가 변경되면 블록 해시가 변경되며 어떤 정직한 피어도 해당 해시에 유효한 헤드를 생성하지 않습니다. + +### 로컬 UTXO 히스토리 보다 오래된 포크가 발생하려 할때 + +노드는 최신 블록 높이 (horizon height - 역자 주) 로 설정된 전체 UTXO를 다운로드 했습니다. 만약 수평선 H + delta에 있는 블록에서 포크가 발생하면 UTXO 세트의 유효성을 검사 할 수 없습니다. 이 상황에서 노드는 `Z '= Z + delta`인 새로운 `Z`값 (new horizon - 역자 주) 을 가진 동기화 모드로 돌아 갈 수 밖에 없습니다. + +(네트웍에서 받아들여지는) 승리한 포크는 현재의 (우리의) 헤드보다 작업 증명의 총 량이 더 많은 헤드일 뿐이라서 현재의 헤드보다 더 적은 작업 증명인 Z + delta의 다른 포크는 무시 될 수 있습니다. 이 방법을 위해서 모든 블록 헤더에는 해당 블록까지의 총 체인 난이도가 포함됩니다. + +#### 체인이 완전히 포크되었을 때 + +하드포크가 발생하면 네트워크가 분리되고 새로운 노드는 하드포크가 발생했을 때로 자신의 최신 블록 상태(horizon)을 항상 되돌릴 것을 강제합니다. 짧은 기간의 하드포크에는 문제가 되지 않지만 장기 또는 완전한 하드포크에선 문제가 될 수 있습니다. 이러한 상황을 방지하기 위해, 피어는 연결이 될때 하드포크 관련 기능 (피어가 노출하는 피쳐의 bitmask)을 항상 확인해야합니다. + +### 몇몇 노드가 가짜 최신블록 (호라이즌 블록)을 지속적으로 줄 때 + +피어가 만약 h의 헤더에서 컨센서스에 도달 할 수 없으면 서서히 뒤로 돌아갑니다 (블록의 유효성을 확인하기 위해). 뒤로 물러나는 유효성을 확인하는 경우, 사기꾼 피어는 시스템적으로 합의가 이뤄지는것을 막고 가짜 헤더를 보내 줌으로써 모든 새로운 피어가 제네시스 블록까지 (유효성을 확인하기 위해) 뒤로 이동하게 함으로써 항상 풀 노드가 되도록 강제 할 수 있습니다. + +상기 얘기한 상태는 유효한 문제이긴 하지만 이래와 같이 몇가지 완화 전략이 있습니다. + +* 피어는`Z`값 (Horizon Z)에서 유효한 블록 헤더를 제공해야합니다. 여기에는 작업 증명이 포함됩니다. +* 최신 블록 (Horizon) 주위의 블록 헤더 그룹은 공격 비용을 증가 시키도록 요청받을 수 있습니다. +* 현저하게 낮은 작업 증명을 제공하는 상이한 블록 헤더는 거부 될 수 있습니다. +* 사용자 또는 노드 운영자는 블록 해시를 확인하도록 요청받을 수 있습니다. +* 최후의 수단으로 위의 전략 중 어느 것도 효과적이지 않으면 체크포인트를 사용할 수 있습니다. \ No newline at end of file diff --git a/doc/coinbase_maturity.md b/doc/coinbase_maturity.md index b53c8cb703..a365c0c26e 100644 --- a/doc/coinbase_maturity.md +++ b/doc/coinbase_maturity.md @@ -119,9 +119,7 @@ To summarize - Output MMR stores output hashes based on `commitment|features` (the commitment itself is not sufficient). -We do not need to include the range proof or the switch commitment hash in the generation of the output hash. - -We do not need to encode the lock height in the switch commitment hash. +We do not need to include the range proof in the generation of the output hash. To spend an output we continue to need - diff --git a/doc/dandelion/dandelion.md b/doc/dandelion/dandelion.md index 71bf064274..b6c20dfce8 100644 --- a/doc/dandelion/dandelion.md +++ b/doc/dandelion/dandelion.md @@ -1,5 +1,6 @@ # Dandelion in Grin: Privacy-Preserving Transaction Aggregation and Propagation +*Read this document in other languages: [Korean](dandelion_KR.md).* This document describes the implementation of Dandelion in Grin and its modification to handle transactions aggregation in the P2P protocol. ## Introduction diff --git a/doc/dandelion/dandelion_KR.md b/doc/dandelion/dandelion_KR.md new file mode 100644 index 0000000000..a6684c2bc4 --- /dev/null +++ b/doc/dandelion/dandelion_KR.md @@ -0,0 +1,89 @@ +# Grin에서 사용하는 Dandelion : 프라이버시 보호 트랜잭션의 통합과 전파 + +*역자 주 : Dandelion 은 민들레라는 뜻으로 앞으로 설명될 각종 용어에서 민들레의 홑씨와 관련된 용어들이 있으니 참고바람.* + +이 문서에서는 Grin에서 구현된 Dandelion 구현체에 대해서 설명하고 그리고 Dandelion이 P2P 프로토콜내에서 트랜잭션 통합을 다루기 위해 어떻게 수정되었는지 설명합니다. + +## 소개 + +Dandelion은 발신 IP에 도청 연결 트랜잭션(eavesdroppers linking transactions)의 위험을 줄이는 새로운 트랜잭션 전파 메커니즘입니다. 또한 전체 네트워크에 퍼지기 전에 추가적인 프라이버시 보호 기능을 제공합니다. 프라이버시 보호 기능은 Grin 트랜잭션을 입력-출력 쌍을 제거하는 방식으로 제공됩니다. + +Dandelion은 G. Fanti 에 의해 소개되었습니다([1] 참고). 그리고 ACM Sigmetrics 2017에서 발표되었습니다. 2017 년 6 월 BIP [2]는 2018 년 후반에 발표될 Dandelion ++ [3]이라고 불리는 더 실용적이고 견고한 Dandelion의 다른 버전을 소개하려고 제안되었습니다. 이 문서는 Grin을 위한 BIP의 개정판이라고 생각하시면 됩니다. + +우선은 오리지널 Dandelion 전파에 대해서 정의한 다음, 트랜잭션 에그레게이션 (transaction aggregation)과 함께 어떻게 Grin의 프로토콜에 적용되었는지 알아보겠습니다. + +## Original Dandelion + +### 매커니즘에 대해서 + +Dandelion 트랜잭션 전파는 두 가지 단계로 진행됩니다. 첫 번째는 "stem" (줄기)페이즈, "fluff"(솜털/보풀, 민들레 홀씨를 연상하면 될 듯 - 역자 주)페이즈 입니다. Stem 페이즈에서 각 노드는 트랜잭션을 *단일* 피어로 릴레이 합니다. Stem를 따라 임의의 수로 (노드를) 몇번 건너뛴 후 (hops) 후 트랜잭션은 일반적인 플러딩 / 확산과 같이 동작하는 fluff 페이즈에 들어갑니다. 공격자가 fluff 단계의 위치를 ​​식별 할 수 있더라도 Stem 페이즈의 발신처를 식별하는 것이 훨씬 더 어렵습니다. + +그림 설명: + +``` + ┌-> F ... + ┌-> D --┤ + | └-> G ... + A --[stem]--> B --[stem]--> C --[fluff]--┤ + | ┌-> H ... + └-> E --┤ + └-> I ... +``` + +### Specifications + +Dandelion 프로토콜은 아래와 같은 세가지 매커니즘을 기반으로 합니다. + +1. *Stem/fluff 전파.* + Dandelion 트랜잭션은 "Stem(줄기) 모드"에서 시작됩니다. 각 노드는 거래를 무작위로 선택된 하나의 노드에게 중계합니다. 고정 된 확률로 트랜잭션은 "fluff(솜털)" 모드로 전환되고 이후에는 일반적인 플러딩 / 확산에 따라 릴레이됩니다. + +2. *Stem Mempool.* Stem 페이즈 동안, 각 Stem node(앨리스)는 transaction pool에 stem transaction만을 포함한 transaction을 저장합니다. 이것이 stem pool 입니다. stem pool의 내용은 각 노드마다 다르므로 공유 할 수 없습니다. 다음 경우에 stem pool에서 stem transaction이 제거됩니다. + + 1. 앨리스는 fluff 모드인 transaction을 받았다고 "정상적으로" 알립니다. + 2. Alice는 이 트랜잭션이 포함 된 블록을 받았고 이러한 것은 이 트랜잭션이 전파되고 블록에 포함되었음을 의미합니다. + +3. *Robust propagation.* 프라이버시 강화가 transaction을 전파 하지 않게 해서는 안됩니다. stem node가 transaction을 중계(relay)하지 못해서 fluff 단계에 가지 못할 상황일때 (악의적이거나 우발적인) 실패를 방지하기 위해 각 노드는 stem 페이즈에서 transaction을 수신 할 때 임의의 타이머를 시작합니다. 타이머가 만료되기 전에 노드가 해당 transaction에 대한 transaction 메시지 또는 블록을 수신하지 않으면 노드는 transaction을 정상적으로 전파합니다. + +Dandelion stem mode transaction은 새로운 타입의 릴레이 메시지 타입으로 표시됩니다. + +Stem transaction relay 메시지 타입은 아래와 같습니다. + +```rust +Type::StemTransaction; +``` +Stem transaction을 수신한 후 node는 바이어스(biased) 된 코인을 뒤집어서 "stem mode"로 전달할지 또는 "fluff mode"로 전환할지 결정합니다. 바이어스는 설정파일에 있는 파라미터에 의해 제어되는데, 초기에는 90 % 확률로 stem mode로 유지하게 합니다.(예상되는 stem 길이가 10번 건너뜀(hops)이 될 것임을 의미함) + +Stem transacion을 수신하는 노드를 stem relay라고합니다. 이 릴레이는 밖으로 향하거나 connection 이나 허가된 연결 중에서 선택 되어지는데 침입자들이 stem graph에 쉽게 잡입하는 것을 방지합니다. 각 노드는 매 10 분마다 주기적으로 무작위로 stem relay를 선택합니다. + +### 고려해야 하는 것들 + +주요 구현의 도전 과제는 (1) Dandelion의 프라이버시를 보장하는 것 과 latency/overhead 사이의 만족스러운 트레이드 오프를 밝히는 것, (2) 기존 매커니즘의 남용을 통해 프라이버시가 질적으로 저하 될 수 없다는 것을 보장하는 것입니다. +특히 구현에서는 효율적이고 DoS 내성 전파를 위한 다양한 기존 메커니즘을 너무 많이 방해하지 않고 공격자가 stem node를 식별하는 것을 방지해야합니다. + +* Dandelion이 제공하는 프라이버시는 다음과 같은 3가지 파라미터에 달려있습니다. Stem 확률(stem probability), Dandelion 중계(relay)역할을 할 수 있는 아웃바운드(outbound) 피어 수 그리고 stem 중계(relay)의 재-무작위 추출 간의 시간입니다. 이러한 파라미터는 프라이버시와 전파 latency/processing overhead 간의 트레이드 오프를 정의합니다. +Stem 확률(stem probability)을 낮추면 프라이버시가 손상되지만 평균 stem 길이를 짧게 해서 latency를 줄이는 데 도움이 됩니다.(그래서) 이론,시뮬레이션 및 실험을 기준으로 stem 확률은 90%를 기본값으로 선택 되었습니다. 각 노드의 stem 중계(relay)의 재-무작위 추출 사이의 시간을 줄이면 공격자가 각 노드의 stem 중계(relay)를 알 기회가 줄어들고 overhead가 증가합니다. +* Dandelion stem transaction을 받을 때, 그 transaction을 `tracking_adapter`에 두는 것을 피합니다. 이렇게 하면 Transaction이 fluff 페이즈에서 Stem을 "위로" 이동할 수도 있습니다. +* 일반 거래와 마찬가지로, Dandelion stem transaction은 mempool에 성공적으로 승인 된 후에 만 ​​중계(relay)됩니다. 이렇게 하면 Dandelion stem transaction을 중계(relay) 할 때 노드가 절대로 불이익을 받지 않습니다. +* Stem orphan transaction이 접수되면 `고아 (orphan)`pool에 추가되고 stem mode로 표시됩니다. transaction이 나중에 mempool에 승인되면 stem transaction 또는 일반 transaction (stem mode 또는 fluff mode, 동전 반전에 따라 다름)으로 중계(relay)됩니다. +* 노드가 하나나 또는 그 이상의 현재 엠바고 상태인 Dandelion transaction에 의존하는 하위 거래(child transaction)를 받으면 transaction도 stem mode로 중계(relay)되고 엠바고 타이머는 상위 트랜잭션 (parent)의 엠바고 기간의 최대치로 설정됩니다. 이렇게 하면 상위 트랜잭션이 하위 트랜잭션 전에 fluff 모드로 들어갈 수 있습니다. 나중에 이 두 transaction은 유니크한 하나의 transaction으로 통합되어 타이머가 필요하지 않게됩니다. +* 트랜잭션 전파 latency는 프라이버시 기능을 넣어도 최소한으로 영향을 받아야 합니다. 특히 Dandelion 때문에 거래가 전혀 방해받지 않아야 합니다. 무작위 타이머는 엠바고 메커니즘이 일시적이며 일반 확산 메커니즘에 따라 모든 트랜잭션이 최대 (임의로) 30-60 초 정도의 딜레이 후에 중계(relay)되도록 보장합니다. + +## Grin 에서의 Dandelion + +Dandelion은 또한 Grin Transaction을 Stem phase에서 통합(Aggregated) 한 다음 네트워크의 모든 노드에 전파 할 수 있습니다. 이로 인해 트랜잭션 통합(transaction aggregation)과 컷 스루(cut-through, 소비 된 출력값 삭제)가 가능해져 컷 스루(cut-through) 방식의 non-interactive coinjoin 과 유사한 매우 중요한 프라이버시 이득을 얻을 수 있습니다. + +### 통합 매커니즘 (Aggregation Mechanism) + +트랜잭션을 통합(aggregate)하기 위해 Grin은 Dandelion 프로토콜의 수정 된 버전을 구현합니다 [4]. + +기본적으로 노드가 네트워크에서 transaction을 전송하면 Dandelion 프로토콜을 사용하여 Dandelion 중계기(relay)에 stem transaction으로 전파됩니다. Dandelion 중계기(relay)는 더 많은 stem transaction를 통합하기 위해 일정 기간 (patience 타이머) 대기합니다. 타이머가 끝날때 중계기(relay)는 새로운 stem transaction마다 코인 플립을 해서 stem을 하거나 (다음 Dandelion relay로 보내거나) fluff(정상적으로 전파하거나) 할지를 결정합니다. 그런 다음 relay는 모든 transaction을 stem으로 가져 와서 통합하여 다음 Dandelion 릴레이에 전파합니다. Transaction이 "정상적으로" 피어의 무작위 하위 집합으로 통합된 Transaction을 전파한다는 점을 제외하고는 fluff(단계)로 가는 transaction에 대해 동일한 작업을 수행합니다. +이 매커니즘은 transaction 병합을 다룰수 있는 P2P protocol을 제공합니다. + +이 시나리오에 대한 시뮬레이션은 [여기](simulation_KR.md)에서 확인 할 수 있습니다. + +## 레퍼런스 + +* [1] (Sigmetrics 2017) [Dandelion: Redesigning the Bitcoin Network for Anonymity](https://arxiv.org/abs/1701.04439) +* [2] [Dandelion BIP](https://github.com/dandelion-org/bips/blob/master/bip-dandelion.mediawiki) +* [3] (Sigmetrics 2018) [Dandelion++: Lightweight Cryptocurrency Networking with Formal Anonymity Guarantees](https://arxiv.org/abs/1805.11060) +* [4] [Dandelion Grin Pull Request #1067](https://github.com/mimblewimble/grin/pull/1067) diff --git a/doc/dandelion/simulation.md b/doc/dandelion/simulation.md index aa12d31b08..f6b24f79c7 100644 --- a/doc/dandelion/simulation.md +++ b/doc/dandelion/simulation.md @@ -1,5 +1,7 @@ # Dandelion Simulation +*Read this document in other languages: [Korean](simulation_KR.md).* + This document describes a network of node using the Dandelion protocol with transaction aggregation. In this scenario, we simulate a successful aggregation. diff --git a/doc/dandelion/simulation_KR.md b/doc/dandelion/simulation_KR.md new file mode 100644 index 0000000000..46b9775c45 --- /dev/null +++ b/doc/dandelion/simulation_KR.md @@ -0,0 +1,73 @@ +# Dandelion 시뮬레이션 + +이 문서는 노드의 네트워크가 Dandelion 프로토콜을 트랜잭션 통합(Transaction aggregation)과 함께 사용하는 것에 대해서 설명합니다. 이 시나리오에서 성공적인 (트랜잭션)통합을 시뮬레이션 할 것입니다. +이 문서는 (트랜잭션의) 모든 순간 순간에 대해서 간단히 시각화 하는것을 도와줄것입니다. + +## T = 0 - Initial Situation + +![t = 0](images/t0.png) + +## T = 5 + +A는 B에게 grin를 보냅니다. A는 거래를 스템풀(stem pool)에 추가하고 이 트랜잭션에 대한 엠바고 타이머를 시작합니다. + +![t = 5](images/t5.png) + +## T = 10 + +A는 인내심이 바닥날때까지 기다립니다. ( 아마도 엠바고 타이머가 끝나는 때를 의미하는 듯 - 역자 주) + +![t = 10](images/t10.png) + +## T = 30 + +A는 인내심이 바닥나면 동전을 뒤집고 Stem transaction을 G에게 Dandelion을 중계(Relay)합니다. G는 Stem transaction을 받은뒤 Stem pool에 Transaction을 추가하고 이 Transaction의 엠바고 타이머를 시작합니다. + +![t = 30](images/t30.png) + +## T = 40 + +G는 E에게 Grin을 보냅니다ㅏ. +G는 이 Transaction을 Stem pool에 Transaction을 추가하고 이 Transaction의 엠바고 타이머를 시작합니다. + +![t = 40](images/t40.png) + +## T = 45 + +G는 인내심이 바닥나면 동전을 뒤집고 Stem transaction을 D에게 Dandelion을 중계(Relay)합니다. + +![t = 45](images/t45.png) + +## T = 50 + +B는 B1을 D에게 씁니다. +B는 B1을 Stem pool에 추가하고 이 Transaction의 엠바고 타이머를 시작합니다. + +![t = 55](images/t55.png) + +## T = 55 + +B는 인내심이 바닥나면 동전을 뒤집고 Stem transaction을 H에게 Dandelion을 중계(Relay)합니다. +D는 인내심이 바닥나면 동전을 뒤집고 통합된(aggregated) Stem transaction을 E에게 Dandelion을 중계(Relay)합니다. +E는 Stem transaction을 받은뒤 Stem pool에 Transaction을 추가하고 이 Transaction의 엠바고 타이머를 시작합니다. + +![t = 55](images/t55.png) + +## T = 60 + +H는 인내심이 바닥나면 동전을 뒤집고 Stem transaction을 E에게 Dandelion을 중계(Relay)합니다. +E는 Stem transaction을 받은뒤 Stem pool에 Transaction을 추가하고 이 Transaction의 엠바고 타이머를 시작합니다. + +![t = 60](images/t60.png) + +## T = 70 - Step 1 + +E는 인내심이 바닥나면 동전을 뒤집고 transaction을 모든 피어에게 전송하기로 합니다.(mempool안의 fluff 상태) + +![t = 70_1](images/t70_1.png) + +## T = 70 - Step 2 + +All the nodes add this transaction to their mempool and remove the related transactions from their stempool. +모든 노드는 이 transaction을 자신의 mempool에 넣고 자신의 stempool 에서 이 transaction과 관련된 transaction을 제거합니다. +![t = 70_2](images/t70_2.png) \ No newline at end of file diff --git a/doc/fast-sync.md b/doc/fast-sync.md index f0da704d61..d88f61dee6 100644 --- a/doc/fast-sync.md +++ b/doc/fast-sync.md @@ -1,6 +1,6 @@ # Fast Sync -*Read this in other languages: [Español](fast-sync_ES.md).* +*Read this in other languages: [Español](fast-sync_ES.md), [Korean](fast-sync_KR.md).* In Grin, we call "sync" the process of synchronizing a new node or a node that hasn't been keeping up with the chain for a while, and bringing it up to the diff --git a/doc/fast-sync_KR.md b/doc/fast-sync_KR.md new file mode 100644 index 0000000000..21fe9ec079 --- /dev/null +++ b/doc/fast-sync_KR.md @@ -0,0 +1,16 @@ +# 빠른 동기화 + +*이 문서를 다른 언어로 읽으시려면: [에스파냐어](fast-sync_ES.md).* + +Grin에서는 새로 네트워크에 참여하는 노드나 얼마 동안 체인을 따라 잡지 않은 노드(의 상태)를 알려진 최신 블록으로( 원문에서는 most-worked block 이라고 표현- 역자 주 ) 가져 오는 프로세스를 "동기화"라고 부릅니다. Initial Block Download (또는 IBD)는 다른 블록 체인에서 자주 사용되지만 빠른 동기화를 사용하는 Grin에서는 일반적으로 전체 블록을 다운로드하지 않으므로 문제가 됩니다. + +요약하자면 Grin 에서의 빠른 동기화는 다음을 설명하는 요소들을 실행합니다. + +1. 다른 노드에서 보여지는 것처럼 가장 긴 체인에서 블록 헤더를 청크별로 다운로드합니다. +1. 최신 블록헤드(원문에서는 chain head 라고 표현 - 역자 주)에서 부터 (동기화 해야 될) 헤더를 찾습니다. 이것은 node horizon 이라고 불리고 node horizon은 가장 긴 체인 ( 가장 긴 체인의 블록헤드에서 부터 동기화 해야 블록헤드 까지이므로 원문에서는 furthest 라고 표현 - 역자 주) 이기 때문에 다른 새로운 전체 동기화의 트리거가 없는 경우 새로운 포크에서 체인을 재 구성 할 수 있습니다. +1. 현재의 horizon에서 unspent 데이터, range proof, kernel 데이터와 해당하는 모든 MMR들 및 모든 스테이트를 다운로드 합니다. + 이러한 데이터는 하나의 큰 zip 파일 입니다. +1. 모든 스테이트를 입증합니다. +1. Horizon 에서부터 최신 체인( 원문에서는 chain head 라고 표현함 - 역자 주 )까지 모든 블록을 다운로드 합니다. + +이 섹션의 나머지는 각각의 단계에 대해서 자세히 설명할 것입니다. diff --git a/doc/intro.md b/doc/intro.md index 1ca6aac274..ccfbf4f965 100644 --- a/doc/intro.md +++ b/doc/intro.md @@ -1,6 +1,6 @@ # Introduction to MimbleWimble and Grin -*Read this in other languages: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*Read this in other languages: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble is a blockchain format and protocol that provides extremely good scalability, privacy and fungibility by relying on strong @@ -23,6 +23,8 @@ The main goal and characteristics of the Grin project are: * Design simplicity that makes it easy to audit and maintain over time. * Community driven, encouraging mining decentralization. +A detailed post on the step-by-step of how Grin transactions work (with graphics) can be found [in this Medium post](https://medium.com/@brandonarvanaghi/grin-transactions-explained-step-by-step-fdceb905a853). + ## Tongue Tying for Everyone This document is targeted at readers with a good @@ -90,7 +92,7 @@ fundamental properties are achieved. Building upon the properties of ECC we described above, one can obscure the values in a transaction. -If _v_ is the value of a transaction input or output and _H_ an elliptic curve, we can simply +If _v_ is the value of a transaction input or output and _H_ a point on the elliptic curve _C_, we can simply embed `v*H` instead of _v_ in a transaction. This works because using the ECC operations, we can still validate that the sum of the outputs of a transaction equals the sum of inputs: @@ -99,11 +101,12 @@ sum of inputs: Verifying this property on every transaction allows the protocol to verify that a transaction doesn't create money out of thin air, without knowing what the actual -values are. However, there are a finite number of usable values and one could try every single +values are. However, there are a finite number of usable values (transaction amounts) and one +could try every single one of them to guess the value of your transaction. In addition, knowing v1 (from a previous transaction for example) and the resulting `v1*H` reveals all outputs with -value v1 across the blockchain. For these reasons, we introduce a second elliptic curve -_G_ (practically _G_ is just another generator point on the same curve group as _H_) and +value v1 across the blockchain. For these reasons, we introduce a second point _G_ on the same elliptic curve +(practically _G_ is just another generator point on the same curve group as _H_) and a private key _r_ used as a *blinding factor*. An input or output value in a transaction can then be expressed as: @@ -112,9 +115,10 @@ An input or output value in a transaction can then be expressed as: Where: -* _r_ is a private key used as a blinding factor, _G_ is an elliptic curve and - their product `r*G` is the public key for _r_ on _G_. -* _v_ is the value of an input or output and _H_ is another elliptic curve. +* _r_ is a private key used as a blinding factor, _G_ is a point on the elliptic curve _C_ and + their product `r*G` is the public key for _r_ (using _G_ as generator point). +* _v_ is the value of an input or output and _H_ is another point on the elliptic curve _C_, + together producing another public key `v*H` (using _H_ as generator point). Neither _v_ nor _r_ can be deduced, leveraging the fundamental properties of Elliptic Curve Cryptography. `r*G + v*H` is called a _Pedersen Commitment_. @@ -122,8 +126,8 @@ Curve Cryptography. `r*G + v*H` is called a _Pedersen Commitment_. As an example, let's assume we want to build a transaction with two inputs and one output. We have (ignoring fees): -* vi1 and vi2 as input values. -* vo3 as output value. +* `vi1` and `vi2` as input values. +* `vo3` as output value. Such that: @@ -143,8 +147,9 @@ transaction can be done without knowing any of the values. As a final note, this idea is actually derived from Greg Maxwell's [Confidential Transactions](https://elementsproject.org/features/confidential-transactions/investigation), -which is itself derived from an Adam Back proposal for homomorphic values applied -to Bitcoin. +which is itself derived from an +[Adam Back proposal for homomorphic values](https://bitcointalk.org/index.php?topic=305791.0) +applied to Bitcoin. #### Ownership @@ -168,7 +173,7 @@ You need to build a simple transaction such that: Xi => Y -Where _Xi_ is an input that spends your _X_ output and Y is Carol's output. There is no way to build +Where _Xi_ is an input that spends your _X_ output and _Y_ is Carol's output. There is no way to build such a transaction and balance it without knowing your private key of 28. Indeed, if Carol is to balance this transaction, she needs to know both the value sent and your private key so that: @@ -190,14 +195,19 @@ She picks 113 say, and what ends up on the blockchain is: Now the transaction no longer sums to zero and we have an _excess value_ on _G_ (85), which is the result of the summation of all blinding factors. But because `85*G` is a valid public key on the elliptic curve _G_, with private key 85, -for any x and y, only if `y = 0` is `x*G + y*H` a valid public key on _G_. +for any x and y, only if `y = 0` is `x*G + y*H` a valid public key on the elliptic curve +using generator point _G_. + +So all the protocol needs to verify is that (`Y - Xi`) is a valid public key on the curve +and that the transacting parties collectively know the private key `x` (85 in our transaction with +Carol) of this public key. If they can prove that they know the private key to `x*G + y*H` using +generator point _G_ then this proves that `y` must be `0` (meaning above that the sum of all +inputs and outputs equals `0`). -So all the protocol needs to verify is that (`Y - Xi`) is a valid public key on _G_ and that -the transacting parties collectively know the private key (85 in our transaction with Carol). The -simplest way to do so is to require a signature built with the excess value (85), +The simplest way to do so is to require a signature built with the excess value (85), which then validates that: -* The transacting parties collectively know the private key, and +* The transacting parties collectively know the private key (the excess value 85), and * The sum of the transaction outputs, minus the inputs, sum to a zero value (because only a valid public key, matching the private key, will check against the signature). @@ -237,16 +247,23 @@ create new funds in every transaction. For example, one could create a transaction with an input of 2 and outputs of 5 and -3 and still obtain a well-balanced transaction, following the definition in the previous sections. This can't be easily detected because even if _x_ is -negative, the corresponding point `x.H` on the curve looks like any other. +negative, the corresponding point `x*H` on the curve looks like any other. To solve this problem, MimbleWimble leverages another cryptographic concept (also coming from Confidential Transactions) called range proofs: a proof that a number falls within a given range, without revealing the number. We won't elaborate on the range proof, but you just need to know -that for any `r.G + v.H` we can build a proof that will show that _v_ is greater than +that for any `r*G + v*H` we can build a proof that will show that _v_ is greater than zero and does not overflow. It's also important to note that in order to create a valid range proof from the example above, both of the values 113 and 28 used in creating and signing for the excess value must be known. The reason for this, as well as a more detailed description of range proofs are further detailed in the [range proof paper](https://eprint.iacr.org/2017/1066.pdf). +The requirement to know both values to generate valid rangeproofs is an important feature since it prevents a censoring attack where a third party could lock up UTXOs without knowing their private key by creating a transaction from + + Carol's UTXO: 113*G + 2*H + Attacker's output: (113 + 99)*G + 2*H + +which can be signed by the attacker since Carols private key of 113 cancels due to the adverserial choice of keys. The new output could only be spent by both the attacker and Carol together. However, while the attacker can provide a valid signature for the transaction, it is impossible to create a valid rangeproof for the new output invalidating this attack. + #### Putting It All Together @@ -255,7 +272,7 @@ A MimbleWimble transaction includes the following: * A set of inputs, that reference and spend a set of previous outputs. * A set of new outputs that include: * A value and a blinding factor (which is just a new private key) multiplied on - a curve and summed to be `r.G + v.H`. + a curve and summed to be `r*G + v*H`. * A range proof that shows that v is non-negative. * An explicit transaction fee, in clear. * A signature, computed by taking the excess blinding value (the sum of all diff --git a/doc/intro_DE.md b/doc/intro_DE.md index e9ae8697a3..275e7d8b05 100644 --- a/doc/intro_DE.md +++ b/doc/intro_DE.md @@ -1,6 +1,6 @@ # Einführung in MimbleWimble und Grin -*In anderen Sprachen lesen: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*In anderen Sprachen lesen: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md)* MimbleWimble ist ein Blockchain-Format und Protokoll, welches auf starke kryptographische Primitiven setzt und dadurch äußerst gute Skalierbarkeit, Privatsphäre und Fungibilität bietet. Es befasst sich mit Lücken, die in fast allen gegenwärtigen Blockchainimplementierungen existieren. diff --git a/doc/intro_ES.md b/doc/intro_ES.md index 90b59122ec..d29171c787 100644 --- a/doc/intro_ES.md +++ b/doc/intro_ES.md @@ -1,6 +1,6 @@ # Introducción a MimbleWimble y Grin -*Lea esto en otros idiomas: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*Lea esto en otros idiomas: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble es un formato y un protocolo de cadena de bloques que proporciona una escalabilidad, privacidad y funcionalidad extremadamente buenas al basarse en fuertes algoritmos criptográficos. Aborda los vacíos existentes en casi todas las diff --git a/doc/intro_JP.md b/doc/intro_JP.md index 6beafa8d12..519668d025 100644 --- a/doc/intro_JP.md +++ b/doc/intro_JP.md @@ -1,6 +1,6 @@ # MimbleWimble と Grin 概論 -*この文章を他の言語で読む: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*この文章を他の言語で読む: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble は、極めてよいスケーラビリティ、プライバシー、そして代替可能性(fungibility)の解決法を提供 するブロックチェーンのフォーマット・プロトコルである。MimbleWimble は、ほとんどすべてのブロックチェーンの diff --git a/doc/intro_KR.md b/doc/intro_KR.md new file mode 100644 index 0000000000..01d3a21b05 --- /dev/null +++ b/doc/intro_KR.md @@ -0,0 +1,318 @@ +# MimbleWimble 과 Grin 에 대한 소개 + +*다른 언어로 Intro를 읽으시려면: [English](intro.md), [简体中文](intro.zh-cn.md), [Español](intro_ES.md), [Русский](intro.ru.md), [日本語](intro.jp.md).* + +MimbleWimlbe은 블록체인 포맷이면서 프로토콜 입니다. +MimbleWimble은 암호학적 기반에 의해서 극대화된 좋은 확장성, 프라이버시, 그리고 대체가능성을 제공합니다. 이러한 특성은 지금 현존하는 모든 블록체인 구현체에 존재하는 문제점들을 처리합니다. + +Grin 은 Mimble Wimble 블록체인을 구현한 오픈소스 프로젝트 입니다. 또한 완전한 블록체인와 크립토 커런시의 배포에 필요한 갭을 채워줍니다. +Grin 프로젝트의 주요 목적과 특성들은 아래 설명을 참고하십시오. + +* 프라이버시가 기본으로 제공됩니다. 이 기능은 필요에 따라서 선택적으로 정보를 공개 할 수 없도록 해서 완전한 대체가능성을 할 수 있게 합니다. +* 주로 유저의 규모와 최소한의 트랜잭션 수의 규모로 (100byte 미만의 kernel(transaction)) 다른 블록체인들과 비교하면 많은 저장공간을 절약할 수 있습니다. +* Mimble Wimble 은 수십년 동안 테스트하고 사용되었던 강력한 암호기술인 ECC만 사용합니다. +* 간단한 디자인은 감사와 유지보수를 시간이 지나도 수월하게 만듭니다. +* 커뮤니티가 주도하며, 채굴 탈중앙화가 권장됩니다. + +## 모두의 혀를 묶자. +이 문서는 블록체인에 대해 어느정도 이해가 있고 암호학에 대한 기본적인 이해가 있는 독자들을 대상으로 합니다. 이것을 염두에 두고 우리는 MimbleWimble의 기술적인 발전과 어떻게 Grin에 적용되었는지 관해 설명 할 것입니다. +저희는 이 문서가 대부분의 기술적인 성격을 가진 독자들을 이해시킬 수 있길 바랍니다. 우리의 목적은 독자가 Grin에 대해 흥미를 느끼게 하고 어떤 방식으로든 Grin에 기여할 수 있게 이끄는 것입니다. +이러한 목적을 이루기 위해, 우리는 MimbleWimble 의 구현체인 Grin을 이해하는데 필요한 주요 컨셉들에 대해서 소개할것입니다. + + 우선 Grin이 어디에서 부터 기초로 하고 있는지에 대해 이해하기 위해서 타원 곡선 암호 (ECC)의 몇몇 속성들에 대한 간단한 설명으로 시작하겠습니다. 그 다음, MimbleWimble 블록체인의 트랜잭션과 블록에 한 모든 요소들을 설명하겠습니다. + +### 타원곡선에 대한 조그마한 조각들 +ECC의 너무 복잡한 사항을 캐지 않고 어떻게 mimble wimble 이 어떻게 작동하는지에 대해 이해하는데 필요한 요소들만 리뷰할 것입니다. 이런 가정들을 좀 더 알고싶은 독자들은 [이 링크](http://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/)를 참고하세요. + +암호학에서의 타원 곡선이란 우리가 _C_ 라고 부르는 단순히 아주 큰 좌표의 집합입니다. +이 좌표들은 정수들로 (인티저, 또는 스칼라 ) 더하고 빼고 곱할 수 있습니다. + +주어진 정수 _K_ 에 스칼라 곱셈을 한다면 우리는 곡선 _c_ 위에 있는 좌표 K*H를 계산 할 수 있습니다. +또 달리 주어진 정수 _j_ 에 우리는`k*H + j*H` 와 같은 `(k+j)*H`를 계산 할 수 있습니다. + +타원곡선 위에서의 덧셈과 정수 곱셈은 제시된 수의 순서에 관계없이 결과가 동일하다는 성질과 덧셈과 곱셈의 계산 순서와 관계없이 동일한 결과가 나온다는 성질을 가지고 있습니다. + + (k+j)*H = k*H + j*H + +ECC 안에서 우리가 매우 큰 숫자인 _k_ 를 프라이빗 키로 가정할 때 `k*H` 는 해당하는 퍼블릭 키로 해당되어 집니다. 누군가 공개키인 `k*H`의 값을 알더라도 _k_ 를 추론해 내는것은 불가능에 가깝습니다. ( 달리 얘기하자면, 곱셉은 쉬우나 곡선 좌표에 의한 "나눗셈"은 정말 어렵습니다. ) + +_k_ 와 _j_ 둘다 비밀키인 이전 공식 `(k+j)*H = k*H + j*H` 는 두개의 비밀키를 더해서 얻은 한 개의 공개키 (`(k+j)*H`) 와 각각 두개의 비밀키에 공개키를 더한것과 같습니다. Bitcoin blockchain에서도 HD 지갑은 이 원칙에 의존하고 있습니다. MimbleWimble 과 Grin의 구현또한 마찬가지 입니다. + +### MimbleWimble 함께 거래하기 +트랜잭션의 구조는 MimbleWimble의 강력한 프라이버시와 비밀이 유지된다라고 하는 중요한 규칙을 나타냅니다. + +MimbleWimble 트랜잭션의 확인은 두가지 기본적인 성격을 전제로 합니다. + +* **제로섬의 검증:** 결과값에서 입력값을 뺸 합은 항상 0과 같습니다. 이것은 실제 전송되는 코인의 양을 드러내지 않고도 트랜잭션ㅇ이 새로운 코인을 만들지 않았다는 것을 증명합니다. +* **비밀키의 소유:** 다른 많은 크립토 커런시 들처럼 , 트랜잭션의 소유권은 ECC 비밀키에 의해 보장됩니다. 그러나 어떤 실체가 이런 비밀키들을 소유하고 있다고 증명하는것이 직접적으로 트랜잭션에 사인한다고해서 얻어지는 것은 아닙니다. + +다음 섹션들에서는 잔고, 소유권, 거스름돈과 증명들의 상세들이 어떻게 저 두가지 기본적인 성질에 의해서 얻어지는지 알아보겠습니다. + +#### 잔고 +위에서 언급한 ECC의 특성들을 기반으로 해서 트랜잭션안의 가치들을 보기 어렵게 할 수 있습니다. +만약 _v_ 가 트랜잭션 입력값이거나 출력값이고 _H_ 가 타원곡선이라면 , 단순히 _v_ 대신 `v*H`를 끼워 넣을 수 있습니다. + +이것은 ECC를 사용하기 때문에 작동하는 것입니다. 우리는 출력값의 합이 입력값의 합과 같다는 것을 여전히 확인할 수 있습니다. + + v1 + v2 = v3 => v1*H + v2*H = v3*H + +이 특성을 모든 트랜잭션에 확인하는것은 프로토콜이 트랜잭션은 돈을 난데없이 만들지 않는다는 것을 실제 돈이 얼마나 있는지 알지 않아도 검증할 수 있게 합니다. +그러나 사용가능한 한정된 숫자가 있고 그 숫자 중 하나를 사용해서 당신의 트랜잭션이 얼마만큼의 코인을 가졌는지 추측 할 수 있습니다. 더해서, v1을 알고 ( 예시로 사용된 이전의 트랜잭션에서 온 값 ) 그에따른 `v1*H`의 결과를 알면 블록체인 전체에 걸쳐서 v1 값이 있는 모든 출력값들이 드러나게 됩니다. + +이러한 이유로 두번째 타원곡선인 _G_ 를 제시합니다. ( 실제로 _G_ 는 _H_ 의 그룹과 같은 곡선에 있으며 단지 다른 좌표를 생성해 냅니다.) 그리고 비밀키 _r_ 은 *blinding factor* 로 사용됩니다. + +그렇다면 트랜잭션 안의 입력값과 출력값은 다음과 같이 표현됩니다. + + r*G + v*H + +여기서 + +* _r_ 은 비밀키이고 blinding factor 로 사용됩니다. _G_ 는 타원 곡선 이고 `r*G`는 _G_ 안에 있는 _r_ 의 공개키 입니다. +* _v_ 는 출력값이거나 입력값이고 _H_ 는 다른 타원곡선입니다.타원곡선의 근본적인 특성을 이용했기 때문에 _v_ 와 _r_ 은 추측될 수 없습니다. `r*G + v*H`를 _Pedersen Commitment_ 라고 부릅니다. + +예를 들어 , ( 전송료는 무시하고) 두개의 입력값과 한개의 출력값으로 트랜잭션을 만들기 원한다고 가정해봅시다. + +* vi1 과 v2 는 출력값 +* vo3는 출력값 이라면 + +그렇다면 + + vi1 + vi2 = vo3 + +입니다. + +각각의 입력값에 대해서 blining factor 로 비밀키를 만들고 각각의 값을 각각의 이전의 공식에 있던 Pederson Commitment로 교체한다고 하면 다음과 같습니다. + + (ri1*G + vi1*H) + (ri2*G + vi2*H) = (ro3*G + vo3*H) + +결과로 다음과 같습니다. + + ri1 + ri2 = ro3 + +이것이 MimbleWimble의 첫번째 특징입니다. 트랜잭션을 검증하는 산술적인 연산은 아무런 값을 알지 못해도 가능합니다. + +이 아이디어는 Greg Maxwell 의 [Confidential Transactions](https://elementsproject.org/features/confidential-transactions/investigation) 에서 유래했습니다. Confidential transaction은 Adam back의 비트코인에 동형암호를 적용하자는 제안에서 비롯되었습니다. + +#### 소유권 + +이전의 섹션에서 트랜잭션의 값을 보기 어렵게 하는 Blinding factor로서 비밀키를 소개했습니다. MimbleWimble 의 두번째 통찰은 비밀키가 어떤 값의 소유권을 증명하는데 사용할 수 있다는 것입니다. + +Alice는 당신에게 3 코인을 보내면서 그 양을 가렸고, 당신은 28을 당신의 blinding factor로 선택했습니다. ( 실제로 blinding factor는 비밀키로 정말 무진장 큰 숫자 입니다.) + +블록체인 어딘가에 다음과 같은 출력값이 나타나 있고 당신에 의해서만 소비될 수 있습니다. + + X = 28*G + 3*H + +_X_ 는 덧셈의 결과이면서 모두에게 다 보여집니다. 3은 당신과 Alice만 알고 있고 28은 당신만이 알고 있습니다. + +다시 3코인을 보내기 위해선, 프로토콜은 어떻게든 28을 알고 있어야 됩니다. 어떻게 이것이 작동하는지 보기 위해서, 당신이 캐롤에게 같은 3코인을 보내고 싶어한다고 합시다. 그렇다면 당신은 아래와 같은 간단한 트랜잭션을 작성해야 합니다. + + Xi => Y + +여기서 _Xi_는 _X_ 출력을 사용하는 입력이고 Y는 Carol의 출력입니다. +당신의 비밀키인 28을 모르고서는 트랜잭션과 잔액을 만들 수 있는 방법이 없습니다. + +실제로 캐롤이 이 트랜잭션의 잔액을 위해선 그녀는 받는 값과 당신의 비밀키를 알아야 합니다. + +그러므로 + + Y - Xi = (28*G + 3*H) - (28*G + 3*H) = 0*G + 0*H + +입니다. + +모든계산이 0으로 되었는지 확인함으로써, 새로운 돈이 만들어지지 않았다는 것을 확인할 수 있습니다. +오 잠시만요! 당신은 지금 캐롤의 출력값에 비밀키가 있다는것을 알았습니다. ( 이런경우에는 당신의 잔액이 나간것과 동일 해야 합니다.) 그리고 당신은 캐롤로 부터 돈을 훔칠수 있습니다. 이걸 해결하기위해서 캐롤은 그녀가 선택한 비밀키를 사용합니다. + +캐롤이 113을 비밀키로 선택했다면 블록체인 안에서는 아래와 같이 마무리 됩니다. + + Y - Xi = (113*G + 3*H) - (28*G + 3*H) = 85*G + 0*H + +모든 blinding factor합계 결과로 타원곡선 _G_ 위에서 트랜잭션은 _초과값_ (85) 을 가지게 되고 트랜잭션의 합은 더이상 0 이 아닙니다. + +그러나 `85*G` 은 비밀키 85 와 함께 타원곡선 _G_ 에서 유효한 공개키이기 때문에 모든 x와 y는 `y = 0`가 `x*G + y*H`일때 곡선 _G_ 에서 유효한 공개키입니다. + +그러므로 모든 프로토콜은 (`Y - Xi`) 가 _G_위에서 유효한 공개키인지 ,거래당사자들이 비밀키를 알고있는지 ( 캐롤과의 트랜잭션에서는 85) 를 검증해야 할 필요가 있습니다. 가장 간단하게 검증하는 방법은 Signature가 초과값과 함께 만들어졌다는 것을 요구한 다음 아래와 같은것을 인증하는 겁니다. + +* 거래하는 당사자들은 모두 비밀키를 알고 있고 +* 트랜잭션의 입력값을 뺀 출력값들의 합은 0입니다. ( 왜냐하면 비밀키와 매칭된 유효한 공개키만 Signature 를 체크할 것이기 때문입니다. ) + +모든 트랜잭션에 포함된 이 Signature 는 덧붙여진 어떤 데이터와 함께(채굴 수수료와 같은 데이터) _transaction kernel_ 이라고 부르고 모든 Validator 에 의해 체크됩니다. + +#### 몇몇 더 좋은 점들 + +이 섹션은 트랜잭션을 만들때 잔돈이 어떻게 보여지고 범위 증명(range proofs)의 요구사항에 대해서 모든 값이 음수가 아닌지에 대해서 좀 더 자세하게 설명하려고 합니다. 이러한 개념들 역시 MimbleWimble 과 Grin 에 대한 이해가 당연히 필요합니다. 만약 당신이 조급하다면 [이 링크를 참고하세요.](#putting-it-all-together). + +##### 잔돈에 대해서 + +캐롤에게 2개의 코인을 보내고 3개를 앨리스에게서 받는다고 해봅시다.이렇게 하려면 당신은 남은 1개의 코인을 잔돈으로 당신에게 돌려줘야 합니다. 이때, 다른 비밀키를 blinding factor 로 만들어서 (12라고 합시다.) 출력값을 보호해야 합니다. 캐롤은 이전에 썻던 그녀의 비밀키를 씁니다. + + 잔돈의 출력값 : 12*G + 1*H + 캐롤의 출력값 : 113*G + 2*H + +블록체인 안에서의 결과는 예전과 매우 흡사합니다. 그리고 Signature 은 초과되는 값과 함께 다시 만들어질겁니다. 이 예시에서는 97이라고 합시다. + + (12*G + 1*H) + (113*G + 2*H) - (28*G + 3*H) = 97*G + 0*H + +##### Range Proofs + +위의 모든 계산에서 트랜잭션의 값들은 항상 양의(+)값입니다. 음의 값은 모든 트랜잭션마다 새로운 돈을 만들수 있다는 것이므로 매우 문제점이 될겁니다. + +예를 들어 입력값이 3이고 출력값이 5과 -3인 트랜잭션을 만들수 있으며 이것은 이전 섹션의 정의에 따라 잘 구성된 트랜잭션입니다. 적절한 좌표 `x.H`가 다른 좌표처럼 곡선위에 있어서 _x_가 음수이더라도 찾기가 쉽지 않습니다. + +이 문제점을 해결하기 위해서, MimbleWimble 은 Range proofs 라는 다른 암호학 개념을 사용합니다. ( 이 또한 Confidential Transaction 에서 유래했습니다.) +Range proof 란 숫자를 밝히지 않고 어떤 숫자가 주어진 범위안에 있는지 증명하는 것입니다. +Range proof 에 대해서 자세히 설명하지 않을것이지만은, 그래도 어떤 `r.G + v.H` 의 결과가 _v_ 가 0보다 크고 오버플로우가 일어나지 않는다는 것을 증명할 수 있습니다. 또한 위의 예에서 유효한 Range proof 를 만들기 위해서 트랜잭션을 만들고 Signing 할때 사용된 초과값인 113과 28 두 값이 알려지는것은 중요합니다. 그 이유에 대해선 [range proof paper](https://eprint.iacr.org/2017/1066.pdf) 안에 Range proof에 대해 좀더 자세한 설명이 있습니다. + +#### 모든것을 함깨 놓고 이해하기 + +MimbleWimlbe 트랜잭션은 다음을 포함합니다. + +* 이전의 출력값들이 참조하고 사용한 입력값의 셋트들 +* 새로운 출력값들은 다음을 포함합니다. + * 곡선위에서 `r.G + v.H` 로 합해 지는 값 과 blinding factor (그냥 새로운 비밀 키). + * v 가 음수가 아님을 보여주는 Range proof. +* 분명히 명시된 트랜잭션 수수료 +* 수수료가 더해진 모든 출력밧에서 입력값을 뺸 초과 blinding 값이 계산되고 그것이 비밀키로 사용된 Signature. + +### 블록들과 체인 state에 대해서 + +위에서 MimbleWimble 트랜잭션이 유요한 블록체인에 필요한 속성을 유지하면서 어떻게 강한 익명성을 보장하는지 설명했습니다.예를 들면 트랜잭션이 더이상 코인을 만들지 않으면서 비밀키를 통해 소유권을 증명하지 않는 방법들 같은것 말이죠. + +추가적으로 _cut-through_ 라는 개념이 MimbleWimble 블록 포멧에 사용 됩니다. 이로 인해 MimbleWimble 체인은 아래와 같은 장점을 얻습니다. + +* 대부분의 트랜잭션 데이터는 보안을 희생하지 않고서도 시간이 지나면 없어 질 수 있으므로 엄청나게 좋은 확장성을 얻게 됩니다. +* 트랜잭션 데이터를 섞고 없애서 익명성을 추가로 획득합니다. +* 새로운 노드가 네트웍에서 동기화를 이룰때 매우 효과적입니다. + +#### 트랜잭션 합치기 + +트랜잭션은 다음와 같은것들로 이뤄져 있다는걸 상기해봅시다. + +* 이전의 출력값들이 참조하고 사용한 입력값의 셋트들 +* 새로운 출력값의 세트들 ( Pederson commitment) +* kernal execess와 (kernel 초과값이 공개키로 사용된) 트랜잭션 Signature로 이뤄진 트랜잭션 Kernel. + +sign 된 트랜잭션과 Signature 은 _transaction kernel_ 에 포함됩니다. +Signature 공개키로서 트랜잭션의 합이 0임을 증명하는 _kernel excess_ 를 이용해서 생성됩니다. + + (42*G + 1*H) + (99*G + 2*H) - (113*G + 3*H) = 28*G + 0*H + +이번 예시에서 공개키는 `28*G` 입니다. + +다음은 어떠한 유효한 트랜잭션에서도 참이라고 말 할 수 있습니다. (단순함을 위해 수수료는 무시합니다. ) + + 출력값의 합 - 입력값의 합 = kernel_excess + +블록이 입력값과 출력값의 합 그리고 트랜잭션 kernel들의 집합이면 블록도 마찬가지라고 할 수 있습니다. 트랜잭션의 출력값을 더할 수 있고 입력값의 합을 뺀다음 그 결과인 Perderson commitment 와 kernal excess와 비교합니다. + + 출력값의 합 - 입력값의 합 = kernel_excess의 합 + +약간 단순화 시켜서 ( 트랜잭션 수수료를 무시하고) 우리는 MimbleWimbl block 이 MimbleWimble 트랜잭션들로 다뤄진다고 말 할 수 있습니다. + +##### Kernel 오프셋들 + +위에 설명했던겉 처럼 MimbleWimble 블록과 트랜잭션에 조그마한 문제가 있습니다. 그것은 블록에 있는 구성 트랜잭션을 재구성하는것이 가능합다는 겁니다.(그리고 어떤 사소한 경우에도요). +이것은 분명히 프라이버시에는 좋지 않습니다. 이걸 "subset" 문제 라고 합니다. +"Subset" 문제란 주어진 입력값들, 출력값들과 트랜잭션 kernel들의 Subset 들이 재조합되어서 유효한 트랜잭션을 다시 만든다는 것입니다. + +예를 들어 다음과 같이 두 트랜잭션이 있다고 해봅시다. + + (in1, in2) -> (out1), (kern1) + (in3) -> (out2), (kern2) + +다음과 같은 블록에 합칠 수 있을겁니다. ( 아니면 트랜잭션을 합쳐도 됩니다.) + + (in1, in2, in3) -> (out1, out2), (kern1, kern2) + +(합계가 0일경우 ) 트랜잭션들 중 하나를 복구하기 위해서 가능한 모든 순열 조합을 조합해보는것은 쉽습니다. + + (in1, in2) -> (out1), (kern1) + +또한 남은 트랜잭션이 다른 유효한 트랜잭션을 만드는데 사용되기도 합니다. + + (in3) -> (out2), (kern2) + +이런것을 완화 시키기 위해 _kernel offset_ 이라는 것을 모든 트랜잭션 kernel 에 포함시킵니다. 실행 값이 0이라는 것을 증명하기 위해 kernel excess 에 더해져야 하는 blinding factor (비밀키)입니다. + + 출력값의 합 - 입력값의 합 = kernel_excess + kernel 오프셋(offset) + +블록 안에서 트랜잭션을 합칠때, _single_ 통합 오프셋(offset)을 블록 헤더에 저장합니다. +그래서 single 오프셋으로 인해 개별 트랜잭션 kernel offset 을 개별로 분리할 수 없고 트랜잭션 들은 더이상 재구성 될 수 없습니다. + + 출력값의 합 - 입력값의 합 = kernel_excess의 합 + kernel_offset + +키 `k`를 트랜잭션 구성 중에 `k1+k2` 안에 나누어서 넣었습니다. 트랜잭션 커널인`(k1+k2)*G` 에 대해 excess 인 `k1*G`와 오프셋(offset) 인 `k2`를 보여주고 이전처럼 `k1*G`로 트랜잭션에 sign 합니다. + +블록을 만드는 동안 블록안의 모든 트랜잭션을 커버하기 위한 한개의 통합 `k` 오프셋을 만들기 위해 `k2`오프셋을 간단히 합할 수 있습니다. `k2`오프셋은 어떤 개별 트랜잭션이 복구되지 못하도록 합니다. + +#### 컷 스루 (Cut-through) + +블록들은 채굴자들이 여러 트랜잭션들을 하나의 세트에 넣고 체인에 더할수 있게 합니다. +다음 블록은 3개의 트랜잭션을 포함하고 있습니다. 오직 입력과 출력만을 보여줍니다. +소비한 출력값은 입력값을 참고 합니다. 출력값은 소문자 x로 표시된 이전 블록을 포함합니다. + + I1(x1) --- O1 + |- O2 + + I2(x2) --- O3 + I3(O2) -| + + I4(O3) --- O4 + |- O5 + +다음과 같은 두가지 성질을 알려드리자면: +* 이 블록 안에서는 어떤 출력값은 포함된 입력값을 바로 사용합니다.(I3는 02를 소비하고 I4는 03을 소비합니다.) +* 실제로 각 트랜잭션의 구조는 문제가 아닙니다. 모든 트랜잭션들의 개개의 합계가 0이듯이 모든 트랜잭션의 입력값과 출력값이 0이여야만 합니다. + +트랜잭션과 비슷하게 블록에서 체크해야 되는 것은 _transaction kernels_ 에서 비롯되는 소유권의 증명과 coinbase 에서 증가하는 코인 외 모든 블록이 돈의 공급을 추가하지 않았다는 것입니다. +매칭된 값은 전체의 값을 상쇄하므로 매치되는 입력값과 출력값은 없앨 수 있고 다음과 같이 좀 더 작은 블록이 됩니다. + + I1(x1) | O1 + I2(x2) | O4 + | O5 + +모든 트랜잭션 구조는 다 제거되었고 입력값과 출력값의 순서는 더이상 중요하지 않습니다. +그러나 블록에서 입력값을 뺸 모든 출력값의 합은 여전히 0임을 보증합니다. + +블록은 아래와 간단히 말하자면 아래를 포함합니다. + +* 블록헤더 +* 컷 스루 이후 남은 입력값의 리스트 +* 컷 스루 이후 남은 출력값의 리스트 +* 모든 블록을 커버하기 위한 단일 kernel offset +* 트랜잭션 kernel들은 각 트랜잭션에 아래와 같은 것들을 포함합니다. + * The public key `r*G` obtained from the summation of all the commitments. + * 모든 커밋들의 합을 포함한 공개키 `r*G` + * 초과값 (excess value) 을 이용해 생성된 Signature + * 채굴 수수료 + +이런 방법으로 구조가 만들어진다면 MimbleWimblw 블록은 엄청나게 좋은 프라이버시를 보장할 수 있습니다. + +* 중간 트랜잭션 ( 컷 스루 트랜잭션) 은 트랜잭션 kernel에서만 표시될것 입니다. +* 모든 출력값은 똑같이 보일것입니다. 출력값은 다른 것과 구분하기 블가능한 아주 큰 숫자일겁니다. 만약 하나를 다른 출력값에서 제외하려면 모든 출력값을 제외해야 합니다. +* 모든 트랜잭션 구조는 지워지고 출력값이 각 입력값과 매치된다고 말하기엔 불가능 해집니다. + +그리고 아직까진 모든게 유효합니다! + +#### 모두 컷 스루( Cut-through ) 하기 + +이전 예시의 블록으로 돌아가서 출력값인 x1,과 x2는 I1과 I2에 대해서 사용되고 이것은 반드시 이전 블록체인 안에서 나타나야 합니다. 이 블록이 추가된 이후에 I1과 I2 과 출력값들은 전체 합계에 영향을 주지 않으므로 모든 체인에서 지워 질 수 있습니다. + +일반화 하자면, 헤더를 제외하고 어떤 시점에서든 체인의 스테이트는 다음과 같은 정보로 요약될 수 있습니다. + + +1. 체인안에서 채굴에 의해서 만들어진 코인의 총량 +2. 쓰지 않은 출력값의 모든 세트 +3. 각 트랜잭션의 트랜잭션 kernel + +첫번째 정보는 Genesis 블록으로부터의 거리인 블록 높이를 가지고 유추 될 수 있습니다. 그리고 쓰지 않는 출력값과 트랜잭션 kernel은 매우 작습니다. 이것에는 아래와 같이 2가지 중요한 결과를 가지고 있습니다. + +* MimbleWimble 블록체인에 있는 노드가 유지해야 되는 스테이트가 매우 작습니다.(비트코인 사이즈의 Blockchain의 경우 수 기가 바이트이고 잠재젹으로 수백 메가바이트까지 최적화 될 수 있습니다.) +* 새로운 노드가 MimbleWimble 체인에 가입히면, 전달해야 하는 정보의 양이 매우 적습니다. + +덧붙여서 출력값을 더하거나 제거하더라도 쓰지 않는 출력값의 모든 세트를 조작할 순 없습니다. 그렇게 하면 트랜잭션 kernel 내의 모든 blinding factor의 합과 출력값 내의 blinding factor의 합이 달라집니다. + +### 결론 내리기 + +이 문서에서는 MimbleWimble 블록체인 안의 기본적인 원리에 대해서 다루었습니다. +타원 곡선 암호의 다른 성질을 사용해서 알아보기 어려우나 적절하게 입증될 수 있는 트랜잭션을 만들수 있습니다. 블록에 이러한 성질들을 일반화 시키면 큰 용량의 블록체인 데이터를 없앨 수 있고 새로운 피어들에게 높은 확장성과 빠른 동기화를 가능하게 할 수 있습니다. diff --git a/doc/intro_NL.md b/doc/intro_NL.md index 0d8c6e5efc..2b39e7270e 100644 --- a/doc/intro_NL.md +++ b/doc/intro_NL.md @@ -1,6 +1,6 @@ # Inleiding tot MimbleWimble en Grin -*Lees dit in andere talen: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*Lees dit in andere talen: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble is een blockchain formaat en protocol die extreem goede schaalbaarheid, privacy en fungibiliteit biedt door zich te berusten op sterke cryptografische primiteven. Het adresseert de lacunes die in bijna alle huidige blockchain-implementaties bestaan. diff --git a/doc/intro_PT-BR.md b/doc/intro_PT-BR.md index 5ecc9dd128..2be97ea76e 100644 --- a/doc/intro_PT-BR.md +++ b/doc/intro_PT-BR.md @@ -1,6 +1,6 @@ # Introdução ao MimbleWimble e ao Grin -*Leia isto em outros idiomas: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*Leia isto em outros idiomas: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* O MimbleWimble é um formato e protocolo blockchain que fornece ótima escalabilidade, privacidade e fungibilidade, para isso contando com primitivas criptográficas fortes. Ele aborda as lacunas existentes em quase todos as implementações blockchain atuais. diff --git a/doc/intro_RU.md b/doc/intro_RU.md index 04242bbdba..16c3a7825b 100644 --- a/doc/intro_RU.md +++ b/doc/intro_RU.md @@ -1,6 +1,6 @@ # Введение в МимблВимбл и Grin -*На других языках: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*На других языках: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* МимблВимбл это формат и протокол блокчейна, предоставляющий исключительную масштабируемость, приватность и обезличенность криптовалюты, diff --git a/doc/intro_SE.md b/doc/intro_SE.md index 8a47caf71e..8bb841a43d 100644 --- a/doc/intro_SE.md +++ b/doc/intro_SE.md @@ -1,6 +1,6 @@ # Introduktion till MimbleWimble och Grin -*Läs detta på andra språk: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*Läs detta på andra språk: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble är ett blockkedjeformat och protokoll som erbjuder extremt bra skalbarhet, integritet, och fungibilitet genom starka kryptografiska primitiver. diff --git a/doc/intro_ZH-CN.md b/doc/intro_ZH-CN.md index ca0dc1ec32..b5c3662d28 100644 --- a/doc/intro_ZH-CN.md +++ b/doc/intro_ZH-CN.md @@ -1,7 +1,7 @@ MimbleWimble 和 Grin 简介 ===================================== -*阅读其它语言版本: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md).* +*阅读其它语言版本: [English](intro.md), [简体中文](intro_ZH-CN.md), [Español](intro_ES.md), [Nederlands](intro_NL.md), [Русский](intro_RU.md), [日本語](intro_JP.md), [Deutsch](intro_DE.md), [Portuguese](intro_PT-BR.md), [Korean](intro_KR.md).* MimbleWimble是一个区块链格式和协议,依托于健壮的加密原语,提供非常好的可扩展性、隐私和可替代性。它解决了当前几乎所有实现的区块链(与现实需求之间)差距。MimbleWimble 的白皮书在[本项目的WiKi](https://github.com/mimblewimble/docs/wiki/A-Brief-History-of-MinbleWimble-White-Paper)中可以找到,WiKi是开放的。 diff --git a/doc/pruning.md b/doc/pruning.md index 80e2ef4b0d..bc05f35bb6 100644 --- a/doc/pruning.md +++ b/doc/pruning.md @@ -1,5 +1,7 @@ # Pruning Blockchain Data +*Read this in other languages: [Korean](pruning_KR.md).* + One of the principal attractions of MimbleWimble is its theoretical space efficiency. Indeed, a trusted or pre-validated full blockchain state only requires unspent transaction outputs, which could be tiny. @@ -63,8 +65,7 @@ The full validation of the chain state requires that: In addition, while not necessary to validate the full chain state, to be able to accept and validate new blocks additional data is required: -* The output features and switch commitments, making the full output data - necessary for all UTXOs. +* The output features, making the full output data necessary for all UTXOs. At minimum, this requires the following data: diff --git a/doc/pruning_KR.md b/doc/pruning_KR.md new file mode 100644 index 0000000000..6c26cc1e3e --- /dev/null +++ b/doc/pruning_KR.md @@ -0,0 +1,62 @@ +# 블록체인 데이터 프루닝(가지치기)에 대해 + +MimbleWimble의 주된 매력 중 하나는 이론적인 공간효율성 입니다. 실제로 신뢰 할수 있거나 또는 사전에 입증된 전체 블록체인 스테이트는 아주 작을수도 있는 UTXO(unspent transaction outputs)만 나타냅니다. + +Grin의 블록체인에는 다음 유형의 데이터가 포함됩니다 (MimbleWimble 프로토콜에 대한 사전 지식이 있다고 가정합니다). + +1. 아래를 포함하는 트랜잭션 출력값 + 1. Pedersen commitment (33 bytes). + 2. range proof (현재는 5KB 이상) +2. 출력값의 레퍼런스인 트랜잭션 입력값 (32 bytes) +3. 각각의 트랜잭션에 포함된 트랜잭션 "증명들" + 1. 트랜잭션의 excess commitment 합계(33 bytes) + 2. 초과값과 함께 생성된 서명 (평균 71 bytes) +4. 머클트리와 작업증명을 포함한 블록헤더 (약 250 bytes) + +백만개의 블록에 천만 개의 트랜잭션 (2 개의 입력이 있고 평균 2.5 개의 출력값이 있다고 가정할때) 과 10만개의 UTXO(원문에서는 unspent outputs라고 표기 - 역자 주)를 가정 할 때 전체 체인 (Pruing 없음, 컷 쓰루 없음)과 함께 대략적인 체인의 크기를 얻습니다. + +* 128GB 크기의 트랜잭션 데이터 (inputs and outputs). +* 1 GB 크기의 트랜잭션 proof data. +* 250MB 크기의 block headers. +* 약 130GB 크기의 전체 체인 사이즈. +* 1.8GB크기의 컷-스루(cut-through) 이후의 전체 체인 사이즈(헤더 데이터는 포함함) +* 520MB 크기의 UTXO 사이즈. +* Total chain size, without range proofs of 4GB. +* 4GB크기의 range proof가 없는 경우 전체 체인 사이즈 +* 3.3MB 크기의 range proof가 없는 경우 UTXO 사이즈 + +모든 데이터에서 체인이 완전히 검증되면 UTXO commitment의 세트 만 노드 작동에 필수적으로 필요합니다. + +데이터가 정리(prune) 될 수있는 아래와 같은 몇 가지 상황이 있을 수 있습니다. + +* 입증된 풀 노드는 여유공간에 확인된 데이터들을 삭제 할 수 있습니다. +* 풀 노드는 빈 공간의 유효성을 확인 +* 부분 검증 노드 (SPV와 유사함)는 모든 데이터를 수신하거나 유지하는 데 관심이 없을 수 있습니다. +* 새 노드가 네트워크에 참여하면 결과적으로 풀 노드가 될지라도 더 빨리 사용할 수있도록 하기 위해 부분 검증 노드로 일시적으로 작동 할 수 있습니다. + +## 완전히 정리된 스테이트(Fully Pruned State)의 입증에 대해서 + +(데이터)Pruning은 가능한 한 많은 양의 데이터를 제거하면서 MimbleWimble 스타일의 검증을 보장하는 것이 필요합니다. +이는 pruning 노드 상태를 정상적으로 유지하는 데 필요할 뿐만 아니라 최소한의 양의 데이터만 새 노드로 전송할 첫번째 고속 동기화에서도 필요합니다. + +체인 스테이트의 완전한 입증을 위해 아래와 같은 사항들이 필요합니다. + +* 모든 Kernel의 서명들은 kernel의 공개키에 의해서 증명됩니다. +* The sum of all UTXO commitments, minus the supply is a valid public key (can + be used to sign the empty string). +* 모든 커널의 pubkeys 합계는 모든 UTXO commitment에서 공급을 뺀 값과 같습니다. +* UTXO PMMR의 루트 해시, Range proof의 PMMR 및 Kernel의 MMR은 유효한 작업증명 체인의 블록헤더와 일치힙니다. +* 모든 Range proof가 유효해야 합니다. + +또한 전체 체인의 스테이트에 대해 확인 할 필요는 없지만 새 블록을 받아들이고 유효성 입증을 하려면 아래와 같은 추가 데이터가 필요합니다. + +* 출력 기능에서 모든 UTXO에 필요한 전체 출력 데이터를 만듭니다 + +(그러기 위해선)최소한 다음과 같은 데이터가 필요합니다. + +* 블록헤더의 체인 +* 체인에 포함된 순서로 되어있는 모든 Kernel들. 이 Kernel들은 Kernel MMR 의 재구성을 가능하게 합니다. +* 모든 UTXO(원문에서는 unspent output 으로 표기 - 역자 주) +* 정리된 데이터(Pruned data)의 해시를 알기위한 UTXO MMR과 Range proof MMR. + +입증된 노드에 의해서 랜덤하게 선택된 Range proof의 하위 set만 증명함으로써 추가 pruning이 가능 할 수 있습니다. \ No newline at end of file diff --git a/doc/release_instruction.md b/doc/release_instruction.md index 21a950a950..c8eb136206 100644 --- a/doc/release_instruction.md +++ b/doc/release_instruction.md @@ -123,9 +123,9 @@ Remember to replace `0.3.1-pre1` as the real version, and warmly remind the [[Ve If you're NOT the owner of the github repo, but at least you have to be a committer which has the right to do a release, the following steps are needed to trigger a version release: 1. Go to release page of the repo, click **Draft a new release**, remember to check the branch is what you're working on! set the **Tag version** to the release number (for example: `0.3.1-pre1`), and set anything in **Release title** and **description**, then click **Publish release**. Don't worry the title and description parts because we need delete it in next step. -1. Because github **release** will be auto-created by our `auto-release` building script, we MUST delete the **release** which we just created in previous step! (Unfortunately, there's no way to only create **tag** by web.) +1. Because github **release** will be auto-created by our `release-jobs` building script, we MUST delete the **release** which we just created in previous step! (Unfortunately, there's no way to only create **tag** by web.) -Even normally Travis-CI need tens of minutes to complete building, I suggest you complete step 2 quickly, otherwise the `auto-release` script will fail on error "release already exist". +Even normally Travis-CI need tens of minutes to complete building, I suggest you complete step 2 quickly, otherwise the `release-jobs` script will fail on error "release already exist". ### 2. Travis-CI Building @@ -135,7 +135,7 @@ The release building is just one of the **TEST_DIRS**, named as `none`. So each So, the point is: the release building job is that one tagged with `TEST_DIR=none`. -Note: `auto-release` script will only be executed on `deploy` stage, and according to Travis-CI, it will be skipped for any **pull-request** trigger, and since we set `tag: true` it will be only executed when triggered by a tag. +Note: `release-jobs` script will only be executed on `deploy` stage, and according to Travis-CI, it will be skipped for any **pull-request** trigger, and since we set `tag: true` it will be only executed when triggered by a tag. ### 3. Check the Release Page diff --git a/doc/state.md b/doc/state.md index b9978427f6..466e347dbc 100644 --- a/doc/state.md +++ b/doc/state.md @@ -1,5 +1,7 @@ # State and Storage +*Read this in other languages: [Korean](state_KR.md), [日本語](state_JP.md).* + ## The Grin State ### Structure diff --git a/doc/state_JP.md b/doc/state_JP.md new file mode 100644 index 0000000000..0dbd7c0a66 --- /dev/null +++ b/doc/state_JP.md @@ -0,0 +1,48 @@ +# 状態とストレージ + +*別の言語で読む: [Korean](state_KR.md), [日本語](state_JP.md).* + +## Grinの状態 + +### 構造 + +Grinのチェーンの全ての情報はこれらによって成り立っている: + +1. 全てのUTXOのセット +1. それぞれのアウトプットのレンジプルーフ +1. 全てのトランザクションカーネル +1. 上記に対応するMMR(アウトプットのMMRはUTXOだけでなく、 *全ての* アウトプットのハッシュを含むという例外はある) + +加えて、チェーン内の全てのハッシュは最も(PoWの)仕事をしているチェーンにアンカーされている必要がある。 +一度それぞれのレンジプルーフをバリデートし、全てのカーネルコミットメントの合計値を計算すれば、もはやレンジプルーフとカーネルはノードにとって必要ないことに注意。 + +### バリデーション + +Grinの全ての状態を知っていれば、これらをバリデートできる: + +1. カーネルシグチャがそれぞれのコミットメント(公開鍵)に対して正しいこと。これによりカーネルが正しいと言える。 +1. 全てのカーネルコミットメントの合計値が、全てのUTXOコミットメント-全ての共有量と等しいこと。これにより、カーネルとアウトプットコミットメントが全て正しく、予想外のコインが生まれていないことが言える。 +1. 全てのUTXO、レンジプルーフ、カーネルのハッシュがそれぞれのMMR内にあり、正しいルートにハッシュされていること。 +1. ある時点で与えられているブロックヘッダーの中で最も(PoWの)仕事をしているブロックヘッダーが3つのMMRのルートを含んでいること。これにより、MMRが正しいことと、全ての状態は最も仕事をしているチェーンによって作られたことが検証できる。 + +### MMRと剪定 + +それぞれのMMRのリーフノードを生成するためのデータは、それらの位置の情報に加え以下の通り: + +* アウトプットMMRはフィーチャーフィールドとジェネシス以降の全てのアウトプットのコミットメントのハッシュ +* レンジプルーフMMRは全てのレンジプルーフのデータのハッシュ +* カーネルMMRは全てのカーネルのフィールド(フィーチャー、手数料、ロックハイト、余剰なコミットメント、余剰な署名)のハッシュ + +全てのアウトプット、レンジプルーフ、カーネルに対応するMMRはそれらが発生したブロックのMMRに加えられる(全てのブロックデータはソートされている必要があるのはこのため)。 + +アウトプットが使用されるように、それぞれのコミットメントとレンジプルーフデータは削除されうる。 +加えて、対応するアウトプットとレンジプルーフのMMRは剪定されうる。 + +## 状態のストレージ + +Grinにおけるアウトプット、レンジプルーフ、カーネルのデータストレージはシンプルで、メモリーマップドなデータアクセスができる追記型のプレーンなファイルを使用。 +アウトプットが使用されたら、削除ログが削除可能な状態として保持される。 +それらの状態は全て同じオーダーとしてインサートされるので、MMRノードの状態と上手いこに一致している。 +削除ログが大きくなった場合、時々削除されたものを除いたうえでリライトする。 +これにより、対応するファイルがコンパクト化され(ここでも追記のみ)、削除ログは空になる。 +MMRのためには少し複雑化が必要。 diff --git a/doc/state_KR.md b/doc/state_KR.md new file mode 100644 index 0000000000..737cd5b630 --- /dev/null +++ b/doc/state_KR.md @@ -0,0 +1,46 @@ +# 상태와 스토리지 + +## Grin의 상태 + +### 구조 + +Grin chain의 모든 상태는 다음 데이터와 같이 이루어져 있습니다. + +1. unspent output(UTXO) 세트 +1. 각 출력값에 대한 range proof +1. 모든 트랜잭션 커널(kernel)들 +1. 1,2,3번의 각각의 MMR들 (예외적으로 출력값 MMR은 사용되지 않은 것 뿐만 아니라 *모든* 출력값의 해쉬를 포함합니다.) + +더해서, 유효한 Proof of work 와 함께 chain 안의 모든 헤더들은 상기 상태에 대해 고정되어야 합니다. (상태는 가장 많이 일한 체인과 일치합니다.) +한번 각각의 range proof 가 인증되고 모든 kernel의 실행 합계가 계산되었다면 range proof와 kernel 들은 node 의 작동에 꼭 필요하진 않습니다. + +### 인증하기 + +완전한 Grin의 상태를 사용해서 우리는 다음과 같은 것들을 인증 할 수 있습니다. + +1. Kernel 의 signature 가 Kernel의 실행에 대해 유효하다면 (공개키), 이것은 Kernel이 유효하다는것을 증명합니다. +2. 모든 커밋 실행의 합이 모든 UTXO 실행의 합에서 총 공급량을 뺸 값이 같다면 이것은 Kernal과 출력값의 실행들이 유효하고 코인이 새로이 만들어지지 않았다는 것을 증명합니다. +3. 모든 UTXO, range prook 와 Kernel 해쉬들은 각각의 MMR이 있고 그 MMR 들은 유효한 root 를 해쉬합니다. +4. 특정 시점에 가장 많이 일했다고 알려진 Block header 에는 3개의 MMR에 대한 root 가 포함됩니다. 이것은 전체 상태가 가장 많이 일한 chain (가장 긴 체인)에서 MMR과 증명들이 만들어졌다는 것을 입증합니다. + +### MMR 과 Pruning + +각각의 MMR에서 리프 노드에 대한 해시를 생성하는 데 사용되는 데이터 위치는 다음과 같습니다. + +* MMR의 출력값은 제네시스 블록 이후부터 피쳐 필드와 모든 출력값의 실행들을 해시합니다. +* range proof MMR은 모든 Range proof 데이터를 해시합니다. +* Kernel MMR 은 피쳐, 수수료, lock height, excess commitment와 excess Signature같은 모든 값을 해시합니다. + +모든 출력, 범위 증명 및 커널은 각 블록에서 발생하는 순서대로 각 MMR에 추가됩니다.블록 데이터는 정렬이(to be sorted) 되어야 합니다. + +산출물이 소비됨에 따라 commitment 및 range proof 데이터를 지울 수 있습니다. 또한 해당 출력 및 range proof MMR을 pruning 할 수 있습니다. + +## 상태 스토리지 + +Grin 에 있는 출력값에 대한 데이터 스토리지, Range proof 와 kernel은 간단합니다. +그 형태는 데이터 엑세스를 위한 메모리 매핑 된 append only 파일입니다. +출력값이 소비되는것에 따라서 제거 로그는 지울수 있는 위치를 유지힙니다. +이런 포지션은 MMR과 노드 포지션이 같은 순서로 입력되었으므로 잘 일치합니다. +제거 로그가 커지면 (Append only 파일도 )때때로 해당 파일을 지워진 부분 없이 다시 작성해서 압축하고 제거 로그를 비울 수 있습니다. + +MMR은 약간 더 복잡합니다. diff --git a/doc/stratum.md b/doc/stratum.md index eb4f8e7580..28a5fff0cf 100644 --- a/doc/stratum.md +++ b/doc/stratum.md @@ -1,5 +1,7 @@ # Grin Stratum RPC Protocol +*Read this in other languages: [Korean](stratum_KR.md).* + This document describes the current Stratum RPC protocol implemented in Grin. ## Table of Contents diff --git a/doc/stratum_KR.md b/doc/stratum_KR.md new file mode 100644 index 0000000000..d91589e05f --- /dev/null +++ b/doc/stratum_KR.md @@ -0,0 +1,536 @@ +# Grin Stratum RPC 프로토콜 + +이 문서는 Grin에 구현되어 있는 현재 Stratum RPC protocol 을 설명한 것입니다. + +## 목차 + +1. [Messages](#메세지_들) + 1. [getjobtemplate](#getjobtemplate) + 2. [job](#job) + 3. [keepalive](#keepalive) + 4. [login](#login) + 5. [status](#status) + 6. [submit](#submit) +2. [에러 메시지들](#error-messages) +3. [채굴자의 행동양식](#miner-behavior) +4. [참고 구현체](#reference-implementation) + +## 메세지 들 + +이 섹션에서는 각 메시지와 그 응답에 대해서 상술합니다. +어느때든, 채굴자가 로그인을 제외한 다음 중 한 요청을 하고 login 이 요구된다면 채굴자는 다음과 같은 에러 메시지를 받게 됩니다. + +| Field | Content | +| :------------ | :-------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | 채굴자가 보낸 method | +| error | {"code":-32500,"message":"login first"} | + +예시: + +```JSON +{ + "id":"10", + "jsonrpc":"2.0", + "method":"getjobtemplate", + "error":{ + "code":-32500, + "message":"login first" + } +} +``` +만약에 요청이 다음중 하나가 아니라면, Stratum 서버가 아래와 같은 에러 메시지를 보내게 됩니다. + +| Field | Content | +| :------------ | :------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | 채굴자가 보낸 method | +| error | {"code":-32601,"message":"Method not found"} | + +예시: + +```JSON +{ + "id":"10", + "jsonrpc":"2.0", + "method":"getgrins", + "error":{ + "code":-32601, + "message":"Method not found" + } +} +``` + +### `getjobtemplate` + +채굴자에 의해 시작되는 메시지입니다. +채굴자는 이 메시지로 작업을 요청 할 수 있습니다. + +#### Request + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "getjobtemplate" | +| params | null | + +예시 : + +``` JSON +{ + "id":"2", + "jsonrpc":"2.0", + "method":"getjobtemplate", + "params":null +} +``` + +#### Response + +Response 는 두가지 타입이 될 수 있습니다. + +##### OK response + +예시 + +``` JSON +{ + "id":"0", + "jsonrpc":"2.0", + "method":"getjobtemplate", + "result":{ + "difficulty":1, + "height":13726, + "job_id":4, + "pre_pow":"00010000000000003c4d0171369781424b39c81eb39de10cdf4a7cc27bbc6769203c7c9bc02cc6a1dfc6000000005b50f8210000000000395f123c6856055aab2369fe325c3d709b129dee5c96f2db60cdbc0dc123a80cb0b89e883ae2614f8dbd169888a95c0513b1ac7e069de82e5d479cf838281f7838b4bf75ea7c9222a1ad7406a4cab29af4e018c402f70dc8e9ef3d085169391c78741c656ec0f11f62d41b463c82737970afaa431c5cabb9b759cdfa52d761ac451276084366d1ba9efff2db9ed07eec1bcd8da352b32227f452dfa987ad249f689d9780000000000000b9e00000000000009954" + } +} +``` + +##### Error response + +만약 노드가 동기화 중이라면, 다음과 같은 메시지를 보낼것입니다. + +| Field | Content | +| :------------ | :-------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "getjobtemplate" | +| error | {"code":-32701,"message":"Node is syncing - Please wait"} | + +예시: + +```JSON +{ + "id":"10", + "jsonrpc":"2.0", + "method":"getjobtemplate", + "error":{ + "code":-32000, + "message":"Node is syncing - Please wait" + } +} +``` + +### `job` + +Stratum 서버로 인해 시작되는 메세지입니다. +Stratum 서버는 연결된 채굴자에게 작업을 자동적으로 보냅니다. +채굴자는 job_id=0 이면 현재의 작업을 중단해야 합니다. 그리고 현재의 작업을 현재 graph 가 완료되면 이 작업으로 대체해야 합니다. + +#### Request + +| Field | Content | +| :------------ | :------------------------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "job" | +| params | Int `difficulty`, `height`, `job_id` and string `pre_pow` | + +예시: + +``` JSON +{ + "id":"Stratum", + "jsonrpc":"2.0", + "method":"job", + "params":{ + "difficulty":1, + "height":16375, + "job_id":5, + "pre_pow":"00010000000000003ff723bc8c987b0c594794a0487e52260c5343288749c7e288de95a80afa558c5fb8000000005b51f15f00000000003cadef6a45edf92d2520bf45cbd4f36b5ef283c53d8266bbe9aa1b8daaa1458ce5578fcb0978b3995dd00e3bfc5a9277190bb9407a30d66aec26ff55a2b50214b22cdc1f3894f27374f568b2fe94d857b6b3808124888dd5eff7e8de7e451ac805a4ebd6551fa7a529a1b9f35f761719ed41bfef6ab081defc45a64a374dfd8321feac083741f29207b044071d93904986fa322df610e210c543c2f95522c9bdaef5f598000000000000c184000000000000a0cf" + } +} +``` + +#### Response + +이 메세지에는 Response 가 필요하지 않습니다. + +### `keepalive` + +연결을 계속 하기 위해서 채굴자에 의해 초기화 되는 메시지입니다. + +#### Request + +| Field | Content | +| :------------ | :--------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "keepalive" | +| params | null | + +예시: + +``` JSON +{ + "id":"2", + "jsonrpc":"2.0", + "method":"keepalive", + "params":null +} +``` + +#### Response + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "keepalive" | +| result | "ok" | +| error | null | + +예시: + +``` JSON +{ + "id":"2", + "jsonrpc":"2.0", + "method":"keepalive", + "result":"ok", + "error":null +} +``` + +### `login` + +*** +채굴자에 의해 시작되는 메시지입니다. +채굴자는 보통 채굴 프로그램으로 고정적으로 정해지는 login, password, agent 로 Grin Stratum 서버에 로그인 할 수 있습니다. + +#### Request + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "login" | +| params | Strings: login, pass and agent | + +예시: + +``` JSON + +{ + "id":"0", + "jsonrpc":"2.0", + "method":"login", + "params":{ + "login":"login", + "pass":"password", + "agent":"grin-miner" + } +} + +``` + +#### Response + +Response 는 두가지 타입이 될 수 있습니다. + +##### OK response + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "login" | +| result | "ok" | +| error | null | + +예사: + +``` JSON +{ + "id":"1", + "jsonrpc":"2.0", + "method":"login", + "result":"ok", + "error":null +} +``` + +##### Error response + +아직 구현되지 않았습니다. login이 필요할때, -32500 "Login firtst" 라는 에러를 리턴합니다. + +### `status` + +채굴자에 의해 시작되는 메시지입니다. +이 메시지는 채굴자에게 현재의 워커와 네트워크의 상태를 얻을 수 있게 합니다. + +#### Request + +| Field | Content | +| :------------ | :--------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "status" | +| params | null | + +예시: + +``` JSON +{ + "id":"2", + "jsonrpc":"2.0", + "method":"status", + "params":null +} +``` + +#### Response + +Response 는 아래와 같습니다. + +| Field | Content | +| :------------ | :------------------------------------------------------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "status" | +| result | String `id`. Integers `height`, `difficulty`, `accepted`, `rejected` and `stale` | +| error | null | + +예시: + +```JSON +{ + "id":"5", + "jsonrpc":"2.0", + "method":"status", + "result":{ + "id":"5", + "height":13726, + "difficulty":1, + "accepted":0, + "rejected":0, + "stale":0 + }, + "error":null +} +``` + +### `submit` + +채굴자에 의해 시작되는 메시지입니다. +마이너가 쉐어를 찾았을때, 노드에게 보내집니다. + +#### Request + +채굴자는 Stratum 서버에 작업 솔루션을 보냅니다. + +| Field | Content | +| :------------ | :-------------------------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| params | Int `edge_bits`,`nonce`, `height`, `job_id` and array of integers `pow` | + +예시: + +``` JSON +{ + "id":"0", + "jsonrpc":"2.0", + "method":"submit", + "params":{ + "edge_bits":29, + "height":16419, + "job_id":0, + "nonce":8895699060858340771, + "pow":[ + 4210040,10141596,13269632,24291934,28079062,84254573,84493890,100560174,100657333,120128285,130518226,140371663,142109188,159800646,163323737,171019100,176840047,191220010,192245584,198941444,209276164,216952635,217795152,225662613,230166736,231315079,248639876,263910393,293995691,298361937,326412694,330363619,414572127,424798984,426489226,466671748,466924466,490048497,495035248,496623057,502828197, 532838434 + ] + } +} +``` + +#### Response + +Response 는 세가지 타입이 될 수 있습니다. + +##### OK response + +이 타입은 Stratum 에 받아들여지지만 네트워크 타켓 난이도에서는 유효한 cuck(at)oo 솔루션이 아닙니다. + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| result | "ok" | +| error | null | + +예시: + +``` JSON +{ + "id":"2", + "jsonrpc":"2.0", + "method":"submit", + "result":"ok", + "error":null +} +``` + +##### Blockfound response + +이 타입은 Stratum 에 받아들여지고 네트워크 타켓 난이도에서는 유효한 cuck(at)oo 솔루션 입니다. + +| Field | Content | +| :------------ | :----------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| result | "block - " + hash of the block | +| error | null | + +예시: + +``` JSON +{ + "id":"6", + "jsonrpc":"2.0", + "method":"submit", + "result":"blockfound - 23025af9032de812d15228121d5e4b0e977d30ad8036ab07131104787b9dcf10", + "error":null +} +``` + +##### Error response + +에러 response는 stale과 rejected 라는 두가지 타입이 될 수 있습니다. + +##### Stale share error response + +이 타입은 유효한 솔루션이나 지난 작업이 현재의 것이 아닙니다. + +| Field | Content | +| :------------ | :-------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| error | {"code":-32503,"message":"Solution submitted too late"} | + +Example: + +```JSON +{ + "id":"5", + "jsonrpc":"2.0", + "method":"submit", + "error":{ + "code":-32503, + "message":"Solution submitted too late" + } +} +``` + +##### Rejected share error responses + +솔루션이 유효하지 않거나 너무 낮은 난이도일 수 있는 두 가지 가능성이 있습니다. + +###### Failed to validate solution error + +재출된 솔루션이 유효하지 않을 수 았습니다. + +| Field | Content | +| :------------ | :-------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| error | {"code":-32502,"message":"Failed to validate solution"} | + +Example: + +```JSON +{ + "id":"5", + "jsonrpc":"2.0", + "method":"submit", + "error":{ + "code":-32502, + "message":"Failed to validate solution" + } +} +``` + +###### Share rejected due to low difficulty error + +제출된 솔루션의 난이도가 너무 낮습니다. + +| Field | Content | +| :------------ | :--------------------------------------------------------------- | +| id | 요청 ID | +| jsonrpc | "2.0" | +| method | "submit" | +| error | {"code":-32501,"message":"Share rejected due to low difficulty"} | + +Example: + +```JSON +{ + "id":"5", + "jsonrpc":"2.0", + "method":"submit", + "error":{ + "code":-32501, + "message":"Share rejected due to low difficulty" + } +} +``` + +## Error Messages + +Grin Stratum protocole 구현체는 다음과 같은 에러 메시지를 포함하고 있습니다. + +| Error code | Error Message | +| :---------- | :------------------------------------- | +| -32000 | Node is syncing - please wait | +| -32500 | Login first | +| -32501 | Share rejected due to low difficulty | +| -32502 | Failed to validate solution | +| -32503 | Solution Submitted too late | +| -32600 | Invalid Request | +| -32601 | Method not found | + +## Miner behavior + +채굴자들은 반드시 다음과 같은 규칙들을 존중해야 할 것입니다. + +- 마이너들은 작업을 시작하기 전에 작업 nounce를 랜덤화 시켜야 합니다. +- 채굴자들은 반드시 서버가 샤로운 작업을 보낼때끼지 같은 작업을 채굴해야 하지만 언제든 새로운 작업을 요청 할 수 있습니다. +- 채굴자들은 서버로 부터 온 작업 요청을 rpc response로 보내면 안됩니다. +- 채굴자들은 RPC "id"를 정할 수 있고 같은 id로 response를 받기를 요구 할 수 있습니다. +- 마이너들은 keepalive 메시지를 보낼수 있습니다. +- 채굴자들은 로그인 request를 보낼 수 있습니다.(어떤 채굴자가 쉐어를 찾았는지 확인하기 위해서 / Log안에서 솔루션을 확인하기 위해 ) 로그인 request는 3가지 파라미터를 가지고 있어야만 합니다. +- Miners MUST return the supplied job_id with submit messages. +- 채굴자들은 주어진 job_id를 제출하는 메시지에 리턴해야 합니다. + +## Reference Implementation + +현재 구현체는 [mimblewimble/grin-miner](https://github.com/mimblewimble/grin-miner/blob/master/src/bin/client.rs) 에서 참고하세요. diff --git a/doc/switch_commitment.md b/doc/switch_commitment.md new file mode 100644 index 0000000000..a5199e3611 --- /dev/null +++ b/doc/switch_commitment.md @@ -0,0 +1,292 @@ +# Introduction to Switch Commitments + +## General introduction + +In cryptography a _Commitment_ (or _commitment scheme_) refers to a concept which can be imagined +like a box with a lock. You can put something into the box (for example a piece of a paper with a +secret number written on it), lock it and give it to another person (or the public). + +The other person doesn't know yet what's the secret number in the box, but if you decide to publish +your secret number later in time and want to prove that this really is the secret which you came +up with in the first place (and not a different one) you can prove this simply by giving the +key of the box to the other person. + +They can unlock the box, compare the secret within the box with the secret you just published +and can be sure that you didn't change your secret since you locked it. You "**committed**" +to the secret number beforehand, meaning you cannot change it between the time of +commitment and the time of revealing. + + +## Examples + +### Hash Commitment + +A simple commitment scheme can be realized with a cryptographic hash function. For example: Alice and Bob +want to play _"Guess my number"_ and Alice comes up with with her really secret number `29` which +Bob has to guess in the game, then before the game starts, Alice calculates: + + hash( 29 + r ) + +and publishes the result to Bob. The `r` is a randomly chosen _Blinding Factor_ which is +needed because otherwise Bob could just try hashing all the possible numbers for the game and +compare the hashes. + +When the game is finished, Alice simply needs to publish her secret number `29` and the +blinding factor `r` and Bob can calculate the hash himself and easily verify that Alice +did not change the secret number during the game. + + +### Pedersen Commitment + +Other, more advanced commitment schemes can have additional properties. For example MimbleWimble +and Confidential Transactions (CT) make heavy use of +_[Pedersen Commitments](https://link.springer.com/content/pdf/10.1007/3-540-46766-1_9.pdf)_, +which are _homomorphic_ commitments. Homomorphic in this context means that (speaking in the +"box" metaphor from above) you can take two of these locked boxes (_box1_ and _box2_) and +somehow "_add_" them together, so that you +get a single box as result (which still is locked), and if you open this single box later +(like in the examples before) the secret it contains, is the sum of the secrets +from _box1_ and _box2_. + +While this "box" metaphor no longer seems to be reasonable in the real-world this +is perfectly possible using the properties of operations on elliptic curves. + +Look into [Introduction to MimbleWimble](intro.md) for further details on Pedersen Commitments +and how they are used in Grin. + + +## Properties of commitment schemes: + +In general for any commitment scheme we can identify two important properties +which can be weaker or stronger, depending on the type of commitment scheme: + +- **Hidingness (or Confidentiality):** How good is the commitment scheme protecting the secret + commitment. Or speaking in terms of our example from above: what would an attacker need to + open the box (and learn the secret number) without having the key to unlock it? + +- **Bindingness:** Is it possible at all (or how hard would it be) for an attacker to somehow + find a different secret, which would produce the same commitment, so that the attacker could + later open the commitment to a different secret, thus breaking the _binding_ of the + commitment. + +### Security of these properties: + +For these two properties different security levels can be identified. + +The two most important combinations of these are + +- **perfectly binding** and **computationally hiding** commitment schemes and +- **computationally binding** and **perfectly hiding** commitment schemes + +"_Computationally_" binding or hiding means that the property (bindingness/hidingness) +is secured by the fact that the underlying mathematical problem is too hard to be solved +with existing computing power in reasonable time (i.e. not breakable today as computational +resources are bound in the real world). + +"_Perfectly_" binding or hiding means that even with infinite computing power +it would be impossible to break the property (bindingness/hidingness). + + + +### Mutual exclusivity: + +It is important to realize that it's **impossible** that any commitment scheme can be +_perfectly binding_ **and** _perfectly hiding_ at the same time. This can be easily shown +with a thought experiment: Imagine an attacker having infinite computing power, he could +simply generate a commitment for all possible values (and blinding factors) until finding a +pair that outputs the same commitment. If we further assume the commitment scheme is +_perfectly binding_ (meaning there cannot be two different values leading to the same +commitment) this uniquely would identify the value within the commitment, thus +breaking the hidingness. + +The same is true the other way around. If a commitment scheme is _perfectly hiding_ +there must exist several input values resulting in the same commitment (otherwise an +attacker with infinite computing power could just try all possible values as +described above). This concludes that the commitment scheme cannot be _perfectly +binding_. + +#### Always a compromise + +The key take-away point is this: it's **always a compromise**, you can never have both +properties (_hidingness_ and _bindingness_) with _perfect_ security. If one is _perfectly_ +secure then the other can be at most _computationally_ secure +(and the other way around). + + +### Considerations for cryptocurrencies + +Which roles do these properties play in the design of cryptocurrencies? + +**Hidingness**: +In privacy oriented cryptocurrencies like Grin, commitment schemes are used to secure +the contents of transactions. The sender commits to an amount of coins he sends, but for +the general public the concrete amount should remain private (protected by the _hidingness_ property of the commitment scheme). + +**Bindingness**: +At the same time no transaction creator should ever be able to change his commitment +to a different transaction amount later in time. If this would be possible, an attacker +could spend more coins than previously committed to in an UTXO (unspent transaction +output) and therefore inflate coins out of thin air. Even worse, as the amounts are +hidden, this could go undetected. + +So there is a valid interest in having both of these properties always secured and +never be violated. + +Even with the intent being that both of these properties will hold for the lifetime +of a cryptocurrency, still a choice has to be made about which commitment scheme to use. + + +#### A hard choice? + +Which one of these two properties needs to be _perfectly_ safe +and for which one it would be sufficient to be _computationally_ safe? +Or in other words: in case of a disaster, if the commitment scheme unexpectedly +gets broken, which one of the two properties should be valued higher? +Economical soundness (no hidden inflation possible) or ensured privacy (privacy will +be preserved)? + +This seems like a hard to choice to make. + + +If we look closer into this we realize that the commitment scheme only needs to be +_perfectly_ binding at the point in time when the scheme actually gets broken. Until +then it will be safe even if it's only _computationally_ binding. + +At the same time a privacy-oriented cryptocurrency needs to ensure the _hidingness_ +property **forever**. Unlike the _binding_ property, which only is important at the +time when a transaction is created and will not affect past transactions, the _hidingness_ +property must be ensured at all times. Otherwise, in the unfortunate case should the +commitment scheme be broken, an attacker could go back in the chain and unblind +past transactions, thus break the privacy property retroactively. + + +## Properties of Pedersen Commitments + +Pedersen Commitments are **computationally binding** and **perfectly hiding** as for a given +commitment to the value `v`: `v*H + r*G` there may exist a pair of different values `r1` +and `v1` such that the sum will be the same. Even if you have infinite computing power +and could try all possible values, you would not be able to tell which one is the original one +(thus _perfectly hiding_). + + +## Introducing Switch Commitments + +So what can be done if the bindingness of the Pedersen Commitment unexpectedly gets broken? + +In general a cryptocurrency confronted with a broken commitment scheme could choose to +change the scheme in use, but the problem with this approach would be that it requires to +create new transaction outputs using the new scheme to make funds secure again. This would +require every coin holder to move his coins into new transaction outputs. +If coins are not moved into new outputs, they will not profit from the +security of the new commitment scheme. Also, this has to happen **before** the scheme gets +actually broken in the wild, otherwise the existing UTXOs no longer can be assumed +to contain correct values. + +In this situation [_Switch Commitments_](https://eprint.iacr.org/2017/237.pdf) offer a neat +solution. These type of commitments allow changing the properties of the commitments just +by changing the revealing / validating procedure without changing the way commitments +are created. (You "_switch_" to a new validation scheme which is backwards +compatible with commitments created long before the actual "_switch_"). + + +### How does this work in detail + +First let's introduce a new commitment scheme: The **ElGamal commitment** scheme is a commitment +scheme similiar to Pedersen Commitments and it's _perfectly binding_ (but only _computationally +hiding_ as we can never have both). +It looks very similar to a Pedersen Commitment, with the addition of a new +element, calculated by multiplying the blinding factor `r` with another generator point `J`: + + v*H + r*G , r*J + +So if we store the additional field `r*J` and ignore it for now, we can treat it like +Pedersen Commitments, until we decide to also validate the full ElGamal +commitment at some time in future. This is exactly what was implemented in an +[earlier version of Grin](https://github.com/mimblewimble/grin/blob/5a47a1710112153fb38e4406251c9874c366f1c0/core/src/core/transaction.rs#L812), +before mainnet was launched. In detail: the hashed value of `r*J` +(_switch\_commit\_hash_) was added to the transaction output, but this came with +the burden of increasing the size of each output by 32 bytes. + +Fortunately, later on the Mimblewimble mailinglist Tim Ruffing came up with a really +[beautiful idea](https://lists.launchpad.net/mimblewimble/msg00479.html) +(initially suggested by Pieter Wuille), which offers the same advantages but doesn't +need this extra storage of an additional element per transaction output: + +The idea is the following: + +A normal Pedersen commitment looks like this: + + v*H + r*G + +(`v` is value of the input/output, `r` is a truly random blinding factor, and `H` and `G` are +two generator points on the elliptic curve). + +If we adapt this by having `r` not being random itself, but using another random number `r'` +and create the Pedersen Commitment: + + v*H + r*G + +such that: + + r = r' + hash( v*H + r'*G , r'*J ) + +(using the additional third generation point `J` on the curve) then `r` still is perfectly +valid as a blinding factor, as it's still randomly distributed, but now we see +that the part within the brackets of the hash function (`v*H + r'*G , r'*J`) is an +**ElGamal commitment**. + +This neat idea lead to the removal of the switch commitment hash from the outputs in this +(and following) [pull requests](https://github.com/mimblewimble/grin/issues/998) as now it +could be easily included into the Pedersen Commitments. + + +This is how it is currently implemented in Grin. Pedersen commitments are +used for the Confidential Transaction but instead of choosing the blinding factor `r` +only by random, it is calculated by adding the hash of an ElGamal commitment to a random `r'` +(see here in [main_impl.h#L267](https://github.com/mimblewimble/secp256k1-zkp/blob/73617d0fcc4f51896cce4f9a1a6977a6958297f8/src/modules/commitment/main_impl.h#L267)). + + +In general switch commitments were first described in the paper +["Switch Commitments: A Safety Switch for Confidential Transactions"](https://eprint.iacr.org/2017/237.pdf)). +The **"switch"** in the name comes from the fact that you can virtually flip a "switch" in +the future and simply by changing the validation procedure you can change the strength of +the bindingness and hidingness property of your commitments and this even works in a +backwards compatible way with commitments created today. + + + +## Conclusion + +Grin uses Pedersen Commitments - like other privacy cryptocurrencies do as well - with +the only difference that the random blinding factor `r` is created using the ElGamal +commitment scheme. + +This might not seem like a big change on a first look, but it provides an +important safety measure: + +Pedersen Commitments are already _perfectly hiding_ so whatever happens, privacy will +never be at risk without requiring any action from users. But in case of a disaster if the +bindingness of the commitment scheme gets broken, then switch commitments can be enabled +(via a soft fork) requiring that all new transactions prove that their commitment is not +breaking the bindingness by validating the full ElGamal commitment. + +But in this case users would still have a choice: + +- they can decide to continue to create new transactions, even if this might compromise + their privacy (only on their **last** UTXOs) as the ElGamal commitment scheme is + only computationally hiding, but at least they would still have access to their coins + +- or users can decide to just leave the money alone, walk away and make no more transactions + (but preserve their privacy, as their old transactions only validated the Pedersen commitment + which is perfectly hiding) + +There are many cases where a privacy leak is much more dangerous to one's life than +some cryptocurrency might be worth. But this is a decision that should be left up to +the individual user and switch commitments enable this type of choice. + +It should be made clear that this is a safety measure meant to be enabled in case of a +disaster. If advances in computing would put the hardness of the discrete log problem +in question, a lot of other cryptographic systems, including other cryptocurrencies, +will be in urgent need of updating their primitives to a future-proof system. The switch +commitments just provide an additional layer of security if the bindingness of Pedersen +commitments ever breaks unexpectedly. diff --git a/doc/table_of_contents.md b/doc/table_of_contents_.md similarity index 96% rename from doc/table_of_contents.md rename to doc/table_of_contents_.md index 77f3831304..67dc673b06 100644 --- a/doc/table_of_contents.md +++ b/doc/table_of_contents_.md @@ -1,5 +1,7 @@ # Documentation structure +*Read this in other languages: [Korean](table_of_contents_KR.md).* + ## Explaining grin - [intro](intro.md) - Technical introduction to grin diff --git a/doc/table_of_contents_KR.md b/doc/table_of_contents_KR.md new file mode 100644 index 0000000000..cd3b756caf --- /dev/null +++ b/doc/table_of_contents_KR.md @@ -0,0 +1,35 @@ +# 문서 목록 + +## Grin 에 대한 설명들 + +- [intro](intro_KR.md) - Grin 에 대한 기술적인 소개 +- [grin4bitcoiners](grin4bitcoiners.md) - Bitcoinner 의 관점에서 Grin 을 설명하기 + +## Grin 구현에 대해서 이해하기 + +- [grin4bitcoiners](grin4bitcoiners.md) - Grin 의 Blockchain이 어떻게 동기화 되는가에 대해서 +- [blocks_and_headers](chain/blocks_and_headers.md) - Grin이 어떻게 block과 header 를 chain안에서 찾는지에 대해서 +- [contract_ideas](contract_ideas.md) - 어떻게 smart contract 를 구현할 것인가에 대한 아이디어 +- [dandelion/dandelion](dandelion/dandelion.md) - 트랜잭션 전파 와 [컷 스루 방식](http://www.ktword.co.kr/abbr_view.php?m_temp1=1823). Stemming과 fluffing. +- [dandelion/simulation](dandelion/simulation.md) - Dandelion 시뮬레이션 - lock height 스테밍과 플러핑 없이 트랜잭션 합치기 +- [internal/pool](internal/pool.md) - 트랜잭션 풀에 대한 기술적인 설명에 대해서 +- [merkle](merkle.md) - Grin의 Merkle tree 에 대한 기술적인 설명 +- [merkle_proof graph](merkle_proof/merkle_proof.png) - Prunning 이 적용된 merkle proof의 예시 +- [pruning](pruning.md) - Pruning 의 기술적인 설명 +- [stratum](stratum.md) -Grin Stratum RPC protocol 의 기술적 설명 +- [transaction UML](wallet/transaction/basic-transaction-wf.png) - 상호작용 트랜잭션의 UML (`lock_height` 없이 트랜잭션 합치기) + +## 빌드하고 사용하기 + +- [api](api/api.md) - Grin 에 있는 다른 API 들과 어떻게 사용하는지에 대해서 +- [build](build.md) - Grin 바이너리를 어떻게 빌드하고 작동시키는 지에 대해서 +- [release](release_instruction.md) - Release 를 만드는것에 대한 안내 +- [usage](usage.md) - Testnet3 에서 어떻게 Grin 을 사용하는지에 대한 설명 +- [wallet](wallet/usage.md) - wallet 디자인에 대한 설명과 `grin wallet` 의 세부 명령어 + +## 외부자료 (위키) + +- [FAQ](https://github.com/mimblewimble/docs/wiki/FAQ) - 자주 물어보는 질문들 +- [Grin 빌드하기](https://github.com/mimblewimble/docs/wiki/Building) +- [Grin을 어떻게 사용하나요?](https://github.com/mimblewimble/docs/wiki/How-to-use-grin) +- [해킹과 기여하기](https://github.com/mimblewimble/docs/wiki/Hacking-and-contributing) diff --git a/keychain/Cargo.toml b/keychain/Cargo.toml index 1b1213f34f..5b3214aeb7 100644 --- a/keychain/Cargo.toml +++ b/keychain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_keychain" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -26,4 +26,4 @@ ripemd160 = "0.7" sha2 = "0.7" pbkdf2 = "0.2" -grin_util = { path = "../util", version = "1.1.0" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } diff --git a/keychain/src/keychain.rs b/keychain/src/keychain.rs index 31a5db408d..9f1948990e 100644 --- a/keychain/src/keychain.rs +++ b/keychain/src/keychain.rs @@ -142,6 +142,15 @@ impl Keychain for ExtKeychain { Ok(BlindingFactor::from_secret_key(sum)) } + fn create_nonce(&self, commit: &Commitment) -> Result { + // hash(commit|wallet root secret key (m)) as nonce + let root_key = self.derive_key(0, &Self::root_key_id())?; + let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.0[..]); + let res = res.as_bytes(); + SecretKey::from_slice(&self.secp, &res) + .map_err(|e| Error::RangeProof(format!("Unable to create nonce: {:?}", e).to_string())) + } + fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result { let skey = self.derive_key(amount, id)?; let sig = self.secp.sign(msg, &skey)?; diff --git a/keychain/src/types.rs b/keychain/src/types.rs index 2eb5de5dc2..9229d67809 100644 --- a/keychain/src/types.rs +++ b/keychain/src/types.rs @@ -468,6 +468,7 @@ pub trait Keychain: Sync + Send + Clone { fn derive_key(&self, amount: u64, id: &Identifier) -> Result; fn commit(&self, amount: u64, id: &Identifier) -> Result; fn blind_sum(&self, blind_sum: &BlindSum) -> Result; + fn create_nonce(&self, commit: &Commitment) -> Result; fn sign(&self, msg: &Message, amount: u64, id: &Identifier) -> Result; fn sign_with_blinding(&self, _: &Message, _: &BlindingFactor) -> Result; fn set_use_switch_commits(&mut self, value: bool); diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 7b70234c2e..ffad720c37 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_p2p" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -21,9 +21,9 @@ serde_derive = "1" log = "0.4" chrono = { version = "0.4.4", features = ["serde"] } -grin_core = { path = "../core", version = "1.1.0" } -grin_store = { path = "../store", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_store = { path = "../store", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] -grin_pool = { path = "../pool", version = "1.1.0" } +grin_pool = { path = "../pool", version = "1.1.0-beta.1" } diff --git a/p2p/src/conn.rs b/p2p/src/conn.rs index d1d5d80627..06a8a206ab 100644 --- a/p2p/src/conn.rs +++ b/p2p/src/conn.rs @@ -113,19 +113,18 @@ impl<'a> Response<'a> { resp_type: Type, body: T, stream: &'a mut dyn Write, - ) -> Response<'a> { - let body = ser::ser_vec(&body).unwrap(); - Response { + ) -> Result, Error> { + let body = ser::ser_vec(&body)?; + Ok(Response { resp_type, body, stream, attachment: None, - } + }) } fn write(mut self, sent_bytes: Arc>) -> Result<(), Error> { - let mut msg = - ser::ser_vec(&MsgHeader::new(self.resp_type, self.body.len() as u64)).unwrap(); + let mut msg = ser::ser_vec(&MsgHeader::new(self.resp_type, self.body.len() as u64))?; msg.append(&mut self.body); write_all(&mut self.stream, &msg[..], time::Duration::from_secs(10))?; // Increase sent bytes counter @@ -177,7 +176,7 @@ impl Tracker { where T: ser::Writeable, { - let buf = write_to_buf(body, msg_type); + let buf = write_to_buf(body, msg_type)?; let buf_len = buf.len(); self.send_channel.try_send(buf)?; diff --git a/p2p/src/msg.rs b/p2p/src/msg.rs index 8e7b5d1518..16fb81c28d 100644 --- a/p2p/src/msg.rs +++ b/p2p/src/msg.rs @@ -160,18 +160,18 @@ pub fn read_message(stream: &mut dyn Read, msg_type: Type) -> Resul read_body(&header, stream) } -pub fn write_to_buf(msg: T, msg_type: Type) -> Vec { +pub fn write_to_buf(msg: T, msg_type: Type) -> Result, Error> { // prepare the body first so we know its serialized length let mut body_buf = vec![]; - ser::serialize(&mut body_buf, &msg).unwrap(); + ser::serialize(&mut body_buf, &msg)?; // build and serialize the header using the body size let mut msg_buf = vec![]; let blen = body_buf.len() as u64; - ser::serialize(&mut msg_buf, &MsgHeader::new(msg_type, blen)).unwrap(); + ser::serialize(&mut msg_buf, &MsgHeader::new(msg_type, blen))?; msg_buf.append(&mut body_buf); - msg_buf + Ok(msg_buf) } pub fn write_message( @@ -179,7 +179,7 @@ pub fn write_message( msg: T, msg_type: Type, ) -> Result<(), Error> { - let buf = write_to_buf(msg, msg_type); + let buf = write_to_buf(msg, msg_type)?; stream.write_all(&buf[..])?; Ok(()) } @@ -268,11 +268,11 @@ impl Writeable for Hand { [write_u32, self.capabilities.bits()], [write_u64, self.nonce] ); - self.total_difficulty.write(writer).unwrap(); - self.sender_addr.write(writer).unwrap(); - self.receiver_addr.write(writer).unwrap(); - writer.write_bytes(&self.user_agent).unwrap(); - self.genesis.write(writer).unwrap(); + self.total_difficulty.write(writer)?; + self.sender_addr.write(writer)?; + self.receiver_addr.write(writer)?; + writer.write_bytes(&self.user_agent)?; + self.genesis.write(writer)?; Ok(()) } } @@ -323,9 +323,9 @@ impl Writeable for Shake { [write_u32, self.version], [write_u32, self.capabilities.bits()] ); - self.total_difficulty.write(writer).unwrap(); - writer.write_bytes(&self.user_agent).unwrap(); - self.genesis.write(writer).unwrap(); + self.total_difficulty.write(writer)?; + writer.write_bytes(&self.user_agent)?; + self.genesis.write(writer)?; Ok(()) } } @@ -379,7 +379,7 @@ impl Writeable for PeerAddrs { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { writer.write_u32(self.peers.len() as u32)?; for p in &self.peers { - p.write(writer).unwrap(); + p.write(writer)?; } Ok(()) } @@ -484,8 +484,8 @@ pub struct Ping { impl Writeable for Ping { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { - self.total_difficulty.write(writer).unwrap(); - self.height.write(writer).unwrap(); + self.total_difficulty.write(writer)?; + self.height.write(writer)?; Ok(()) } } @@ -511,8 +511,8 @@ pub struct Pong { impl Writeable for Pong { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { - self.total_difficulty.write(writer).unwrap(); - self.height.write(writer).unwrap(); + self.total_difficulty.write(writer)?; + self.height.write(writer)?; Ok(()) } } @@ -537,7 +537,7 @@ pub struct BanReason { impl Writeable for BanReason { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { let ban_reason_i32 = self.ban_reason as i32; - ban_reason_i32.write(writer).unwrap(); + ban_reason_i32.write(writer)?; Ok(()) } } diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index e57d25a84a..d964dc84f6 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -55,6 +55,15 @@ pub struct Peer { connection: Option>, } +macro_rules! connection { + ($holder:expr) => { + match $holder.connection.as_ref() { + Some(conn) => conn.lock(), + None => return Err(Error::Internal), + } + }; +} + impl fmt::Debug for Peer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Peer({:?})", &self.info) @@ -240,29 +249,15 @@ impl Peer { total_difficulty, height, }; - self.connection - .as_ref() - .unwrap() - .lock() - .send(ping_msg, msg::Type::Ping) + connection!(self).send(ping_msg, msg::Type::Ping) } /// Send the ban reason before banning - pub fn send_ban_reason(&self, ban_reason: ReasonForBan) { + pub fn send_ban_reason(&self, ban_reason: ReasonForBan) -> Result<(), Error> { let ban_reason_msg = BanReason { ban_reason }; - match self - .connection - .as_ref() - .unwrap() - .lock() + connection!(self) .send(ban_reason_msg, msg::Type::BanReason) - { - Ok(_) => debug!("Sent ban reason {:?} to {}", ban_reason, self.info.addr), - Err(e) => error!( - "Could not send ban reason {:?} to {}: {:?}", - ban_reason, self.info.addr, e - ), - }; + .map(|_| ()) } /// Sends the provided block to the remote peer. The request may be dropped @@ -270,11 +265,7 @@ impl Peer { pub fn send_block(&self, b: &core::Block) -> Result { if !self.tracking_adapter.has_recv(b.hash()) { trace!("Send block {} to {}", b.hash(), self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(b, msg::Type::Block)?; + connection!(self).send(b, msg::Type::Block)?; Ok(true) } else { debug!( @@ -289,11 +280,7 @@ impl Peer { pub fn send_compact_block(&self, b: &core::CompactBlock) -> Result { if !self.tracking_adapter.has_recv(b.hash()) { trace!("Send compact block {} to {}", b.hash(), self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(b, msg::Type::CompactBlock)?; + connection!(self).send(b, msg::Type::CompactBlock)?; Ok(true) } else { debug!( @@ -308,11 +295,7 @@ impl Peer { pub fn send_header(&self, bh: &core::BlockHeader) -> Result { if !self.tracking_adapter.has_recv(bh.hash()) { debug!("Send header {} to {}", bh.hash(), self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(bh, msg::Type::Header)?; + connection!(self).send(bh, msg::Type::Header)?; Ok(true) } else { debug!( @@ -327,11 +310,7 @@ impl Peer { pub fn send_tx_kernel_hash(&self, h: Hash) -> Result { if !self.tracking_adapter.has_recv(h) { debug!("Send tx kernel hash {} to {}", h, self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(h, msg::Type::TransactionKernel)?; + connection!(self).send(h, msg::Type::TransactionKernel)?; Ok(true) } else { debug!( @@ -359,11 +338,7 @@ impl Peer { if !self.tracking_adapter.has_recv(kernel.hash()) { debug!("Send full tx {} to {}", tx.hash(), self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(tx, msg::Type::Transaction)?; + connection!(self).send(tx, msg::Type::Transaction)?; Ok(true) } else { debug!( @@ -380,21 +355,12 @@ impl Peer { /// embargo). pub fn send_stem_transaction(&self, tx: &core::Transaction) -> Result<(), Error> { debug!("Send (stem) tx {} to {}", tx.hash(), self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(tx, msg::Type::StemTransaction)?; - Ok(()) + connection!(self).send(tx, msg::Type::StemTransaction) } /// Sends a request for block headers from the provided block locator pub fn send_header_request(&self, locator: Vec) -> Result<(), Error> { - self.connection - .as_ref() - .unwrap() - .lock() - .send(&Locator { hashes: locator }, msg::Type::GetHeaders) + connection!(self).send(&Locator { hashes: locator }, msg::Type::GetHeaders) } pub fn send_tx_request(&self, h: Hash) -> Result<(), Error> { @@ -402,37 +368,25 @@ impl Peer { "Requesting tx (kernel hash) {} from peer {}.", h, self.info.addr ); - self.connection - .as_ref() - .unwrap() - .lock() - .send(&h, msg::Type::GetTransaction) + connection!(self).send(&h, msg::Type::GetTransaction) } /// Sends a request for a specific block by hash pub fn send_block_request(&self, h: Hash) -> Result<(), Error> { debug!("Requesting block {} from peer {}.", h, self.info.addr); self.tracking_adapter.push_req(h); - self.connection - .as_ref() - .unwrap() - .lock() - .send(&h, msg::Type::GetBlock) + connection!(self).send(&h, msg::Type::GetBlock) } /// Sends a request for a specific compact block by hash pub fn send_compact_block_request(&self, h: Hash) -> Result<(), Error> { debug!("Requesting compact block {} from {}", h, self.info.addr); - self.connection - .as_ref() - .unwrap() - .lock() - .send(&h, msg::Type::GetCompactBlock) + connection!(self).send(&h, msg::Type::GetCompactBlock) } pub fn send_peer_request(&self, capab: Capabilities) -> Result<(), Error> { trace!("Asking {} for more peers {:?}", self.info.addr, capab); - self.connection.as_ref().unwrap().lock().send( + connection!(self).send( &GetPeerAddrs { capabilities: capab, }, @@ -445,7 +399,7 @@ impl Peer { "Asking {} for txhashset archive at {} {}.", self.info.addr, height, hash ); - self.connection.as_ref().unwrap().lock().send( + connection!(self).send( &TxHashSetRequest { hash, height }, msg::Type::TxHashSetRequest, ) @@ -453,11 +407,16 @@ impl Peer { /// Stops the peer, closing its connection pub fn stop(&self) { - stop_with_connection(&self.connection.as_ref().unwrap().lock()); + if let Some(conn) = self.connection.as_ref() { + stop_with_connection(&conn.lock()); + } } fn check_connection(&self) -> bool { - let connection = self.connection.as_ref().unwrap().lock(); + let connection = match self.connection.as_ref() { + Some(conn) => conn.lock(), + None => return false, + }; match connection.error_channel.try_recv() { Ok(Error::Serialization(e)) => { let need_stop = { diff --git a/p2p/src/peers.rs b/p2p/src/peers.rs index da1a4067d4..3028b12a15 100644 --- a/p2p/src/peers.rs +++ b/p2p/src/peers.rs @@ -182,11 +182,10 @@ impl Peers { return vec![]; } - let max_total_difficulty = peers - .iter() - .map(|x| x.info.total_difficulty()) - .max() - .unwrap(); + let max_total_difficulty = match peers.iter().map(|x| x.info.total_difficulty()).max() { + Some(v) => v, + None => return vec![], + }; let mut max_peers = peers .into_iter() @@ -221,7 +220,10 @@ impl Peers { if let Some(peer) = self.get_connected_peer(peer_addr) { debug!("Banning peer {}", peer_addr); // setting peer status will get it removed at the next clean_peer - peer.send_ban_reason(ban_reason); + match peer.send_ban_reason(ban_reason) { + Err(e) => error!("failed to send a ban reason to{}: {:?}", peer_addr, e), + Ok(_) => debug!("ban reason {:?} was sent to {}", ban_reason, peer_addr), + }; peer.set_banned(); peer.stop(); } @@ -328,12 +330,24 @@ impl Peers { /// All peer information we have in storage pub fn all_peers(&self) -> Vec { - self.store.all_peers() + match self.store.all_peers() { + Ok(peers) => peers, + Err(e) => { + error!("all_peers failed: {:?}", e); + vec![] + } + } } /// Find peers in store (not necessarily connected) and return their data pub fn find_peers(&self, state: State, cap: Capabilities, count: usize) -> Vec { - self.store.find_peers(state, cap, count) + match self.store.find_peers(state, cap, count) { + Ok(peers) => peers, + Err(e) => { + error!("failed to find peers: {:?}", e); + vec![] + } + } } /// Get peer in store by address @@ -373,11 +387,12 @@ impl Peers { debug!("clean_peers {:?}, not connected", peer.info.addr); rm.push(peer.info.addr.clone()); } else if peer.is_abusive() { - let counts = peer.last_min_message_counts().unwrap(); - debug!( - "clean_peers {:?}, abusive ({} sent, {} recv)", - peer.info.addr, counts.0, counts.1, - ); + if let Some(counts) = peer.last_min_message_counts() { + debug!( + "clean_peers {:?}, abusive ({} sent, {} recv)", + peer.info.addr, counts.0, counts.1, + ); + } let _ = self.update_state(peer.info.addr, State::Banned); rm.push(peer.info.addr.clone()); } else { diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index 38df07c759..cc49abd3f5 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -72,7 +72,7 @@ impl MessageHandler for Protocol { height: adapter.total_height(), }, writer, - ))) + )?)) } Type::Pong => { @@ -105,7 +105,7 @@ impl MessageHandler for Protocol { ); let tx = adapter.get_transaction(h); if let Some(tx) = tx { - Ok(Some(Response::new(Type::Transaction, tx, writer))) + Ok(Some(Response::new(Type::Transaction, tx, writer)?)) } else { Ok(None) } @@ -141,7 +141,7 @@ impl MessageHandler for Protocol { let bo = adapter.get_block(h); if let Some(b) = bo { - return Ok(Some(Response::new(Type::Block, b, writer))); + return Ok(Some(Response::new(Type::Block, b, writer)?)); } Ok(None) } @@ -163,7 +163,7 @@ impl MessageHandler for Protocol { let h: Hash = msg.body()?; if let Some(b) = adapter.get_block(h) { let cb: CompactBlock = b.into(); - Ok(Some(Response::new(Type::CompactBlock, cb, writer))) + Ok(Some(Response::new(Type::CompactBlock, cb, writer)?)) } else { Ok(None) } @@ -190,7 +190,7 @@ impl MessageHandler for Protocol { Type::Headers, Headers { headers }, writer, - ))) + )?)) } // "header first" block propagation - if we have not yet seen this block @@ -235,7 +235,7 @@ impl MessageHandler for Protocol { Type::PeerAddrs, PeerAddrs { peers }, writer, - ))) + )?)) } Type::PeerAddrs => { @@ -263,7 +263,7 @@ impl MessageHandler for Protocol { bytes: file_sz, }, writer, - ); + )?; resp.add_attachment(txhashset.reader); Ok(Some(resp)) } else { @@ -312,7 +312,10 @@ impl MessageHandler for Protocol { received_bytes.inc_quiet(size as u64); } } - tmp_zip.into_inner().unwrap().sync_all()?; + tmp_zip + .into_inner() + .map_err(|_| Error::Internal)? + .sync_all()?; Ok(()) }; diff --git a/p2p/src/store.rs b/p2p/src/store.rs index 54b2b275bf..46faa6dc6f 100644 --- a/p2p/src/store.rs +++ b/p2p/src/store.rs @@ -83,10 +83,9 @@ impl Readable for PeerData { let lc = reader.read_i64(); // this only works because each PeerData is read in its own vector and this // is the last data element - let last_connected = if let Err(_) = lc { - Utc::now().timestamp() - } else { - lc.unwrap() + let last_connected = match lc { + Err(_) => Utc::now().timestamp(), + Ok(lc) => lc, }; let user_agent = String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)?; @@ -147,22 +146,31 @@ impl PeerStore { batch.commit() } - pub fn find_peers(&self, state: State, cap: Capabilities, count: usize) -> Vec { + pub fn find_peers( + &self, + state: State, + cap: Capabilities, + count: usize, + ) -> Result, Error> { let mut peers = self .db - .iter::(&to_key(PEER_PREFIX, &mut "".to_string().into_bytes())) - .unwrap() + .iter::(&to_key(PEER_PREFIX, &mut "".to_string().into_bytes()))? + .map(|(_, v)| v) .filter(|p| p.flags == state && p.capabilities.contains(cap)) .collect::>(); thread_rng().shuffle(&mut peers[..]); - peers.iter().take(count).cloned().collect() + Ok(peers.iter().take(count).cloned().collect()) } /// List all known peers /// Used for /v1/peers/all api endpoint - pub fn all_peers(&self) -> Vec { + pub fn all_peers(&self) -> Result, Error> { let key = to_key(PEER_PREFIX, &mut "".to_string().into_bytes()); - self.db.iter::(&key).unwrap().collect::>() + Ok(self + .db + .iter::(&key)? + .map(|(_, v)| v) + .collect::>()) } /// Convenience method to load a peer data, update its status and save it @@ -190,7 +198,7 @@ impl PeerStore { { let mut to_remove = vec![]; - for x in self.all_peers() { + for x in self.all_peers()? { if predicate(&x) { to_remove.push(x) } diff --git a/p2p/src/types.rs b/p2p/src/types.rs index c6cffefdd1..48f308dc92 100644 --- a/p2p/src/types.rs +++ b/p2p/src/types.rs @@ -75,6 +75,7 @@ pub enum Error { }, Send(String), PeerException, + Internal, } impl From for Error { diff --git a/pool/Cargo.toml b/pool/Cargo.toml index 0b6c41a92f..d9bc2b8421 100644 --- a/pool/Cargo.toml +++ b/pool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_pool" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Chain implementation for grin, a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -19,10 +19,10 @@ chrono = "0.4.4" failure = "0.1" failure_derive = "0.1" -grin_core = { path = "../core", version = "1.1.0" } -grin_keychain = { path = "../keychain", version = "1.1.0" } -grin_store = { path = "../store", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_keychain = { path = "../keychain", version = "1.1.0-beta.1" } +grin_store = { path = "../store", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] -grin_chain = { path = "../chain", version = "1.1.0" } +grin_chain = { path = "../chain", version = "1.1.0-beta.1" } diff --git a/servers/Cargo.toml b/servers/Cargo.toml index 109145fc0c..a8a03a26f7 100644 --- a/servers/Cargo.toml +++ b/servers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_servers" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -25,11 +25,11 @@ serde_json = "1" chrono = "0.4.4" tokio = "0.1.11" -grin_api = { path = "../api", version = "1.1.0" } -grin_chain = { path = "../chain", version = "1.1.0" } -grin_core = { path = "../core", version = "1.1.0" } -grin_keychain = { path = "../keychain", version = "1.1.0" } -grin_p2p = { path = "../p2p", version = "1.1.0" } -grin_pool = { path = "../pool", version = "1.1.0" } -grin_store = { path = "../store", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_api = { path = "../api", version = "1.1.0-beta.1" } +grin_chain = { path = "../chain", version = "1.1.0-beta.1" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_keychain = { path = "../keychain", version = "1.1.0-beta.1" } +grin_p2p = { path = "../p2p", version = "1.1.0-beta.1" } +grin_pool = { path = "../pool", version = "1.1.0-beta.1" } +grin_store = { path = "../store", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } diff --git a/servers/src/common/adapters.rs b/servers/src/common/adapters.rs index 2c0559b488..b04e1ab704 100644 --- a/servers/src/common/adapters.rs +++ b/servers/src/common/adapters.rs @@ -331,14 +331,20 @@ impl p2p::ChainAdapter for NetToChainAdapter { total_size: u64, ) -> bool { match self.sync_state.status() { - SyncStatus::TxHashsetDownload { .. } => { - self.sync_state - .update_txhashset_download(SyncStatus::TxHashsetDownload { - start_time, - downloaded_size, - total_size, - }) - } + SyncStatus::TxHashsetDownload { + update_time: old_update_time, + downloaded_size: old_downloaded_size, + .. + } => self + .sync_state + .update_txhashset_download(SyncStatus::TxHashsetDownload { + start_time, + prev_update_time: old_update_time, + update_time: Utc::now(), + prev_downloaded_size: old_downloaded_size, + downloaded_size, + total_size, + }), _ => false, } } @@ -358,6 +364,7 @@ impl p2p::ChainAdapter for NetToChainAdapter { .chain() .txhashset_write(h, txhashset_data, self.sync_state.as_ref()) { + self.chain().clean_txhashset_sandbox(); error!("Failed to save txhashset archive: {}", e); let is_good_data = !e.is_bad_data(); self.sync_state.set_sync_error(types::Error::Chain(e)); diff --git a/servers/src/common/types.rs b/servers/src/common/types.rs index 374bddef29..1b7c9f34d9 100644 --- a/servers/src/common/types.rs +++ b/servers/src/common/types.rs @@ -22,7 +22,8 @@ use rand::prelude::*; use crate::api; use crate::chain; use crate::core::global::ChainTypes; -use crate::core::{core, pow}; +use crate::core::{core, libtx, pow}; +use crate::keychain; use crate::p2p; use crate::pool; use crate::pool::types::DandelionConfig; @@ -34,6 +35,8 @@ use crate::util::RwLock; pub enum Error { /// Error originating from the core implementation. Core(core::block::Error), + /// Error originating from the libtx implementation. + LibTx(libtx::Error), /// Error originating from the db storage. Store(store::Error), /// Error originating from the blockchain implementation. @@ -46,12 +49,18 @@ pub enum Error { Cuckoo(pow::Error), /// Error originating from the transaction pool. Pool(pool::PoolError), + /// Error originating from the keychain. + Keychain(keychain::Error), /// Invalid Arguments. ArgumentError(String), /// Wallet communication error WalletComm(String), /// Error originating from some I/O operation (likely a file on disk). IOError(std::io::Error), + /// Configuration error + Configuration(String), + /// General error + General(String), } impl From for Error { @@ -99,6 +108,18 @@ impl From for Error { } } +impl From for Error { + fn from(e: keychain::Error) -> Error { + Error::Keychain(e) + } +} + +impl From for Error { + fn from(e: libtx::Error) -> Error { + Error::LibTx(e) + } +} + /// Type of seeding the server will use to find other peers on the network. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum ChainValidationMode { @@ -299,6 +320,9 @@ pub enum SyncStatus { /// Downloading the various txhashsets TxHashsetDownload { start_time: DateTime, + prev_update_time: DateTime, + update_time: DateTime, + prev_downloaded_size: u64, downloaded_size: u64, total_size: u64, }, diff --git a/servers/src/grin/dandelion_monitor.rs b/servers/src/grin/dandelion_monitor.rs index 665874298a..3316d4d347 100644 --- a/servers/src/grin/dandelion_monitor.rs +++ b/servers/src/grin/dandelion_monitor.rs @@ -183,6 +183,5 @@ fn process_expired_entries( Err(e) => warn!("dand_mon: failed to fluff expired tx {}, {:?}", txhash, e), }; } - Ok(()) } diff --git a/servers/src/grin/seed.rs b/servers/src/grin/seed.rs index 68886586cf..1624fb8f73 100644 --- a/servers/src/grin/seed.rs +++ b/servers/src/grin/seed.rs @@ -292,7 +292,7 @@ fn listen_for_addrs( let addrs: Vec = rx.try_iter().collect(); // If we have a healthy number of outbound peers then we are done here. - if peers.healthy_peers_mix() { + if peers.peer_count() > peers.peer_outbound_count() && peers.healthy_peers_mix() { return; } @@ -312,7 +312,9 @@ fn listen_for_addrs( ); continue; } else { - *connecting_history.get_mut(&addr).unwrap() = now; + if let Some(history) = connecting_history.get_mut(&addr) { + *history = now; + } } } connecting_history.insert(addr, now); diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs index 167201c258..7ed10aa2fd 100644 --- a/servers/src/grin/server.rs +++ b/servers/src/grin/server.rs @@ -219,9 +219,14 @@ impl Server { warn!("No seed configured, will stay solo until connected to"); seed::predefined_seeds(vec![]) } - p2p::Seeding::List => { - seed::predefined_seeds(config.p2p_config.seeds.clone().unwrap()) - } + p2p::Seeding::List => match &config.p2p_config.seeds { + Some(seeds) => seed::predefined_seeds(seeds.clone()), + None => { + return Err(Error::Configuration( + "Seeds must be configured for seeding type List".to_owned(), + )); + } + }, p2p::Seeding::DNSSeed => seed::dns_seeds(), _ => unreachable!(), }; @@ -388,13 +393,13 @@ impl Server { } /// The chain head - pub fn head(&self) -> chain::Tip { - self.chain.head().unwrap() + pub fn head(&self) -> Result { + self.chain.head().map_err(|e| e.into()) } /// The head of the block header chain - pub fn header_head(&self) -> chain::Tip { - self.chain.header_head().unwrap() + pub fn header_head(&self) -> Result { + self.chain.header_head().map_err(|e| e.into()) } /// Returns a set of stats about this server. This and the ServerStats @@ -412,11 +417,11 @@ impl Server { // for release let diff_stats = { let last_blocks: Vec = - global::difficulty_data_to_vector(self.chain.difficulty_iter()) + global::difficulty_data_to_vector(self.chain.difficulty_iter()?) .into_iter() .collect(); - let tip_height = self.chain.head().unwrap().height as i64; + let tip_height = self.head()?.height as i64; let mut height = tip_height as i64 - last_blocks.len() as i64 + 1; let txhashset = self.chain.txhashset(); @@ -474,8 +479,8 @@ impl Server { .collect(); Ok(ServerStats { peer_count: self.peer_count(), - head: self.head(), - header_head: self.header_head(), + head: self.head()?, + header_head: self.header_head()?, sync_status: self.sync_state.status(), stratum_stats: stratum_stats, peer_stats: peer_stats, diff --git a/servers/src/grin/sync/body_sync.rs b/servers/src/grin/sync/body_sync.rs index c1221f2845..37403c6c0d 100644 --- a/servers/src/grin/sync/body_sync.rs +++ b/servers/src/grin/sync/body_sync.rs @@ -51,11 +51,15 @@ impl BodySync { /// Check whether a body sync is needed and run it if so. /// Return true if txhashset download is needed (when requested block is under the horizon). - pub fn check_run(&mut self, head: &chain::Tip, highest_height: u64) -> bool { + pub fn check_run( + &mut self, + head: &chain::Tip, + highest_height: u64, + ) -> Result { // run the body_sync every 5s - if self.body_sync_due() { - if self.body_sync() { - return true; + if self.body_sync_due()? { + if self.body_sync()? { + return Ok(true); } self.sync_state.update(SyncStatus::BodySync { @@ -63,23 +67,37 @@ impl BodySync { highest_height: highest_height, }); } - false + Ok(false) } /// Return true if txhashset download is needed (when requested block is under the horizon). - fn body_sync(&mut self) -> bool { + fn body_sync(&mut self) -> Result { let mut hashes: Option> = Some(vec![]); - if self + let txhashset_needed = match self .chain .check_txhashset_needed("body_sync".to_owned(), &mut hashes) { + Ok(v) => v, + Err(e) => { + error!("body_sync: failed to call txhashset_needed: {:?}", e); + return Ok(false); + } + }; + if txhashset_needed { debug!( "body_sync: cannot sync full blocks earlier than horizon. will request txhashset", ); - return true; + return Ok(true); } - let mut hashes = hashes.unwrap(); + let mut hashes = match hashes { + Some(v) => v, + None => { + error!("unexpected: hashes is None"); + return Ok(false); + } + }; + hashes.reverse(); let peers = self.peers.more_work_peers(); @@ -103,8 +121,8 @@ impl BodySync { .collect::>(); if hashes_to_get.len() > 0 { - let body_head = self.chain.head().unwrap(); - let header_head = self.chain.header_head().unwrap(); + let body_head = self.chain.head()?; + let header_head = self.chain.header_head()?; debug!( "block_sync: {}/{} requesting blocks {:?} from {} peers", @@ -129,12 +147,12 @@ impl BodySync { } } } - return false; + return Ok(false); } // Should we run block body sync and ask for more full blocks? - fn body_sync_due(&mut self) -> bool { - let blocks_received = self.blocks_received(); + fn body_sync_due(&mut self) -> Result { + let blocks_received = self.blocks_received()?; // some blocks have been requested if self.blocks_requested > 0 { @@ -145,7 +163,7 @@ impl BodySync { "body_sync: expecting {} more blocks and none received for a while", self.blocks_requested, ); - return true; + return Ok(true); } } @@ -162,16 +180,16 @@ impl BodySync { if self.blocks_requested < 2 { // no pending block requests, ask more debug!("body_sync: no pending block request, asking more"); - return true; + return Ok(true); } - return false; + Ok(false) } // Total numbers received on this chain, including the head and orphans - fn blocks_received(&self) -> u64 { - self.chain.head().unwrap().height + fn blocks_received(&self) -> Result { + Ok((self.chain.head()?).height + self.chain.orphans_len() as u64 - + self.chain.orphans_evicted_len() as u64 + + self.chain.orphans_evicted_len() as u64) } } diff --git a/servers/src/grin/sync/header_sync.rs b/servers/src/grin/sync/header_sync.rs index 81c049315d..2bccae54cb 100644 --- a/servers/src/grin/sync/header_sync.rs +++ b/servers/src/grin/sync/header_sync.rs @@ -50,9 +50,13 @@ impl HeaderSync { } } - pub fn check_run(&mut self, header_head: &chain::Tip, highest_height: u64) -> bool { + pub fn check_run( + &mut self, + header_head: &chain::Tip, + highest_height: u64, + ) -> Result { if !self.header_sync_due(header_head) { - return false; + return Ok(false); } let enable_header_sync = match self.sync_state.status() { @@ -60,7 +64,7 @@ impl HeaderSync { | SyncStatus::HeaderSync { .. } | SyncStatus::TxHashsetDone => true, SyncStatus::NoSync | SyncStatus::Initial | SyncStatus::AwaitingPeers(_) => { - let sync_head = self.chain.get_sync_head().unwrap(); + let sync_head = self.chain.get_sync_head()?; debug!( "sync: initial transition to HeaderSync. sync_head: {} at {}, resetting to: {} at {}", sync_head.hash(), @@ -77,10 +81,10 @@ impl HeaderSync { // correctly, so reset any previous (and potentially stale) sync_head to match // our last known "good" header_head. // - self.chain.reset_sync_head().unwrap(); + self.chain.reset_sync_head()?; // Rebuild the sync MMR to match our updated sync_head. - self.chain.rebuild_sync_mmr(&header_head).unwrap(); + self.chain.rebuild_sync_mmr(&header_head)?; self.history_locator.retain(|&x| x.0 == 0); true @@ -95,9 +99,9 @@ impl HeaderSync { }); self.syncing_peer = self.header_sync(); - return true; + return Ok(true); } - false + Ok(false) } fn header_sync_due(&mut self, header_head: &chain::Tip) -> bool { diff --git a/servers/src/grin/sync/state_sync.rs b/servers/src/grin/sync/state_sync.rs index c4d012ecae..cd730960b0 100644 --- a/servers/src/grin/sync/state_sync.rs +++ b/servers/src/grin/sync/state_sync.rs @@ -113,7 +113,7 @@ impl StateSync { } // run fast sync if applicable, normally only run one-time, except restart in error - if header_head.height == highest_height { + if sync_need_restart || header_head.height == highest_height { let (go, download_timeout) = self.state_sync_due(); if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() { @@ -147,6 +147,9 @@ impl StateSync { self.sync_state.update(SyncStatus::TxHashsetDownload { start_time: Utc::now(), + prev_update_time: Utc::now(), + update_time: Utc::now(), + prev_downloaded_size: 0, downloaded_size: 0, total_size: 0, }); @@ -163,9 +166,25 @@ impl StateSync { let mut txhashset_head = self .chain .get_block_header(&header_head.prev_block_h) - .unwrap(); + .map_err(|e| { + error!( + "chain error dirung getting a block header {}: {:?}", + &header_head.prev_block_h, e + ); + p2p::Error::Internal + })?; for _ in 0..threshold { - txhashset_head = self.chain.get_previous_header(&txhashset_head).unwrap(); + txhashset_head = self + .chain + .get_previous_header(&txhashset_head) + .map_err(|e| { + error!( + "chain error dirung getting a previous block header {}: {:?}", + txhashset_head.hash(), + e + ); + p2p::Error::Internal + })?; } let bhash = txhashset_head.hash(); debug!( diff --git a/servers/src/grin/sync/syncer.rs b/servers/src/grin/sync/syncer.rs index f66856c28b..f9230e7da0 100644 --- a/servers/src/grin/sync/syncer.rs +++ b/servers/src/grin/sync/syncer.rs @@ -62,7 +62,7 @@ impl SyncRunner { } } - fn wait_for_min_peers(&self) { + fn wait_for_min_peers(&self) -> Result<(), chain::Error> { // Initial sleep to give us time to peer with some nodes. // Note: Even if we have skip peer wait we need to wait a // short period of time for tests to do the right thing. @@ -72,7 +72,7 @@ impl SyncRunner { 3 }; - let head = self.chain.head().unwrap(); + let head = self.chain.head()?; let mut n = 0; const MIN_PEERS: usize = 3; @@ -95,12 +95,27 @@ impl SyncRunner { thread::sleep(time::Duration::from_secs(1)); n += 1; } + Ok(()) } /// Starts the syncing loop, just spawns two threads that loop forever fn sync_loop(&self) { + macro_rules! unwrap_or_restart_loop( + ($obj: expr) =>( + match $obj { + Ok(v) => v, + Err(e) => { + error!("unexpected error: {:?}", e); + thread::sleep(time::Duration::from_secs(1)); + continue; + }, + } + )); + // Wait for connections reach at least MIN_PEERS - self.wait_for_min_peers(); + if let Err(e) = self.wait_for_min_peers() { + error!("wait_for_min_peers failed: {:?}", e); + } // Our 3 main sync stages let mut header_sync = HeaderSync::new( @@ -132,8 +147,7 @@ impl SyncRunner { thread::sleep(time::Duration::from_millis(10)); // check whether syncing is generally needed, when we compare our state with others - let (syncing, most_work_height) = self.needs_syncing(); - + let (syncing, most_work_height) = unwrap_or_restart_loop!(self.needs_syncing()); if most_work_height > 0 { // we can occasionally get a most work height of 0 if read locks fail highest_height = most_work_height; @@ -147,13 +161,13 @@ impl SyncRunner { } // if syncing is needed - let head = self.chain.head().unwrap(); + let head = unwrap_or_restart_loop!(self.chain.head()); let tail = self.chain.tail().unwrap_or_else(|_| head.clone()); - let header_head = self.chain.header_head().unwrap(); + let header_head = unwrap_or_restart_loop!(self.chain.header_head()); // run each sync stage, each of them deciding whether they're needed // except for state sync that only runs if body sync return true (means txhashset is needed) - header_sync.check_run(&header_head, highest_height); + unwrap_or_restart_loop!(header_sync.check_run(&header_head, highest_height)); let mut check_state_sync = false; match self.sync_state.status() { @@ -168,7 +182,15 @@ impl SyncRunner { continue; } - if body_sync.check_run(&head, highest_height) { + let check_run = match body_sync.check_run(&head, highest_height) { + Ok(v) => v, + Err(e) => { + error!("check_run failed: {:?}", e); + continue; + } + }; + + if check_run { check_state_sync = true; } } @@ -182,8 +204,8 @@ impl SyncRunner { /// Whether we're currently syncing the chain or we're fully caught up and /// just receiving blocks through gossip. - fn needs_syncing(&self) -> (bool, u64) { - let local_diff = self.chain.head().unwrap().total_difficulty; + fn needs_syncing(&self) -> Result<(bool, u64), chain::Error> { + let local_diff = self.chain.head()?.total_difficulty; let mut is_syncing = self.sync_state.is_syncing(); let peer = self.peers.most_work_peer(); @@ -191,14 +213,14 @@ impl SyncRunner { p.info.clone() } else { warn!("sync: no peers available, disabling sync"); - return (false, 0); + return Ok((false, 0)); }; // if we're already syncing, we're caught up if no peer has a higher // difficulty than us if is_syncing { if peer_info.total_difficulty() <= local_diff { - let ch = self.chain.head().unwrap(); + let ch = self.chain.head()?; info!( "synchronized at {} @ {} [{}]", local_diff.to_num(), @@ -209,12 +231,20 @@ impl SyncRunner { } } else { // sum the last 5 difficulties to give us the threshold - let threshold = self - .chain - .difficulty_iter() - .map(|x| x.difficulty) - .take(5) - .fold(Difficulty::zero(), |sum, val| sum + val); + let threshold = { + let diff_iter = match self.chain.difficulty_iter() { + Ok(v) => v, + Err(e) => { + error!("failed to get difficulty iterator: {:?}", e); + // we handle 0 height in the caller + return Ok((false, 0)); + } + }; + diff_iter + .map(|x| x.difficulty) + .take(5) + .fold(Difficulty::zero(), |sum, val| sum + val) + }; let peer_diff = peer_info.total_difficulty(); if peer_diff > local_diff.clone() + threshold.clone() { @@ -227,6 +257,6 @@ impl SyncRunner { is_syncing = true; } } - (is_syncing, peer_info.height()) + Ok((is_syncing, peer_info.height())) } } diff --git a/servers/src/mining/mine_block.rs b/servers/src/mining/mine_block.rs index 312dbacaf5..30421cee6c 100644 --- a/servers/src/mining/mine_block.rs +++ b/servers/src/mining/mine_block.rs @@ -138,7 +138,7 @@ fn build_block( // Determine the difficulty our block should be at. // Note: do not keep the difficulty_iter in scope (it has an active batch). - let difficulty = consensus::next_difficulty(head.height + 1, chain.difficulty_iter()); + let difficulty = consensus::next_difficulty(head.height + 1, chain.difficulty_iter()?); // Extract current "mineable" transactions from the pool. // If this fails for *any* reason then fallback to an empty vec of txs. @@ -212,7 +212,7 @@ fn build_block( /// fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, BlockFees), Error> { warn!("Burning block fees: {:?}", block_fees); - let keychain = ExtKeychain::from_random_seed(global::is_floonet()).unwrap(); + let keychain = ExtKeychain::from_random_seed(global::is_floonet())?; let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0); let (out, kernel) = crate::core::libtx::reward::output(&keychain, &key_id, block_fees.fees, false).unwrap(); diff --git a/src/bin/tui/status.rs b/src/bin/tui/status.rs index afc92cd178..6651c66b30 100644 --- a/src/bin/tui/status.rs +++ b/src/bin/tui/status.rs @@ -128,6 +128,9 @@ impl TUIStatusListener for TUIStatusView { } SyncStatus::TxHashsetDownload { start_time, + prev_update_time, + update_time: _, + prev_downloaded_size, downloaded_size, total_size, } => { @@ -137,14 +140,14 @@ impl TUIStatusListener for TUIStatusView { } else { 0 }; - let start = start_time.timestamp_nanos(); + let start = prev_update_time.timestamp_nanos(); let fin = Utc::now().timestamp_nanos(); let dur_ms = (fin - start) as f64 * NANO_TO_MILLIS; format!("Downloading {}(MB) chain state for state sync: {}% at {:.1?}(kB/s), step 2/4", total_size / 1_000_000, percent, - if dur_ms > 1.0f64 { downloaded_size as f64 / dur_ms as f64 } else { 0f64 }, + if dur_ms > 1.0f64 { (downloaded_size - prev_downloaded_size) as f64 / dur_ms as f64 } else { 0f64 }, ) } else { let start = start_time.timestamp_millis(); diff --git a/store/Cargo.toml b/store/Cargo.toml index 97f6284a6a..1617bc57b8 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_store" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -22,8 +22,8 @@ serde = "1" serde_derive = "1" log = "0.4" -grin_core = { path = "../core", version = "1.1.0" } -grin_util = { path = "../util", version = "1.1.0" } +grin_core = { path = "../core", version = "1.1.0-beta.1" } +grin_util = { path = "../util", version = "1.1.0-beta.1" } [dev-dependencies] chrono = "0.4.4" diff --git a/store/src/leaf_set.rs b/store/src/leaf_set.rs index f75d4e148a..b6646eb74b 100644 --- a/store/src/leaf_set.rs +++ b/store/src/leaf_set.rs @@ -199,4 +199,9 @@ impl LeafSet { pub fn is_empty(&self) -> bool { self.len() == 0 } + + /// Iterator over positionns in the leaf_set (all leaf positions). + pub fn iter(&self) -> impl Iterator + '_ { + self.bitmap.iter().map(|x| x as u64) + } } diff --git a/store/src/lmdb.rs b/store/src/lmdb.rs index 01484928fc..ba47101f1a 100644 --- a/store/src/lmdb.rs +++ b/store/src/lmdb.rs @@ -248,8 +248,8 @@ impl Store { res.to_opt().map(|r| r.is_some()).map_err(From::from) } - /// Produces an iterator of `Readable` types moving forward from the - /// provided key. + /// Produces an iterator of (key, value) pairs, where values are `Readable` types + /// moving forward from the provided key. pub fn iter(&self, from: &[u8]) -> Result, Error> { let db = self.db.read(); let tx = Arc::new(lmdb::ReadTransaction::new(self.env.clone())?); @@ -367,9 +367,9 @@ impl Iterator for SerIterator where T: ser::Readable, { - type Item = T; + type Item = (Vec, T); - fn next(&mut self) -> Option { + fn next(&mut self) -> Option<(Vec, T)> { let access = self.tx.access(); let kv = if self.seek { Arc::get_mut(&mut self.cursor).unwrap().next(&access) @@ -379,7 +379,10 @@ where .unwrap() .seek_range_k(&access, &self.prefix[..]) }; - self.deser_if_prefix_match(kv) + match kv { + Ok((k, v)) => self.deser_if_prefix_match(k, v), + Err(_) => None, + } } } @@ -387,17 +390,16 @@ impl SerIterator where T: ser::Readable, { - fn deser_if_prefix_match(&self, kv: Result<(&[u8], &[u8]), lmdb::Error>) -> Option { - match kv { - Ok((k, v)) => { - let plen = self.prefix.len(); - if plen == 0 || k[0..plen] == self.prefix[..] { - ser::deserialize(&mut &v[..]).ok() - } else { - None - } + fn deser_if_prefix_match(&self, key: &[u8], value: &[u8]) -> Option<(Vec, T)> { + let plen = self.prefix.len(); + if plen == 0 || key[0..plen] == self.prefix[..] { + if let Ok(value) = ser::deserialize(&mut &value[..]) { + Some((key.to_vec(), value)) + } else { + None } - Err(_) => None, + } else { + None } } } diff --git a/store/src/pmmr.rs b/store/src/pmmr.rs index 4fc031d43e..f57867c462 100644 --- a/store/src/pmmr.rs +++ b/store/src/pmmr.rs @@ -21,7 +21,7 @@ use crate::core::core::BlockHeader; use crate::core::ser::PMMRable; use crate::leaf_set::LeafSet; use crate::prune_list::PruneList; -use crate::types::{prune_noop, DataFile}; +use crate::types::DataFile; use croaring::Bitmap; use std::path::{Path, PathBuf}; @@ -121,6 +121,17 @@ impl Backend for PMMRBackend { self.get_data_from_file(pos) } + /// Returns an iterator over all the leaf positions. + /// for a prunable PMMR this is an iterator over the leaf_set bitmap. + /// For a non-prunable PMMR this is *all* leaves (this is not yet implemented). + fn leaf_pos_iter(&self) -> Box + '_> { + if self.prunable { + Box::new(self.leaf_set.iter()) + } else { + panic!("leaf_pos_iter not implemented for non-prunable PMMR") + } + } + /// Rewind the PMMR backend to the given position. fn rewind(&mut self, position: u64, rewind_rm_pos: &Bitmap) -> Result<(), String> { // First rewind the leaf_set with the necessary added and removed positions. @@ -199,13 +210,7 @@ impl PMMRBackend { data_dir.join(PMMR_LEAF_FILE).to_str().unwrap(), header.hash() ); - // Check for a ... (3 dot) ending version of the file - could probably be removed after mainnet - let compatible_snapshot_path = PathBuf::from(leaf_snapshot_path.clone() + "..."); - if compatible_snapshot_path.exists() { - LeafSet::copy_snapshot(&leaf_set_path, &compatible_snapshot_path)?; - } else { - LeafSet::copy_snapshot(&leaf_set_path, &PathBuf::from(leaf_snapshot_path))?; - } + LeafSet::copy_snapshot(&leaf_set_path, &PathBuf::from(leaf_snapshot_path))?; } let leaf_set = LeafSet::open(&leaf_set_path)?; @@ -284,15 +289,7 @@ impl PMMRBackend { /// aligned. The block_marker in the db/index for the particular block /// will have a suitable output_pos. This is used to enforce a horizon /// after which the local node should have all the data to allow rewinding. - pub fn check_compact

( - &mut self, - cutoff_pos: u64, - rewind_rm_pos: &Bitmap, - prune_cb: P, - ) -> io::Result - where - P: Fn(&[u8]), - { + pub fn check_compact(&mut self, cutoff_pos: u64, rewind_rm_pos: &Bitmap) -> io::Result { assert!(self.prunable, "Trying to compact a non-prunable PMMR"); // Paths for tmp hash and data files. @@ -312,7 +309,7 @@ impl PMMRBackend { }); self.hash_file - .save_prune(&tmp_prune_file_hash, &off_to_rm, &prune_noop)?; + .save_prune(&tmp_prune_file_hash, &off_to_rm)?; } // 2. Save compact copy of the data file, skipping removed leaves. @@ -330,7 +327,7 @@ impl PMMRBackend { }); self.data_file - .save_prune(&tmp_prune_file_data, &off_to_rm, prune_cb)?; + .save_prune(&tmp_prune_file_data, &off_to_rm)?; } // 3. Update the prune list and write to disk. diff --git a/store/src/types.rs b/store/src/types.rs index 379749a31e..bfe53bf5de 100644 --- a/store/src/types.rs +++ b/store/src/types.rs @@ -20,9 +20,6 @@ use std::io::{self, BufWriter, ErrorKind, Read, Write}; use std::marker; use std::path::{Path, PathBuf}; -/// A no-op function for doing nothing with some pruned data. -pub fn prune_noop(_pruned_data: &[u8]) {} - /// Data file (MMR) wrapper around an append only file. pub struct DataFile { file: AppendOnlyFile, @@ -113,16 +110,13 @@ where } /// Write the file out to disk, pruning removed elements. - pub fn save_prune(&self, target: &str, prune_offs: &[u64], prune_cb: F) -> io::Result<()> - where - F: Fn(&[u8]), - { + pub fn save_prune(&self, target: &str, prune_offs: &[u64]) -> io::Result<()> { let prune_offs = prune_offs .iter() .map(|x| x * T::LEN as u64) .collect::>(); self.file - .save_prune(target, prune_offs.as_slice(), T::LEN as u64, prune_cb) + .save_prune(target, prune_offs.as_slice(), T::LEN as u64) } } @@ -294,15 +288,8 @@ impl AppendOnlyFile { /// Saves a copy of the current file content, skipping data at the provided /// prune indices. The prune Vec must be ordered. - pub fn save_prune( - &self, - target: P, - prune_offs: &[u64], - prune_len: u64, - prune_cb: T, - ) -> io::Result<()> + pub fn save_prune

(&self, target: P, prune_offs: &[u64], prune_len: u64) -> io::Result<()> where - T: Fn(&[u8]), P: AsRef, { if prune_offs.is_empty() { @@ -332,8 +319,6 @@ impl AppendOnlyFile { let prune_at = (prune_offs[prune_pos] - read) as usize; if prune_at != buf_start { writer.write_all(&buf[buf_start..prune_at])?; - } else { - prune_cb(&buf[buf_start..prune_at]); } buf_start = prune_at + (prune_len as usize); if prune_offs.len() > prune_pos + 1 { diff --git a/store/tests/pmmr.rs b/store/tests/pmmr.rs index 00abd7a5ff..c6585e37a2 100644 --- a/store/tests/pmmr.rs +++ b/store/tests/pmmr.rs @@ -26,7 +26,6 @@ use crate::core::core::pmmr::{Backend, PMMR}; use crate::core::ser::{ Error, FixedLength, PMMRIndexHashable, PMMRable, Readable, Reader, Writeable, Writer, }; -use crate::store::types::prune_noop; #[test] fn pmmr_append() { @@ -128,9 +127,7 @@ fn pmmr_compact_leaf_sibling() { assert_eq!(backend.get_from_file(1).unwrap(), pos_1_hash); // aggressively compact the PMMR files - backend - .check_compact(1, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(1, &Bitmap::create()).unwrap(); // check pos 1, 2, 3 are in the state we expect after compacting { @@ -188,9 +185,7 @@ fn pmmr_prune_compact() { } // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); // recheck the root and stored data { @@ -236,9 +231,7 @@ fn pmmr_reload() { backend.sync().unwrap(); // now check and compact the backend - backend - .check_compact(1, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(1, &Bitmap::create()).unwrap(); backend.sync().unwrap(); // prune another node to force compact to actually do something @@ -249,9 +242,7 @@ fn pmmr_reload() { } backend.sync().unwrap(); - backend - .check_compact(4, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(4, &Bitmap::create()).unwrap(); backend.sync().unwrap(); assert_eq!(backend.unpruned_size(), mmr_size); @@ -351,9 +342,7 @@ fn pmmr_rewind() { } // and compact the MMR to remove the pruned elements - backend - .check_compact(6, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(6, &Bitmap::create()).unwrap(); backend.sync().unwrap(); println!("after compacting - "); @@ -453,9 +442,7 @@ fn pmmr_compact_single_leaves() { backend.sync().unwrap(); // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); { let mut pmmr: PMMR<'_, TestElem, _> = PMMR::at(&mut backend, mmr_size); @@ -466,9 +453,7 @@ fn pmmr_compact_single_leaves() { backend.sync().unwrap(); // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); } teardown(data_dir); @@ -499,9 +484,7 @@ fn pmmr_compact_entire_peak() { backend.sync().unwrap(); // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); // now check we have pruned up to and including the peak at pos 7 // hash still available in underlying hash file @@ -587,9 +570,7 @@ fn pmmr_compact_horizon() { } // compact - backend - .check_compact(4, &Bitmap::of(&vec![1, 2]), &prune_noop) - .unwrap(); + backend.check_compact(4, &Bitmap::of(&vec![1, 2])).unwrap(); backend.sync().unwrap(); // check we can read a hash by pos correctly after compaction @@ -644,9 +625,7 @@ fn pmmr_compact_horizon() { } // compact some more - backend - .check_compact(9, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(9, &Bitmap::create()).unwrap(); } // recheck stored data @@ -711,9 +690,7 @@ fn compact_twice() { } // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); // recheck the root and stored data { @@ -740,9 +717,7 @@ fn compact_twice() { } // compact - backend - .check_compact(2, &Bitmap::create(), &prune_noop) - .unwrap(); + backend.check_compact(2, &Bitmap::create()).unwrap(); // recheck the root and stored data { diff --git a/util/Cargo.toml b/util/Cargo.toml index 058289d2b4..bd0fc9dec7 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_util" -version = "1.1.0" +version = "1.1.0-beta.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" diff --git a/util/src/logger.rs b/util/src/logger.rs index e5048267cc..322098f1c9 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -18,7 +18,7 @@ use std::ops::Deref; use backtrace::Backtrace; use std::{panic, thread}; -use crate::types::{LogLevel, LoggingConfig}; +use crate::types::{self, LogLevel, LoggingConfig}; use log::{LevelFilter, Record}; use log4rs; @@ -124,8 +124,11 @@ pub fn init_logger(config: Option) { let filter = Box::new(ThresholdFilter::new(level_file)); let file: Box = { if let Some(size) = c.log_max_size { + let count = c + .log_max_files + .unwrap_or_else(|| types::DEFAULT_ROTATE_LOG_FILES); let roller = FixedWindowRoller::builder() - .build(&format!("{}.{{}}.gz", c.log_file_path), 32) + .build(&format!("{}.{{}}.gz", c.log_file_path), count) .unwrap(); let trigger = SizeTrigger::new(size); diff --git a/util/src/types.rs b/util/src/types.rs index f6505662eb..a7f9c84da6 100644 --- a/util/src/types.rs +++ b/util/src/types.rs @@ -29,6 +29,9 @@ pub enum LogLevel { Trace, } +/// 32 log files to rotate over by default +pub const DEFAULT_ROTATE_LOG_FILES: u32 = 32 as u32; + /// Logging config #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct LoggingConfig { @@ -46,6 +49,8 @@ pub struct LoggingConfig { pub log_file_append: bool, /// Size of the log in bytes to rotate over (optional) pub log_max_size: Option, + /// Number of the log files to rotate over (optional) + pub log_max_files: Option, /// Whether the tui is running (optional) pub tui_running: Option, } @@ -60,6 +65,7 @@ impl Default for LoggingConfig { log_file_path: String::from("grin.log"), log_file_append: true, log_max_size: Some(1024 * 1024 * 16), // 16 megabytes default + log_max_files: Some(DEFAULT_ROTATE_LOG_FILES), tui_running: None, } } diff --git a/util/src/zip.rs b/util/src/zip.rs index 94c36b8fe6..f4eb2b28f6 100644 --- a/util/src/zip.rs +++ b/util/src/zip.rs @@ -15,6 +15,7 @@ use std::fs::{self, File}; /// Wrappers around the `zip-rs` library to compress and decompress zip archives. use std::io; +use std::panic; use std::path::Path; use walkdir::WalkDir; @@ -64,58 +65,80 @@ pub fn compress(src_dir: &Path, dst_file: &File) -> ZipResult<()> { /// Decompress a source file into the provided destination path. pub fn decompress(src_file: R, dest: &Path, expected: F) -> ZipResult where - R: io::Read + io::Seek, - F: Fn(&Path) -> bool, + R: io::Read + io::Seek + panic::UnwindSafe, + F: Fn(&Path) -> bool + panic::UnwindSafe, { let mut decompressed = 0; - let mut archive = zip_rs::ZipArchive::new(src_file)?; - for i in 0..archive.len() { - let mut file = archive.by_index(i)?; - let san_name = file.sanitized_name(); - if san_name.to_str().unwrap_or("").replace("\\", "/") != file.name().replace("\\", "/") - || !expected(&san_name) - { - info!( - "ignoring a suspicious file: {}, got {:?}", - file.name(), - san_name.to_str() - ); - continue; - } - let file_path = dest.join(san_name); + // catch the panic to avoid the thread quit + panic::set_hook(Box::new(|panic_info| { + error!( + "panic occurred: {:?}", + panic_info.payload().downcast_ref::<&str>().unwrap() + ); + })); + let result = panic::catch_unwind(move || { + let mut archive = zip_rs::ZipArchive::new(src_file)?; - if (&*file.name()).ends_with('/') { - fs::create_dir_all(&file_path)?; - } else { - if let Some(p) = file_path.parent() { - if !p.exists() { - fs::create_dir_all(&p)?; - } + for i in 0..archive.len() { + let mut file = archive.by_index(i)?; + let san_name = file.sanitized_name(); + if san_name.to_str().unwrap_or("").replace("\\", "/") != file.name().replace("\\", "/") + || !expected(&san_name) + { + info!( + "ignoring a suspicious file: {}, got {:?}", + file.name(), + san_name.to_str() + ); + continue; } - let res = fs::File::create(&file_path); - let mut outfile = match res { - Err(e) => { - error!("{:?}", e); - return Err(zip::result::ZipError::Io(e)); + let file_path = dest.join(san_name); + + if (&*file.name()).ends_with('/') { + fs::create_dir_all(&file_path)?; + } else { + if let Some(p) = file_path.parent() { + if !p.exists() { + fs::create_dir_all(&p)?; + } } - Ok(r) => r, - }; - io::copy(&mut file, &mut outfile)?; - decompressed += 1; - } + let res = fs::File::create(&file_path); + let mut outfile = match res { + Err(e) => { + error!("{:?}", e); + return Err(zip::result::ZipError::Io(e)); + } + Ok(r) => r, + }; + io::copy(&mut file, &mut outfile)?; + decompressed += 1; + } - // Get and Set permissions - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - if let Some(mode) = file.unix_mode() { - fs::set_permissions( - &file_path.to_str().unwrap(), - PermissionsExt::from_mode(mode), - )?; + // Get and Set permissions + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Some(mode) = file.unix_mode() { + fs::set_permissions( + &file_path.to_str().unwrap(), + PermissionsExt::from_mode(mode), + )?; + } } } + Ok(decompressed) + }); + match result { + Ok(res) => match res { + Err(e) => Err(e.into()), + Ok(_) => res, + }, + Err(_) => { + error!("panic occurred on zip::decompress!"); + Err(zip::result::ZipError::InvalidArchive( + "panic occurred on zip::decompress", + )) + } } - Ok(decompressed) }