From 0bec20a1e3b716add4d105c8576b4dadd9339109 Mon Sep 17 00:00:00 2001 From: Zach Date: Sat, 8 Sep 2018 08:45:12 -0400 Subject: [PATCH 01/47] update readme, clsoes #2357 (#2359) --- README.md | 33 ++++++++++++++++++--------------- docs/introduction/install.md | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 94d8d7f01..d97042008 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Or [Blockchain](https://en.wikipedia.org/wiki/Blockchain_(database)) for short. [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 )](https://godoc.org/github.com/tendermint/tendermint) -[![Go version](https://img.shields.io/badge/go-1.9.2-blue.svg)](https://github.com/moovweb/gvm) +[![Go version](https://img.shields.io/badge/go-1.10.4-blue.svg)](https://github.com/moovweb/gvm) [![riot.im](https://img.shields.io/badge/riot.im-JOIN%20CHAT-green.svg)](https://riot.im/app/#/room/#tendermint:matrix.org) [![license](https://img.shields.io/github/license/tendermint/tendermint.svg)](https://github.com/tendermint/tendermint/blob/master/LICENSE) [![](https://tokei.rs/b1/github/tendermint/tendermint?category=lines)](https://github.com/tendermint/tendermint) @@ -30,7 +30,7 @@ While Tendermint is being used in production in private, permissioned environments, we are still working actively to harden and audit it in preparation for use in public blockchains, such as the [Cosmos Network](https://cosmos.network/). We are also still making breaking changes to the protocol and the APIs. -Thus we tag the releases as *alpha software*. +Thus, we tag the releases as *alpha software*. In any case, if you intend to run Tendermint in production, please [contact us](https://riot.im/app/#/room/#tendermint:matrix.org) :) @@ -46,7 +46,7 @@ For examples of the kinds of bugs we're looking for, see [SECURITY.md](SECURITY. Requirement|Notes ---|--- -Go version | Go1.9 or higher +Go version | Go1.10 or higher ## Install @@ -54,10 +54,10 @@ See the [install instructions](/docs/introduction/install.md) ## Quick Start -- [Single node](/docs/using-tendermint.md) +- [Single node](/docs/tendermint-core/using-tendermint.md) - [Local cluster using docker-compose](/networks/local) - [Remote cluster using terraform and ansible](/docs/networks/terraform-and-ansible.md) -- [Join the public testnet](https://cosmos.network/testnet) +- [Join the Cosmos testnet](https://cosmos.network/testnet) ## Resources @@ -66,30 +66,31 @@ See the [install instructions](/docs/introduction/install.md) For details about the blockchain data structures and the p2p protocols, see the the [Tendermint specification](/docs/spec). -For details on using the software, [Read The Docs](https://tendermint.readthedocs.io/en/master/). -Additional information about some - and eventually all - of the sub-projects below, can be found at Read The Docs. +For details on using the software, see the [documentation](/docs/) which is also +hosted at: https://tendermint.com/docs/ +### Tools + +Benchmarking and monitoring is provided by `tm-bench` and `tm-monitor`, respectively. +Their code is found [here](/tools) and these binaries need to be built seperately. +Additional documentation is found [here](/docs/tools). ### Sub-projects * [Amino](http://github.com/tendermint/go-amino), a reflection-based improvement on proto3 * [IAVL](http://github.com/tendermint/iavl), Merkleized IAVL+ Tree implementation -### Tools -* [Deployment, Benchmarking, and Monitoring](http://tendermint.readthedocs.io/projects/tools/en/develop/index.html#tendermint-tools) - ### Applications * [Cosmos SDK](http://github.com/cosmos/cosmos-sdk); a cryptocurrency application framework -* [Ethermint](http://github.com/tendermint/ethermint); Ethereum on Tendermint -* [Many more](https://tendermint.readthedocs.io/en/master/ecosystem.html#abci-applications) +* [Ethermint](http://github.com/cosmos/ethermint); Ethereum on Tendermint +* [Many more](https://tendermint.com/ecosystem) -### More +### Research * [Master's Thesis on Tendermint](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769) * [Original Whitepaper](https://tendermint.com/static/docs/tendermint.pdf) -* [Tendermint Blog](https://blog.cosmos.network/tendermint/home) -* [Cosmos Blog](https://blog.cosmos.network) +* [Blog](https://blog.cosmos.network/tendermint/home) ## Contributing @@ -130,6 +131,8 @@ data into the new chain. However, any bump in the PATCH version should be compatible with existing histories (if not please open an [issue](https://github.com/tendermint/tendermint/issues)). +For more information on upgrading, see [here](./UPGRADING.md) + ## Code of Conduct Please read, understand and adhere to our [code of conduct](CODE_OF_CONDUCT.md). diff --git a/docs/introduction/install.md b/docs/introduction/install.md index d02691102..10b66dad0 100644 --- a/docs/introduction/install.md +++ b/docs/introduction/install.md @@ -5,7 +5,7 @@ is to run [this script](https://github.com/tendermint/tendermint/blob/develop/sc a fresh Ubuntu instance, or [this script](https://github.com/tendermint/tendermint/blob/develop/scripts/install/install_tendermint_bsd.sh) on a fresh FreeBSD instance. Read the comments / instructions carefully (i.e., reset your terminal after running the script, -make sure your okay with the network connections being made). +make sure you are okay with the network connections being made). ## From Binary From a57aae7072ac1ed97f4b782b08fc262e8f1d30af Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 9 Sep 2018 14:04:01 -0400 Subject: [PATCH 02/47] [ADR] ABCI errors and events (#2314) * Start of ADR * flesh out abci events and errors adrs * adr: move 012 to 023 * adr-022: add note from cwgoes --- docs/architecture/adr-021-abci-events.md | 47 ++++++++++++++ docs/architecture/adr-022-abci-errors.md | 64 +++++++++++++++++++ ...opose-tx.md => adr-023-ABCI-propose-tx.md} | 0 3 files changed, 111 insertions(+) create mode 100644 docs/architecture/adr-021-abci-events.md create mode 100644 docs/architecture/adr-022-abci-errors.md rename docs/architecture/{adr-012-ABCI-propose-tx.md => adr-023-ABCI-propose-tx.md} (100%) diff --git a/docs/architecture/adr-021-abci-events.md b/docs/architecture/adr-021-abci-events.md new file mode 100644 index 000000000..7d60d45a0 --- /dev/null +++ b/docs/architecture/adr-021-abci-events.md @@ -0,0 +1,47 @@ +# ADR 012: ABCI Events + +## Changelog + +- *2018-09-02* Remove ABCI errors component. Update description for events +- *2018-07-12* Initial version + +## Context + +ABCI tags were first described in [ADR 002](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-002-event-subscription.md). +They are key-value pairs that can be used to index transactions. + +Currently, ABCI messages return a list of tags to describe an +"event" that took place during the Check/DeliverTx/Begin/EndBlock, +where each tag refers to a different property of the event, like the sending and receiving account addresses. + +Since there is only one list of tags, recording data for multiple such events in +a single Check/DeliverTx/Begin/EndBlock must be done using prefixes in the key +space. + +TODO: brief description of how the indexing works + +## Decision + +Instead of returning a list of tags, return a list of events, where +each event is a list of tags. This way we naturally capture the concept of +multiple events happening during a single ABCI message. + +TODO: describe impact on indexing and querying + +## Status + +Proposed + +## Consequences + +### Positive + +- Ability to track distinct events separate from ABCI calls (DeliverTx/BeginBlock/EndBlock) +- More powerful query abilities + +### Negative + +- More complex query syntax +- More complex search implementation + +### Neutral diff --git a/docs/architecture/adr-022-abci-errors.md b/docs/architecture/adr-022-abci-errors.md new file mode 100644 index 000000000..23e917f47 --- /dev/null +++ b/docs/architecture/adr-022-abci-errors.md @@ -0,0 +1,64 @@ +# ADR 023: ABCI Codespaces + +## Changelog + +- *2018-09-01* Initial version + +## Context + +ABCI errors should provide an abstraction between application details +and the client interface responsible for formatting & displaying errors to the user. + +Currently, this abstraction consists of a single integer (the `code`), where any +`code > 0` is considered an error (ie. invalid transaction) and all type +information about the error is contained in the code. This integer is +expected to be decoded by the client into a known error string, where any +more specific data is contained in the `data`. + +In a [previous conversation](https://github.com/tendermint/abci/issues/165#issuecomment-353704015), +it was suggested that not all non-zero codes need to be errors, hence why it's called `code` and not `error code`. +It is unclear exactly how the semantics of the `code` field will evolve, though +better lite-client proofs (like discussed for tags +[here](https://github.com/tendermint/tendermint/issues/1007#issuecomment-413917763)) +may play a role. + +Note that having all type information in a single integer +precludes an easy coordination method between "module implementers" and "client +implementers", especially for apps with many "modules". With an unbounded error domain (such as a string), module +implementers can pick a globally unique prefix & error code set, so client +implementers could easily implement support for "module A" regardless of which +particular blockchain network it was running in and which other modules were running with it. With +only error codes, globally unique codes are difficult/impossible, as the space +is finite and collisions are likely without an easy way to coordinate. + +For instance, while trying to build an ecosystem of modules that can be composed into a single +ABCI application, the Cosmos-SDK had to hack a higher level "codespace" into the +single integer so that each module could have its own space to express its +errors. + +## Decision + +Include a `string code_space` in all ABCI messages that have a `code`. +This allows applications to namespace the codes so they can experiment with +their own code schemes. + +It is the responsibility of applications to limit the size of the `code_space` +string. + +How the codespace is hashed into block headers (ie. so it can be queried +efficiently by lite clients) is left for a separate ADR. + +## Consequences + +## Positive + +- No need for complex codespacing on a single integer +- More expressive type system for errors + +## Negative + +- Another field in the response needs to be accounted for +- Some redundancy with `code` field +- May encourage more error/code type info to move to the `codespace` string, which + could impact lite clients. + diff --git a/docs/architecture/adr-012-ABCI-propose-tx.md b/docs/architecture/adr-023-ABCI-propose-tx.md similarity index 100% rename from docs/architecture/adr-012-ABCI-propose-tx.md rename to docs/architecture/adr-023-ABCI-propose-tx.md From dea4e96f6630921c479c62fa6216d0bd68dd7426 Mon Sep 17 00:00:00 2001 From: xiaoping Date: Mon, 10 Sep 2018 14:42:48 +0800 Subject: [PATCH 03/47] fix docs links (#2352) --- .gitignore | 4 ++++ docs/DOCS_README.md | 18 ++++++++++++++++-- docs/app-dev/getting-started.md | 6 +++--- docs/networks/deploy-testnets.md | 2 +- docs/research/transactional-semantics.md | 2 +- docs/spec/blockchain/encoding.md | 2 +- docs/spec/consensus/consensus.md | 2 +- docs/tendermint-core/how-to-read-logs.md | 2 +- docs/tendermint-core/light-client-protocol.md | 6 +++--- docs/tendermint-core/using-tendermint.md | 2 +- docs/tendermint-core/validators.md | 4 ++-- 11 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 193a42894..f4adfcaa1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ test/p2p/data/ test/logs coverage.txt docs/_build +docs/.vuepress +docs/dist *.log abci-cli docs/node_modules/ @@ -25,6 +27,8 @@ scripts/cutWALUntil/cutWALUntil .idea/ *.iml +.vscode/ + libs/pubsub/query/fuzz_test/output shunit2 diff --git a/docs/DOCS_README.md b/docs/DOCS_README.md index 0be6e4c66..01ec07ad9 100644 --- a/docs/DOCS_README.md +++ b/docs/DOCS_README.md @@ -4,9 +4,15 @@ The documentation found in this directory is hosted at: - https://tendermint.com/docs/ -and built using [VuePress](https://vuepress.vuejs.org/) from the tendermint website repo: +and built using [VuePress](https://vuepress.vuejs.org/) like below: -- https://github.com/tendermint/tendermint.com +```bash +npm install -g vuepress # global install vuepress tool, only once +npm install + +mkdir -p .vuepress && cp config.js .vuepress/ +vuepress build +``` Under the hood, Jenkins listens for changes (on develop or master) in ./docs then rebuilds either the staging or production site depending on which branch the changes were made. @@ -15,3 +21,11 @@ To update the Table of Contents (layout of the documentation sidebar), edit the `config.js` in this directory, while the `README.md` is the landing page for the website documentation. +To view the latest documentation on the develop branch, see the staging site: + +- https://tendermint-staging.interblock.io/docs/ + +and the documentation on master branch is found here: + +- https://tendermint.com/docs/ + diff --git a/docs/app-dev/getting-started.md b/docs/app-dev/getting-started.md index 40820bea7..ae74d98aa 100644 --- a/docs/app-dev/getting-started.md +++ b/docs/app-dev/getting-started.md @@ -7,7 +7,7 @@ application you want to run. So, to run a complete blockchain that does something useful, you must start two programs: one is Tendermint Core, the other is your application, which can be written in any programming language. Recall from [the intro to -ABCI](./introduction.md#ABCI-Overview) that Tendermint Core handles all +ABCI](../introduction/introduction.md#ABCI-Overview) that Tendermint Core handles all the p2p and consensus stuff, and just forwards transactions to the application when they need to be validated, or when they're ready to be committed to a block. @@ -64,7 +64,7 @@ tendermint node If you have used Tendermint, you may want to reset the data for a new blockchain by running `tendermint unsafe_reset_all`. Then you can run `tendermint node` to start Tendermint, and connect to the app. For more -details, see [the guide on using Tendermint](./using-tendermint.md). +details, see [the guide on using Tendermint](../tendermint-core/using-tendermint.md). You should see Tendermint making blocks! We can get the status of our Tendermint node as follows: @@ -244,7 +244,7 @@ But if we send a `1`, it works again: ``` For more details on the `broadcast_tx` API, see [the guide on using -Tendermint](./using-tendermint.md). +Tendermint](../tendermint-core/using-tendermint.md). ## CounterJS - Example in Another Language diff --git a/docs/networks/deploy-testnets.md b/docs/networks/deploy-testnets.md index 04f953105..35732f9b3 100644 --- a/docs/networks/deploy-testnets.md +++ b/docs/networks/deploy-testnets.md @@ -36,7 +36,7 @@ tendermint node --proxy_app=kvstore --p2p.persistent_peers=96663a3dd0d7b9d17d4c8 After a few seconds, all the nodes should connect to each other and start making blocks! For more information, see the Tendermint Networks -section of [the guide to using Tendermint](./using-tendermint.md). +section of [the guide to using Tendermint](../tendermint-core/using-tendermint.md). But wait! Steps 3, 4 and 5 are quite manual. Instead, use the `tendermint testnet` command. By default, running `tendermint testnet` will create all the required files, but it won't populate the list of persistent peers. It will do diff --git a/docs/research/transactional-semantics.md b/docs/research/transactional-semantics.md index bab1864e8..99b5a00cb 100644 --- a/docs/research/transactional-semantics.md +++ b/docs/research/transactional-semantics.md @@ -1,6 +1,6 @@ # Transactional Semantics -In [Using Tendermint](./using-tendermint.md#broadcast-api) we +In [Using Tendermint](../tendermint-core/using-tendermint.md#broadcast-api) we discussed different API endpoints for sending transactions and differences between them. diff --git a/docs/spec/blockchain/encoding.md b/docs/spec/blockchain/encoding.md index 1af470403..38e27e7e0 100644 --- a/docs/spec/blockchain/encoding.md +++ b/docs/spec/blockchain/encoding.md @@ -269,7 +269,7 @@ similarly derived. ### IAVL+ Tree -Because Tendermint only uses a Simple Merkle Tree, application developers are expect to use their own Merkle tree in their applications. For example, the IAVL+ Tree - an immutable self-balancing binary tree for persisting application state is used by the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/core/multistore.md) +Because Tendermint only uses a Simple Merkle Tree, application developers are expect to use their own Merkle tree in their applications. For example, the IAVL+ Tree - an immutable self-balancing binary tree for persisting application state is used by the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/sdk/core/multistore.md) ## JSON diff --git a/docs/spec/consensus/consensus.md b/docs/spec/consensus/consensus.md index c77c09d26..a0136bff4 100644 --- a/docs/spec/consensus/consensus.md +++ b/docs/spec/consensus/consensus.md @@ -282,7 +282,7 @@ may make JSet verification/gossip logic easier to implement. ### Censorship Attacks Due to the definition of a block -[commit](../../tendermint-core/validator.md#commiting-a-block), any 1/3+ coalition of +[commit](../../tendermint-core/validators.md#commit-a-block), any 1/3+ coalition of validators can halt the blockchain by not broadcasting their votes. Such a coalition can also censor particular transactions by rejecting blocks that include these transactions, though this would result in a diff --git a/docs/tendermint-core/how-to-read-logs.md b/docs/tendermint-core/how-to-read-logs.md index bf9b49252..54c2c8a32 100644 --- a/docs/tendermint-core/how-to-read-logs.md +++ b/docs/tendermint-core/how-to-read-logs.md @@ -127,7 +127,7 @@ little overview what they do. found [here](https://github.com/tendermint/tendermint/blob/master/types/events.go). You can subscribe to them by calling `subscribe` RPC method. Refer - to [RPC docs](./specification/rpc.md) for additional information. + to [RPC docs](./rpc.md) for additional information. - `mempool` Mempool module handles all incoming transactions, whenever they are coming from peers or the application. - `p2p` Provides an abstraction around peer-to-peer communication. For diff --git a/docs/tendermint-core/light-client-protocol.md b/docs/tendermint-core/light-client-protocol.md index 7318ad16f..f9ef4bd03 100644 --- a/docs/tendermint-core/light-client-protocol.md +++ b/docs/tendermint-core/light-client-protocol.md @@ -10,11 +10,11 @@ package](https://godoc.org/github.com/tendermint/tendermint/lite). ## Overview The objective of the light client protocol is to get a -[commit](./validators.md#committing-a-block) for a recent [block -hash](../spec/consensus/consensus.md.md#block-hash) where the commit includes a +commit for a recent block +hash where the commit includes a majority of signatures from the last known validator set. From there, all the application state is verifiable with [merkle -proofs](./merkle.md#iavl-tree). +proofs](../spec/blockchain/encoding.md#iavl-tree). ## Properties diff --git a/docs/tendermint-core/using-tendermint.md b/docs/tendermint-core/using-tendermint.md index 28acc046b..a54412849 100644 --- a/docs/tendermint-core/using-tendermint.md +++ b/docs/tendermint-core/using-tendermint.md @@ -225,7 +225,7 @@ new blockchain will not make any blocks. ## Configuration Tendermint uses a `config.toml` for configuration. For details, see [the -config specification](./tendermint-core/configuration.md). +config specification](./configuration.md). Notable options include the socket address of the application (`proxy_app`), the listening address of the Tendermint peer diff --git a/docs/tendermint-core/validators.md b/docs/tendermint-core/validators.md index 5513886ad..307d267c6 100644 --- a/docs/tendermint-core/validators.md +++ b/docs/tendermint-core/validators.md @@ -22,7 +22,7 @@ Validators have a cryptographic key-pair and an associated amount of There are two ways to become validator. -1. They can be pre-established in the [genesis state](../../tendermint-core/using-tendermint.md#genesis) +1. They can be pre-established in the [genesis state](./using-tendermint.md#genesis) 2. The ABCI app responds to the EndBlock message with changes to the existing validator set. @@ -36,4 +36,4 @@ The +2/3 set of precommit votes is called a [_commit_](../spec/blockchain/blockchain.md#commit). While any +2/3 set of precommits for the same block at the same height&round can serve as validation, the canonical commit is included in the next block (see -[LastCommit](../spec/blockchain/blockchain.md#last-commit)). +[LastCommit](../spec/blockchain/blockchain.md#lastcommit)). From 503de8c9b8c3749f42bb1ed61feb76d2f3fed76a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 10 Sep 2018 09:10:53 -0400 Subject: [PATCH 04/47] docs/spec/abci: improve docs on AppHash (#2363) --- docs/spec/abci/abci.md | 18 +++++++++----- docs/spec/abci/apps.md | 54 +++++++++++++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/docs/spec/abci/abci.md b/docs/spec/abci/abci.md index b4314e3e1..287406b76 100644 --- a/docs/spec/abci/abci.md +++ b/docs/spec/abci/abci.md @@ -175,7 +175,8 @@ Commit are included in the header of the next block. - `Index (int64)`: The index of the key in the tree. - `Key ([]byte)`: The key of the matching data. - `Value ([]byte)`: The value of the matching data. - - `Proof ([]byte)`: Proof for the data, if requested. + - `Proof ([]byte)`: Serialized proof for the data, if requested, to be + verified against the `AppHash` for the given Height. - `Height (int64)`: The block height from which data was derived. Note that this is the height of the block containing the application's Merkle root hash, which represents the state as it @@ -275,13 +276,18 @@ Commit are included in the header of the next block. ### Commit - **Response**: - - `Data ([]byte)`: The Merkle root hash + - `Data ([]byte)`: The Merkle root hash of the application state - **Usage**: - Persist the application state. - - Return a Merkle root hash of the application state. - - It's critical that all application instances return the - same hash. If not, they will not be able to agree on the next - block, because the hash is included in the next block! + - Return an (optional) Merkle root hash of the application state + - `ResponseCommit.Data` is included as the `Header.AppHash` in the next block + - it may be empty + - Later calls to `Query` can return proofs about the application state anchored + in this Merkle root hash + - Note developers can return whatever they want here (could be nothing, or a + constant string, etc.), so long as it is deterministic - it must not be a + function of anything that did not come from the + BeginBlock/DeliverTx/EndBlock methods. ## Data Types diff --git a/docs/spec/abci/apps.md b/docs/spec/abci/apps.md index 92a4f49d5..ac0736161 100644 --- a/docs/spec/abci/apps.md +++ b/docs/spec/abci/apps.md @@ -4,19 +4,20 @@ Please ensure you've first read the spec for [ABCI Methods and Types](abci.md) Here we cover the following components of ABCI applications: -- [State](#state) - the interplay between ABCI connections and application state +- [Connection State](#state) - the interplay between ABCI connections and application state and the differences between `CheckTx` and `DeliverTx`. - [Transaction Results](#transaction-results) - rules around transaction results and validity - [Validator Set Updates](#validator-updates) - how validator sets are changed during `InitChain` and `EndBlock` -- [Query](#query) - standards for using the `Query` method +- [Query](#query) - standards for using the `Query` method and proofs about the + application state - [Crash Recovery](#crash-recovery) - handshake protocol to synchronize Tendermint and the application on startup. ## State -Since Tendermint maintains multiple concurrent ABCI connections, it is typical +Since Tendermint maintains three concurrent ABCI connections, it is typical for an application to maintain a distinct state for each, and for the states to be synchronized during `Commit`. @@ -96,7 +97,7 @@ though see issues [#1861](https://github.com/tendermint/tendermint/issues/1861), [#2299](https://github.com/tendermint/tendermint/issues/2299) and [#2310](https://github.com/tendermint/tendermint/issues/2310) for how this may -change. +soon change. ### CheckTx @@ -180,11 +181,46 @@ Note the updates returned in block `H` will only take effect at block `H+2`. ## Query -Query is a generic message type with lots of flexibility to enable diverse sets -of queries from applications. Tendermint has no requirements from the Query -message for normal operation - that is, the ABCI app developer need not implement Query functionality if they do not wish too. -That said, Tendermint makes a number of queries to support some optional -features. These are: +Query is a generic method with lots of flexibility to enable diverse sets +of queries on application state. Tendermint makes use of Query to filter new peers +based on ID and IP, and exposes Query to the user over RPC. +Note that calls to Query are not replicated across nodes, but rather query the +local node's state - hence they may provide stale reads. For reads that require +consensus, a transaction is required. + +The most important use of Query is to return Merkle proofs of the application state at some height +that can be used for efficient application-specific lite-clients. + +Note Tendermint has technically no requirements from the Query +message for normal operation - that is, the ABCI app developer need not implement +Query functionality if they do not wish too. + +### Query Proofs + +The Tendermint block header includes a number of hashes, each providing an +anchor for some type of proof about the blockchain. The `ValidatorsHash` enables +quick verification of the validator set, the `DataHash` gives quick +verification of the transactions included in the block, etc. + +The `AppHash` is unique in that it is application specific, and allows for +application-specific Merkle proofs about the state of the application. +While some applications keep all relevant state in the transactions themselves +(like Bitcoin and its UTXOs), others maintain a separated state that is +computed deterministically *from* transactions, but is not contained directly in +the transactions themselves (like Ethereum contracts and accounts). +For such applications, the `AppHash` provides a much more efficient way to verify lite-client proofs. + +ABCI applications can take advantage of more efficient lite-client proofs for +their state as follows: + +- return the Merkle root of the deterministic application state in +`ResponseCommit.Data`. +- it will be included as the `AppHash` in the next block. +- return efficient Merkle proofs about that application state in `ResponseQuery.Proof` + that can be verified using the `AppHash` of the corresponding block. + +For instance, this allows an application's lite-client to verify proofs of +absence in the application state, something which is much less efficient to do using the block hash. ### Peer Filtering From 33b4617e9a48edf48a073b7597c92171b33e2496 Mon Sep 17 00:00:00 2001 From: Zach Date: Wed, 12 Sep 2018 13:03:17 -0400 Subject: [PATCH 05/47] docs: update link to rpc (#2361) * md links dont work in slate * docs: link to rpc * docs: use unsafe_reset_all * do not advertise unsafe_reset_priv_validator --- docs/tendermint-core/rpc.md | 6 ++++-- docs/tendermint-core/running-in-production.md | 3 ++- docs/tendermint-core/using-tendermint.md | 16 ++++++++-------- rpc/core/doc.go | 3 ++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/tendermint-core/rpc.md b/docs/tendermint-core/rpc.md index 51f34fc25..7ae59f0d3 100644 --- a/docs/tendermint-core/rpc.md +++ b/docs/tendermint-core/rpc.md @@ -1,5 +1,7 @@ # RPC -The RPC documentation is hosted [here](https://tendermint.github.io/slate) and is generated by the CI from our [Slate repo](https://github.com/tendermint/slate). To update the documentation, edit the relevant `godoc` comments in the [rpc/core directory](https://github.com/tendermint/tendermint/tree/develop/rpc/core). +The RPC documentation is hosted here: -NOTE: We will be moving the RPC documentation into the website in the near future. Stay tuned! +- https://tendermint.com/rpc/ + +To update the documentation, edit the relevant `godoc` comments in the [rpc/core directory](https://github.com/tendermint/tendermint/tree/develop/rpc/core). diff --git a/docs/tendermint-core/running-in-production.md b/docs/tendermint-core/running-in-production.md index cb228be4a..f647bd9b0 100644 --- a/docs/tendermint-core/running-in-production.md +++ b/docs/tendermint-core/running-in-production.md @@ -28,7 +28,8 @@ send & receive rate per connection (`SendRate`, `RecvRate`). ### RPC Endpoints returning multiple entries are limited by default to return 30 -elements (100 max). See [here](./rpc.md) for more information about the RPC. +elements (100 max). See the [RPC Documentation](https://tendermint.com/rpc/) +for more information. Rate-limiting and authentication are another key aspects to help protect against DOS attacks. While in the future we may implement these diff --git a/docs/tendermint-core/using-tendermint.md b/docs/tendermint-core/using-tendermint.md index a54412849..33d981e4d 100644 --- a/docs/tendermint-core/using-tendermint.md +++ b/docs/tendermint-core/using-tendermint.md @@ -156,6 +156,10 @@ Visit http://localhost:26657 in your browser to see the list of other endpoints. Some take no arguments (like `/status`), while others specify the argument name and use `_` as a placeholder. +::: tip +Find the RPC Documentation [here](https://tendermint.com/rpc/) +::: + ### Formatting The following nuances when sending/formatting transactions should be @@ -209,18 +213,14 @@ Note that raw hex cannot be used in `POST` transactions. **WARNING: UNSAFE** Only do this in development and only if you can afford to lose all blockchain data! -To reset a blockchain, stop the node, remove the `~/.tendermint/data` -directory and run +To reset a blockchain, stop the node and run: ``` -tendermint unsafe_reset_priv_validator +tendermint unsafe_reset_all ``` -This final step is necessary to reset the `priv_validator.json`, which -otherwise prevents you from making conflicting votes in the consensus -(something that could get you in trouble if you do it on a real -blockchain). If you don't reset the `priv_validator.json`, your fresh -new blockchain will not make any blocks. +This command will remove the data directory and reset private validator and +address book files. ## Configuration diff --git a/rpc/core/doc.go b/rpc/core/doc.go index 75f6ac82e..603b6679e 100644 --- a/rpc/core/doc.go +++ b/rpc/core/doc.go @@ -7,7 +7,8 @@ Tendermint supports the following RPC protocols: * JSONRPC over HTTP * JSONRPC over websockets -Tendermint RPC is built using [our own RPC library](https://github.com/tendermint/tendermint/tree/master/rpc/lib) which contains its own set of documentation and tests. +Tendermint RPC is built using our own RPC library which contains its own set of documentation and tests. +See it here: https://github.com/tendermint/tendermint/tree/master/rpc/lib ## Configuration From 0e1cd888636628a97dd2a3dc3c59bdd6e1145b72 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 12 Sep 2018 23:44:43 +0400 Subject: [PATCH 06/47] Remove ConsensusParams.TxSize and ConsensusParams.BlockGossip (#2364) * remove ConsensusParams.TxSize and ConsensusParams.BlockGossip Refs #2347 * block part size is now fixed Refs #2347 * use max data size, not max bytes for tx limit Refs #2347 --- abci/types/types.pb.go | 983 ++++++++++++++++--------------------- abci/types/types.proto | 20 +- abci/types/typespb_test.go | 158 +----- blockchain/reactor.go | 2 +- blockchain/reactor_test.go | 2 +- consensus/replay_test.go | 12 +- consensus/state.go | 11 +- consensus/state_test.go | 14 +- consensus/wal.go | 2 +- node/node.go | 8 +- state/execution.go | 7 +- state/state.go | 2 +- state/state_test.go | 37 +- types/block.go | 22 + types/evidence.go | 5 + types/params.go | 100 ++-- types/params_test.go | 87 ++-- types/protobuf.go | 27 +- 18 files changed, 585 insertions(+), 914 deletions(-) diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 7873f0975..e94bd93ae 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -60,7 +60,7 @@ func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{0} + return fileDescriptor_types_bfbaec40016cbadd, []int{0} } func (m *Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -482,7 +482,7 @@ func (m *RequestEcho) Reset() { *m = RequestEcho{} } func (m *RequestEcho) String() string { return proto.CompactTextString(m) } func (*RequestEcho) ProtoMessage() {} func (*RequestEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{1} + return fileDescriptor_types_bfbaec40016cbadd, []int{1} } func (m *RequestEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -528,7 +528,7 @@ func (m *RequestFlush) Reset() { *m = RequestFlush{} } func (m *RequestFlush) String() string { return proto.CompactTextString(m) } func (*RequestFlush) ProtoMessage() {} func (*RequestFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{2} + return fileDescriptor_types_bfbaec40016cbadd, []int{2} } func (m *RequestFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -568,7 +568,7 @@ func (m *RequestInfo) Reset() { *m = RequestInfo{} } func (m *RequestInfo) String() string { return proto.CompactTextString(m) } func (*RequestInfo) ProtoMessage() {} func (*RequestInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{3} + return fileDescriptor_types_bfbaec40016cbadd, []int{3} } func (m *RequestInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -617,7 +617,7 @@ func (m *RequestSetOption) Reset() { *m = RequestSetOption{} } func (m *RequestSetOption) String() string { return proto.CompactTextString(m) } func (*RequestSetOption) ProtoMessage() {} func (*RequestSetOption) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{4} + return fileDescriptor_types_bfbaec40016cbadd, []int{4} } func (m *RequestSetOption) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -675,7 +675,7 @@ func (m *RequestInitChain) Reset() { *m = RequestInitChain{} } func (m *RequestInitChain) String() string { return proto.CompactTextString(m) } func (*RequestInitChain) ProtoMessage() {} func (*RequestInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{5} + return fileDescriptor_types_bfbaec40016cbadd, []int{5} } func (m *RequestInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -753,7 +753,7 @@ func (m *RequestQuery) Reset() { *m = RequestQuery{} } func (m *RequestQuery) String() string { return proto.CompactTextString(m) } func (*RequestQuery) ProtoMessage() {} func (*RequestQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{6} + return fileDescriptor_types_bfbaec40016cbadd, []int{6} } func (m *RequestQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -825,7 +825,7 @@ func (m *RequestBeginBlock) Reset() { *m = RequestBeginBlock{} } func (m *RequestBeginBlock) String() string { return proto.CompactTextString(m) } func (*RequestBeginBlock) ProtoMessage() {} func (*RequestBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{7} + return fileDescriptor_types_bfbaec40016cbadd, []int{7} } func (m *RequestBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -893,7 +893,7 @@ func (m *RequestCheckTx) Reset() { *m = RequestCheckTx{} } func (m *RequestCheckTx) String() string { return proto.CompactTextString(m) } func (*RequestCheckTx) ProtoMessage() {} func (*RequestCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{8} + return fileDescriptor_types_bfbaec40016cbadd, []int{8} } func (m *RequestCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -940,7 +940,7 @@ func (m *RequestDeliverTx) Reset() { *m = RequestDeliverTx{} } func (m *RequestDeliverTx) String() string { return proto.CompactTextString(m) } func (*RequestDeliverTx) ProtoMessage() {} func (*RequestDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{9} + return fileDescriptor_types_bfbaec40016cbadd, []int{9} } func (m *RequestDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -987,7 +987,7 @@ func (m *RequestEndBlock) Reset() { *m = RequestEndBlock{} } func (m *RequestEndBlock) String() string { return proto.CompactTextString(m) } func (*RequestEndBlock) ProtoMessage() {} func (*RequestEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{10} + return fileDescriptor_types_bfbaec40016cbadd, []int{10} } func (m *RequestEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1033,7 +1033,7 @@ func (m *RequestCommit) Reset() { *m = RequestCommit{} } func (m *RequestCommit) String() string { return proto.CompactTextString(m) } func (*RequestCommit) ProtoMessage() {} func (*RequestCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{11} + return fileDescriptor_types_bfbaec40016cbadd, []int{11} } func (m *RequestCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1086,7 +1086,7 @@ func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{12} + return fileDescriptor_types_bfbaec40016cbadd, []int{12} } func (m *Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1539,7 +1539,7 @@ func (m *ResponseException) Reset() { *m = ResponseException{} } func (m *ResponseException) String() string { return proto.CompactTextString(m) } func (*ResponseException) ProtoMessage() {} func (*ResponseException) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{13} + return fileDescriptor_types_bfbaec40016cbadd, []int{13} } func (m *ResponseException) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1586,7 +1586,7 @@ func (m *ResponseEcho) Reset() { *m = ResponseEcho{} } func (m *ResponseEcho) String() string { return proto.CompactTextString(m) } func (*ResponseEcho) ProtoMessage() {} func (*ResponseEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{14} + return fileDescriptor_types_bfbaec40016cbadd, []int{14} } func (m *ResponseEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1632,7 +1632,7 @@ func (m *ResponseFlush) Reset() { *m = ResponseFlush{} } func (m *ResponseFlush) String() string { return proto.CompactTextString(m) } func (*ResponseFlush) ProtoMessage() {} func (*ResponseFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{15} + return fileDescriptor_types_bfbaec40016cbadd, []int{15} } func (m *ResponseFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1675,7 +1675,7 @@ func (m *ResponseInfo) Reset() { *m = ResponseInfo{} } func (m *ResponseInfo) String() string { return proto.CompactTextString(m) } func (*ResponseInfo) ProtoMessage() {} func (*ResponseInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{16} + return fileDescriptor_types_bfbaec40016cbadd, []int{16} } func (m *ResponseInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1747,7 +1747,7 @@ func (m *ResponseSetOption) Reset() { *m = ResponseSetOption{} } func (m *ResponseSetOption) String() string { return proto.CompactTextString(m) } func (*ResponseSetOption) ProtoMessage() {} func (*ResponseSetOption) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{17} + return fileDescriptor_types_bfbaec40016cbadd, []int{17} } func (m *ResponseSetOption) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1809,7 +1809,7 @@ func (m *ResponseInitChain) Reset() { *m = ResponseInitChain{} } func (m *ResponseInitChain) String() string { return proto.CompactTextString(m) } func (*ResponseInitChain) ProtoMessage() {} func (*ResponseInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{18} + return fileDescriptor_types_bfbaec40016cbadd, []int{18} } func (m *ResponseInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1871,7 +1871,7 @@ func (m *ResponseQuery) Reset() { *m = ResponseQuery{} } func (m *ResponseQuery) String() string { return proto.CompactTextString(m) } func (*ResponseQuery) ProtoMessage() {} func (*ResponseQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{19} + return fileDescriptor_types_bfbaec40016cbadd, []int{19} } func (m *ResponseQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1967,7 +1967,7 @@ func (m *ResponseBeginBlock) Reset() { *m = ResponseBeginBlock{} } func (m *ResponseBeginBlock) String() string { return proto.CompactTextString(m) } func (*ResponseBeginBlock) ProtoMessage() {} func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{20} + return fileDescriptor_types_bfbaec40016cbadd, []int{20} } func (m *ResponseBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2020,7 +2020,7 @@ func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} } func (m *ResponseCheckTx) String() string { return proto.CompactTextString(m) } func (*ResponseCheckTx) ProtoMessage() {} func (*ResponseCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{21} + return fileDescriptor_types_bfbaec40016cbadd, []int{21} } func (m *ResponseCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2115,7 +2115,7 @@ func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } func (m *ResponseDeliverTx) String() string { return proto.CompactTextString(m) } func (*ResponseDeliverTx) ProtoMessage() {} func (*ResponseDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{22} + return fileDescriptor_types_bfbaec40016cbadd, []int{22} } func (m *ResponseDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2206,7 +2206,7 @@ func (m *ResponseEndBlock) Reset() { *m = ResponseEndBlock{} } func (m *ResponseEndBlock) String() string { return proto.CompactTextString(m) } func (*ResponseEndBlock) ProtoMessage() {} func (*ResponseEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{23} + return fileDescriptor_types_bfbaec40016cbadd, []int{23} } func (m *ResponseEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2268,7 +2268,7 @@ func (m *ResponseCommit) Reset() { *m = ResponseCommit{} } func (m *ResponseCommit) String() string { return proto.CompactTextString(m) } func (*ResponseCommit) ProtoMessage() {} func (*ResponseCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{24} + return fileDescriptor_types_bfbaec40016cbadd, []int{24} } func (m *ResponseCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2307,19 +2307,18 @@ func (m *ResponseCommit) GetData() []byte { // ConsensusParams contains all consensus-relevant parameters // that can be adjusted by the abci app type ConsensusParams struct { - BlockSize *BlockSize `protobuf:"bytes,1,opt,name=block_size,json=blockSize" json:"block_size,omitempty"` - TxSize *TxSize `protobuf:"bytes,2,opt,name=tx_size,json=txSize" json:"tx_size,omitempty"` - BlockGossip *BlockGossip `protobuf:"bytes,3,opt,name=block_gossip,json=blockGossip" json:"block_gossip,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + BlockSize *BlockSize `protobuf:"bytes,1,opt,name=block_size,json=blockSize" json:"block_size,omitempty"` + EvidenceParams *EvidenceParams `protobuf:"bytes,2,opt,name=evidence_params,json=evidenceParams" json:"evidence_params,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ConsensusParams) Reset() { *m = ConsensusParams{} } func (m *ConsensusParams) String() string { return proto.CompactTextString(m) } func (*ConsensusParams) ProtoMessage() {} func (*ConsensusParams) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{25} + return fileDescriptor_types_bfbaec40016cbadd, []int{25} } func (m *ConsensusParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2355,23 +2354,18 @@ func (m *ConsensusParams) GetBlockSize() *BlockSize { return nil } -func (m *ConsensusParams) GetTxSize() *TxSize { +func (m *ConsensusParams) GetEvidenceParams() *EvidenceParams { if m != nil { - return m.TxSize - } - return nil -} - -func (m *ConsensusParams) GetBlockGossip() *BlockGossip { - if m != nil { - return m.BlockGossip + return m.EvidenceParams } return nil } // BlockSize contains limits on the block size. type BlockSize struct { - MaxBytes int32 `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` + // Note: must be greater than 0 + MaxBytes int32 `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` + // Note: must be greater or equal to -1 MaxGas int64 `protobuf:"varint,2,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -2382,7 +2376,7 @@ func (m *BlockSize) Reset() { *m = BlockSize{} } func (m *BlockSize) String() string { return proto.CompactTextString(m) } func (*BlockSize) ProtoMessage() {} func (*BlockSize) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{26} + return fileDescriptor_types_bfbaec40016cbadd, []int{26} } func (m *BlockSize) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2425,27 +2419,27 @@ func (m *BlockSize) GetMaxGas() int64 { return 0 } -// TxSize contains limits on the tx size. -type TxSize struct { - MaxBytes int32 `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` - MaxGas int64 `protobuf:"varint,2,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` +// EvidenceParams contains limits on the evidence. +type EvidenceParams struct { + // Note: must be greater than 0 + MaxAge int64 `protobuf:"varint,1,opt,name=max_age,json=maxAge,proto3" json:"max_age,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *TxSize) Reset() { *m = TxSize{} } -func (m *TxSize) String() string { return proto.CompactTextString(m) } -func (*TxSize) ProtoMessage() {} -func (*TxSize) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{27} +func (m *EvidenceParams) Reset() { *m = EvidenceParams{} } +func (m *EvidenceParams) String() string { return proto.CompactTextString(m) } +func (*EvidenceParams) ProtoMessage() {} +func (*EvidenceParams) Descriptor() ([]byte, []int) { + return fileDescriptor_types_bfbaec40016cbadd, []int{27} } -func (m *TxSize) XXX_Unmarshal(b []byte) error { +func (m *EvidenceParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *TxSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *EvidenceParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_TxSize.Marshal(b, m, deterministic) + return xxx_messageInfo_EvidenceParams.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalTo(b) @@ -2455,78 +2449,21 @@ func (m *TxSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (dst *TxSize) XXX_Merge(src proto.Message) { - xxx_messageInfo_TxSize.Merge(dst, src) +func (dst *EvidenceParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_EvidenceParams.Merge(dst, src) } -func (m *TxSize) XXX_Size() int { +func (m *EvidenceParams) XXX_Size() int { return m.Size() } -func (m *TxSize) XXX_DiscardUnknown() { - xxx_messageInfo_TxSize.DiscardUnknown(m) +func (m *EvidenceParams) XXX_DiscardUnknown() { + xxx_messageInfo_EvidenceParams.DiscardUnknown(m) } -var xxx_messageInfo_TxSize proto.InternalMessageInfo +var xxx_messageInfo_EvidenceParams proto.InternalMessageInfo -func (m *TxSize) GetMaxBytes() int32 { +func (m *EvidenceParams) GetMaxAge() int64 { if m != nil { - return m.MaxBytes - } - return 0 -} - -func (m *TxSize) GetMaxGas() int64 { - if m != nil { - return m.MaxGas - } - return 0 -} - -// BlockGossip determine consensus critical -// elements of how blocks are gossiped -type BlockGossip struct { - // Note: must not be 0 - BlockPartSizeBytes int32 `protobuf:"varint,1,opt,name=block_part_size_bytes,json=blockPartSizeBytes,proto3" json:"block_part_size_bytes,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BlockGossip) Reset() { *m = BlockGossip{} } -func (m *BlockGossip) String() string { return proto.CompactTextString(m) } -func (*BlockGossip) ProtoMessage() {} -func (*BlockGossip) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{28} -} -func (m *BlockGossip) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BlockGossip) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BlockGossip.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalTo(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (dst *BlockGossip) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlockGossip.Merge(dst, src) -} -func (m *BlockGossip) XXX_Size() int { - return m.Size() -} -func (m *BlockGossip) XXX_DiscardUnknown() { - xxx_messageInfo_BlockGossip.DiscardUnknown(m) -} - -var xxx_messageInfo_BlockGossip proto.InternalMessageInfo - -func (m *BlockGossip) GetBlockPartSizeBytes() int32 { - if m != nil { - return m.BlockPartSizeBytes + return m.MaxAge } return 0 } @@ -2543,7 +2480,7 @@ func (m *LastCommitInfo) Reset() { *m = LastCommitInfo{} } func (m *LastCommitInfo) String() string { return proto.CompactTextString(m) } func (*LastCommitInfo) ProtoMessage() {} func (*LastCommitInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{29} + return fileDescriptor_types_bfbaec40016cbadd, []int{28} } func (m *LastCommitInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2616,7 +2553,7 @@ func (m *Header) Reset() { *m = Header{} } func (m *Header) String() string { return proto.CompactTextString(m) } func (*Header) ProtoMessage() {} func (*Header) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{30} + return fileDescriptor_types_bfbaec40016cbadd, []int{29} } func (m *Header) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2762,7 +2699,7 @@ func (m *BlockID) Reset() { *m = BlockID{} } func (m *BlockID) String() string { return proto.CompactTextString(m) } func (*BlockID) ProtoMessage() {} func (*BlockID) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{31} + return fileDescriptor_types_bfbaec40016cbadd, []int{30} } func (m *BlockID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2817,7 +2754,7 @@ func (m *PartSetHeader) Reset() { *m = PartSetHeader{} } func (m *PartSetHeader) String() string { return proto.CompactTextString(m) } func (*PartSetHeader) ProtoMessage() {} func (*PartSetHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{32} + return fileDescriptor_types_bfbaec40016cbadd, []int{31} } func (m *PartSetHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2874,7 +2811,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{33} + return fileDescriptor_types_bfbaec40016cbadd, []int{32} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2930,7 +2867,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{34} + return fileDescriptor_types_bfbaec40016cbadd, []int{33} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2986,7 +2923,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{35} + return fileDescriptor_types_bfbaec40016cbadd, []int{34} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3041,7 +2978,7 @@ func (m *PubKey) Reset() { *m = PubKey{} } func (m *PubKey) String() string { return proto.CompactTextString(m) } func (*PubKey) ProtoMessage() {} func (*PubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{36} + return fileDescriptor_types_bfbaec40016cbadd, []int{35} } func (m *PubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3099,7 +3036,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_types_c68d3007ea320b94, []int{37} + return fileDescriptor_types_bfbaec40016cbadd, []int{36} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3218,10 +3155,8 @@ func init() { golang_proto.RegisterType((*ConsensusParams)(nil), "types.ConsensusParams") proto.RegisterType((*BlockSize)(nil), "types.BlockSize") golang_proto.RegisterType((*BlockSize)(nil), "types.BlockSize") - proto.RegisterType((*TxSize)(nil), "types.TxSize") - golang_proto.RegisterType((*TxSize)(nil), "types.TxSize") - proto.RegisterType((*BlockGossip)(nil), "types.BlockGossip") - golang_proto.RegisterType((*BlockGossip)(nil), "types.BlockGossip") + proto.RegisterType((*EvidenceParams)(nil), "types.EvidenceParams") + golang_proto.RegisterType((*EvidenceParams)(nil), "types.EvidenceParams") proto.RegisterType((*LastCommitInfo)(nil), "types.LastCommitInfo") golang_proto.RegisterType((*LastCommitInfo)(nil), "types.LastCommitInfo") proto.RegisterType((*Header)(nil), "types.Header") @@ -4647,10 +4582,7 @@ func (this *ConsensusParams) Equal(that interface{}) bool { if !this.BlockSize.Equal(that1.BlockSize) { return false } - if !this.TxSize.Equal(that1.TxSize) { - return false - } - if !this.BlockGossip.Equal(that1.BlockGossip) { + if !this.EvidenceParams.Equal(that1.EvidenceParams) { return false } if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { @@ -4688,14 +4620,14 @@ func (this *BlockSize) Equal(that interface{}) bool { } return true } -func (this *TxSize) Equal(that interface{}) bool { +func (this *EvidenceParams) Equal(that interface{}) bool { if that == nil { return this == nil } - that1, ok := that.(*TxSize) + that1, ok := that.(*EvidenceParams) if !ok { - that2, ok := that.(TxSize) + that2, ok := that.(EvidenceParams) if ok { that1 = &that2 } else { @@ -4707,37 +4639,7 @@ func (this *TxSize) Equal(that interface{}) bool { } else if this == nil { return false } - if this.MaxBytes != that1.MaxBytes { - return false - } - if this.MaxGas != that1.MaxGas { - return false - } - if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { - return false - } - return true -} -func (this *BlockGossip) Equal(that interface{}) bool { - if that == nil { - return this == nil - } - - that1, ok := that.(*BlockGossip) - if !ok { - that2, ok := that.(BlockGossip) - if ok { - that1 = &that2 - } else { - return false - } - } - if that1 == nil { - return this == nil - } else if this == nil { - return false - } - if this.BlockPartSizeBytes != that1.BlockPartSizeBytes { + if this.MaxAge != that1.MaxAge { return false } if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { @@ -5201,8 +5103,7 @@ func (c *aBCIApplicationClient) EndBlock(ctx context.Context, in *RequestEndBloc return out, nil } -// Server API for ABCIApplication service - +// ABCIApplicationServer is the server API for ABCIApplication service. type ABCIApplicationServer interface { Echo(context.Context, *RequestEcho) (*ResponseEcho, error) Flush(context.Context, *RequestFlush) (*ResponseFlush, error) @@ -6765,26 +6666,16 @@ func (m *ConsensusParams) MarshalTo(dAtA []byte) (int, error) { } i += n32 } - if m.TxSize != nil { + if m.EvidenceParams != nil { dAtA[i] = 0x12 i++ - i = encodeVarintTypes(dAtA, i, uint64(m.TxSize.Size())) - n33, err := m.TxSize.MarshalTo(dAtA[i:]) + i = encodeVarintTypes(dAtA, i, uint64(m.EvidenceParams.Size())) + n33, err := m.EvidenceParams.MarshalTo(dAtA[i:]) if err != nil { return 0, err } i += n33 } - if m.BlockGossip != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintTypes(dAtA, i, uint64(m.BlockGossip.Size())) - n34, err := m.BlockGossip.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n34 - } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -6822,38 +6713,7 @@ func (m *BlockSize) MarshalTo(dAtA []byte) (int, error) { return i, nil } -func (m *TxSize) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TxSize) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.MaxBytes != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintTypes(dAtA, i, uint64(m.MaxBytes)) - } - if m.MaxGas != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintTypes(dAtA, i, uint64(m.MaxGas)) - } - if m.XXX_unrecognized != nil { - i += copy(dAtA[i:], m.XXX_unrecognized) - } - return i, nil -} - -func (m *BlockGossip) Marshal() (dAtA []byte, err error) { +func (m *EvidenceParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -6863,15 +6723,15 @@ func (m *BlockGossip) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *BlockGossip) MarshalTo(dAtA []byte) (int, error) { +func (m *EvidenceParams) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l - if m.BlockPartSizeBytes != 0 { + if m.MaxAge != 0 { dAtA[i] = 0x8 i++ - i = encodeVarintTypes(dAtA, i, uint64(m.BlockPartSizeBytes)) + i = encodeVarintTypes(dAtA, i, uint64(m.MaxAge)) } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -6946,11 +6806,11 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Time))) - n35, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) + n34, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) if err != nil { return 0, err } - i += n35 + i += n34 if m.NumTxs != 0 { dAtA[i] = 0x20 i++ @@ -6964,11 +6824,11 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x32 i++ i = encodeVarintTypes(dAtA, i, uint64(m.LastBlockId.Size())) - n36, err := m.LastBlockId.MarshalTo(dAtA[i:]) + n35, err := m.LastBlockId.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n36 + i += n35 if len(m.LastCommitHash) > 0 { dAtA[i] = 0x3a i++ @@ -7053,11 +6913,11 @@ func (m *BlockID) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintTypes(dAtA, i, uint64(m.PartsHeader.Size())) - n37, err := m.PartsHeader.MarshalTo(dAtA[i:]) + n36, err := m.PartsHeader.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n37 + i += n36 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -7146,11 +7006,11 @@ func (m *ValidatorUpdate) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintTypes(dAtA, i, uint64(m.PubKey.Size())) - n38, err := m.PubKey.MarshalTo(dAtA[i:]) + n37, err := m.PubKey.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n38 + i += n37 if m.Power != 0 { dAtA[i] = 0x10 i++ @@ -7180,11 +7040,11 @@ func (m *VoteInfo) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintTypes(dAtA, i, uint64(m.Validator.Size())) - n39, err := m.Validator.MarshalTo(dAtA[i:]) + n38, err := m.Validator.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n39 + i += n38 if m.SignedLastBlock { dAtA[i] = 0x10 i++ @@ -7258,11 +7118,11 @@ func (m *Evidence) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintTypes(dAtA, i, uint64(m.Validator.Size())) - n40, err := m.Validator.MarshalTo(dAtA[i:]) + n39, err := m.Validator.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n40 + i += n39 if m.Height != 0 { dAtA[i] = 0x18 i++ @@ -7271,11 +7131,11 @@ func (m *Evidence) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Time))) - n41, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) + n40, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:]) if err != nil { return 0, err } - i += n41 + i += n40 if m.TotalVotingPower != 0 { dAtA[i] = 0x28 i++ @@ -7867,13 +7727,10 @@ func NewPopulatedConsensusParams(r randyTypes, easy bool) *ConsensusParams { this.BlockSize = NewPopulatedBlockSize(r, easy) } if r.Intn(10) != 0 { - this.TxSize = NewPopulatedTxSize(r, easy) - } - if r.Intn(10) != 0 { - this.BlockGossip = NewPopulatedBlockGossip(r, easy) + this.EvidenceParams = NewPopulatedEvidenceParams(r, easy) } if !easy && r.Intn(10) != 0 { - this.XXX_unrecognized = randUnrecognizedTypes(r, 4) + this.XXX_unrecognized = randUnrecognizedTypes(r, 3) } return this } @@ -7894,27 +7751,11 @@ func NewPopulatedBlockSize(r randyTypes, easy bool) *BlockSize { return this } -func NewPopulatedTxSize(r randyTypes, easy bool) *TxSize { - this := &TxSize{} - this.MaxBytes = int32(r.Int31()) +func NewPopulatedEvidenceParams(r randyTypes, easy bool) *EvidenceParams { + this := &EvidenceParams{} + this.MaxAge = int64(r.Int63()) if r.Intn(2) == 0 { - this.MaxBytes *= -1 - } - this.MaxGas = int64(r.Int63()) - if r.Intn(2) == 0 { - this.MaxGas *= -1 - } - if !easy && r.Intn(10) != 0 { - this.XXX_unrecognized = randUnrecognizedTypes(r, 3) - } - return this -} - -func NewPopulatedBlockGossip(r randyTypes, easy bool) *BlockGossip { - this := &BlockGossip{} - this.BlockPartSizeBytes = int32(r.Int31()) - if r.Intn(2) == 0 { - this.BlockPartSizeBytes *= -1 + this.MaxAge *= -1 } if !easy && r.Intn(10) != 0 { this.XXX_unrecognized = randUnrecognizedTypes(r, 2) @@ -8194,6 +8035,9 @@ func encodeVarintPopulateTypes(dAtA []byte, v uint64) []byte { return dAtA } func (m *Request) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Value != nil { @@ -8206,6 +8050,9 @@ func (m *Request) Size() (n int) { } func (m *Request_Echo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Echo != nil { @@ -8215,6 +8062,9 @@ func (m *Request_Echo) Size() (n int) { return n } func (m *Request_Flush) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Flush != nil { @@ -8224,6 +8074,9 @@ func (m *Request_Flush) Size() (n int) { return n } func (m *Request_Info) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Info != nil { @@ -8233,6 +8086,9 @@ func (m *Request_Info) Size() (n int) { return n } func (m *Request_SetOption) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.SetOption != nil { @@ -8242,6 +8098,9 @@ func (m *Request_SetOption) Size() (n int) { return n } func (m *Request_InitChain) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.InitChain != nil { @@ -8251,6 +8110,9 @@ func (m *Request_InitChain) Size() (n int) { return n } func (m *Request_Query) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Query != nil { @@ -8260,6 +8122,9 @@ func (m *Request_Query) Size() (n int) { return n } func (m *Request_BeginBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.BeginBlock != nil { @@ -8269,6 +8134,9 @@ func (m *Request_BeginBlock) Size() (n int) { return n } func (m *Request_CheckTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.CheckTx != nil { @@ -8278,6 +8146,9 @@ func (m *Request_CheckTx) Size() (n int) { return n } func (m *Request_EndBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.EndBlock != nil { @@ -8287,6 +8158,9 @@ func (m *Request_EndBlock) Size() (n int) { return n } func (m *Request_Commit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Commit != nil { @@ -8296,6 +8170,9 @@ func (m *Request_Commit) Size() (n int) { return n } func (m *Request_DeliverTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.DeliverTx != nil { @@ -8305,6 +8182,9 @@ func (m *Request_DeliverTx) Size() (n int) { return n } func (m *RequestEcho) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Message) @@ -8318,6 +8198,9 @@ func (m *RequestEcho) Size() (n int) { } func (m *RequestFlush) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.XXX_unrecognized != nil { @@ -8327,6 +8210,9 @@ func (m *RequestFlush) Size() (n int) { } func (m *RequestInfo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Version) @@ -8340,6 +8226,9 @@ func (m *RequestInfo) Size() (n int) { } func (m *RequestSetOption) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Key) @@ -8357,6 +8246,9 @@ func (m *RequestSetOption) Size() (n int) { } func (m *RequestInitChain) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time) @@ -8386,6 +8278,9 @@ func (m *RequestInitChain) Size() (n int) { } func (m *RequestQuery) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Data) @@ -8409,6 +8304,9 @@ func (m *RequestQuery) Size() (n int) { } func (m *RequestBeginBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Hash) @@ -8432,6 +8330,9 @@ func (m *RequestBeginBlock) Size() (n int) { } func (m *RequestCheckTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Tx) @@ -8445,6 +8346,9 @@ func (m *RequestCheckTx) Size() (n int) { } func (m *RequestDeliverTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Tx) @@ -8458,6 +8362,9 @@ func (m *RequestDeliverTx) Size() (n int) { } func (m *RequestEndBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Height != 0 { @@ -8470,6 +8377,9 @@ func (m *RequestEndBlock) Size() (n int) { } func (m *RequestCommit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.XXX_unrecognized != nil { @@ -8479,6 +8389,9 @@ func (m *RequestCommit) Size() (n int) { } func (m *Response) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Value != nil { @@ -8491,6 +8404,9 @@ func (m *Response) Size() (n int) { } func (m *Response_Exception) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Exception != nil { @@ -8500,6 +8416,9 @@ func (m *Response_Exception) Size() (n int) { return n } func (m *Response_Echo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Echo != nil { @@ -8509,6 +8428,9 @@ func (m *Response_Echo) Size() (n int) { return n } func (m *Response_Flush) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Flush != nil { @@ -8518,6 +8440,9 @@ func (m *Response_Flush) Size() (n int) { return n } func (m *Response_Info) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Info != nil { @@ -8527,6 +8452,9 @@ func (m *Response_Info) Size() (n int) { return n } func (m *Response_SetOption) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.SetOption != nil { @@ -8536,6 +8464,9 @@ func (m *Response_SetOption) Size() (n int) { return n } func (m *Response_InitChain) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.InitChain != nil { @@ -8545,6 +8476,9 @@ func (m *Response_InitChain) Size() (n int) { return n } func (m *Response_Query) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Query != nil { @@ -8554,6 +8488,9 @@ func (m *Response_Query) Size() (n int) { return n } func (m *Response_BeginBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.BeginBlock != nil { @@ -8563,6 +8500,9 @@ func (m *Response_BeginBlock) Size() (n int) { return n } func (m *Response_CheckTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.CheckTx != nil { @@ -8572,6 +8512,9 @@ func (m *Response_CheckTx) Size() (n int) { return n } func (m *Response_DeliverTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.DeliverTx != nil { @@ -8581,6 +8524,9 @@ func (m *Response_DeliverTx) Size() (n int) { return n } func (m *Response_EndBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.EndBlock != nil { @@ -8590,6 +8536,9 @@ func (m *Response_EndBlock) Size() (n int) { return n } func (m *Response_Commit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Commit != nil { @@ -8599,6 +8548,9 @@ func (m *Response_Commit) Size() (n int) { return n } func (m *ResponseException) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Error) @@ -8612,6 +8564,9 @@ func (m *ResponseException) Size() (n int) { } func (m *ResponseEcho) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Message) @@ -8625,6 +8580,9 @@ func (m *ResponseEcho) Size() (n int) { } func (m *ResponseFlush) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.XXX_unrecognized != nil { @@ -8634,6 +8592,9 @@ func (m *ResponseFlush) Size() (n int) { } func (m *ResponseInfo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Data) @@ -8658,6 +8619,9 @@ func (m *ResponseInfo) Size() (n int) { } func (m *ResponseSetOption) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Code != 0 { @@ -8678,6 +8642,9 @@ func (m *ResponseSetOption) Size() (n int) { } func (m *ResponseInitChain) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ConsensusParams != nil { @@ -8697,6 +8664,9 @@ func (m *ResponseInitChain) Size() (n int) { } func (m *ResponseQuery) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Code != 0 { @@ -8735,6 +8705,9 @@ func (m *ResponseQuery) Size() (n int) { } func (m *ResponseBeginBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Tags) > 0 { @@ -8750,6 +8723,9 @@ func (m *ResponseBeginBlock) Size() (n int) { } func (m *ResponseCheckTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Code != 0 { @@ -8786,6 +8762,9 @@ func (m *ResponseCheckTx) Size() (n int) { } func (m *ResponseDeliverTx) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Code != 0 { @@ -8822,6 +8801,9 @@ func (m *ResponseDeliverTx) Size() (n int) { } func (m *ResponseEndBlock) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.ValidatorUpdates) > 0 { @@ -8847,6 +8829,9 @@ func (m *ResponseEndBlock) Size() (n int) { } func (m *ResponseCommit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Data) @@ -8860,18 +8845,17 @@ func (m *ResponseCommit) Size() (n int) { } func (m *ConsensusParams) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.BlockSize != nil { l = m.BlockSize.Size() n += 1 + l + sovTypes(uint64(l)) } - if m.TxSize != nil { - l = m.TxSize.Size() - n += 1 + l + sovTypes(uint64(l)) - } - if m.BlockGossip != nil { - l = m.BlockGossip.Size() + if m.EvidenceParams != nil { + l = m.EvidenceParams.Size() n += 1 + l + sovTypes(uint64(l)) } if m.XXX_unrecognized != nil { @@ -8881,21 +8865,9 @@ func (m *ConsensusParams) Size() (n int) { } func (m *BlockSize) Size() (n int) { - var l int - _ = l - if m.MaxBytes != 0 { - n += 1 + sovTypes(uint64(m.MaxBytes)) + if m == nil { + return 0 } - if m.MaxGas != 0 { - n += 1 + sovTypes(uint64(m.MaxGas)) - } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n -} - -func (m *TxSize) Size() (n int) { var l int _ = l if m.MaxBytes != 0 { @@ -8910,11 +8882,14 @@ func (m *TxSize) Size() (n int) { return n } -func (m *BlockGossip) Size() (n int) { +func (m *EvidenceParams) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l - if m.BlockPartSizeBytes != 0 { - n += 1 + sovTypes(uint64(m.BlockPartSizeBytes)) + if m.MaxAge != 0 { + n += 1 + sovTypes(uint64(m.MaxAge)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) @@ -8923,6 +8898,9 @@ func (m *BlockGossip) Size() (n int) { } func (m *LastCommitInfo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Round != 0 { @@ -8941,6 +8919,9 @@ func (m *LastCommitInfo) Size() (n int) { } func (m *Header) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ChainID) @@ -9003,6 +8984,9 @@ func (m *Header) Size() (n int) { } func (m *BlockID) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Hash) @@ -9018,6 +9002,9 @@ func (m *BlockID) Size() (n int) { } func (m *PartSetHeader) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Total != 0 { @@ -9034,6 +9021,9 @@ func (m *PartSetHeader) Size() (n int) { } func (m *Validator) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Address) @@ -9050,6 +9040,9 @@ func (m *Validator) Size() (n int) { } func (m *ValidatorUpdate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.PubKey.Size() @@ -9064,6 +9057,9 @@ func (m *ValidatorUpdate) Size() (n int) { } func (m *VoteInfo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Validator.Size() @@ -9078,6 +9074,9 @@ func (m *VoteInfo) Size() (n int) { } func (m *PubKey) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Type) @@ -9095,6 +9094,9 @@ func (m *PubKey) Size() (n int) { } func (m *Evidence) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Type) @@ -12803,7 +12805,7 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TxSize", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EvidenceParams", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -12827,43 +12829,10 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.TxSize == nil { - m.TxSize = &TxSize{} + if m.EvidenceParams == nil { + m.EvidenceParams = &EvidenceParams{} } - if err := m.TxSize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockGossip", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.BlockGossip == nil { - m.BlockGossip = &BlockGossip{} - } - if err := m.BlockGossip.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.EvidenceParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -12978,96 +12947,7 @@ func (m *BlockSize) Unmarshal(dAtA []byte) error { } return nil } -func (m *TxSize) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TxSize: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TxSize: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxBytes", wireType) - } - m.MaxBytes = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxBytes |= (int32(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxGas", wireType) - } - m.MaxGas = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MaxGas |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BlockGossip) Unmarshal(dAtA []byte) error { +func (m *EvidenceParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -13090,17 +12970,17 @@ func (m *BlockGossip) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: BlockGossip: wiretype end group for non-group") + return fmt.Errorf("proto: EvidenceParams: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: BlockGossip: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: EvidenceParams: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockPartSizeBytes", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxAge", wireType) } - m.BlockPartSizeBytes = 0 + m.MaxAge = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -13110,7 +12990,7 @@ func (m *BlockGossip) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.BlockPartSizeBytes |= (int32(b) & 0x7F) << shift + m.MaxAge |= (int64(b) & 0x7F) << shift if b < 0x80 { break } @@ -14623,143 +14503,140 @@ var ( ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_c68d3007ea320b94) } +func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_bfbaec40016cbadd) } func init() { - golang_proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_c68d3007ea320b94) -} - -var fileDescriptor_types_c68d3007ea320b94 = []byte{ - // 2099 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0x4f, 0x73, 0x1b, 0x49, - 0x15, 0xf7, 0x48, 0xb2, 0xfe, 0x3c, 0xd9, 0x92, 0xd3, 0x76, 0x6c, 0x45, 0x80, 0x9d, 0x1a, 0x20, - 0x6b, 0xb3, 0x5e, 0x7b, 0xf1, 0x12, 0xca, 0xd9, 0x2c, 0x5b, 0x58, 0x49, 0x58, 0xbb, 0x76, 0x01, - 0x33, 0x49, 0xcc, 0x85, 0xaa, 0xa9, 0x96, 0xa6, 0x2d, 0x4d, 0x45, 0x9a, 0x99, 0x9d, 0x6e, 0x79, - 0xe5, 0x7c, 0x86, 0x3d, 0xec, 0x81, 0x2a, 0xce, 0xdc, 0xf8, 0x02, 0x54, 0x71, 0xe4, 0x44, 0xed, - 0x91, 0xa2, 0xa0, 0xb8, 0x05, 0x30, 0xc5, 0x01, 0x3e, 0x01, 0x47, 0xaa, 0x5f, 0xf7, 0xfc, 0xf5, - 0x28, 0x95, 0x84, 0xdb, 0x5e, 0xa4, 0xee, 0x7e, 0xef, 0x75, 0xf7, 0x7b, 0xf3, 0xde, 0xfb, 0xbd, - 0xd7, 0xb0, 0x4e, 0xfb, 0x03, 0x77, 0x5f, 0x5c, 0x06, 0x8c, 0xab, 0xdf, 0xbd, 0x20, 0xf4, 0x85, - 0x4f, 0x16, 0x71, 0xd2, 0x7d, 0x67, 0xe8, 0x8a, 0xd1, 0xb4, 0xbf, 0x37, 0xf0, 0x27, 0xfb, 0x43, - 0x7f, 0xe8, 0xef, 0x23, 0xb5, 0x3f, 0x3d, 0xc7, 0x19, 0x4e, 0x70, 0xa4, 0xa4, 0xba, 0x5b, 0x43, - 0xdf, 0x1f, 0x8e, 0x59, 0xc2, 0x25, 0xdc, 0x09, 0xe3, 0x82, 0x4e, 0x02, 0xcd, 0x70, 0x98, 0xda, - 0x4f, 0x30, 0xcf, 0x61, 0xe1, 0xc4, 0xf5, 0x44, 0x7a, 0x38, 0x76, 0xfb, 0x7c, 0x7f, 0xe0, 0x4f, - 0x26, 0xbe, 0x97, 0xbe, 0x90, 0xf9, 0x87, 0x0a, 0xd4, 0x2c, 0xf6, 0xe9, 0x94, 0x71, 0x41, 0xb6, - 0xa1, 0xc2, 0x06, 0x23, 0xbf, 0x53, 0xba, 0x6d, 0x6c, 0x37, 0x0f, 0xc8, 0x9e, 0xe2, 0xd3, 0xd4, - 0x47, 0x83, 0x91, 0x7f, 0xbc, 0x60, 0x21, 0x07, 0x79, 0x1b, 0x16, 0xcf, 0xc7, 0x53, 0x3e, 0xea, - 0x94, 0x91, 0x75, 0x35, 0xcb, 0xfa, 0x23, 0x49, 0x3a, 0x5e, 0xb0, 0x14, 0x8f, 0xdc, 0xd6, 0xf5, - 0xce, 0xfd, 0x4e, 0xa5, 0x68, 0xdb, 0x13, 0xef, 0x1c, 0xb7, 0x95, 0x1c, 0xe4, 0x10, 0x80, 0x33, - 0x61, 0xfb, 0x81, 0x70, 0x7d, 0xaf, 0xb3, 0x88, 0xfc, 0x1b, 0x59, 0xfe, 0xc7, 0x4c, 0xfc, 0x14, - 0xc9, 0xc7, 0x0b, 0x56, 0x83, 0x47, 0x13, 0x29, 0xe9, 0x7a, 0xae, 0xb0, 0x07, 0x23, 0xea, 0x7a, - 0x9d, 0x6a, 0x91, 0xe4, 0x89, 0xe7, 0x8a, 0x07, 0x92, 0x2c, 0x25, 0xdd, 0x68, 0x22, 0x55, 0xf9, - 0x74, 0xca, 0xc2, 0xcb, 0x4e, 0xad, 0x48, 0x95, 0x9f, 0x49, 0x92, 0x54, 0x05, 0x79, 0xc8, 0x7d, - 0x68, 0xf6, 0xd9, 0xd0, 0xf5, 0xec, 0xfe, 0xd8, 0x1f, 0x3c, 0xeb, 0xd4, 0x51, 0xa4, 0x93, 0x15, - 0xe9, 0x49, 0x86, 0x9e, 0xa4, 0x1f, 0x2f, 0x58, 0xd0, 0x8f, 0x67, 0xe4, 0x00, 0xea, 0x83, 0x11, - 0x1b, 0x3c, 0xb3, 0xc5, 0xac, 0xd3, 0x40, 0xc9, 0x9b, 0x59, 0xc9, 0x07, 0x92, 0xfa, 0x64, 0x76, - 0xbc, 0x60, 0xd5, 0x06, 0x6a, 0x48, 0xee, 0x42, 0x83, 0x79, 0x8e, 0x3e, 0xae, 0x89, 0x42, 0xeb, - 0xb9, 0xef, 0xe2, 0x39, 0xd1, 0x61, 0x75, 0xa6, 0xc7, 0x64, 0x0f, 0xaa, 0xf2, 0x5b, 0xbb, 0xa2, - 0xb3, 0x84, 0x32, 0x6b, 0xb9, 0x83, 0x90, 0x76, 0xbc, 0x60, 0x69, 0x2e, 0x69, 0x3e, 0x87, 0x8d, - 0xdd, 0x0b, 0x16, 0xca, 0xcb, 0xad, 0x16, 0x99, 0xef, 0xa1, 0xa2, 0xe3, 0xf5, 0x1a, 0x4e, 0x34, - 0xe9, 0xd5, 0x60, 0xf1, 0x82, 0x8e, 0xa7, 0xcc, 0x7c, 0x0b, 0x9a, 0x29, 0x4f, 0x21, 0x1d, 0xa8, - 0x4d, 0x18, 0xe7, 0x74, 0xc8, 0x3a, 0xc6, 0x6d, 0x63, 0xbb, 0x61, 0x45, 0x53, 0xb3, 0x05, 0x4b, - 0x69, 0x3f, 0x49, 0x09, 0x4a, 0x5f, 0x90, 0x82, 0x17, 0x2c, 0xe4, 0xd2, 0x01, 0xb4, 0xa0, 0x9e, - 0x9a, 0xef, 0xc3, 0x4a, 0xde, 0x09, 0xc8, 0x0a, 0x94, 0x9f, 0xb1, 0x4b, 0xcd, 0x29, 0x87, 0x64, - 0x4d, 0x5f, 0x08, 0xbd, 0xb8, 0x61, 0xe9, 0xdb, 0x7d, 0x51, 0x8a, 0x85, 0x63, 0x3f, 0x20, 0x87, - 0x50, 0x91, 0x81, 0x84, 0xd2, 0xcd, 0x83, 0xee, 0x9e, 0x8a, 0xb2, 0xbd, 0x28, 0xca, 0xf6, 0x9e, - 0x44, 0x51, 0xd6, 0xab, 0x7f, 0xf9, 0x62, 0x6b, 0xe1, 0x8b, 0xbf, 0x6d, 0x19, 0x16, 0x4a, 0x90, - 0x5b, 0xf2, 0x53, 0x52, 0xd7, 0xb3, 0x5d, 0x47, 0x9f, 0x53, 0xc3, 0xf9, 0x89, 0x43, 0x8e, 0x60, - 0x65, 0xe0, 0x7b, 0x9c, 0x79, 0x7c, 0xca, 0xed, 0x80, 0x86, 0x74, 0xc2, 0x75, 0x94, 0x44, 0x1f, - 0xee, 0x41, 0x44, 0x3e, 0x45, 0xaa, 0xd5, 0x1e, 0x64, 0x17, 0xc8, 0x07, 0x00, 0x17, 0x74, 0xec, - 0x3a, 0x54, 0xf8, 0x21, 0xef, 0x54, 0x6e, 0x97, 0x53, 0xc2, 0x67, 0x11, 0xe1, 0x69, 0xe0, 0x50, - 0xc1, 0x7a, 0x15, 0x79, 0x33, 0x2b, 0xc5, 0x4f, 0xee, 0x40, 0x9b, 0x06, 0x81, 0xcd, 0x05, 0x15, - 0xcc, 0xee, 0x5f, 0x0a, 0xc6, 0x31, 0x92, 0x96, 0xac, 0x65, 0x1a, 0x04, 0x8f, 0xe5, 0x6a, 0x4f, - 0x2e, 0x9a, 0x4e, 0xfc, 0x1d, 0xd0, 0xc9, 0x09, 0x81, 0x8a, 0x43, 0x05, 0x45, 0x6b, 0x2c, 0x59, - 0x38, 0x96, 0x6b, 0x01, 0x15, 0x23, 0xad, 0x23, 0x8e, 0xc9, 0x3a, 0x54, 0x47, 0xcc, 0x1d, 0x8e, - 0x04, 0xaa, 0x55, 0xb6, 0xf4, 0x4c, 0x1a, 0x3e, 0x08, 0xfd, 0x0b, 0x86, 0x71, 0x5e, 0xb7, 0xd4, - 0xc4, 0xfc, 0x97, 0x01, 0x37, 0xae, 0x05, 0x86, 0xdc, 0x77, 0x44, 0xf9, 0x28, 0x3a, 0x4b, 0x8e, - 0xc9, 0xdb, 0x72, 0x5f, 0xea, 0xb0, 0x50, 0xe7, 0x9f, 0x65, 0xad, 0xf1, 0x31, 0x2e, 0x6a, 0x45, - 0x35, 0x0b, 0x79, 0x04, 0x2b, 0x63, 0xca, 0x85, 0xad, 0xfc, 0xd7, 0xc6, 0xfc, 0x52, 0xce, 0xc4, - 0xd4, 0x27, 0x34, 0xf2, 0x73, 0xe9, 0x56, 0x5a, 0xbc, 0x35, 0xce, 0xac, 0x92, 0x63, 0x58, 0xeb, - 0x5f, 0x3e, 0xa7, 0x9e, 0x70, 0x3d, 0x66, 0x5f, 0xb3, 0x79, 0x5b, 0x6f, 0xf5, 0xe8, 0xc2, 0x75, - 0x98, 0x37, 0x88, 0x8c, 0xbd, 0x1a, 0x8b, 0xc4, 0x1f, 0x83, 0x9b, 0xb7, 0xa1, 0x95, 0x8d, 0x62, - 0xd2, 0x82, 0x92, 0x98, 0x69, 0x0d, 0x4b, 0x62, 0x66, 0x9a, 0xb1, 0x07, 0xc6, 0xa1, 0x74, 0x8d, - 0x67, 0x07, 0xda, 0xb9, 0xb0, 0x4e, 0x99, 0xdb, 0x48, 0x9b, 0xdb, 0x6c, 0xc3, 0x72, 0x26, 0x9a, - 0xcd, 0xcf, 0x17, 0xa1, 0x6e, 0x31, 0x1e, 0x48, 0x67, 0x22, 0x87, 0xd0, 0x60, 0xb3, 0x01, 0x53, - 0x89, 0xd4, 0xc8, 0xa5, 0x29, 0xc5, 0xf3, 0x28, 0xa2, 0xcb, 0x80, 0x8e, 0x99, 0xc9, 0x4e, 0x06, - 0x04, 0x56, 0xf3, 0x42, 0x69, 0x14, 0xd8, 0xcd, 0xa2, 0xc0, 0x5a, 0x8e, 0x37, 0x07, 0x03, 0x3b, - 0x19, 0x18, 0xc8, 0x6f, 0x9c, 0xc1, 0x81, 0x7b, 0x05, 0x38, 0x90, 0xbf, 0xfe, 0x1c, 0x20, 0xb8, - 0x57, 0x00, 0x04, 0x9d, 0x6b, 0x67, 0x15, 0x22, 0xc1, 0x6e, 0x16, 0x09, 0xf2, 0xea, 0xe4, 0xa0, - 0xe0, 0x83, 0x22, 0x28, 0xb8, 0x95, 0x93, 0x99, 0x8b, 0x05, 0xef, 0x5d, 0xc3, 0x82, 0xf5, 0x9c, - 0x68, 0x01, 0x18, 0xdc, 0xcb, 0x64, 0x69, 0x28, 0xd4, 0xad, 0x38, 0x4d, 0x93, 0xef, 0x5f, 0xc7, - 0x91, 0x8d, 0xfc, 0xa7, 0x2d, 0x02, 0x92, 0xfd, 0x1c, 0x90, 0xdc, 0xcc, 0xdf, 0x32, 0x87, 0x24, - 0x09, 0x1e, 0xec, 0xc8, 0xb8, 0xcf, 0x79, 0x9a, 0xcc, 0x11, 0x2c, 0x0c, 0xfd, 0x50, 0x27, 0x6c, - 0x35, 0x31, 0xb7, 0x65, 0x26, 0x4a, 0xfc, 0xeb, 0x25, 0xd8, 0x81, 0x4e, 0x9f, 0xf2, 0x2e, 0xf3, - 0x57, 0x46, 0x22, 0x8b, 0x11, 0x9d, 0xce, 0x62, 0x0d, 0x9d, 0xc5, 0x52, 0x90, 0x52, 0xca, 0x40, - 0x0a, 0xf9, 0x0e, 0xdc, 0xc0, 0x34, 0x82, 0x76, 0xb1, 0x33, 0x69, 0xad, 0x2d, 0x09, 0xca, 0x20, - 0x2a, 0xbf, 0xbd, 0x03, 0xab, 0x29, 0x5e, 0x99, 0x62, 0x31, 0x85, 0x55, 0x30, 0x78, 0x57, 0x62, - 0xee, 0xa3, 0x20, 0x38, 0xa6, 0x7c, 0x64, 0xfe, 0x38, 0xd1, 0x3f, 0x81, 0x2b, 0x02, 0x95, 0x81, - 0xef, 0x28, 0xb5, 0x96, 0x2d, 0x1c, 0x4b, 0x08, 0x1b, 0xfb, 0x43, 0x3c, 0xb5, 0x61, 0xc9, 0xa1, - 0xe4, 0x8a, 0x23, 0xa5, 0xa1, 0x42, 0xc2, 0xfc, 0xa5, 0x91, 0xec, 0x97, 0x20, 0x58, 0x11, 0xd8, - 0x18, 0xff, 0x0f, 0xd8, 0x94, 0x5e, 0x0f, 0x6c, 0xcc, 0xdf, 0x1a, 0xc9, 0x17, 0x89, 0x61, 0xe4, - 0xcd, 0x54, 0x94, 0xce, 0xe1, 0x7a, 0x0e, 0x9b, 0x61, 0xc0, 0x97, 0x2d, 0x35, 0x89, 0x10, 0xbe, - 0x8a, 0x66, 0xce, 0x22, 0x7c, 0x0d, 0xd7, 0xd4, 0x44, 0xc3, 0x8f, 0x7f, 0x8e, 0x91, 0xb8, 0x64, - 0xa9, 0x49, 0x2a, 0x7b, 0x36, 0x32, 0xd9, 0xf3, 0x14, 0xc8, 0xf5, 0x18, 0x25, 0xef, 0x43, 0x45, - 0xd0, 0xa1, 0x34, 0xa1, 0xb4, 0x42, 0x6b, 0x4f, 0xd5, 0xcb, 0x7b, 0x1f, 0x9f, 0x9d, 0x52, 0x37, - 0xec, 0xad, 0x4b, 0xed, 0xff, 0xf3, 0x62, 0xab, 0x25, 0x79, 0x76, 0xfd, 0x89, 0x2b, 0xd8, 0x24, - 0x10, 0x97, 0x16, 0xca, 0x98, 0x7f, 0x31, 0x64, 0xee, 0xce, 0xc4, 0x6e, 0xa1, 0x2d, 0x22, 0x07, - 0x2d, 0xa5, 0x60, 0xf6, 0xd5, 0xec, 0xf3, 0x0d, 0x80, 0x21, 0xe5, 0xf6, 0x67, 0xd4, 0x13, 0xcc, - 0xd1, 0x46, 0x6a, 0x0c, 0x29, 0xff, 0x39, 0x2e, 0xc8, 0x9a, 0x44, 0x92, 0xa7, 0x9c, 0x39, 0x68, - 0xad, 0xb2, 0x55, 0x1b, 0x52, 0xfe, 0x94, 0x33, 0x27, 0xd6, 0xab, 0xf6, 0x06, 0x7a, 0xfd, 0x35, - 0xe5, 0x78, 0x09, 0x70, 0x7d, 0x15, 0x34, 0xfb, 0xb7, 0x21, 0x11, 0x39, 0x9b, 0xfc, 0xc8, 0x09, - 0xdc, 0x88, 0xdd, 0xdb, 0x9e, 0xa2, 0xdb, 0x47, 0xfe, 0xf0, 0xf2, 0xa8, 0x58, 0xb9, 0xc8, 0x2e, - 0x73, 0xf2, 0x13, 0xd8, 0xc8, 0x05, 0x67, 0xbc, 0x61, 0xe9, 0xa5, 0x31, 0x7a, 0x33, 0x1b, 0xa3, - 0xd1, 0x7e, 0x91, 0xae, 0xe5, 0x37, 0xd0, 0xf5, 0x5b, 0xb2, 0x3c, 0x49, 0xa7, 0xec, 0xa2, 0xaf, - 0x65, 0xfe, 0xda, 0x80, 0x76, 0xee, 0x32, 0x64, 0x1f, 0x40, 0x65, 0x3c, 0xee, 0x3e, 0x8f, 0x4a, - 0xe5, 0x15, 0x7d, 0x71, 0x34, 0xd9, 0x63, 0xf7, 0x39, 0xb3, 0x1a, 0xfd, 0x68, 0x48, 0xee, 0x40, - 0x4d, 0xcc, 0x14, 0x77, 0xb6, 0x90, 0x7b, 0x32, 0x43, 0xd6, 0xaa, 0xc0, 0x7f, 0x72, 0x17, 0x96, - 0xd4, 0xc6, 0x43, 0x9f, 0x73, 0x37, 0xd0, 0x45, 0x04, 0x49, 0x6f, 0xfd, 0x11, 0x52, 0xac, 0x66, - 0x3f, 0x99, 0x98, 0x47, 0xd0, 0x88, 0x8f, 0x25, 0x5f, 0x83, 0xc6, 0x84, 0xce, 0x74, 0x95, 0x2b, - 0xef, 0xb6, 0x68, 0xd5, 0x27, 0x74, 0x86, 0x05, 0x2e, 0xd9, 0x80, 0x9a, 0x24, 0x0e, 0xa9, 0xb2, - 0x77, 0xd9, 0xaa, 0x4e, 0xe8, 0xec, 0x23, 0xca, 0xcd, 0x0f, 0xa1, 0xaa, 0xee, 0xf2, 0x86, 0xf2, - 0x3f, 0x84, 0x66, 0xea, 0x7a, 0xe4, 0xbb, 0x70, 0x53, 0x29, 0x12, 0xd0, 0x50, 0xa0, 0xe2, 0x99, - 0x0d, 0x09, 0x12, 0x4f, 0x69, 0x28, 0xe4, 0x91, 0xaa, 0xf6, 0x7e, 0x0c, 0xad, 0x6c, 0x7d, 0x2a, - 0xd3, 0x57, 0xe8, 0x4f, 0x3d, 0x47, 0x0b, 0xa9, 0x89, 0x6c, 0x4e, 0x2f, 0x7c, 0xe5, 0x30, 0xe9, - 0x82, 0xf4, 0xcc, 0x17, 0x2c, 0x55, 0xd5, 0x2a, 0x1e, 0xf3, 0x4f, 0x15, 0xa8, 0xaa, 0x62, 0x99, - 0xdc, 0x49, 0xf5, 0x27, 0x88, 0x84, 0xbd, 0xe6, 0xd5, 0x8b, 0xad, 0x1a, 0x82, 0xc6, 0xc9, 0xc3, - 0xa4, 0x59, 0x49, 0xd2, 0x63, 0x29, 0x53, 0xcb, 0x47, 0x9d, 0x51, 0xf9, 0xb5, 0x3b, 0xa3, 0x0d, - 0xa8, 0x79, 0xd3, 0x89, 0x2d, 0x66, 0x1c, 0x23, 0xbc, 0x6c, 0x55, 0xbd, 0xe9, 0xe4, 0xc9, 0x8c, - 0x4b, 0x53, 0x0b, 0x5f, 0xd0, 0x31, 0x92, 0x54, 0x88, 0xd7, 0x71, 0x41, 0x12, 0x0f, 0x61, 0x39, - 0x85, 0xad, 0xae, 0xa3, 0x0b, 0xb7, 0x56, 0xda, 0x19, 0x4e, 0x1e, 0x6a, 0x75, 0x9b, 0x31, 0xd6, - 0x9e, 0x38, 0x64, 0x3b, 0xdb, 0x08, 0x20, 0x24, 0x2b, 0x5c, 0x48, 0xd5, 0xfa, 0x12, 0x90, 0xe5, - 0x05, 0xa4, 0x93, 0x2b, 0x16, 0x05, 0x12, 0x75, 0xb9, 0x80, 0xc4, 0xb7, 0xa0, 0x9d, 0xa0, 0x9a, - 0x62, 0x69, 0xa8, 0x5d, 0x92, 0x65, 0x64, 0x7c, 0x17, 0xd6, 0x3c, 0x36, 0x13, 0x76, 0x9e, 0x1b, - 0x90, 0x9b, 0x48, 0xda, 0x59, 0x56, 0xe2, 0xdb, 0xd0, 0x4a, 0xd2, 0x00, 0xf2, 0x36, 0x55, 0x3b, - 0x16, 0xaf, 0x22, 0xdb, 0x2d, 0xa8, 0xc7, 0x35, 0xc5, 0x12, 0x32, 0xd4, 0xa8, 0x2a, 0x25, 0xe2, - 0x2a, 0x25, 0x64, 0x7c, 0x3a, 0x16, 0x7a, 0x93, 0x65, 0xe4, 0xc1, 0x2a, 0xc5, 0x52, 0xeb, 0xc8, - 0xfb, 0x4d, 0x58, 0x66, 0xba, 0x5d, 0x51, 0x7c, 0x2d, 0xe4, 0x5b, 0x8a, 0x16, 0x91, 0x69, 0x07, - 0x56, 0x82, 0xd0, 0x0f, 0x7c, 0xce, 0x42, 0x9b, 0x3a, 0x4e, 0xc8, 0x38, 0xef, 0xb4, 0xd5, 0x7e, - 0xd1, 0xfa, 0x91, 0x5a, 0x36, 0x7f, 0x01, 0x35, 0x6d, 0xfd, 0xc2, 0xa6, 0xed, 0x07, 0xb0, 0x24, - 0xbd, 0x9e, 0xdb, 0x99, 0xd6, 0x2d, 0x2a, 0x9d, 0xd1, 0xe9, 0x99, 0xc8, 0x74, 0x70, 0x4d, 0xe4, - 0x57, 0x4b, 0xe6, 0x3d, 0x58, 0xce, 0xf0, 0xc8, 0x30, 0x40, 0xa7, 0x88, 0xc2, 0x00, 0x27, 0xf1, - 0xc9, 0xa5, 0xe4, 0x64, 0xf3, 0x3e, 0x34, 0x62, 0x43, 0xcb, 0x0a, 0x2f, 0xd2, 0xc3, 0xd0, 0xb6, - 0x53, 0x53, 0x2c, 0x0b, 0xfc, 0xcf, 0x58, 0xa8, 0xab, 0x3a, 0x35, 0x31, 0x9f, 0x42, 0x3b, 0x97, - 0xc5, 0xc9, 0x2e, 0xd4, 0x82, 0x69, 0xdf, 0x8e, 0x5e, 0x13, 0x92, 0xb4, 0x75, 0x3a, 0xed, 0x7f, - 0xcc, 0x2e, 0xa3, 0xfe, 0x33, 0xc0, 0x59, 0xb2, 0x6d, 0x29, 0xbd, 0xed, 0x18, 0xea, 0x51, 0x68, - 0x92, 0xef, 0x41, 0x23, 0xf6, 0x91, 0x5c, 0xda, 0x8c, 0x8f, 0xd6, 0x9b, 0x26, 0x8c, 0xf2, 0x53, - 0x73, 0x77, 0xe8, 0x31, 0xc7, 0x4e, 0xe2, 0x01, 0xcf, 0xa8, 0x5b, 0x6d, 0x45, 0xf8, 0x24, 0x72, - 0x7e, 0xf3, 0x5d, 0xa8, 0xaa, 0xbb, 0x49, 0xfb, 0xc8, 0x9d, 0xa3, 0xa2, 0x57, 0x8e, 0x0b, 0xf3, - 0xfb, 0x9f, 0x0d, 0xa8, 0x47, 0xcd, 0x6c, 0xa1, 0x50, 0xe6, 0xd2, 0xa5, 0x57, 0xbd, 0xf4, 0xbc, - 0x17, 0x81, 0x28, 0x8b, 0x54, 0x5e, 0x3b, 0x8b, 0xec, 0x02, 0x51, 0xc9, 0xe2, 0xc2, 0x17, 0xae, - 0x37, 0xb4, 0x95, 0xad, 0x55, 0xd6, 0x58, 0x41, 0xca, 0x19, 0x12, 0x4e, 0xe5, 0xfa, 0xc1, 0xe7, - 0x8b, 0xd0, 0x3e, 0xea, 0x3d, 0x38, 0x39, 0x0a, 0x82, 0xb1, 0x3b, 0xa0, 0x58, 0x69, 0xef, 0x43, - 0x05, 0x7b, 0x89, 0x82, 0x57, 0xcc, 0x6e, 0x51, 0x53, 0x4b, 0x0e, 0x60, 0x11, 0x5b, 0x0a, 0x52, - 0xf4, 0x98, 0xd9, 0x2d, 0xec, 0x6d, 0xe5, 0x21, 0xaa, 0xe9, 0xb8, 0xfe, 0xa6, 0xd9, 0x2d, 0x6a, - 0x70, 0xc9, 0x87, 0xd0, 0x48, 0x9a, 0x81, 0x79, 0x2f, 0x9b, 0xdd, 0xb9, 0xad, 0xae, 0x94, 0x4f, - 0x6a, 0xb0, 0x79, 0x0f, 0x74, 0xdd, 0xb9, 0x3d, 0x21, 0x39, 0x84, 0x5a, 0x54, 0x9b, 0x16, 0xbf, - 0x3d, 0x76, 0xe7, 0xb4, 0xa1, 0xd2, 0x3c, 0xaa, 0xbe, 0x2f, 0x7a, 0x20, 0xed, 0x16, 0xf6, 0xca, - 0xe4, 0x2e, 0x54, 0x75, 0xb1, 0x51, 0xf8, 0xfe, 0xd8, 0x2d, 0x6e, 0x26, 0xa5, 0x92, 0x49, 0x87, - 0x33, 0xef, 0x11, 0xb7, 0x3b, 0xb7, 0xa9, 0x27, 0x47, 0x00, 0xa9, 0x9a, 0x7e, 0xee, 0xeb, 0x6c, - 0x77, 0x7e, 0xb3, 0x4e, 0xee, 0x43, 0x3d, 0x79, 0x80, 0x29, 0x7e, 0x6f, 0xed, 0xce, 0xeb, 0x9f, - 0x7b, 0x5f, 0xff, 0xef, 0x3f, 0x36, 0x8d, 0xdf, 0x5c, 0x6d, 0x1a, 0xbf, 0xbb, 0xda, 0x34, 0xbe, - 0xbc, 0xda, 0x34, 0xfe, 0x78, 0xb5, 0x69, 0xfc, 0xfd, 0x6a, 0xd3, 0xf8, 0xfd, 0x3f, 0x37, 0x8d, - 0x7e, 0x15, 0xdd, 0xff, 0xbd, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x48, 0x26, 0x13, 0xca, 0x22, - 0x18, 0x00, 0x00, + golang_proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_bfbaec40016cbadd) +} + +var fileDescriptor_types_bfbaec40016cbadd = []byte{ + // 2062 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0x4f, 0x6f, 0x23, 0x49, + 0x15, 0x4f, 0xdb, 0x8e, 0xed, 0x7e, 0x49, 0xec, 0x4c, 0x25, 0x93, 0x78, 0x0c, 0x24, 0xa3, 0x06, + 0x76, 0x13, 0x36, 0x9b, 0xac, 0xb2, 0x2c, 0xca, 0xec, 0x2c, 0x2b, 0xc5, 0x33, 0x03, 0x89, 0x76, + 0x81, 0xd0, 0x33, 0x13, 0x2e, 0x48, 0xad, 0xb2, 0xbb, 0x62, 0xb7, 0xc6, 0xee, 0xee, 0xed, 0x2e, + 0x67, 0x9d, 0x39, 0x72, 0xde, 0xc3, 0x1e, 0x90, 0xf8, 0x0a, 0x7c, 0x01, 0x24, 0x8e, 0x9c, 0xd0, + 0x1e, 0x11, 0x02, 0x71, 0x1b, 0x20, 0x88, 0x03, 0x7c, 0x02, 0x8e, 0xa8, 0x5e, 0x55, 0xf5, 0xbf, + 0xb4, 0x47, 0x33, 0xc3, 0x8d, 0x4b, 0xab, 0xab, 0xde, 0x7b, 0x55, 0xf5, 0x5e, 0xbd, 0xf7, 0x7e, + 0xef, 0x15, 0x6c, 0xd0, 0xfe, 0xc0, 0x3b, 0xe0, 0x57, 0x21, 0x8b, 0xe5, 0x77, 0x3f, 0x8c, 0x02, + 0x1e, 0x90, 0x45, 0x1c, 0x74, 0xdf, 0x1d, 0x7a, 0x7c, 0x34, 0xed, 0xef, 0x0f, 0x82, 0xc9, 0xc1, + 0x30, 0x18, 0x06, 0x07, 0x48, 0xed, 0x4f, 0x2f, 0x70, 0x84, 0x03, 0xfc, 0x93, 0x52, 0xdd, 0xed, + 0x61, 0x10, 0x0c, 0xc7, 0x2c, 0xe5, 0xe2, 0xde, 0x84, 0xc5, 0x9c, 0x4e, 0x42, 0xc5, 0x70, 0x94, + 0x59, 0x8f, 0x33, 0xdf, 0x65, 0xd1, 0xc4, 0xf3, 0x79, 0xf6, 0x77, 0xec, 0xf5, 0xe3, 0x83, 0x41, + 0x30, 0x99, 0x04, 0x7e, 0xf6, 0x40, 0xd6, 0xef, 0x6b, 0xd0, 0xb0, 0xd9, 0x67, 0x53, 0x16, 0x73, + 0xb2, 0x03, 0x35, 0x36, 0x18, 0x05, 0x9d, 0xca, 0x5d, 0x63, 0x67, 0xe9, 0x90, 0xec, 0x4b, 0x3e, + 0x45, 0x7d, 0x34, 0x18, 0x05, 0x27, 0x0b, 0x36, 0x72, 0x90, 0x77, 0x60, 0xf1, 0x62, 0x3c, 0x8d, + 0x47, 0x9d, 0x2a, 0xb2, 0xae, 0xe5, 0x59, 0x7f, 0x20, 0x48, 0x27, 0x0b, 0xb6, 0xe4, 0x11, 0xcb, + 0x7a, 0xfe, 0x45, 0xd0, 0xa9, 0x95, 0x2d, 0x7b, 0xea, 0x5f, 0xe0, 0xb2, 0x82, 0x83, 0x1c, 0x01, + 0xc4, 0x8c, 0x3b, 0x41, 0xc8, 0xbd, 0xc0, 0xef, 0x2c, 0x22, 0xff, 0x66, 0x9e, 0xff, 0x31, 0xe3, + 0x3f, 0x41, 0xf2, 0xc9, 0x82, 0x6d, 0xc6, 0x7a, 0x20, 0x24, 0x3d, 0xdf, 0xe3, 0xce, 0x60, 0x44, + 0x3d, 0xbf, 0x53, 0x2f, 0x93, 0x3c, 0xf5, 0x3d, 0xfe, 0x40, 0x90, 0x85, 0xa4, 0xa7, 0x07, 0x42, + 0x95, 0xcf, 0xa6, 0x2c, 0xba, 0xea, 0x34, 0xca, 0x54, 0xf9, 0xa9, 0x20, 0x09, 0x55, 0x90, 0x87, + 0xdc, 0x87, 0xa5, 0x3e, 0x1b, 0x7a, 0xbe, 0xd3, 0x1f, 0x07, 0x83, 0x67, 0x9d, 0x26, 0x8a, 0x74, + 0xf2, 0x22, 0x3d, 0xc1, 0xd0, 0x13, 0xf4, 0x93, 0x05, 0x1b, 0xfa, 0xc9, 0x88, 0x1c, 0x42, 0x73, + 0x30, 0x62, 0x83, 0x67, 0x0e, 0x9f, 0x75, 0x4c, 0x94, 0xbc, 0x9d, 0x97, 0x7c, 0x20, 0xa8, 0x4f, + 0x66, 0x27, 0x0b, 0x76, 0x63, 0x20, 0x7f, 0xc9, 0x07, 0x60, 0x32, 0xdf, 0x55, 0xdb, 0x2d, 0xa1, + 0xd0, 0x46, 0xe1, 0x5e, 0x7c, 0x57, 0x6f, 0xd6, 0x64, 0xea, 0x9f, 0xec, 0x43, 0x5d, 0xdc, 0xb5, + 0xc7, 0x3b, 0xcb, 0x28, 0xb3, 0x5e, 0xd8, 0x08, 0x69, 0x27, 0x0b, 0xb6, 0xe2, 0x12, 0xe6, 0x73, + 0xd9, 0xd8, 0xbb, 0x64, 0x91, 0x38, 0xdc, 0x5a, 0x99, 0xf9, 0x1e, 0x4a, 0x3a, 0x1e, 0xcf, 0x74, + 0xf5, 0xa0, 0xd7, 0x80, 0xc5, 0x4b, 0x3a, 0x9e, 0x32, 0xeb, 0x6d, 0x58, 0xca, 0x78, 0x0a, 0xe9, + 0x40, 0x63, 0xc2, 0xe2, 0x98, 0x0e, 0x59, 0xc7, 0xb8, 0x6b, 0xec, 0x98, 0xb6, 0x1e, 0x5a, 0x2d, + 0x58, 0xce, 0xfa, 0x49, 0x46, 0x50, 0xf8, 0x82, 0x10, 0xbc, 0x64, 0x51, 0x2c, 0x1c, 0x40, 0x09, + 0xaa, 0xa1, 0xf5, 0x21, 0xac, 0x16, 0x9d, 0x80, 0xac, 0x42, 0xf5, 0x19, 0xbb, 0x52, 0x9c, 0xe2, + 0x97, 0xac, 0xab, 0x03, 0xa1, 0x17, 0x9b, 0xb6, 0x3a, 0xdd, 0x97, 0x95, 0x44, 0x38, 0xf1, 0x03, + 0x72, 0x04, 0x35, 0x11, 0x48, 0x28, 0xbd, 0x74, 0xd8, 0xdd, 0x97, 0x51, 0xb6, 0xaf, 0xa3, 0x6c, + 0xff, 0x89, 0x8e, 0xb2, 0x5e, 0xf3, 0xab, 0x17, 0xdb, 0x0b, 0x5f, 0xfe, 0x75, 0xdb, 0xb0, 0x51, + 0x82, 0xdc, 0x11, 0x57, 0x49, 0x3d, 0xdf, 0xf1, 0x5c, 0xb5, 0x4f, 0x03, 0xc7, 0xa7, 0x2e, 0x39, + 0x86, 0xd5, 0x41, 0xe0, 0xc7, 0xcc, 0x8f, 0xa7, 0xb1, 0x13, 0xd2, 0x88, 0x4e, 0x62, 0x15, 0x25, + 0xfa, 0xe2, 0x1e, 0x68, 0xf2, 0x19, 0x52, 0xed, 0xf6, 0x20, 0x3f, 0x41, 0x3e, 0x02, 0xb8, 0xa4, + 0x63, 0xcf, 0xa5, 0x3c, 0x88, 0xe2, 0x4e, 0xed, 0x6e, 0x35, 0x23, 0x7c, 0xae, 0x09, 0x4f, 0x43, + 0x97, 0x72, 0xd6, 0xab, 0x89, 0x93, 0xd9, 0x19, 0x7e, 0xf2, 0x16, 0xb4, 0x69, 0x18, 0x3a, 0x31, + 0xa7, 0x9c, 0x39, 0xfd, 0x2b, 0xce, 0x62, 0x8c, 0xa4, 0x65, 0x7b, 0x85, 0x86, 0xe1, 0x63, 0x31, + 0xdb, 0x13, 0x93, 0x96, 0x9b, 0xdc, 0x03, 0x3a, 0x39, 0x21, 0x50, 0x73, 0x29, 0xa7, 0x68, 0x8d, + 0x65, 0x1b, 0xff, 0xc5, 0x5c, 0x48, 0xf9, 0x48, 0xe9, 0x88, 0xff, 0x64, 0x03, 0xea, 0x23, 0xe6, + 0x0d, 0x47, 0x1c, 0xd5, 0xaa, 0xda, 0x6a, 0x24, 0x0c, 0x1f, 0x46, 0xc1, 0x25, 0xc3, 0x38, 0x6f, + 0xda, 0x72, 0x60, 0xfd, 0xd3, 0x80, 0x5b, 0x37, 0x02, 0x43, 0xac, 0x3b, 0xa2, 0xf1, 0x48, 0xef, + 0x25, 0xfe, 0xc9, 0x3b, 0x62, 0x5d, 0xea, 0xb2, 0x48, 0xe5, 0x9f, 0x15, 0xa5, 0xf1, 0x09, 0x4e, + 0x2a, 0x45, 0x15, 0x0b, 0x79, 0x04, 0xab, 0x63, 0x1a, 0x73, 0x47, 0xfa, 0xaf, 0x83, 0xf9, 0xa5, + 0x9a, 0x8b, 0xa9, 0x4f, 0xa9, 0xf6, 0x73, 0xe1, 0x56, 0x4a, 0xbc, 0x35, 0xce, 0xcd, 0x92, 0x13, + 0x58, 0xef, 0x5f, 0x3d, 0xa7, 0x3e, 0xf7, 0x7c, 0xe6, 0xdc, 0xb0, 0x79, 0x5b, 0x2d, 0xf5, 0xe8, + 0xd2, 0x73, 0x99, 0x3f, 0xd0, 0xc6, 0x5e, 0x4b, 0x44, 0x92, 0xcb, 0x88, 0xad, 0xbb, 0xd0, 0xca, + 0x47, 0x31, 0x69, 0x41, 0x85, 0xcf, 0x94, 0x86, 0x15, 0x3e, 0xb3, 0xac, 0xc4, 0x03, 0x93, 0x50, + 0xba, 0xc1, 0xb3, 0x0b, 0xed, 0x42, 0x58, 0x67, 0xcc, 0x6d, 0x64, 0xcd, 0x6d, 0xb5, 0x61, 0x25, + 0x17, 0xcd, 0xd6, 0x17, 0x8b, 0xd0, 0xb4, 0x59, 0x1c, 0x0a, 0x67, 0x22, 0x47, 0x60, 0xb2, 0xd9, + 0x80, 0xc9, 0x44, 0x6a, 0x14, 0xd2, 0x94, 0xe4, 0x79, 0xa4, 0xe9, 0x22, 0xa0, 0x13, 0x66, 0xb2, + 0x9b, 0x03, 0x81, 0xb5, 0xa2, 0x50, 0x16, 0x05, 0xf6, 0xf2, 0x28, 0xb0, 0x5e, 0xe0, 0x2d, 0xc0, + 0xc0, 0x6e, 0x0e, 0x06, 0x8a, 0x0b, 0xe7, 0x70, 0xe0, 0x5e, 0x09, 0x0e, 0x14, 0x8f, 0x3f, 0x07, + 0x08, 0xee, 0x95, 0x00, 0x41, 0xe7, 0xc6, 0x5e, 0xa5, 0x48, 0xb0, 0x97, 0x47, 0x82, 0xa2, 0x3a, + 0x05, 0x28, 0xf8, 0xa8, 0x0c, 0x0a, 0xee, 0x14, 0x64, 0xe6, 0x62, 0xc1, 0xfb, 0x37, 0xb0, 0x60, + 0xa3, 0x20, 0x5a, 0x02, 0x06, 0xf7, 0x72, 0x59, 0x1a, 0x4a, 0x75, 0x2b, 0x4f, 0xd3, 0xe4, 0x7b, + 0x37, 0x71, 0x64, 0xb3, 0x78, 0xb5, 0x65, 0x40, 0x72, 0x50, 0x00, 0x92, 0xdb, 0xc5, 0x53, 0x16, + 0x90, 0x24, 0xc5, 0x83, 0x5d, 0x11, 0xf7, 0x05, 0x4f, 0x13, 0x39, 0x82, 0x45, 0x51, 0x10, 0xa9, + 0x84, 0x2d, 0x07, 0xd6, 0x8e, 0xc8, 0x44, 0xa9, 0x7f, 0xbd, 0x04, 0x3b, 0xd0, 0xe9, 0x33, 0xde, + 0x65, 0xfd, 0xca, 0x48, 0x65, 0x31, 0xa2, 0xb3, 0x59, 0xcc, 0x54, 0x59, 0x2c, 0x03, 0x29, 0x95, + 0x1c, 0xa4, 0x90, 0xef, 0xc0, 0x2d, 0x4c, 0x23, 0x68, 0x17, 0x27, 0x97, 0xd6, 0xda, 0x82, 0x20, + 0x0d, 0x22, 0xf3, 0xdb, 0xbb, 0xb0, 0x96, 0xe1, 0x15, 0x29, 0x16, 0x53, 0x58, 0x0d, 0x83, 0x77, + 0x35, 0xe1, 0x3e, 0x0e, 0xc3, 0x13, 0x1a, 0x8f, 0xac, 0x1f, 0xa5, 0xfa, 0xa7, 0x70, 0x45, 0xa0, + 0x36, 0x08, 0x5c, 0xa9, 0xd6, 0x8a, 0x8d, 0xff, 0x02, 0xc2, 0xc6, 0xc1, 0x10, 0x77, 0x35, 0x6d, + 0xf1, 0x2b, 0xb8, 0x92, 0x48, 0x31, 0x65, 0x48, 0x58, 0xbf, 0x34, 0xd2, 0xf5, 0x52, 0x04, 0x2b, + 0x03, 0x1b, 0xe3, 0x7f, 0x01, 0x9b, 0xca, 0xeb, 0x81, 0x8d, 0xf5, 0x1b, 0x23, 0xbd, 0x91, 0x04, + 0x46, 0xde, 0x4c, 0x45, 0xe1, 0x1c, 0x9e, 0xef, 0xb2, 0x19, 0x06, 0x7c, 0xd5, 0x96, 0x03, 0x8d, + 0xf0, 0x75, 0x34, 0x73, 0x1e, 0xe1, 0x1b, 0x38, 0x27, 0x07, 0x0a, 0x7e, 0x82, 0x0b, 0x8c, 0xc4, + 0x65, 0x5b, 0x0e, 0x32, 0xd9, 0xd3, 0xcc, 0x65, 0xcf, 0x33, 0x20, 0x37, 0x63, 0x94, 0x7c, 0x08, + 0x35, 0x4e, 0x87, 0xc2, 0x84, 0xc2, 0x0a, 0xad, 0x7d, 0x59, 0x2f, 0xef, 0x7f, 0x72, 0x7e, 0x46, + 0xbd, 0xa8, 0xb7, 0x21, 0xb4, 0xff, 0xf7, 0x8b, 0xed, 0x96, 0xe0, 0xd9, 0x0b, 0x26, 0x1e, 0x67, + 0x93, 0x90, 0x5f, 0xd9, 0x28, 0x63, 0xfd, 0xd9, 0x10, 0xb9, 0x3b, 0x17, 0xbb, 0xa5, 0xb6, 0xd0, + 0x0e, 0x5a, 0xc9, 0xc0, 0xec, 0xab, 0xd9, 0xe7, 0x1b, 0x00, 0x43, 0x1a, 0x3b, 0x9f, 0x53, 0x9f, + 0x33, 0x57, 0x19, 0xc9, 0x1c, 0xd2, 0xf8, 0x67, 0x38, 0x21, 0x6a, 0x12, 0x41, 0x9e, 0xc6, 0xcc, + 0x45, 0x6b, 0x55, 0xed, 0xc6, 0x90, 0xc6, 0x4f, 0x63, 0xe6, 0x26, 0x7a, 0x35, 0xde, 0x40, 0xaf, + 0xbf, 0x64, 0x1c, 0x2f, 0x05, 0xae, 0xff, 0x07, 0xcd, 0xfe, 0x65, 0x08, 0x44, 0xce, 0x27, 0x3f, + 0x72, 0x0a, 0xb7, 0x12, 0xf7, 0x76, 0xa6, 0xe8, 0xf6, 0xda, 0x1f, 0x5e, 0x1e, 0x15, 0xab, 0x97, + 0xf9, 0xe9, 0x98, 0xfc, 0x18, 0x36, 0x0b, 0xc1, 0x99, 0x2c, 0x58, 0x79, 0x69, 0x8c, 0xde, 0xce, + 0xc7, 0xa8, 0x5e, 0x4f, 0xeb, 0x5a, 0x7d, 0x03, 0x5d, 0xbf, 0x25, 0xca, 0x93, 0x6c, 0xca, 0x2e, + 0xbb, 0x2d, 0xeb, 0x17, 0x06, 0xb4, 0x0b, 0x87, 0x21, 0x07, 0x00, 0x32, 0xe3, 0xc5, 0xde, 0x73, + 0x5d, 0x2a, 0xaf, 0xaa, 0x83, 0xa3, 0xc9, 0x1e, 0x7b, 0xcf, 0x99, 0x6d, 0xf6, 0xf5, 0x2f, 0xf9, + 0x18, 0xda, 0x4c, 0x15, 0x4c, 0x3a, 0x25, 0x55, 0x72, 0xd8, 0xa1, 0xcb, 0x29, 0xa5, 0x6d, 0x8b, + 0xe5, 0xc6, 0xd6, 0x31, 0x98, 0xc9, 0xba, 0xe4, 0x6b, 0x60, 0x4e, 0xe8, 0x4c, 0x95, 0xb1, 0x62, + 0xf3, 0x45, 0xbb, 0x39, 0xa1, 0x33, 0xac, 0x60, 0xc9, 0x26, 0x34, 0x04, 0x71, 0x48, 0xe5, 0x0e, + 0x55, 0xbb, 0x3e, 0xa1, 0xb3, 0x1f, 0xd2, 0xd8, 0xda, 0x85, 0x56, 0x7e, 0x13, 0xcd, 0xaa, 0x21, + 0x45, 0xb2, 0x1e, 0x0f, 0x99, 0xf5, 0x18, 0x5a, 0xf9, 0x4a, 0x51, 0x24, 0x92, 0x28, 0x98, 0xfa, + 0xae, 0xda, 0x4e, 0x0e, 0x44, 0x9b, 0x78, 0x19, 0xc8, 0xab, 0xcb, 0x96, 0x86, 0xe7, 0x01, 0x67, + 0x99, 0xfa, 0x52, 0xf2, 0x58, 0x7f, 0xac, 0x41, 0x5d, 0x96, 0xad, 0xe4, 0xad, 0x4c, 0xa7, 0x80, + 0x98, 0xd4, 0x5b, 0xba, 0x7e, 0xb1, 0xdd, 0xc0, 0xf4, 0x7d, 0xfa, 0x30, 0x6d, 0x1b, 0xd2, 0x44, + 0x55, 0xc9, 0x55, 0xd5, 0xba, 0x47, 0xa9, 0xbe, 0x76, 0x8f, 0xb2, 0x09, 0x0d, 0x7f, 0x3a, 0x71, + 0xf8, 0x2c, 0xc6, 0x58, 0xab, 0xda, 0x75, 0x7f, 0x3a, 0x79, 0x32, 0x8b, 0x85, 0x4d, 0x79, 0xc0, + 0xe9, 0x18, 0x49, 0x32, 0xd8, 0x9a, 0x38, 0x21, 0x88, 0x47, 0xb0, 0x92, 0x41, 0x39, 0xcf, 0x55, + 0x25, 0x54, 0x2b, 0x7b, 0xe3, 0xa7, 0x0f, 0x95, 0xba, 0x4b, 0x09, 0xea, 0x9d, 0xba, 0x64, 0x27, + 0x5f, 0x92, 0x23, 0x38, 0xca, 0x0c, 0x9d, 0xa9, 0xba, 0x05, 0x34, 0x8a, 0x03, 0x08, 0x77, 0x93, + 0x2c, 0x32, 0x5d, 0x37, 0xc5, 0x04, 0x12, 0xdf, 0x86, 0x76, 0x8a, 0x2f, 0x92, 0xc5, 0x94, 0xab, + 0xa4, 0xd3, 0xc8, 0xf8, 0x1e, 0xac, 0xfb, 0x6c, 0xc6, 0x9d, 0x22, 0x37, 0x20, 0x37, 0x11, 0xb4, + 0xf3, 0xbc, 0xc4, 0xb7, 0xa1, 0x95, 0x06, 0x24, 0xf2, 0x2e, 0xc9, 0xc6, 0x28, 0x99, 0x45, 0xb6, + 0x3b, 0xd0, 0x4c, 0xd0, 0x7d, 0x19, 0x19, 0x1a, 0x54, 0x82, 0x7a, 0x52, 0x2f, 0x44, 0x2c, 0x9e, + 0x8e, 0xb9, 0x5a, 0x64, 0x05, 0x79, 0xb0, 0x5e, 0xb0, 0xe5, 0x3c, 0xf2, 0x7e, 0x13, 0x56, 0x92, + 0x38, 0x40, 0xbe, 0x16, 0xf2, 0x2d, 0xeb, 0x49, 0x64, 0xda, 0x85, 0xd5, 0x30, 0x0a, 0xc2, 0x20, + 0x66, 0x91, 0x43, 0x5d, 0x37, 0x62, 0x71, 0xdc, 0x69, 0xcb, 0xf5, 0xf4, 0xfc, 0xb1, 0x9c, 0xb6, + 0x7e, 0x0e, 0x0d, 0x65, 0xfd, 0xd2, 0xf6, 0xe9, 0xfb, 0xb0, 0x1c, 0xd2, 0x48, 0x9c, 0x29, 0xdb, + 0x44, 0xe9, 0x22, 0xf6, 0x8c, 0x46, 0xa2, 0x6b, 0xce, 0xf5, 0x52, 0x4b, 0xc8, 0x2f, 0xa7, 0xac, + 0x7b, 0xb0, 0x92, 0xe3, 0x11, 0x61, 0x80, 0x4e, 0xa1, 0xc3, 0x00, 0x07, 0xc9, 0xce, 0x95, 0x74, + 0x67, 0xeb, 0x3e, 0x98, 0x89, 0xa1, 0x45, 0xad, 0xa5, 0xf5, 0x30, 0x94, 0xed, 0xe4, 0x10, 0x01, + 0x3a, 0xf8, 0x9c, 0x45, 0xaa, 0xbe, 0x92, 0x03, 0xeb, 0x29, 0xb4, 0x0b, 0xf9, 0x94, 0xec, 0x41, + 0x23, 0x9c, 0xf6, 0x1d, 0xdd, 0xd7, 0xa7, 0x9d, 0xe0, 0xd9, 0xb4, 0xff, 0x09, 0xbb, 0xd2, 0x9d, + 0x60, 0x88, 0xa3, 0x74, 0xd9, 0x4a, 0x76, 0xd9, 0x31, 0x34, 0x75, 0x68, 0x92, 0xef, 0x82, 0x99, + 0xf8, 0x48, 0x21, 0x81, 0x25, 0x5b, 0xab, 0x45, 0x53, 0x46, 0x71, 0xd5, 0xb1, 0x37, 0xf4, 0x99, + 0xeb, 0xa4, 0xf1, 0x80, 0x7b, 0x34, 0xed, 0xb6, 0x24, 0x7c, 0xaa, 0x9d, 0xdf, 0x7a, 0x0f, 0xea, + 0xf2, 0x6c, 0xc2, 0x3e, 0x62, 0x65, 0x5d, 0x7e, 0x8a, 0xff, 0xd2, 0x4c, 0xfb, 0x27, 0x03, 0x9a, + 0x3a, 0x45, 0x95, 0x0a, 0xe5, 0x0e, 0x5d, 0x79, 0xd5, 0x43, 0xcf, 0xeb, 0xcd, 0x75, 0x16, 0xa9, + 0xbd, 0x76, 0x16, 0xd9, 0x03, 0x22, 0x93, 0xc5, 0x65, 0xc0, 0x3d, 0x7f, 0xe8, 0x48, 0x5b, 0xcb, + 0xac, 0xb1, 0x8a, 0x94, 0x73, 0x24, 0x9c, 0x89, 0xf9, 0xc3, 0x2f, 0x16, 0xa1, 0x7d, 0xdc, 0x7b, + 0x70, 0x7a, 0x1c, 0x86, 0x63, 0x6f, 0x40, 0xb1, 0xe6, 0x3d, 0x80, 0x1a, 0x56, 0xf5, 0x25, 0xef, + 0x89, 0xdd, 0xb2, 0xf6, 0x92, 0x1c, 0xc2, 0x22, 0x16, 0xf7, 0xa4, 0xec, 0x59, 0xb1, 0x5b, 0xda, + 0x65, 0x8a, 0x4d, 0x64, 0xf9, 0x7f, 0xf3, 0x75, 0xb1, 0x5b, 0xd6, 0x6a, 0x92, 0x8f, 0xc1, 0x4c, + 0xcb, 0xf2, 0x79, 0x6f, 0x8c, 0xdd, 0xb9, 0x4d, 0xa7, 0x90, 0x4f, 0xab, 0xa1, 0x79, 0x4f, 0x65, + 0xdd, 0xb9, 0xdd, 0x19, 0x39, 0x82, 0x86, 0xae, 0x12, 0xcb, 0x5f, 0x01, 0xbb, 0x73, 0x1a, 0x42, + 0x61, 0x1e, 0x59, 0x69, 0x97, 0x3d, 0x55, 0x76, 0x4b, 0xbb, 0x56, 0xf2, 0x01, 0xd4, 0x15, 0xec, + 0x97, 0xbe, 0x04, 0x76, 0xcb, 0xdb, 0x3a, 0xa1, 0x64, 0xda, 0x6b, 0xcc, 0x7b, 0x4e, 0xed, 0xce, + 0x6d, 0xaf, 0xc9, 0x31, 0x40, 0xa6, 0xba, 0x9e, 0xfb, 0x4e, 0xda, 0x9d, 0xdf, 0x36, 0x93, 0xfb, + 0xd0, 0x4c, 0x9f, 0x42, 0xca, 0x5f, 0x3e, 0xbb, 0xf3, 0x3a, 0xd9, 0xde, 0xd7, 0xff, 0xf3, 0xf7, + 0x2d, 0xe3, 0xd7, 0xd7, 0x5b, 0xc6, 0x6f, 0xaf, 0xb7, 0x8c, 0xaf, 0xae, 0xb7, 0x8c, 0x3f, 0x5c, + 0x6f, 0x19, 0x7f, 0xbb, 0xde, 0x32, 0x7e, 0xf7, 0x8f, 0x2d, 0xa3, 0x5f, 0x47, 0xf7, 0x7f, 0xff, + 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x29, 0x33, 0xce, 0x77, 0xac, 0x17, 0x00, 0x00, } diff --git a/abci/types/types.proto b/abci/types/types.proto index 75a53ac46..eacce5442 100644 --- a/abci/types/types.proto +++ b/abci/types/types.proto @@ -200,27 +200,21 @@ message ResponseCommit { // that can be adjusted by the abci app message ConsensusParams { BlockSize block_size = 1; - TxSize tx_size = 2; - BlockGossip block_gossip = 3; + EvidenceParams evidence_params = 2; } // BlockSize contains limits on the block size. message BlockSize { + // Note: must be greater than 0 int32 max_bytes = 1; + // Note: must be greater or equal to -1 int64 max_gas = 2; } -// TxSize contains limits on the tx size. -message TxSize { - int32 max_bytes = 1; - int64 max_gas = 2; -} - -// BlockGossip determine consensus critical -// elements of how blocks are gossiped -message BlockGossip { - // Note: must not be 0 - int32 block_part_size_bytes = 1; +// EvidenceParams contains limits on the evidence. +message EvidenceParams { + // Note: must be greater than 0 + int64 max_age = 1; } message LastCommitInfo { diff --git a/abci/types/typespb_test.go b/abci/types/typespb_test.go index 0411afc84..5da925e17 100644 --- a/abci/types/typespb_test.go +++ b/abci/types/typespb_test.go @@ -1534,15 +1534,15 @@ func TestBlockSizeMarshalTo(t *testing.T) { } } -func TestTxSizeProto(t *testing.T) { +func TestEvidenceParamsProto(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, false) + p := NewPopulatedEvidenceParams(popr, false) dAtA, err := github_com_gogo_protobuf_proto.Marshal(p) if err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } - msg := &TxSize{} + msg := &EvidenceParams{} if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } @@ -1565,10 +1565,10 @@ func TestTxSizeProto(t *testing.T) { } } -func TestTxSizeMarshalTo(t *testing.T) { +func TestEvidenceParamsMarshalTo(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, false) + p := NewPopulatedEvidenceParams(popr, false) size := p.Size() dAtA := make([]byte, size) for i := range dAtA { @@ -1578,63 +1578,7 @@ func TestTxSizeMarshalTo(t *testing.T) { if err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } - msg := &TxSize{} - if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - for i := range dAtA { - dAtA[i] = byte(popr.Intn(256)) - } - if !p.Equal(msg) { - t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p) - } -} - -func TestBlockGossipProto(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, false) - dAtA, err := github_com_gogo_protobuf_proto.Marshal(p) - if err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - msg := &BlockGossip{} - if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - littlefuzz := make([]byte, len(dAtA)) - copy(littlefuzz, dAtA) - for i := range dAtA { - dAtA[i] = byte(popr.Intn(256)) - } - if !p.Equal(msg) { - t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p) - } - if len(littlefuzz) > 0 { - fuzzamount := 100 - for i := 0; i < fuzzamount; i++ { - littlefuzz[popr.Intn(len(littlefuzz))] = byte(popr.Intn(256)) - littlefuzz = append(littlefuzz, byte(popr.Intn(256))) - } - // shouldn't panic - _ = github_com_gogo_protobuf_proto.Unmarshal(littlefuzz, msg) - } -} - -func TestBlockGossipMarshalTo(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, false) - size := p.Size() - dAtA := make([]byte, size) - for i := range dAtA { - dAtA[i] = byte(popr.Intn(256)) - } - _, err := p.MarshalTo(dAtA) - if err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - msg := &BlockGossip{} + msg := &EvidenceParams{} if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } @@ -2636,34 +2580,16 @@ func TestBlockSizeJSON(t *testing.T) { t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p) } } -func TestTxSizeJSON(t *testing.T) { +func TestEvidenceParamsJSON(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, true) + p := NewPopulatedEvidenceParams(popr, true) marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{} jsondata, err := marshaler.MarshalToString(p) if err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } - msg := &TxSize{} - err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg) - if err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - if !p.Equal(msg) { - t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p) - } -} -func TestBlockGossipJSON(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, true) - marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{} - jsondata, err := marshaler.MarshalToString(p) - if err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - msg := &BlockGossip{} + msg := &EvidenceParams{} err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg) if err != nil { t.Fatalf("seed = %d, err = %v", seed, err) @@ -3590,12 +3516,12 @@ func TestBlockSizeProtoCompactText(t *testing.T) { } } -func TestTxSizeProtoText(t *testing.T) { +func TestEvidenceParamsProtoText(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, true) + p := NewPopulatedEvidenceParams(popr, true) dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p) - msg := &TxSize{} + msg := &EvidenceParams{} if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } @@ -3604,40 +3530,12 @@ func TestTxSizeProtoText(t *testing.T) { } } -func TestTxSizeProtoCompactText(t *testing.T) { +func TestEvidenceParamsProtoCompactText(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, true) + p := NewPopulatedEvidenceParams(popr, true) dAtA := github_com_gogo_protobuf_proto.CompactTextString(p) - msg := &TxSize{} - if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - if !p.Equal(msg) { - t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p) - } -} - -func TestBlockGossipProtoText(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, true) - dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p) - msg := &BlockGossip{} - if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - if !p.Equal(msg) { - t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p) - } -} - -func TestBlockGossipProtoCompactText(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, true) - dAtA := github_com_gogo_protobuf_proto.CompactTextString(p) - msg := &BlockGossip{} + msg := &EvidenceParams{} if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil { t.Fatalf("seed = %d, err = %v", seed, err) } @@ -4492,32 +4390,10 @@ func TestBlockSizeSize(t *testing.T) { } } -func TestTxSizeSize(t *testing.T) { - seed := time.Now().UnixNano() - popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedTxSize(popr, true) - size2 := github_com_gogo_protobuf_proto.Size(p) - dAtA, err := github_com_gogo_protobuf_proto.Marshal(p) - if err != nil { - t.Fatalf("seed = %d, err = %v", seed, err) - } - size := p.Size() - if len(dAtA) != size { - t.Errorf("seed = %d, size %v != marshalled size %v", seed, size, len(dAtA)) - } - if size2 != size { - t.Errorf("seed = %d, size %v != before marshal proto.Size %v", seed, size, size2) - } - size3 := github_com_gogo_protobuf_proto.Size(p) - if size3 != size { - t.Errorf("seed = %d, size %v != after marshal proto.Size %v", seed, size, size3) - } -} - -func TestBlockGossipSize(t *testing.T) { +func TestEvidenceParamsSize(t *testing.T) { seed := time.Now().UnixNano() popr := math_rand.New(math_rand.NewSource(seed)) - p := NewPopulatedBlockGossip(popr, true) + p := NewPopulatedEvidenceParams(popr, true) size2 := github_com_gogo_protobuf_proto.Size(p) dAtA, err := github_com_gogo_protobuf_proto.Marshal(p) if err != nil { diff --git a/blockchain/reactor.go b/blockchain/reactor.go index f975737c6..fc1b1f4d3 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -290,7 +290,7 @@ FOR_LOOP: didProcessCh <- struct{}{} } - firstParts := first.MakePartSet(state.ConsensusParams.BlockPartSizeBytes) + firstParts := first.MakePartSet(types.BlockPartSizeBytes) firstPartsHeader := firstParts.Header() firstID := types.BlockID{first.Hash(), firstPartsHeader} // Finally, verify the first block using the second's commit diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index f590fd52e..0ef38a6c4 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -48,7 +48,7 @@ func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainRe for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { firstBlock := makeBlock(blockHeight, state) secondBlock := makeBlock(blockHeight+1, state) - firstParts := firstBlock.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes) + firstParts := firstBlock.MakePartSet(types.BlockPartSizeBytes) blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit) } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 8ea71d353..44280f694 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -102,14 +102,6 @@ func TestWALCrash(t *testing.T) { {"empty block", func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) {}, 1}, - {"block with a smaller part size", - func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) { - // XXX: is there a better way to change BlockPartSizeBytes? - cs.state.ConsensusParams.BlockPartSizeBytes = 512 - sm.SaveState(stateDB, cs.state) - go sendTxs(cs, ctx) - }, - 1}, {"many non-empty blocks", func(stateDB dbm.DB, cs *ConsensusState, ctx context.Context) { go sendTxs(cs, ctx) @@ -397,7 +389,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { } func applyBlock(stateDB dbm.DB, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State { - testPartSize := st.ConsensusParams.BlockPartSizeBytes + testPartSize := types.BlockPartSizeBytes blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool) blkID := types.BlockID{blk.Hash(), blk.MakePartSet(testPartSize).Header()} @@ -620,7 +612,7 @@ func (bs *mockBlockStore) LoadBlock(height int64) *types.Block { return bs.chain func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { block := bs.chain[height-1] return &types.BlockMeta{ - BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.params.BlockPartSizeBytes).Header()}, + BlockID: types.BlockID{block.Hash(), block.MakePartSet(types.BlockPartSizeBytes).Header()}, Header: block.Header, } } diff --git a/consensus/state.go b/consensus/state.go index d77afafe9..aeb2b8675 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -950,22 +950,15 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts maxBytes := cs.state.ConsensusParams.BlockSize.MaxBytes // bound evidence to 1/10th of the block - evidence := cs.evpool.PendingEvidence(maxBytes / 10) + evidence := cs.evpool.PendingEvidence(types.MaxEvidenceBytesPerBlock(maxBytes)) // Mempool validated transactions - txs := cs.mempool.ReapMaxBytes(maxDataBytes(maxBytes, cs.state.Validators.Size(), len(evidence))) + txs := cs.mempool.ReapMaxBytes(types.MaxDataBytes(maxBytes, cs.state.Validators.Size(), len(evidence))) proposerAddr := cs.privValidator.GetAddress() block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr) return block, parts } -func maxDataBytes(maxBytes, valsCount, evidenceCount int) int { - return maxBytes - - types.MaxAminoOverheadForBlock - - types.MaxHeaderBytes - - (valsCount * types.MaxVoteBytes) - - (evidenceCount * types.MaxEvidenceBytes) -} // Enter: `timeoutPropose` after entering Propose. // Enter: proposal block and POL is ready. diff --git a/consensus/state_test.go b/consensus/state_test.go index 14cd0593e..9c3631504 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -184,7 +184,7 @@ func TestStateBadProposal(t *testing.T) { height, round := cs1.Height, cs1.Round vs2 := vss[1] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) @@ -339,7 +339,7 @@ func TestStateLockNoPOL(t *testing.T) { vs2 := vss[1] height := cs1.Height - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) @@ -507,7 +507,7 @@ func TestStateLockPOLRelock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) @@ -622,7 +622,7 @@ func TestStateLockPOLUnlock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -719,7 +719,7 @@ func TestStateLockPOLSafety1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -842,7 +842,7 @@ func TestStateLockPOLSafety2(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -1021,7 +1021,7 @@ func TestStateHalt1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.ConsensusParams.BlockPartSizeBytes + partSize := types.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) diff --git a/consensus/wal.go b/consensus/wal.go index 870701f1c..10bef542b 100644 --- a/consensus/wal.go +++ b/consensus/wal.go @@ -18,7 +18,7 @@ import ( ) const ( - // must be greater than params.BlockGossip.BlockPartSizeBytes + a few bytes + // must be greater than types.BlockPartSizeBytes + a few bytes maxMsgSizeBytes = 1024 * 1024 // 1MB ) diff --git a/node/node.go b/node/node.go index 76f23dfdd..cb3d7d67d 100644 --- a/node/node.go +++ b/node/node.go @@ -241,13 +241,16 @@ func NewNode(config *cfg.Config, csMetrics, p2pMetrics, memplMetrics := metricsProvider() // Make MempoolReactor - maxBytes := state.ConsensusParams.TxSize.MaxBytes + maxDataBytes := types.MaxDataBytesUnknownEvidence( + state.ConsensusParams.BlockSize.MaxBytes, + state.Validators.Size(), + ) mempool := mempl.NewMempool( config.Mempool, proxyApp.Mempool(), state.LastBlockHeight, mempl.WithMetrics(memplMetrics), - mempl.WithFilter(func(tx types.Tx) bool { return len(tx) <= maxBytes }), + mempl.WithFilter(func(tx types.Tx) bool { return len(tx) <= maxDataBytes }), ) mempoolLogger := logger.With("module", "mempool") mempool.SetLogger(mempoolLogger) @@ -751,7 +754,6 @@ func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) { db.SetSync(genesisDocKey, bytes) } - // splitAndTrimEmpty slices s into all subslices separated by sep and returns a // slice of the string s with all leading and trailing Unicode code points // contained in cutset removed. If sep is empty, SplitAndTrim splits after each diff --git a/state/execution.go b/state/execution.go index b1859c220..b4cdb7a3e 100644 --- a/state/execution.go +++ b/state/execution.go @@ -145,8 +145,11 @@ func (blockExec *BlockExecutor) Commit(state State, block *types.Block) ([]byte, "appHash", fmt.Sprintf("%X", res.Data)) // Update mempool. - maxBytes := state.ConsensusParams.TxSize.MaxBytes - filter := func(tx types.Tx) bool { return len(tx) <= maxBytes } + maxDataBytes := types.MaxDataBytesUnknownEvidence( + state.ConsensusParams.BlockSize.MaxBytes, + state.Validators.Size(), + ) + filter := func(tx types.Tx) bool { return len(tx) <= maxDataBytes } if err := blockExec.mempool.Update(block.Height, block.Txs, filter); err != nil { return nil, err } diff --git a/state/state.go b/state/state.go index 10da67e92..26510816b 100644 --- a/state/state.go +++ b/state/state.go @@ -139,7 +139,7 @@ func (state State) MakeBlock( // IncrementAccum for rounds there. block.ProposerAddress = proposerAddress - return block, block.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes) + return block, block.MakePartSet(types.BlockPartSizeBytes) } // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the diff --git a/state/state_test.go b/state/state_test.go index 9a793c8e7..51e98814e 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -373,18 +373,14 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { } } -func makeParams(txsBytes, blockGas, txBytes, txGas, partSize int) types.ConsensusParams { +func makeParams(txsBytes, blockGas, evidenceAge int) types.ConsensusParams { return types.ConsensusParams{ BlockSize: types.BlockSize{ MaxBytes: txsBytes, MaxGas: int64(blockGas), }, - TxSize: types.TxSize{ - MaxBytes: txBytes, - MaxGas: int64(txGas), - }, - BlockGossip: types.BlockGossip{ - BlockPartSizeBytes: partSize, + EvidenceParams: types.EvidenceParams{ + MaxAge: int64(evidenceAge), }, } } @@ -394,7 +390,7 @@ func pk() []byte { } func TestApplyUpdates(t *testing.T) { - initParams := makeParams(1, 2, 3, 4, 5) + initParams := makeParams(1, 2, 3) cases := [...]struct { init types.ConsensusParams @@ -404,33 +400,20 @@ func TestApplyUpdates(t *testing.T) { 0: {initParams, abci.ConsensusParams{}, initParams}, 1: {initParams, abci.ConsensusParams{}, initParams}, 2: {initParams, - abci.ConsensusParams{ - TxSize: &abci.TxSize{ - MaxBytes: 123, - }, - }, - makeParams(1, 2, 123, 4, 5)}, - 3: {initParams, abci.ConsensusParams{ BlockSize: &abci.BlockSize{ - MaxBytes: 1, + MaxBytes: 44, MaxGas: 55, }, }, - makeParams(1, 55, 3, 4, 5)}, - 4: {initParams, + makeParams(44, 55, 3)}, + 3: {initParams, abci.ConsensusParams{ - BlockSize: &abci.BlockSize{ - MaxBytes: 1, - }, - TxSize: &abci.TxSize{ - MaxGas: 888, - }, - BlockGossip: &abci.BlockGossip{ - BlockPartSizeBytes: 2002, + EvidenceParams: &abci.EvidenceParams{ + MaxAge: 66, }, }, - makeParams(1, 2, 3, 888, 2002)}, + makeParams(1, 2, 66)}, } for i, tc := range cases { diff --git a/types/block.go b/types/block.go index d0a1a826f..951ad96fe 100644 --- a/types/block.go +++ b/types/block.go @@ -204,6 +204,28 @@ func (b *Block) StringShort() string { //----------------------------------------------------------------------------- +// MaxDataBytes returns the maximum size of block's data. +func MaxDataBytes(maxBytes, valsCount, evidenceCount int) int { + return maxBytes - + MaxAminoOverheadForBlock - + MaxHeaderBytes - + (valsCount * MaxVoteBytes) - + (evidenceCount * MaxEvidenceBytes) +} + +// MaxDataBytesUnknownEvidence returns the maximum size of block's data when +// evidence count is unknown. MaxEvidenceBytesPerBlock will be used as the size +// of evidence. +func MaxDataBytesUnknownEvidence(maxBytes, valsCount int) int { + return maxBytes - + MaxAminoOverheadForBlock - + MaxHeaderBytes - + (valsCount * MaxVoteBytes) - + MaxEvidenceBytesPerBlock(maxBytes) +} + +//----------------------------------------------------------------------------- + // Header defines the structure of a Tendermint block header // TODO: limit header size // NOTE: changes to the Header should be duplicated in the abci Header diff --git a/types/evidence.go b/types/evidence.go index 8377fcd7f..2526a3942 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -52,6 +52,11 @@ func RegisterEvidences(cdc *amino.Codec) { cdc.RegisterConcrete(MockBadEvidence{}, "tendermint/MockBadEvidence", nil) } +// MaxEvidenceBytesPerBlock returns the maximum evidence size per block. +func MaxEvidenceBytesPerBlock(blockMaxBytes int) int { + return blockMaxBytes / 10 +} + //------------------------------------------- // DuplicateVoteEvidence contains evidence a validator signed two conflicting votes. diff --git a/types/params.go b/types/params.go index 77f68eb7b..902b7873f 100644 --- a/types/params.go +++ b/types/params.go @@ -9,34 +9,24 @@ import ( const ( // MaxBlockSizeBytes is the maximum permitted size of the blocks. MaxBlockSizeBytes = 104857600 // 100MB + + // BlockPartSizeBytes is the size of one block part. + BlockPartSizeBytes = 65536 // 64kB ) -// ConsensusParams contains consensus critical parameters -// that determine the validity of blocks. +// ConsensusParams contains consensus critical parameters that determine the +// validity of blocks. type ConsensusParams struct { BlockSize `json:"block_size_params"` - TxSize `json:"tx_size_params"` - BlockGossip `json:"block_gossip_params"` EvidenceParams `json:"evidence_params"` } // BlockSize contain limits on the block size. type BlockSize struct { - MaxBytes int `json:"max_txs_bytes"` // NOTE: must not be 0 nor greater than 100MB - MaxGas int64 `json:"max_gas"` -} - -// TxSize contain limits on the tx size. -type TxSize struct { - MaxBytes int `json:"max_bytes"` + MaxBytes int `json:"max_txs_bytes"` MaxGas int64 `json:"max_gas"` } -// BlockGossip determine consensus critical elements of how blocks are gossiped -type BlockGossip struct { - BlockPartSizeBytes int `json:"block_part_size_bytes"` // NOTE: must not be 0 -} - // EvidenceParams determine how we handle evidence of malfeasance type EvidenceParams struct { MaxAge int64 `json:"max_age"` // only accept new evidence more recent than this @@ -46,8 +36,6 @@ type EvidenceParams struct { func DefaultConsensusParams() *ConsensusParams { return &ConsensusParams{ DefaultBlockSize(), - DefaultTxSize(), - DefaultBlockGossip(), DefaultEvidenceParams(), } } @@ -55,61 +43,49 @@ func DefaultConsensusParams() *ConsensusParams { // DefaultBlockSize returns a default BlockSize. func DefaultBlockSize() BlockSize { return BlockSize{ - MaxBytes: 22020096, // 21MB - MaxGas: -1, - } -} - -// DefaultTxSize returns a default TxSize. -func DefaultTxSize() TxSize { - return TxSize{ - MaxBytes: 10240, // 10kB + MaxBytes: 22020096, // 21MB MaxGas: -1, } } -// DefaultBlockGossip returns a default BlockGossip. -func DefaultBlockGossip() BlockGossip { - return BlockGossip{ - BlockPartSizeBytes: 65536, // 64kB, - } -} - -// DefaultEvidence Params returns a default EvidenceParams. +// DefaultEvidenceParams Params returns a default EvidenceParams. func DefaultEvidenceParams() EvidenceParams { return EvidenceParams{ MaxAge: 100000, // 27.8 hrs at 1block/s } } -// Validate validates the ConsensusParams to ensure all values -// are within their allowed limits, and returns an error if they are not. +// Validate validates the ConsensusParams to ensure all values are within their +// allowed limits, and returns an error if they are not. func (params *ConsensusParams) Validate() error { - // ensure some values are greater than 0 if params.BlockSize.MaxBytes <= 0 { - return cmn.NewError("BlockSize.MaxBytes must be greater than 0. Got %d", params.BlockSize.MaxBytes) - } - if params.BlockGossip.BlockPartSizeBytes <= 0 { - return cmn.NewError("BlockGossip.BlockPartSizeBytes must be greater than 0. Got %d", params.BlockGossip.BlockPartSizeBytes) + return cmn.NewError("BlockSize.MaxBytes must be greater than 0. Got %d", + params.BlockSize.MaxBytes) } - - // ensure blocks aren't too big if params.BlockSize.MaxBytes > MaxBlockSizeBytes { return cmn.NewError("BlockSize.MaxBytes is too big. %d > %d", params.BlockSize.MaxBytes, MaxBlockSizeBytes) } + + if params.BlockSize.MaxGas < -1 { + return cmn.NewError("BlockSize.MaxGas must be greater or equal to -1. Got %d", + params.BlockSize.MaxGas) + } + + if params.EvidenceParams.MaxAge <= 0 { + return cmn.NewError("EvidenceParams.MaxAge must be greater than 0. Got %d", + params.EvidenceParams.MaxAge) + } + return nil } -// Hash returns a merkle hash of the parameters to store -// in the block header +// Hash returns a merkle hash of the parameters to store in the block header func (params *ConsensusParams) Hash() []byte { return merkle.SimpleHashFromMap(map[string]merkle.Hasher{ - "block_gossip_part_size_bytes": aminoHasher(params.BlockGossip.BlockPartSizeBytes), - "block_size_max_bytes": aminoHasher(params.BlockSize.MaxBytes), - "block_size_max_gas": aminoHasher(params.BlockSize.MaxGas), - "tx_size_max_bytes": aminoHasher(params.TxSize.MaxBytes), - "tx_size_max_gas": aminoHasher(params.TxSize.MaxGas), + "block_size_max_bytes": aminoHasher(params.BlockSize.MaxBytes), + "block_size_max_gas": aminoHasher(params.BlockSize.MaxGas), + "evidence_params_max_age": aminoHasher(params.EvidenceParams.MaxAge), }) } @@ -126,25 +102,11 @@ func (params ConsensusParams) Update(params2 *abci.ConsensusParams) ConsensusPar // XXX: it's cast city over here. It's ok because we only do int32->int // but still, watch it champ. if params2.BlockSize != nil { - if params2.BlockSize.MaxBytes > 0 { - res.BlockSize.MaxBytes = int(params2.BlockSize.MaxBytes) - } - if params2.BlockSize.MaxGas > 0 { - res.BlockSize.MaxGas = params2.BlockSize.MaxGas - } - } - if params2.TxSize != nil { - if params2.TxSize.MaxBytes > 0 { - res.TxSize.MaxBytes = int(params2.TxSize.MaxBytes) - } - if params2.TxSize.MaxGas > 0 { - res.TxSize.MaxGas = params2.TxSize.MaxGas - } + res.BlockSize.MaxBytes = int(params2.BlockSize.MaxBytes) + res.BlockSize.MaxGas = params2.BlockSize.MaxGas } - if params2.BlockGossip != nil { - if params2.BlockGossip.BlockPartSizeBytes > 0 { - res.BlockGossip.BlockPartSizeBytes = int(params2.BlockGossip.BlockPartSizeBytes) - } + if params2.EvidenceParams != nil { + res.EvidenceParams.MaxAge = params2.EvidenceParams.MaxAge } return res } diff --git a/types/params_test.go b/types/params_test.go index 119109ce0..ab235bc47 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -9,10 +9,10 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -func newConsensusParams(txsBytes, partSize int) ConsensusParams { +func newConsensusParams(txsBytes, evidenceAge int) ConsensusParams { return ConsensusParams{ - BlockSize: BlockSize{MaxBytes: txsBytes}, - BlockGossip: BlockGossip{BlockPartSizeBytes: partSize}, + BlockSize: BlockSize{MaxBytes: txsBytes}, + EvidenceParams: EvidenceParams{MaxAge: int64(evidenceAge)}, } } @@ -21,50 +21,45 @@ func TestConsensusParamsValidation(t *testing.T) { params ConsensusParams valid bool }{ - {newConsensusParams(1, 1), true}, - {newConsensusParams(1, 0), false}, - {newConsensusParams(0, 1), false}, - {newConsensusParams(0, 0), false}, - {newConsensusParams(0, 10), false}, - {newConsensusParams(10, -1), false}, - {newConsensusParams(47*1024*1024, 400), true}, - {newConsensusParams(10, 400), true}, - {newConsensusParams(100*1024*1024, 400), true}, - {newConsensusParams(101*1024*1024, 400), false}, - {newConsensusParams(1024*1024*1024, 400), false}, + // test block size + 0: {newConsensusParams(1, 1), true}, + 1: {newConsensusParams(0, 1), false}, + 2: {newConsensusParams(47*1024*1024, 1), true}, + 3: {newConsensusParams(10, 1), true}, + 4: {newConsensusParams(100*1024*1024, 1), true}, + 5: {newConsensusParams(101*1024*1024, 1), false}, + 6: {newConsensusParams(1024*1024*1024, 1), false}, + 7: {newConsensusParams(1024*1024*1024, -1), false}, + // test evidence age + 8: {newConsensusParams(1, 0), false}, + 9: {newConsensusParams(1, -1), false}, } - for _, tc := range testCases { + for i, tc := range testCases { if tc.valid { - assert.NoError(t, tc.params.Validate(), "expected no error for valid params") + assert.NoErrorf(t, tc.params.Validate(), "expected no error for valid params (#%d)", i) } else { - assert.Error(t, tc.params.Validate(), "expected error for non valid params") + assert.Errorf(t, tc.params.Validate(), "expected error for non valid params (#%d)", i) } } } -func makeParams(txsBytes, blockGas, txBytes, txGas, partSize int) ConsensusParams { +func makeParams(txsBytes, blockGas, evidenceAge int) ConsensusParams { return ConsensusParams{ BlockSize: BlockSize{ MaxBytes: txsBytes, MaxGas: int64(blockGas), }, - TxSize: TxSize{ - MaxBytes: txBytes, - MaxGas: int64(txGas), - }, - BlockGossip: BlockGossip{ - BlockPartSizeBytes: partSize, + EvidenceParams: EvidenceParams{ + MaxAge: int64(evidenceAge), }, } } func TestConsensusParamsHash(t *testing.T) { params := []ConsensusParams{ - makeParams(6, 2, 3, 4, 5), - makeParams(1, 6, 3, 4, 5), - makeParams(1, 2, 6, 4, 5), - makeParams(1, 2, 3, 6, 5), - makeParams(1, 2, 3, 4, 6), + makeParams(4, 2, 3), + makeParams(1, 4, 3), + makeParams(1, 2, 4), } hashes := make([][]byte, len(params)) @@ -90,45 +85,23 @@ func TestConsensusParamsUpdate(t *testing.T) { }{ // empty updates { - makeParams(1, 2, 3, 4, 5), + makeParams(1, 2, 3), &abci.ConsensusParams{}, - makeParams(1, 2, 3, 4, 5), - }, - // negative BlockPartSizeBytes - { - makeParams(1, 2, 3, 4, 5), - &abci.ConsensusParams{ - BlockSize: &abci.BlockSize{ - MaxBytes: -100, - MaxGas: -200, - }, - TxSize: &abci.TxSize{ - MaxBytes: -400, - MaxGas: -500, - }, - BlockGossip: &abci.BlockGossip{ - BlockPartSizeBytes: -600, - }, - }, - makeParams(1, 2, 3, 4, 5), + makeParams(1, 2, 3), }, // fine updates { - makeParams(1, 2, 3, 4, 5), + makeParams(1, 2, 3), &abci.ConsensusParams{ BlockSize: &abci.BlockSize{ MaxBytes: 100, MaxGas: 200, }, - TxSize: &abci.TxSize{ - MaxBytes: 300, - MaxGas: 400, - }, - BlockGossip: &abci.BlockGossip{ - BlockPartSizeBytes: 500, + EvidenceParams: &abci.EvidenceParams{ + MaxAge: 300, }, }, - makeParams(100, 200, 300, 400, 500), + makeParams(100, 200, 300), }, } for _, tc := range testCases { diff --git a/types/protobuf.go b/types/protobuf.go index 9c448cd84..df19a5b55 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -115,15 +115,11 @@ func (tm2pb) ValidatorUpdates(vals *ValidatorSet) []abci.ValidatorUpdate { func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams { return &abci.ConsensusParams{ BlockSize: &abci.BlockSize{ - MaxBytes: int32(params.BlockSize.MaxBytes), - MaxGas: params.BlockSize.MaxGas, + MaxBytes: int32(params.BlockSize.MaxBytes), + MaxGas: params.BlockSize.MaxGas, }, - TxSize: &abci.TxSize{ - MaxBytes: int32(params.TxSize.MaxBytes), - MaxGas: params.TxSize.MaxGas, - }, - BlockGossip: &abci.BlockGossip{ - BlockPartSizeBytes: int32(params.BlockGossip.BlockPartSizeBytes), + EvidenceParams: &abci.EvidenceParams{ + MaxAge: params.EvidenceParams.MaxAge, }, } } @@ -215,18 +211,11 @@ func (pb2tm) ValidatorUpdates(vals []abci.ValidatorUpdate) ([]*Validator, error) func (pb2tm) ConsensusParams(csp *abci.ConsensusParams) ConsensusParams { return ConsensusParams{ BlockSize: BlockSize{ - MaxBytes: int(csp.BlockSize.MaxBytes), // XXX - MaxGas: csp.BlockSize.MaxGas, - }, - TxSize: TxSize{ - MaxBytes: int(csp.TxSize.MaxBytes), // XXX - MaxGas: csp.TxSize.MaxGas, + MaxBytes: int(csp.BlockSize.MaxBytes), // XXX + MaxGas: csp.BlockSize.MaxGas, }, - BlockGossip: BlockGossip{ - BlockPartSizeBytes: int(csp.BlockGossip.BlockPartSizeBytes), // XXX + EvidenceParams: EvidenceParams{ + MaxAge: csp.EvidenceParams.MaxAge, // XXX }, - // TODO: EvidenceParams: EvidenceParams{ - // MaxAge: int(csp.Evidence.MaxAge), // XXX - // }, } } From 1ea64fc27ff51079a85c3cc741115ad8fe6ee88c Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 12 Sep 2018 13:41:19 -0700 Subject: [PATCH 07/47] Make mempool aware of MaxGas requirement (#2360) * Make mempool aware of MaxGas requirement * update spec * Add tests * Switch GasWanted from kv store to persistent kv store * Fix typo in test name * switch back to using kvstore, not persistent kv store --- CHANGELOG_PENDING.md | 3 +- abci/example/kvstore/kvstore.go | 2 +- consensus/mempool_test.go | 2 +- consensus/state.go | 4 +- docs/spec/reactors/mempool/functionality.md | 3 +- mempool/mempool.go | 34 +++++++----- mempool/mempool_test.go | 58 +++++++++++++++++++-- state/services.go | 6 ++- 8 files changed, 88 insertions(+), 24 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index cd5dc06d6..a32b43207 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -9,13 +9,14 @@ BREAKING CHANGES: * Apps * Go API - + * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas * Blockchain Protocol * P2P Protocol FEATURES: + * \#2310 Mempool is now aware of the MaxGas requirement IMPROVEMENTS: diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index d8d18d5e2..c1554cc57 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -88,7 +88,7 @@ func (app *KVStoreApplication) DeliverTx(tx []byte) types.ResponseDeliverTx { } func (app *KVStoreApplication) CheckTx(tx []byte) types.ResponseCheckTx { - return types.ResponseCheckTx{Code: code.CodeTypeOK} + return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1} } func (app *KVStoreApplication) Commit() types.ResponseCommit { diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index 16a167fd6..fbf46c2da 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -148,7 +148,7 @@ func TestMempoolRmBadTx(t *testing.T) { // check for the tx for { - txs := cs.mempool.ReapMaxBytes(len(txBytes)) + txs := cs.mempool.ReapMaxBytesMaxGas(len(txBytes), -1) if len(txs) == 0 { emptyMempoolCh <- struct{}{} return diff --git a/consensus/state.go b/consensus/state.go index aeb2b8675..63b10e0bf 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -949,10 +949,12 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts } maxBytes := cs.state.ConsensusParams.BlockSize.MaxBytes + maxGas := cs.state.ConsensusParams.BlockSize.MaxGas // bound evidence to 1/10th of the block evidence := cs.evpool.PendingEvidence(types.MaxEvidenceBytesPerBlock(maxBytes)) // Mempool validated transactions - txs := cs.mempool.ReapMaxBytes(types.MaxDataBytes(maxBytes, cs.state.Validators.Size(), len(evidence))) + txs := cs.mempool.ReapMaxBytesMaxGas(types.MaxDataBytes(maxBytes, cs.state.Validators.Size(), len(evidence)), maxGas) + proposerAddr := cs.privValidator.GetAddress() block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr) diff --git a/docs/spec/reactors/mempool/functionality.md b/docs/spec/reactors/mempool/functionality.md index 4f811801f..4064def0b 100644 --- a/docs/spec/reactors/mempool/functionality.md +++ b/docs/spec/reactors/mempool/functionality.md @@ -22,7 +22,8 @@ to potentially untrusted actors. Internal functionality is exposed via method calls to other code compiled into the tendermint binary. -- Reap - get tx to propose in next block +- ReapMaxBytesMaxGas - get txs to propose in the next block. Guarantees that the + size of the txs is less than MaxBytes, and gas is less than MaxGas - Update - remove tx that were included in last block - ABCI.CheckTx - call ABCI app to validate the tx diff --git a/mempool/mempool.go b/mempool/mempool.go index 381653e64..0e4a95361 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -302,9 +302,10 @@ func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) { if r.CheckTx.Code == abci.CodeTypeOK { mem.counter++ memTx := &mempoolTx{ - counter: mem.counter, - height: mem.height, - tx: tx, + counter: mem.counter, + height: mem.height, + gasWanted: r.CheckTx.GasWanted, + tx: tx, } mem.txs.PushBack(memTx) mem.logger.Info("Added good transaction", "tx", TxID(tx), "res", r, "total", mem.Size()) @@ -380,10 +381,11 @@ func (mem *Mempool) notifyTxsAvailable() { } } -// ReapMaxBytes reaps transactions from the mempool up to n bytes total. -// If max is negative, there is no cap on the size of all returned +// ReapMaxBytesMaxGas reaps transactions from the mempool up to maxBytes bytes total +// with the condition that the total gasWanted must be less than maxGas. +// If both maxes are negative, there is no cap on the size of all returned // transactions (~ all available transactions). -func (mem *Mempool) ReapMaxBytes(max int) types.Txs { +func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { var buf [binary.MaxVarintLen64]byte mem.proxyMtx.Lock() @@ -394,19 +396,26 @@ func (mem *Mempool) ReapMaxBytes(max int) types.Txs { time.Sleep(time.Millisecond * 10) } - var cur int + var totalBytes int + var totalGas int64 // TODO: we will get a performance boost if we have a good estimate of avg // size per tx, and set the initial capacity based off of that. // txs := make([]types.Tx, 0, cmn.MinInt(mem.txs.Len(), max/mem.avgTxSize)) txs := make([]types.Tx, 0, mem.txs.Len()) for e := mem.txs.Front(); e != nil; e = e.Next() { memTx := e.Value.(*mempoolTx) + // Check total size requirement // amino.UvarintSize is not used here because it won't be possible to reuse buf aminoOverhead := binary.PutUvarint(buf[:], uint64(len(memTx.tx))) - if max > 0 && cur+len(memTx.tx)+aminoOverhead > max { + if maxBytes > -1 && totalBytes+len(memTx.tx)+aminoOverhead > maxBytes { + return txs + } + totalBytes += len(memTx.tx) + aminoOverhead + // Check total gas requirement + if maxGas > -1 && totalGas+memTx.gasWanted > maxGas { return txs } - cur += len(memTx.tx) + aminoOverhead + totalGas += memTx.gasWanted txs = append(txs, memTx.tx) } return txs @@ -513,9 +522,10 @@ func (mem *Mempool) recheckTxs(goodTxs []types.Tx) { // mempoolTx is a transaction that successfully ran type mempoolTx struct { - counter int64 // a simple incrementing counter - height int64 // height that this tx had been validated in - tx types.Tx // + counter int64 // a simple incrementing counter + height int64 // height that this tx had been validated in + gasWanted int64 // amount of gas this tx states it will require + tx types.Tx // } // Height returns the height for this transaction diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index 0dbe2bb6f..1004421f0 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -11,16 +11,16 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/counter" "github.com/tendermint/tendermint/abci/example/kvstore" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" - - "github.com/stretchr/testify/require" ) func newMempoolWithApp(cc proxy.ClientCreator) *Mempool { @@ -71,6 +71,54 @@ func checkTxs(t *testing.T, mempool *Mempool, count int) types.Txs { return txs } +func TestReapMaxBytesMaxGas(t *testing.T) { + app := kvstore.NewKVStoreApplication() + cc := proxy.NewLocalClientCreator(app) + mempool := newMempoolWithApp(cc) + + // Ensure gas calculation behaves as expected + checkTxs(t, mempool, 1) + tx0 := mempool.TxsFront().Value.(*mempoolTx) + // assert that kv store has gas wanted = 1. + require.Equal(t, app.CheckTx(tx0.tx).GasWanted, int64(1), "KVStore had a gas value neq to 1") + require.Equal(t, tx0.gasWanted, int64(1), "transactions gas was set incorrectly") + // ensure each tx is 20 bytes long + require.Equal(t, len(tx0.tx), 20, "Tx is longer than 20 bytes") + mempool.Flush() + + // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. + // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas + tests := []struct { + numTxsToCreate int + maxBytes int + maxGas int64 + expectedNumTxs int + }{ + {20, -1, -1, 20}, + {20, -1, 0, 0}, + {20, -1, 10, 10}, + {20, -1, 30, 20}, + {20, 0, -1, 0}, + {20, 0, 10, 0}, + {20, 10, 10, 0}, + {20, 21, 10, 1}, + {20, 210, -1, 10}, + {20, 210, 5, 5}, + {20, 210, 10, 10}, + {20, 210, 15, 10}, + {20, 20000, -1, 20}, + {20, 20000, 5, 5}, + {20, 20000, 30, 20}, + } + for tcIndex, tt := range tests { + checkTxs(t, mempool, tt.numTxsToCreate) + got := mempool.ReapMaxBytesMaxGas(tt.maxBytes, tt.maxGas) + assert.Equal(t, tt.expectedNumTxs, len(got), "Got %d txs, expected %d, tc #%d", + len(got), tt.expectedNumTxs, tcIndex) + mempool.Flush() + } +} + func TestTxsAvailable(t *testing.T) { app := kvstore.NewKVStoreApplication() cc := proxy.NewLocalClientCreator(app) @@ -149,7 +197,7 @@ func TestSerialReap(t *testing.T) { } reapCheck := func(exp int) { - txs := mempool.ReapMaxBytes(-1) + txs := mempool.ReapMaxBytesMaxGas(-1, -1) require.Equal(t, len(txs), exp, fmt.Sprintf("Expected to reap %v txs but got %v", exp, len(txs))) } diff --git a/state/services.go b/state/services.go index 13ab7383f..fd98a06c6 100644 --- a/state/services.go +++ b/state/services.go @@ -22,7 +22,7 @@ type Mempool interface { Size() int CheckTx(types.Tx, func(*abci.Response)) error - ReapMaxBytes(max int) types.Txs + ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs Update(height int64, txs types.Txs, filter func(types.Tx) bool) error Flush() FlushAppConn() error @@ -34,11 +34,13 @@ type Mempool interface { // MockMempool is an empty implementation of a Mempool, useful for testing. type MockMempool struct{} +var _ Mempool = MockMempool{} + func (MockMempool) Lock() {} func (MockMempool) Unlock() {} func (MockMempool) Size() int { return 0 } func (MockMempool) CheckTx(tx types.Tx, cb func(*abci.Response)) error { return nil } -func (MockMempool) ReapMaxBytes(max int) types.Txs { return types.Txs{} } +func (MockMempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { return types.Txs{} } func (MockMempool) Update(height int64, txs types.Txs, filter func(types.Tx) bool) error { return nil } func (MockMempool) Flush() {} func (MockMempool) FlushAppConn() error { return nil } From e3e3c13741acd4dbedb2d03e3f5cff42891cfaa4 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 13 Sep 2018 03:07:29 +0400 Subject: [PATCH 08/47] [common] revert started flag when service already stopped (#2326) also, return ErrNotStarted when trying to stop a not-running service --- libs/common/service.go | 15 +++++++++++++++ rpc/lib/client/ws_client.go | 3 --- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/common/service.go b/libs/common/service.go index 03e392855..96a5e632a 100644 --- a/libs/common/service.go +++ b/libs/common/service.go @@ -9,8 +9,15 @@ import ( ) var ( + // ErrAlreadyStarted is returned when somebody tries to start an already + // running service. ErrAlreadyStarted = errors.New("already started") + // ErrAlreadyStopped is returned when somebody tries to stop an already + // stopped service (without resetting it). ErrAlreadyStopped = errors.New("already stopped") + // ErrNotStarted is returned when somebody tries to stop a not running + // service. + ErrNotStarted = errors.New("not started") ) // Service defines a service that can be started, stopped, and reset. @@ -124,6 +131,8 @@ func (bs *BaseService) Start() error { if atomic.CompareAndSwapUint32(&bs.started, 0, 1) { if atomic.LoadUint32(&bs.stopped) == 1 { bs.Logger.Error(fmt.Sprintf("Not starting %v -- already stopped", bs.name), "impl", bs.impl) + // revert flag + atomic.StoreUint32(&bs.started, 0) return ErrAlreadyStopped } bs.Logger.Info(fmt.Sprintf("Starting %v", bs.name), "impl", bs.impl) @@ -148,6 +157,12 @@ func (bs *BaseService) OnStart() error { return nil } // channel. An error will be returned if the service is already stopped. func (bs *BaseService) Stop() error { if atomic.CompareAndSwapUint32(&bs.stopped, 0, 1) { + if atomic.LoadUint32(&bs.started) == 0 { + bs.Logger.Error(fmt.Sprintf("Not stopping %v -- have not been started yet", bs.name), "impl", bs.impl) + // revert flag + atomic.StoreUint32(&bs.stopped, 0) + return ErrNotStarted + } bs.Logger.Info(fmt.Sprintf("Stopping %v", bs.name), "impl", bs.impl) bs.impl.OnStop() close(bs.quit) diff --git a/rpc/lib/client/ws_client.go b/rpc/lib/client/ws_client.go index cff285222..6da996e2c 100644 --- a/rpc/lib/client/ws_client.go +++ b/rpc/lib/client/ws_client.go @@ -174,9 +174,6 @@ func (c *WSClient) OnStart() error { return nil } -// OnStop implements cmn.Service. -func (c *WSClient) OnStop() {} - // Stop overrides cmn.Service#Stop. There is no other way to wait until Quit // channel is closed. func (c *WSClient) Stop() error { From c6c0b52d0c501dea94e1c767a053e44e2b61971e Mon Sep 17 00:00:00 2001 From: zhangzheng Date: Mon, 17 Sep 2018 17:08:47 +0800 Subject: [PATCH 09/47] tools/tm-bench: bounds check for txSize and improving test cases (#2410) Fixes #2409 --- tools/tm-bench/main.go | 10 +++++++++- tools/tm-bench/transacter_test.go | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/tm-bench/main.go b/tools/tm-bench/main.go index a8ede4a0c..a418e0363 100644 --- a/tools/tm-bench/main.go +++ b/tools/tm-bench/main.go @@ -25,7 +25,7 @@ func main() { flagSet.IntVar(&connections, "c", 1, "Connections to keep open per endpoint") flagSet.IntVar(&durationInt, "T", 10, "Exit after the specified amount of time in seconds") flagSet.IntVar(&txsRate, "r", 1000, "Txs per second to send in a connection") - flagSet.IntVar(&txSize, "s", 250, "The size of a transaction in bytes.") + flagSet.IntVar(&txSize, "s", 250, "The size of a transaction in bytes, must be greater than or equal to 40.") flagSet.StringVar(&outputFormat, "output-format", "plain", "Output format: plain or json") flagSet.StringVar(&broadcastTxMethod, "broadcast-tx-method", "async", "Broadcast method: async (no guarantees; fastest), sync (ensures tx is checked) or commit (ensures tx is checked and committed; slowest)") flagSet.BoolVar(&verbose, "v", false, "Verbose output") @@ -68,6 +68,14 @@ Examples: fmt.Printf("Running %ds test @ %s\n", durationInt, flagSet.Arg(0)) } + if txSize < 40 { + fmt.Fprintln( + os.Stderr, + "The size of a transaction must be greater than or equal to 40.", + ) + os.Exit(1) + } + if broadcastTxMethod != "async" && broadcastTxMethod != "sync" && broadcastTxMethod != "commit" { diff --git a/tools/tm-bench/transacter_test.go b/tools/tm-bench/transacter_test.go index 086a43c31..03f304605 100644 --- a/tools/tm-bench/transacter_test.go +++ b/tools/tm-bench/transacter_test.go @@ -22,7 +22,7 @@ func TestGenerateTxUpdateTxConsistentency(t *testing.T) { hostname string numTxsToTest int }{ - {0, 0, 50, "localhost:26657", 1000}, + {0, 0, 40, "localhost:26657", 1000}, {70, 300, 10000, "localhost:26657", 1000}, {0, 50, 100000, "localhost:26657", 1000}, } From 8ae333442342f627d1f78d463bfe1f575cc257ae Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Mon, 17 Sep 2018 12:38:29 +0200 Subject: [PATCH 10/47] [libs/autofile & db/fsdb] Throw error if file permissions change (#2286) * Enforce file permissions in case they've changed * test behaviour for autofile * use testify in tests and rename `fInf` to `fileInfo` * return an error if file permissions have changed - if we can't read the file, we'll still panic * get rid of "github.com/pkg/errors" dependency * address review comments: - prefix instead of suffix - add state to err and construct formatting in Error() method * address review comments: - move error to libs/errors --- libs/autofile/autofile.go | 15 ++++++- libs/autofile/autofile_test.go | 73 +++++++++++++++++++++------------- libs/db/fsdb.go | 9 +++++ libs/errors/errors.go | 26 ++++++++++++ 4 files changed, 93 insertions(+), 30 deletions(-) create mode 100644 libs/errors/errors.go diff --git a/libs/autofile/autofile.go b/libs/autofile/autofile.go index b00585285..fa1eab20b 100644 --- a/libs/autofile/autofile.go +++ b/libs/autofile/autofile.go @@ -6,6 +6,7 @@ import ( "time" cmn "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/libs/errors" ) /* AutoFile usage @@ -30,7 +31,10 @@ if err != nil { } */ -const autoFileOpenDuration = 1000 * time.Millisecond +const ( + autoFileOpenDuration = 1000 * time.Millisecond + autoFilePerms = os.FileMode(0600) +) // Automatically closes and re-opens file for writing. // This is useful for using a log file with the logrotate tool. @@ -116,10 +120,17 @@ func (af *AutoFile) Sync() error { } func (af *AutoFile) openFile() error { - file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) + file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, autoFilePerms) if err != nil { return err } + fileInfo, err := file.Stat() + if err != nil { + return err + } + if fileInfo.Mode() != autoFilePerms { + return errors.NewErrPermissionsChanged(file.Name(), fileInfo.Mode(), autoFilePerms) + } af.file = file return nil } diff --git a/libs/autofile/autofile_test.go b/libs/autofile/autofile_test.go index 67397380b..e8a9b3e4d 100644 --- a/libs/autofile/autofile_test.go +++ b/libs/autofile/autofile_test.go @@ -8,41 +8,33 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + cmn "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/libs/errors" ) func TestSIGHUP(t *testing.T) { - // First, create an AutoFile writing to a tempfile dir file, err := ioutil.TempFile("", "sighup_test") - if err != nil { - t.Fatalf("Error creating tempfile: %v", err) - } - if err := file.Close(); err != nil { - t.Fatalf("Error closing tempfile: %v", err) - } + require.NoError(t, err) + err = file.Close() + require.NoError(t, err) name := file.Name() + // Here is the actual AutoFile af, err := OpenAutoFile(name) - if err != nil { - t.Fatalf("Error creating autofile: %v", err) - } + require.NoError(t, err) // Write to the file. _, err = af.Write([]byte("Line 1\n")) - if err != nil { - t.Fatalf("Error writing to autofile: %v", err) - } + require.NoError(t, err) _, err = af.Write([]byte("Line 2\n")) - if err != nil { - t.Fatalf("Error writing to autofile: %v", err) - } + require.NoError(t, err) // Move the file over err = os.Rename(name, name+"_old") - if err != nil { - t.Fatalf("Error moving autofile: %v", err) - } + require.NoError(t, err) // Send SIGHUP to self. oldSighupCounter := atomic.LoadInt32(&sighupCounter) @@ -55,16 +47,11 @@ func TestSIGHUP(t *testing.T) { // Write more to the file. _, err = af.Write([]byte("Line 3\n")) - if err != nil { - t.Fatalf("Error writing to autofile: %v", err) - } + require.NoError(t, err) _, err = af.Write([]byte("Line 4\n")) - if err != nil { - t.Fatalf("Error writing to autofile: %v", err) - } - if err := af.Close(); err != nil { - t.Fatalf("Error closing autofile") - } + require.NoError(t, err) + err = af.Close() + require.NoError(t, err) // Both files should exist if body := cmn.MustReadFile(name + "_old"); string(body) != "Line 1\nLine 2\n" { @@ -74,3 +61,33 @@ func TestSIGHUP(t *testing.T) { t.Errorf("Unexpected body %s", body) } } + +// Manually modify file permissions, close, and reopen using autofile: +// We expect the file permissions to be changed back to the intended perms. +func TestOpenAutoFilePerms(t *testing.T) { + file, err := ioutil.TempFile("", "permission_test") + require.NoError(t, err) + err = file.Close() + require.NoError(t, err) + name := file.Name() + + // open and change permissions + af, err := OpenAutoFile(name) + require.NoError(t, err) + err = af.file.Chmod(0755) + require.NoError(t, err) + err = af.Close() + require.NoError(t, err) + + // reopen and expect an ErrPermissionsChanged as Cause + af, err = OpenAutoFile(name) + require.Error(t, err) + if e, ok := err.(*errors.ErrPermissionsChanged); ok { + t.Logf("%v", e) + } else { + t.Errorf("unexpected error %v", e) + } + + err = af.Close() + require.NoError(t, err) +} diff --git a/libs/db/fsdb.go b/libs/db/fsdb.go index fc861decc..92c059d42 100644 --- a/libs/db/fsdb.go +++ b/libs/db/fsdb.go @@ -10,7 +10,9 @@ import ( "sync" "github.com/pkg/errors" + cmn "github.com/tendermint/tendermint/libs/common" + tmerrors "github.com/tendermint/tendermint/libs/errors" ) const ( @@ -205,6 +207,13 @@ func write(path string, d []byte) error { return err } defer f.Close() + fInfo, err := f.Stat() + if err != nil { + return err + } + if fInfo.Mode() != keyPerm { + return tmerrors.NewErrPermissionsChanged(f.Name(), keyPerm, fInfo.Mode()) + } _, err = f.Write(d) if err != nil { return err diff --git a/libs/errors/errors.go b/libs/errors/errors.go new file mode 100644 index 000000000..ae5d94392 --- /dev/null +++ b/libs/errors/errors.go @@ -0,0 +1,26 @@ +// Package errors contains errors that are thrown across packages. +package errors + +import ( + "fmt" + "os" +) + +// ErrPermissionsChanged occurs if the file permission have changed since the file was created. +type ErrPermissionsChanged struct { + name string + got, want os.FileMode +} + +func NewErrPermissionsChanged(name string, got, want os.FileMode) *ErrPermissionsChanged { + return &ErrPermissionsChanged{name: name, got: got, want: want} +} + +func (e ErrPermissionsChanged) Error() string { + return fmt.Sprintf( + "file: [%v]\nexpected file permissions: %v, got: %v", + e.name, + e.want, + e.got, + ) +} From fc7f9bcaf6c4acc3cf87b2f8871b9e4d3950cbc5 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 17 Sep 2018 20:39:52 +0400 Subject: [PATCH 11/47] rpc: Transform /status result.node_info.other into map (#2417) * [rpc] transform /status result.node_info.other into map * amino does not support maps, duh Refs #2391 --- CHANGELOG_PENDING.md | 1 + benchmarks/codec_test.go | 15 +++++-- docs/spec/p2p/peer.md | 10 ++++- node/node.go | 14 +++--- p2p/node_info.go | 48 ++++++++++++++++++--- p2p/test_util.go | 11 ++++- rpc/core/status.go | 74 ++++++++++++++++---------------- rpc/core/types/responses.go | 9 +--- rpc/core/types/responses_test.go | 22 ++++------ 9 files changed, 128 insertions(+), 76 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index a32b43207..2d77ed906 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -7,6 +7,7 @@ BREAKING CHANGES: * CLI/RPC/Config * Apps + [rpc] /status `result.node_info.other` became a map #[2391](https://github.com/tendermint/tendermint/issues/2391) * Go API * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas diff --git a/benchmarks/codec_test.go b/benchmarks/codec_test.go index 09487563a..c0e13d168 100644 --- a/benchmarks/codec_test.go +++ b/benchmarks/codec_test.go @@ -24,7 +24,10 @@ func BenchmarkEncodeStatusWire(b *testing.B) { Network: "SOMENAME", ListenAddr: "SOMEADDR", Version: "SOMEVER", - Other: []string{"SOMESTRING", "OTHERSTRING"}, + Other: p2p.NodeInfoOther{ + AminoVersion: "SOMESTRING", + P2PVersion: "OTHERSTRING", + }, }, SyncInfo: ctypes.SyncInfo{ LatestBlockHash: []byte("SOMEBYTES"), @@ -59,7 +62,10 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) { Network: "SOMENAME", ListenAddr: "SOMEADDR", Version: "SOMEVER", - Other: []string{"SOMESTRING", "OTHERSTRING"}, + Other: p2p.NodeInfoOther{ + AminoVersion: "SOMESTRING", + P2PVersion: "OTHERSTRING", + }, } b.StartTimer() @@ -84,7 +90,10 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) { Network: "SOMENAME", ListenAddr: "SOMEADDR", Version: "SOMEVER", - Other: []string{"SOMESTRING", "OTHERSTRING"}, + Other: p2p.NodeInfoOther{ + AminoVersion: "SOMESTRING", + P2PVersion: "OTHERSTRING", + }, } b.StartTimer() diff --git a/docs/spec/p2p/peer.md b/docs/spec/p2p/peer.md index 116fec4f7..eb344c291 100644 --- a/docs/spec/p2p/peer.md +++ b/docs/spec/p2p/peer.md @@ -83,7 +83,15 @@ type NodeInfo struct { Channels []int8 Moniker string - Other []string + Other NodeInfoOther +} + +type NodeInfoOther struct { + AminoVersion string + P2PVersion string + ConsensusVersion string + RPCVersion string + TxIndex string } ``` diff --git a/node/node.go b/node/node.go index cb3d7d67d..7f288fe4c 100644 --- a/node/node.go +++ b/node/node.go @@ -690,12 +690,12 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo { evidence.EvidenceChannel, }, Moniker: n.config.Moniker, - Other: []string{ - fmt.Sprintf("amino_version=%v", amino.Version), - fmt.Sprintf("p2p_version=%v", p2p.Version), - fmt.Sprintf("consensus_version=%v", cs.Version), - fmt.Sprintf("rpc_version=%v/%v", rpc.Version, rpccore.Version), - fmt.Sprintf("tx_index=%v", txIndexerStatus), + Other: p2p.NodeInfoOther{ + AminoVersion: amino.Version, + P2PVersion: p2p.Version, + ConsensusVersion: cs.Version, + RPCVersion: fmt.Sprintf("%v/%v", rpc.Version, rpccore.Version), + TxIndex: txIndexerStatus, }, } @@ -704,7 +704,7 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo { } rpcListenAddr := n.config.RPC.ListenAddress - nodeInfo.Other = append(nodeInfo.Other, fmt.Sprintf("rpc_addr=%v", rpcListenAddr)) + nodeInfo.Other.RPCAddress = rpcListenAddr if !n.sw.IsListening() { return nodeInfo diff --git a/p2p/node_info.go b/p2p/node_info.go index fa1333b27..c0718deee 100644 --- a/p2p/node_info.go +++ b/p2p/node_info.go @@ -32,8 +32,29 @@ type NodeInfo struct { Channels cmn.HexBytes `json:"channels"` // channels this node knows about // ASCIIText fields - Moniker string `json:"moniker"` // arbitrary moniker - Other []string `json:"other"` // other application specific data + Moniker string `json:"moniker"` // arbitrary moniker + Other NodeInfoOther `json:"other"` // other application specific data +} + +// NodeInfoOther is the misc. applcation specific data +type NodeInfoOther struct { + AminoVersion string `json:"amino_version"` + P2PVersion string `json:"p2p_version"` + ConsensusVersion string `json:"consensus_version"` + RPCVersion string `json:"rpc_version"` + TxIndex string `json:"tx_index"` + RPCAddress string `json:"rpc_address"` +} + +func (o NodeInfoOther) String() string { + return fmt.Sprintf( + "{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v}", + o.AminoVersion, + o.P2PVersion, + o.ConsensusVersion, + o.RPCVersion, + o.TxIndex, + ) } // Validate checks the self-reported NodeInfo is safe. @@ -56,13 +77,28 @@ func (info NodeInfo) Validate() error { // Sanitize ASCII text fields. if !cmn.IsASCIIText(info.Moniker) || cmn.ASCIITrim(info.Moniker) == "" { - return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v.", info.Moniker) + return fmt.Errorf("info.Moniker must be valid non-empty ASCII text without tabs, but got %v", info.Moniker) } - for i, s := range info.Other { - if !cmn.IsASCIIText(s) || cmn.ASCIITrim(s) == "" { - return fmt.Errorf("info.Other[%v] must be valid non-empty ASCII text without tabs, but got %v.", i, s) + + // Sanitize versions + // XXX: Should we be more strict about version and address formats? + other := info.Other + versions := []string{other.AminoVersion, + other.AminoVersion, + other.P2PVersion, + other.ConsensusVersion, + other.RPCVersion} + for i, v := range versions { + if cmn.ASCIITrim(v) != "" && !cmn.IsASCIIText(v) { + return fmt.Errorf("info.Other[%d]=%v must be valid non-empty ASCII text without tabs", i, v) } } + if cmn.ASCIITrim(other.TxIndex) != "" && (other.TxIndex != "on" && other.TxIndex != "off") { + return fmt.Errorf("info.Other.TxIndex should be either 'on' or 'off', got '%v'", other.TxIndex) + } + if cmn.ASCIITrim(other.RPCAddress) != "" && !cmn.IsASCIIText(other.RPCAddress) { + return fmt.Errorf("info.Other.RPCAddress=%v must be valid non-empty ASCII text without tabs", other.RPCAddress) + } channels := make(map[byte]struct{}) for _, ch := range info.Channels { diff --git a/p2p/test_util.go b/p2p/test_util.go index 90bcba4f1..b88dfb06a 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -140,12 +140,21 @@ func MakeSwitch(cfg *config.P2PConfig, i int, network, version string, initSwitc sw := NewSwitch(cfg) sw.SetLogger(log.TestingLogger()) sw = initSwitch(i, sw) + addr := fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023) ni := NodeInfo{ ID: nodeKey.ID(), Moniker: fmt.Sprintf("switch%d", i), Network: network, Version: version, - ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023), + ListenAddr: addr, + Other: NodeInfoOther{ + AminoVersion: "1.0", + P2PVersion: "1.0", + ConsensusVersion: "1.0", + RPCVersion: "1.0", + TxIndex: "off", + RPCAddress: addr, + }, } for ch := range sw.reactorsByCh { ni.Channels = append(ni.Channels, ch) diff --git a/rpc/core/status.go b/rpc/core/status.go index e34f5244c..de8d69cce 100644 --- a/rpc/core/status.go +++ b/rpc/core/status.go @@ -25,43 +25,43 @@ import ( // > The above command returns JSON structured like this: // // ```json -//{ -// "jsonrpc": "2.0", -// "id": "", -// "result": { -// "node_info": { -// "id": "562dd7f579f0ecee8c94a11a3c1e378c1876f433", -// "listen_addr": "192.168.1.2:26656", -// "network": "test-chain-I6zScH", -// "version": "0.19.0", -// "channels": "4020212223303800", -// "moniker": "Ethans-MacBook-Pro.local", -// "other": [ -// "amino_version=0.9.8", -// "p2p_version=0.5.0", -// "consensus_version=v1/0.2.2", -// "rpc_version=0.7.0/3", -// "tx_index=on", -// "rpc_addr=tcp://0.0.0.0:26657" -// ] -// }, -// "sync_info": { -// "latest_block_hash": "2D4D7055BE685E3CB2410603C92AD37AE557AC59", -// "latest_app_hash": "0000000000000000", -// "latest_block_height": 231, -// "latest_block_time": "2018-04-27T23:18:08.459766485-04:00", -// "catching_up": false -// }, -// "validator_info": { -// "address": "5875562FF0FFDECC895C20E32FC14988952E99E7", -// "pub_key": { -// "type": "tendermint/PubKeyEd25519", -// "value": "PpDJRUrLG2RgFqYYjawfn/AcAgacSXpLFrmfYYQnuzE=" -// }, -// "voting_power": 10 -// } -// } -//} +// { +// "jsonrpc": "2.0", +// "id": "", +// "result": { +// "node_info": { +// "id": "53729852020041b956e86685e24394e0bee4373f", +// "listen_addr": "10.0.2.15:26656", +// "network": "test-chain-Y1OHx6", +// "version": "0.24.0-2ce1abc2", +// "channels": "4020212223303800", +// "moniker": "ubuntu-xenial", +// "other": { +// "amino_version": "0.12.0", +// "p2p_version": "0.5.0", +// "consensus_version": "v1/0.2.2", +// "rpc_version": "0.7.0/3", +// "tx_index": "on", +// "rpc_addr": "tcp://0.0.0.0:26657" +// } +// }, +// "sync_info": { +// "latest_block_hash": "F51538DA498299F4C57AC8162AAFA0254CE08286", +// "latest_app_hash": "0000000000000000", +// "latest_block_height": "18", +// "latest_block_time": "2018-09-17T11:42:19.149920551Z", +// "catching_up": false +// }, +// "validator_info": { +// "address": "D9F56456D7C5793815D0E9AF07C3A355D0FC64FD", +// "pub_key": { +// "type": "tendermint/PubKeyEd25519", +// "value": "wVxKNtEsJmR4vvh651LrVoRguPs+6yJJ9Bz174gw9DM=" +// }, +// "voting_power": "10" +// } +// } +// } // ``` func Status() (*ctypes.ResultStatus, error) { var latestHeight int64 = -1 diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index dbb50ff6b..77672910f 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -2,7 +2,6 @@ package core_types import ( "encoding/json" - "strings" "time" abci "github.com/tendermint/tendermint/abci/types" @@ -85,13 +84,7 @@ func (s *ResultStatus) TxIndexEnabled() bool { if s == nil { return false } - for _, s := range s.NodeInfo.Other { - info := strings.Split(s, "=") - if len(info) == 2 && info[0] == "tx_index" { - return info[1] == "on" - } - } - return false + return s.NodeInfo.Other.TxIndex == "on" } // Info about peer connections diff --git a/rpc/core/types/responses_test.go b/rpc/core/types/responses_test.go index e410d47ae..c6c86e1f7 100644 --- a/rpc/core/types/responses_test.go +++ b/rpc/core/types/responses_test.go @@ -9,31 +9,27 @@ import ( ) func TestStatusIndexer(t *testing.T) { - assert := assert.New(t) - var status *ResultStatus - assert.False(status.TxIndexEnabled()) + assert.False(t, status.TxIndexEnabled()) status = &ResultStatus{} - assert.False(status.TxIndexEnabled()) + assert.False(t, status.TxIndexEnabled()) status.NodeInfo = p2p.NodeInfo{} - assert.False(status.TxIndexEnabled()) + assert.False(t, status.TxIndexEnabled()) cases := []struct { expected bool - other []string + other p2p.NodeInfoOther }{ - {false, nil}, - {false, []string{}}, - {false, []string{"a=b"}}, - {false, []string{"tx_indexiskv", "some=dood"}}, - {true, []string{"tx_index=on", "tx_index=other"}}, - {true, []string{"^(*^(", "tx_index=on", "a=n=b=d="}}, + {false, p2p.NodeInfoOther{}}, + {false, p2p.NodeInfoOther{TxIndex: "aa"}}, + {false, p2p.NodeInfoOther{TxIndex: "off"}}, + {true, p2p.NodeInfoOther{TxIndex: "on"}}, } for _, tc := range cases { status.NodeInfo.Other = tc.other - assert.Equal(tc.expected, status.TxIndexEnabled()) + assert.Equal(t, tc.expected, status.TxIndexEnabled()) } } From 4fe990636131274846a118bbe9812bfbcb6b1194 Mon Sep 17 00:00:00 2001 From: Zach Date: Mon, 17 Sep 2018 12:43:10 -0400 Subject: [PATCH 12/47] docs: Update README (#2393) * update DOCS_README * add spec to docs & other lil fixes (#2402) --- docs/DOCS_README.md | 76 ++++++++++++++----- docs/README.md | 40 ++++++---- docs/config.js | 49 ++++++++++-- .../fast-sync.md | 0 4 files changed, 127 insertions(+), 38 deletions(-) rename docs/{networks => tendermint-core}/fast-sync.md (100%) diff --git a/docs/DOCS_README.md b/docs/DOCS_README.md index 01ec07ad9..0d1e3f979 100644 --- a/docs/DOCS_README.md +++ b/docs/DOCS_README.md @@ -1,31 +1,69 @@ -# Documentation Maintenance Overview +# Docs Build Workflow -The documentation found in this directory is hosted at: +The documentation for Tendermint Core is hosted at: -- https://tendermint.com/docs/ +- https://tendermint.com/docs/ and +- https://tendermint-staging.interblock.io/docs/ -and built using [VuePress](https://vuepress.vuejs.org/) like below: +built from the files in this (`/docs`) directory for +[master](https://github.com/tendermint/tendermint/tree/master/docs) +and [develop](https://github.com/tendermint/tendermint/tree/develop/docs), +respectively. -```bash -npm install -g vuepress # global install vuepress tool, only once -npm install +## How It Works -mkdir -p .vuepress && cp config.js .vuepress/ -vuepress build -``` +There is a Jenkins job listening for changes in the `/docs` directory, on both +the `master` and `develop` branches. Any updates to files in this directory +on those branches will automatically trigger a website deployment. Under the hood, +a private website repository has make targets consumed by a standard Jenkins task. -Under the hood, Jenkins listens for changes (on develop or master) in ./docs then rebuilds -either the staging or production site depending on which branch the changes were made. +## README -To update the Table of Contents (layout of the documentation sidebar), edit the -`config.js` in this directory, while the `README.md` is the landing page for the -website documentation. +The [README.md](./README.md) is also the landing page for the documentation +on the website. -To view the latest documentation on the develop branch, see the staging site: +## Config.js -- https://tendermint-staging.interblock.io/docs/ +The [config.js](./config.js) generates the sidebar and Table of Contents +on the website docs. Note the use of relative links and the omission of +file extensions. Additional features are available to improve the look +of the sidebar. + +## Links + +**NOTE:** Strongly consider the existing links - both within this directory +and to the website docs - when moving or deleting files. + +Relative links should be used nearly everywhere, having discovered and weighed the following: + +### Relative + +Where is the other file, relative to the current one? + +- works both on GitHub and for the VuePress build +- confusing / annoying to have things like: `../../../../myfile.md` +- requires more updates when files are re-shuffled + +### Absolute + +Where is the other file, given the root of the repo? + +- works on GitHub, doesn't work for the VuePress build +- this is much nicer: `/docs/hereitis/myfile.md` +- if you move that file around, the links inside it are preserved (but not to it, of course) + +### Full + +The full GitHub URL to a file or directory. Used occasionally when it makes sense +to send users to the GitHub. + +## Building Locally -and the documentation on master branch is found here: +Not currently possible but coming soon! Doing so requires +assets held in the (private) website repo, installing +[VuePress](https://vuepress.vuejs.org/), and modifying the `config.js`. -- https://tendermint.com/docs/ +## Consistency +Because the build processes are identical (as is the information contained herein), this file should be kept in sync as +much as possible with its [counterpart in the Cosmos SDK repo](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/DOCS_README.md). diff --git a/docs/README.md b/docs/README.md index 8c6c5d105..58b3bcb6b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,7 @@ # Tendermint -Welcome to the Tendermint Core documentation! The introduction below provides -an overview to help you navigate to your area of interest. - -## Introduction +Welcome to the Tendermint Core documentation! Below you'll find an +overview of the documentation. Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine - written in any programming language - and securely @@ -11,17 +9,33 @@ replicates it on many machines. In other words, a blockchain. Tendermint requires an application running over the Application Blockchain Interface (ABCI) - and comes packaged with an example application to do so. -Follow the [installation instructions](./introduction/install.md) to get up and running -quickly. For more details on [using tendermint](./tendermint-core/using-tendermint.md) see that -and the following sections. + +## Getting Started + +Here you'll find quick start guides and links to more advanced "get up and running" +documentation. + +## Core + +Details about the core functionality and configuration of Tendermint. + +## Tools + +Benchmarking and monitoring tools. ## Networks -Testnets can be setup manually on one or more machines, or automatically on one -or more machine, using a variety of methods described in the [deploy testnets -section](./networks/deploy-testnets.md). +Setting up testnets manually or automated, local or in the cloud. + +## Apps + +Building appplications with the ABCI. + +## Specification + +Dive deep into the spec. There's one for each Tendermint and the ABCI -## Application Development +## Edit the Documentation -The first step to building application on Tendermint is to [install -ABCI-CLI](./app-dev/getting-started.md) and play with the example applications. +See [this file](./DOCS_README.md) for details of the build process and +considerations when making changes. diff --git a/docs/config.js b/docs/config.js index a006a0756..983f0c678 100644 --- a/docs/config.js +++ b/docs/config.js @@ -27,6 +27,7 @@ module.exports = { "/tendermint-core/configuration", "/tendermint-core/rpc", "/tendermint-core/running-in-production", + "/tendermint-core/fast-sync", "/tendermint-core/how-to-read-logs", "/tendermint-core/block-structure", "/tendermint-core/light-client-protocol", @@ -36,21 +37,23 @@ module.exports = { ] }, { - title: "Tendermint Tools", + title: "Tools", collapsable: false, - children: ["tools/benchmarking", "tools/monitoring"] + children: [ + "tools/benchmarking", + "tools/monitoring" + ] }, { - title: "Tendermint Networks", + title: "Networks", collapsable: false, children: [ "/networks/deploy-testnets", "/networks/terraform-and-ansible", - "/networks/fast-sync" ] }, { - title: "Application Development", + title: "Apps", collapsable: false, children: [ "/app-dev/getting-started", @@ -62,6 +65,37 @@ module.exports = { "/app-dev/abci-spec", "/app-dev/ecosystem" ] + }, + title: "Tendermint Spec", + collapsable: true, + children: [ + "/spec/README", + "/spec/blockchain/blockchain", + "/spec/blockchain/encoding", + "/spec/blockchain/state", + "/spec/consensus/abci", + "/spec/consensus/bft-time", + "/spec/consensus/consensus", + "/spec/consensus/light-client", + "/spec/consensus/wal", + "/spec/p2p/config", + "/spec/p2p/connection", + "/spec/p2p/node", + "/spec/p2p/peer", + "/spec/reactors/block_sync/reactor", + "/spec/reactors/block_sync/impl", + "/spec/reactors/consensus/consensus", + "/spec/reactors/consensus/consensus-reactor", + "/spec/reactors/consensus/proposer-selection", + "/spec/reactors/evidence/reactor", + "/spec/reactors/mempool/concurrency", + "/spec/reactors/mempool/config", + "/spec/reactors/mempool/functionality", + "/spec/reactors/mempool/messages", + "/spec/reactors/mempool/reactor", + "/spec/reactors/pex/pex", + "/spec/reactors/pex/reactor", + ] }, { title: "ABCI Specification", @@ -75,7 +109,10 @@ module.exports = { { title: "Research", collapsable: false, - children: ["/research/determinism", "/research/transactional-semantics"] + children: [ + "/research/determinism", + "/research/transactional-semantics" + ] } ] } diff --git a/docs/networks/fast-sync.md b/docs/tendermint-core/fast-sync.md similarity index 100% rename from docs/networks/fast-sync.md rename to docs/tendermint-core/fast-sync.md From 38bced2440cc59b00f9782408559c0411a75ad43 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 18 Sep 2018 11:59:52 +0400 Subject: [PATCH 13/47] [types] add Address to GenesisValidator (#2418) Refs #1714 --- CHANGELOG_PENDING.md | 1 + cmd/tendermint/commands/init.go | 1 + cmd/tendermint/commands/testnet.go | 1 + state/execution_test.go | 5 ++++- types/genesis.go | 18 +++++++++++++----- types/genesis_test.go | 13 +++++++++++-- 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 2d77ed906..ad745fb82 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -20,5 +20,6 @@ FEATURES: * \#2310 Mempool is now aware of the MaxGas requirement IMPROVEMENTS: +- [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714) BUG FIXES: diff --git a/cmd/tendermint/commands/init.go b/cmd/tendermint/commands/init.go index dac4cd9a5..5136ded3c 100644 --- a/cmd/tendermint/commands/init.go +++ b/cmd/tendermint/commands/init.go @@ -58,6 +58,7 @@ func initFilesWithConfig(config *cfg.Config) error { ConsensusParams: types.DefaultConsensusParams(), } genDoc.Validators = []types.GenesisValidator{{ + Address: pv.GetPubKey().Address(), PubKey: pv.GetPubKey(), Power: 10, }} diff --git a/cmd/tendermint/commands/testnet.go b/cmd/tendermint/commands/testnet.go index d29c29eb1..19f137e4e 100644 --- a/cmd/tendermint/commands/testnet.go +++ b/cmd/tendermint/commands/testnet.go @@ -91,6 +91,7 @@ func testnetFiles(cmd *cobra.Command, args []string) error { pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator) pv := privval.LoadFilePV(pvFile) genVals[i] = types.GenesisValidator{ + Address: pv.GetPubKey().Address(), PubKey: pv.GetPubKey(), Power: 1, Name: nodeDirName, diff --git a/state/execution_test.go b/state/execution_test.go index 6a2008493..02beeb9b7 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -307,7 +307,10 @@ func state(nVals, height int) (State, dbm.DB) { secret := []byte(fmt.Sprintf("test%d", i)) pk := ed25519.GenPrivKeyFromSecret(secret) vals[i] = types.GenesisValidator{ - pk.PubKey(), 1000, fmt.Sprintf("test%d", i), + pk.PubKey().Address(), + pk.PubKey(), + 1000, + fmt.Sprintf("test%d", i), } } s, _ := MakeGenesisState(&types.GenesisDoc{ diff --git a/types/genesis.go b/types/genesis.go index 4cf3b7309..8684eb33b 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -21,9 +22,10 @@ const ( // GenesisValidator is an initial validator. type GenesisValidator struct { - PubKey crypto.PubKey `json:"pub_key"` - Power int64 `json:"power"` - Name string `json:"name"` + Address Address `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + Power int64 `json:"power"` + Name string `json:"name"` } // GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set. @@ -62,7 +64,7 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { return cmn.NewError("Genesis doc must include non-empty chain_id") } if len(genDoc.ChainID) > MaxChainIDLen { - return cmn.NewError(fmt.Sprintf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen)) + return cmn.NewError("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen) } if genDoc.ConsensusParams == nil { @@ -73,10 +75,16 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { } } - for _, v := range genDoc.Validators { + for i, v := range genDoc.Validators { if v.Power == 0 { return cmn.NewError("The genesis file cannot contain validators with no voting power: %v", v) } + if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) { + return cmn.NewError("Incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address()) + } + if len(v.Address) == 0 { + genDoc.Validators[i].Address = v.PubKey.Address() + } } if genDoc.GenesisTime.IsZero() { diff --git a/types/genesis_test.go b/types/genesis_test.go index c0cfcdeaa..a0686ce0d 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -22,6 +22,10 @@ func TestGenesisBad(t *testing.T) { []byte(`{"validators":[{"pub_key":{"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`), // missing chain_id []byte(`{"validators":[{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`), + // too big chain_id + []byte(`{"chain_id": "Lorem ipsum dolor sit amet, consectetuer adipiscing", "validators": [{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`), + // wrong address + []byte(`{"chain_id":"mychain", "validators":[{"address": "A", "pub_key":{"type":"tendermint/PubKeyEd25519","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`), } for _, testCase := range testCases { @@ -36,10 +40,11 @@ func TestGenesisGood(t *testing.T) { _, err := GenesisDocFromJSON(genDocBytes) assert.NoError(t, err, "expected no error for good genDoc json") + pubkey := ed25519.GenPrivKey().PubKey() // create a base gendoc from struct baseGenDoc := &GenesisDoc{ ChainID: "abc", - Validators: []GenesisValidator{{ed25519.GenPrivKey().PubKey(), 10, "myval"}}, + Validators: []GenesisValidator{{pubkey.Address(), pubkey, 10, "myval"}}, } genDocBytes, err = cdc.MarshalJSON(baseGenDoc) assert.NoError(t, err, "error marshalling genDoc") @@ -49,6 +54,9 @@ func TestGenesisGood(t *testing.T) { assert.NoError(t, err, "expected no error for valid genDoc json") assert.NotNil(t, genDoc.ConsensusParams, "expected consensus params to be filled in") + // check validator's address is filled + assert.NotNil(t, genDoc.Validators[0].Address, "expected validator's address to be filled in") + // create json with consensus params filled genDocBytes, err = cdc.MarshalJSON(genDoc) assert.NoError(t, err, "error marshalling genDoc") @@ -109,10 +117,11 @@ func TestGenesisValidatorHash(t *testing.T) { } func randomGenesisDoc() *GenesisDoc { + pubkey := ed25519.GenPrivKey().PubKey() return &GenesisDoc{ GenesisTime: tmtime.Now(), ChainID: "abc", - Validators: []GenesisValidator{{ed25519.GenPrivKey().PubKey(), 10, "myval"}}, + Validators: []GenesisValidator{{pubkey.Address(), pubkey, 10, "myval"}}, ConsensusParams: DefaultConsensusParams(), } } From 5bfb9001eb1edfdeabff61a53c5031271066bef5 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 5 Sep 2018 16:49:34 +0400 Subject: [PATCH 14/47] switch from jmhodges/levigo to DataDog/leveldb Why: original fork is abandoned and not supported anymore. Changes: - LevelDB 1.19 (LevelDB and Snappy are both compiled and linked statically, so while you will not need them installed on your target machine, you should have a roughly compatible version of libstdc++.) - snappy and lz4 libs included by default --- Gopkg.lock | 16 +++++------ Gopkg.toml | 4 +-- config/config.go | 8 +++--- config/toml.go | 2 +- docs/introduction/install.md | 41 ++++++++++++++++++++++++--- docs/tendermint-core/configuration.md | 2 +- libs/db/Makefile | 4 +++ libs/db/backend_test.go | 12 ++++---- libs/db/c_level_db.go | 2 +- libs/db/c_level_db_test.go | 7 +++-- 10 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 libs/db/Makefile diff --git a/Gopkg.lock b/Gopkg.lock index 8deb06378..9a27f344a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,6 +1,13 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + digest = "1:5da259989116f6ab5e05a80086c639c82efdbdb799ca07183eb0b660edfd91fe" + name = "github.com/DataDog/leveldb" + packages = ["."] + pruneopts = "UT" + revision = "12a0b6e10a5bf779330ed8b7c0f1f39f212d34e2" + [[projects]] branch = "master" digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" @@ -161,13 +168,6 @@ revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0" -[[projects]] - digest = "1:39b27d1381a30421f9813967a5866fba35dc1d4df43a6eefe3b7a5444cb07214" - name = "github.com/jmhodges/levigo" - packages = ["."] - pruneopts = "UT" - revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" - [[projects]] branch = "master" digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72" @@ -511,6 +511,7 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ + "github.com/DataDog/leveldb", "github.com/btcsuite/btcutil/base58", "github.com/btcsuite/btcutil/bech32", "github.com/ebuchman/fail-test", @@ -529,7 +530,6 @@ "github.com/golang/protobuf/proto", "github.com/golang/protobuf/ptypes/timestamp", "github.com/gorilla/websocket", - "github.com/jmhodges/levigo", "github.com/pkg/errors", "github.com/prometheus/client_golang/prometheus", "github.com/prometheus/client_golang/prometheus/promhttp", diff --git a/Gopkg.toml b/Gopkg.toml index d3bca19e8..cda7988c5 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -73,8 +73,8 @@ ## Pin to revision [[override]] - name = "github.com/jmhodges/levigo" - revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" + name = "github.com/DataDog/leveldb" + revision = "12a0b6e10a5bf779330ed8b7c0f1f39f212d34e2" [[constraint]] name = "github.com/ebuchman/fail-test" diff --git a/config/config.go b/config/config.go index c0882546f..d0e075477 100644 --- a/config/config.go +++ b/config/config.go @@ -113,7 +113,7 @@ type BaseConfig struct { // and verifying their commits FastSync bool `mapstructure:"fast_sync"` - // Database backend: leveldb | memdb + // Database backend: leveldb | memdb | cleveldb DBBackend string `mapstructure:"db_backend"` // Database directory @@ -587,15 +587,15 @@ type TxIndexConfig struct { // Comma-separated list of tags to index (by default the only tag is "tx.hash") // // You can also index transactions by height by adding "tx.height" tag here. - // + // // It's recommended to index only a subset of tags due to possible memory // bloat. This is, of course, depends on the indexer's DB and the volume of // transactions. IndexTags string `mapstructure:"index_tags"` // When set to true, tells indexer to index all tags (predefined tags: - // "tx.hash", "tx.height" and all tags from DeliverTx responses). - // + // "tx.hash", "tx.height" and all tags from DeliverTx responses). + // // Note this may be not desirable (see the comment above). IndexTags has a // precedence over IndexAllTags (i.e. when given both, IndexTags will be // indexed). diff --git a/config/toml.go b/config/toml.go index 2a35d7c36..9beb9d799 100644 --- a/config/toml.go +++ b/config/toml.go @@ -77,7 +77,7 @@ moniker = "{{ .BaseConfig.Moniker }}" # and verifying their commits fast_sync = {{ .BaseConfig.FastSync }} -# Database backend: leveldb | memdb +# Database backend: leveldb | memdb | cleveldb db_backend = "{{ .BaseConfig.DBBackend }}" # Database directory diff --git a/docs/introduction/install.md b/docs/introduction/install.md index 10b66dad0..925ed2a80 100644 --- a/docs/introduction/install.md +++ b/docs/introduction/install.md @@ -48,6 +48,15 @@ to put the binary in `./build`. The latest `tendermint version` is now installed. +## Run + +To start a one-node blockchain with a simple in-process application: + +``` +tendermint init +tendermint node --proxy_app=kvstore +``` + ## Reinstall If you already have Tendermint installed, and you make updates, simply @@ -66,11 +75,35 @@ make get_vendor_deps make install ``` -## Run +## Compile with CLevelDB support -To start a one-node blockchain with a simple in-process application: +Make sure you have a roughly compatible version of libstdc++ (tested with +5.3.1). For example, on Ubuntu: ``` -tendermint init -tendermint node --proxy_app=kvstore +sudo apt-get update +sudo apt-get install gcc +sudo apt-cache show libstdc++6 +Version: 5.3.1-14ubuntu2 +``` + +Check out leveldb dependency using git (for some reason dep does not check out +submodules): + +``` +cd vendor/github.com/DataDog && rm -rf leveldb +git clone https://github.com/DataDog/leveldb.git +``` + +Set database backend to cleveldb: + +``` +# config/config.toml +db_backend = "cleveldb" +``` + +To build Tendermint, run + +``` +CGO_ENABLED=1 CGO_CXXFLAGS_ALLOW="(-fno-builtin-memcmp|-lpthread)" CGO_CFLAGS_ALLOW="-fno-builtin-memcmp" go build -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`" -tags "tendermint gcc" -o build/tendermint ./cmd/tendermint/ ``` diff --git a/docs/tendermint-core/configuration.md b/docs/tendermint-core/configuration.md index 7e20277f4..29db12125 100644 --- a/docs/tendermint-core/configuration.md +++ b/docs/tendermint-core/configuration.md @@ -30,7 +30,7 @@ moniker = "anonymous" # and verifying their commits fast_sync = true -# Database backend: leveldb | memdb +# Database backend: leveldb | memdb | cleveldb db_backend = "leveldb" # Database directory diff --git a/libs/db/Makefile b/libs/db/Makefile new file mode 100644 index 000000000..e0cd45b0a --- /dev/null +++ b/libs/db/Makefile @@ -0,0 +1,4 @@ +test_gcc: + CGO_CXXFLAGS_ALLOW="(-fno-builtin-memcmp|-lpthread)" CGO_CFLAGS_ALLOW="-fno-builtin-memcmp" go test -tags gcc + +.PHONY: test_gcc diff --git a/libs/db/backend_test.go b/libs/db/backend_test.go index 496f4c410..a93698226 100644 --- a/libs/db/backend_test.go +++ b/libs/db/backend_test.go @@ -55,9 +55,10 @@ func TestBackendsGetSetDelete(t *testing.T) { func withDB(t *testing.T, creator dbCreator, fn func(DB)) { name := fmt.Sprintf("test_%x", cmn.RandStr(12)) - db, err := creator(name, "") - defer cleanupDBDir("", name) - assert.Nil(t, err) + dir := os.TempDir() + db, err := creator(name, dir) + require.Nil(t, err) + defer cleanupDBDir(dir, name) fn(db) db.Close() } @@ -161,8 +162,9 @@ func TestDBIterator(t *testing.T) { func testDBIterator(t *testing.T, backend DBBackendType) { name := fmt.Sprintf("test_%x", cmn.RandStr(12)) - db := NewDB(name, backend, "") - defer cleanupDBDir("", name) + dir := os.TempDir() + db := NewDB(name, backend, dir) + defer cleanupDBDir(dir, name) for i := 0; i < 10; i++ { if i != 6 { // but skip 6. diff --git a/libs/db/c_level_db.go b/libs/db/c_level_db.go index 307461261..10f03aa0c 100644 --- a/libs/db/c_level_db.go +++ b/libs/db/c_level_db.go @@ -7,7 +7,7 @@ import ( "fmt" "path/filepath" - "github.com/jmhodges/levigo" + levigo "github.com/DataDog/leveldb" ) func init() { diff --git a/libs/db/c_level_db_test.go b/libs/db/c_level_db_test.go index d01a85e9d..c81b4185a 100644 --- a/libs/db/c_level_db_test.go +++ b/libs/db/c_level_db_test.go @@ -5,9 +5,11 @@ package db import ( "bytes" "fmt" + "os" "testing" "github.com/stretchr/testify/assert" + cmn "github.com/tendermint/tendermint/libs/common" ) @@ -88,8 +90,9 @@ func bytes2Int64(buf []byte) int64 { func TestCLevelDBBackend(t *testing.T) { name := fmt.Sprintf("test_%x", cmn.RandStr(12)) - db := NewDB(name, LevelDBBackend, "") - defer cleanupDBDir("", name) + dir := os.TempDir() + db := NewDB(name, LevelDBBackend, dir) + defer cleanupDBDir(dir, name) _, ok := db.(*CLevelDB) assert.True(t, ok) From 76302c651f786f3662011d3120d2de2bbd26956f Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 5 Sep 2018 16:53:51 +0400 Subject: [PATCH 15/47] remove LICENSE from libs/db in favor of root license --- libs/db/LICENSE.md | 3 --- libs/db/README.md | 1 - 2 files changed, 4 deletions(-) delete mode 100644 libs/db/LICENSE.md delete mode 100644 libs/db/README.md diff --git a/libs/db/LICENSE.md b/libs/db/LICENSE.md deleted file mode 100644 index ab8da59d8..000000000 --- a/libs/db/LICENSE.md +++ /dev/null @@ -1,3 +0,0 @@ -Tendermint Go-DB Copyright (C) 2015 All in Bits, Inc - -Released under the Apache2.0 license diff --git a/libs/db/README.md b/libs/db/README.md deleted file mode 100644 index ca5ab33f9..000000000 --- a/libs/db/README.md +++ /dev/null @@ -1 +0,0 @@ -TODO: syndtr/goleveldb should be replaced with actual LevelDB instance From 747797bf3b2581408ae69bdfd158b0df3435f563 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 5 Sep 2018 17:08:51 +0400 Subject: [PATCH 16/47] cleanup after tests! --- libs/db/backend_test.go | 6 +++++- libs/db/c_level_db_test.go | 4 +++- libs/db/common_test.go | 5 ++--- libs/db/db_test.go | 24 ++++++++++++++++++------ libs/db/go_level_db_test.go | 2 ++ libs/db/util_test.go | 16 +++++++++++----- 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/libs/db/backend_test.go b/libs/db/backend_test.go index a93698226..2aebde1c6 100644 --- a/libs/db/backend_test.go +++ b/libs/db/backend_test.go @@ -13,7 +13,10 @@ import ( ) func cleanupDBDir(dir, name string) { - os.RemoveAll(filepath.Join(dir, name) + ".db") + err := os.RemoveAll(filepath.Join(dir, name) + ".db") + if err != nil { + panic(err) + } } func testBackendGetSetDelete(t *testing.T, backend DBBackendType) { @@ -21,6 +24,7 @@ func testBackendGetSetDelete(t *testing.T, backend DBBackendType) { dirname, err := ioutil.TempDir("", fmt.Sprintf("test_backend_%s_", backend)) require.Nil(t, err) db := NewDB("testdb", backend, dirname) + defer cleanupDBDir(dirname, "testdb") // A nonexistent key should return nil, even if the key is empty require.Nil(t, db.Get([]byte(""))) diff --git a/libs/db/c_level_db_test.go b/libs/db/c_level_db_test.go index c81b4185a..eab3dfc41 100644 --- a/libs/db/c_level_db_test.go +++ b/libs/db/c_level_db_test.go @@ -34,7 +34,7 @@ func BenchmarkRandomReadsWrites2(b *testing.B) { // Write something { idx := (int64(cmn.RandInt()) % numItems) - internal[idx] += 1 + internal[idx]++ val := internal[idx] idxBytes := int642Bytes(int64(idx)) valBytes := int642Bytes(int64(val)) @@ -90,6 +90,8 @@ func bytes2Int64(buf []byte) int64 { func TestCLevelDBBackend(t *testing.T) { name := fmt.Sprintf("test_%x", cmn.RandStr(12)) + // Can't use "" (current directory) or "./" here because levigo.Open returns: + // "Error initializing DB: IO error: test_XXX.db: Invalid argument" dir := os.TempDir() db := NewDB(name, LevelDBBackend, dir) defer cleanupDBDir(dir, name) diff --git a/libs/db/common_test.go b/libs/db/common_test.go index 68420cd2b..13e6ed377 100644 --- a/libs/db/common_test.go +++ b/libs/db/common_test.go @@ -60,11 +60,10 @@ func checkValuePanics(t *testing.T, itr Iterator) { assert.Panics(t, func() { itr.Key() }, "checkValuePanics expected panic but didn't") } -func newTempDB(t *testing.T, backend DBBackendType) (db DB) { +func newTempDB(t *testing.T, backend DBBackendType) (db DB, dbDir string) { dirname, err := ioutil.TempDir("", "db_common_test") require.Nil(t, err) - db = NewDB("testdb", backend, dirname) - return db + return NewDB("testdb", backend, dirname), dirname } //---------------------------------------- diff --git a/libs/db/db_test.go b/libs/db/db_test.go index a56901016..ffa7bb6aa 100644 --- a/libs/db/db_test.go +++ b/libs/db/db_test.go @@ -2,6 +2,7 @@ package db import ( "fmt" + "os" "testing" "github.com/stretchr/testify/assert" @@ -10,7 +11,9 @@ import ( func TestDBIteratorSingleKey(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) + db.SetSync(bz("1"), bz("value_1")) itr := db.Iterator(nil, nil) @@ -28,7 +31,9 @@ func TestDBIteratorSingleKey(t *testing.T) { func TestDBIteratorTwoKeys(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) + db.SetSync(bz("1"), bz("value_1")) db.SetSync(bz("2"), bz("value_1")) @@ -54,7 +59,8 @@ func TestDBIteratorTwoKeys(t *testing.T) { func TestDBIteratorMany(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) keys := make([][]byte, 100) for i := 0; i < 100; i++ { @@ -78,7 +84,9 @@ func TestDBIteratorMany(t *testing.T) { func TestDBIteratorEmpty(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) + itr := db.Iterator(nil, nil) checkInvalid(t, itr) @@ -89,7 +97,9 @@ func TestDBIteratorEmpty(t *testing.T) { func TestDBIteratorEmptyBeginAfter(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) + itr := db.Iterator(bz("1"), nil) checkInvalid(t, itr) @@ -100,7 +110,9 @@ func TestDBIteratorEmptyBeginAfter(t *testing.T) { func TestDBIteratorNonemptyBeginAfter(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) + db.SetSync(bz("1"), bz("value_1")) itr := db.Iterator(bz("2"), nil) diff --git a/libs/db/go_level_db_test.go b/libs/db/go_level_db_test.go index 2b2346588..c24eec3c8 100644 --- a/libs/db/go_level_db_test.go +++ b/libs/db/go_level_db_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "fmt" + "os" "testing" "github.com/syndtr/goleveldb/leveldb/opt" @@ -17,6 +18,7 @@ func TestNewGoLevelDB(t *testing.T) { // Test write locks db, err := NewGoLevelDB(name, "") require.Nil(t, err) + defer os.RemoveAll("./" + name + ".db") _, err = NewGoLevelDB(name, "") require.NotNil(t, err) db.Close() // Close the db to release the lock diff --git a/libs/db/util_test.go b/libs/db/util_test.go index 44f1f9f73..07f9dd23e 100644 --- a/libs/db/util_test.go +++ b/libs/db/util_test.go @@ -2,6 +2,7 @@ package db import ( "fmt" + "os" "testing" ) @@ -9,7 +10,8 @@ import ( func TestPrefixIteratorNoMatchNil(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) itr := IteratePrefix(db, []byte("2")) checkInvalid(t, itr) @@ -21,7 +23,8 @@ func TestPrefixIteratorNoMatchNil(t *testing.T) { func TestPrefixIteratorNoMatch1(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) itr := IteratePrefix(db, []byte("2")) db.SetSync(bz("1"), bz("value_1")) @@ -34,7 +37,8 @@ func TestPrefixIteratorNoMatch1(t *testing.T) { func TestPrefixIteratorNoMatch2(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) db.SetSync(bz("3"), bz("value_3")) itr := IteratePrefix(db, []byte("4")) @@ -47,7 +51,8 @@ func TestPrefixIteratorNoMatch2(t *testing.T) { func TestPrefixIteratorMatch1(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) db.SetSync(bz("2"), bz("value_2")) itr := IteratePrefix(db, bz("2")) @@ -65,7 +70,8 @@ func TestPrefixIteratorMatch1(t *testing.T) { func TestPrefixIteratorMatches1N(t *testing.T) { for backend := range backends { t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) { - db := newTempDB(t, backend) + db, dir := newTempDB(t, backend) + defer os.RemoveAll(dir) // prefixed db.SetSync(bz("a/1"), bz("value_1")) From 484194789fc4f5f62101ce96bee25e2e1da73244 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 10 Sep 2018 14:55:06 +0400 Subject: [PATCH 17/47] update Vagrantfile to install go1.11 --- Vagrantfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 095a6b061..320f3b1c3 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -29,10 +29,10 @@ Vagrant.configure("2") do |config| usermod -a -G docker vagrant # install go - wget -q https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz - tar -xvf go1.10.1.linux-amd64.tar.gz + wget -q https://dl.google.com/go/go1.11.linux-amd64.tar.gz + tar -xvf go1.11.linux-amd64.tar.gz mv go /usr/local - rm -f go1.10.1.linux-amd64.tar.gz + rm -f go1.11.linux-amd64.tar.gz # cleanup apt-get autoremove -y From 788474d08d460b5d6074690adcade1ac1688c1d7 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 12 Sep 2018 13:12:12 +0400 Subject: [PATCH 18/47] change consensus_block_interval_seconds metric type to gauge Otherwise, it's impossible to see outliers https://github.com/tendermint/tendermint/issues/1835#issuecomment-402054099 --- CHANGELOG_PENDING.md | 1 + consensus/metrics.go | 8 ++++---- consensus/state.go | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index ad745fb82..bf4f3348b 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -21,5 +21,6 @@ FEATURES: IMPROVEMENTS: - [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714) +- [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) BUG FIXES: diff --git a/consensus/metrics.go b/consensus/metrics.go index 253880e84..91ae738d5 100644 --- a/consensus/metrics.go +++ b/consensus/metrics.go @@ -30,7 +30,7 @@ type Metrics struct { ByzantineValidatorsPower metrics.Gauge // Time between this and the last block. - BlockIntervalSeconds metrics.Histogram + BlockIntervalSeconds metrics.Gauge // Number of transactions. NumTxs metrics.Gauge @@ -85,11 +85,11 @@ func PrometheusMetrics() *Metrics { Help: "Total power of the byzantine validators.", }, []string{}), - BlockIntervalSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{ + + BlockIntervalSeconds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ Subsystem: "consensus", Name: "block_interval_seconds", Help: "Time between this and the last block.", - Buckets: []float64{1, 2.5, 5, 10, 60}, }, []string{}), NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ @@ -124,7 +124,7 @@ func NopMetrics() *Metrics { ByzantineValidators: discard.NewGauge(), ByzantineValidatorsPower: discard.NewGauge(), - BlockIntervalSeconds: discard.NewHistogram(), + BlockIntervalSeconds: discard.NewGauge(), NumTxs: discard.NewGauge(), BlockSizeBytes: discard.NewGauge(), diff --git a/consensus/state.go b/consensus/state.go index 63b10e0bf..bee0f893e 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1374,7 +1374,7 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) { if height > 1 { lastBlockMeta := cs.blockStore.LoadBlockMeta(height - 1) - cs.metrics.BlockIntervalSeconds.Observe( + cs.metrics.BlockIntervalSeconds.Set( block.Time.Sub(lastBlockMeta.Header.Time).Seconds(), ) } From ff9d0cdfb62f89bdcc522366facaca4e81b743ab Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 14 Sep 2018 12:35:41 +0400 Subject: [PATCH 19/47] generate random txs otherwise we're benchmarking overriding single key (because hash stays the same!) --- state/txindex/kv/kv_test.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/state/txindex/kv/kv_test.go b/state/txindex/kv/kv_test.go index 67fdf9e24..f6ebe822c 100644 --- a/state/txindex/kv/kv_test.go +++ b/state/txindex/kv/kv_test.go @@ -190,34 +190,34 @@ func txResultWithTags(tags []cmn.KVPair) *types.TxResult { } func benchmarkTxIndex(txsCount int64, b *testing.B) { - tx := types.Tx("HELLO WORLD") - txResult := &types.TxResult{ - Height: 1, - Index: 0, - Tx: tx, - Result: abci.ResponseDeliverTx{ - Data: []byte{0}, - Code: abci.CodeTypeOK, - Log: "", - Tags: []cmn.KVPair{}, - }, - } - dir, err := ioutil.TempDir("", "tx_index_db") if err != nil { b.Fatal(err) } defer os.RemoveAll(dir) // nolint: errcheck - store := db.NewDB("tx_index", "leveldb", dir) + store := db.NewDB("tx_index", "bboltdb", dir) indexer := NewTxIndex(store) batch := txindex.NewBatch(txsCount) + txIndex := uint32(0) for i := int64(0); i < txsCount; i++ { + tx := cmn.RandBytes(250) + txResult := &types.TxResult{ + Height: 1, + Index: txIndex, + Tx: tx, + Result: abci.ResponseDeliverTx{ + Data: []byte{0}, + Code: abci.CodeTypeOK, + Log: "", + Tags: []cmn.KVPair{}, + }, + } if err := batch.Add(txResult); err != nil { b.Fatal(err) } - txResult.Index++ + txIndex++ } b.ResetTimer() From e1bda36c6ccc665df14819c82e38d67a1f0399b7 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 17 Sep 2018 13:25:17 +0400 Subject: [PATCH 20/47] switch back to original fork --- Gopkg.lock | 16 ++++++++-------- Gopkg.toml | 4 ++-- docs/introduction/install.md | 26 ++++++++++++++------------ libs/db/Makefile | 4 ---- libs/db/c_level_db.go | 2 +- state/txindex/kv/kv_test.go | 2 +- 6 files changed, 26 insertions(+), 28 deletions(-) delete mode 100644 libs/db/Makefile diff --git a/Gopkg.lock b/Gopkg.lock index 9a27f344a..8deb06378 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,13 +1,6 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - digest = "1:5da259989116f6ab5e05a80086c639c82efdbdb799ca07183eb0b660edfd91fe" - name = "github.com/DataDog/leveldb" - packages = ["."] - pruneopts = "UT" - revision = "12a0b6e10a5bf779330ed8b7c0f1f39f212d34e2" - [[projects]] branch = "master" digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" @@ -168,6 +161,13 @@ revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0" +[[projects]] + digest = "1:39b27d1381a30421f9813967a5866fba35dc1d4df43a6eefe3b7a5444cb07214" + name = "github.com/jmhodges/levigo" + packages = ["."] + pruneopts = "UT" + revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" + [[projects]] branch = "master" digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72" @@ -511,7 +511,6 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ - "github.com/DataDog/leveldb", "github.com/btcsuite/btcutil/base58", "github.com/btcsuite/btcutil/bech32", "github.com/ebuchman/fail-test", @@ -530,6 +529,7 @@ "github.com/golang/protobuf/proto", "github.com/golang/protobuf/ptypes/timestamp", "github.com/gorilla/websocket", + "github.com/jmhodges/levigo", "github.com/pkg/errors", "github.com/prometheus/client_golang/prometheus", "github.com/prometheus/client_golang/prometheus/promhttp", diff --git a/Gopkg.toml b/Gopkg.toml index cda7988c5..d3bca19e8 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -73,8 +73,8 @@ ## Pin to revision [[override]] - name = "github.com/DataDog/leveldb" - revision = "12a0b6e10a5bf779330ed8b7c0f1f39f212d34e2" + name = "github.com/jmhodges/levigo" + revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" [[constraint]] name = "github.com/ebuchman/fail-test" diff --git a/docs/introduction/install.md b/docs/introduction/install.md index 925ed2a80..c7b83b03c 100644 --- a/docs/introduction/install.md +++ b/docs/introduction/install.md @@ -77,22 +77,24 @@ make install ## Compile with CLevelDB support -Make sure you have a roughly compatible version of libstdc++ (tested with -5.3.1). For example, on Ubuntu: +Install [LevelDB](https://github.com/google/leveldb) (minimum version is 1.7) +with snappy. Example for Ubuntu: ``` sudo apt-get update -sudo apt-get install gcc -sudo apt-cache show libstdc++6 -Version: 5.3.1-14ubuntu2 -``` +sudo apt install build-essential -Check out leveldb dependency using git (for some reason dep does not check out -submodules): +sudo apt-get install libsnappy-dev -``` -cd vendor/github.com/DataDog && rm -rf leveldb -git clone https://github.com/DataDog/leveldb.git +wget https://github.com/google/leveldb/archive/v1.20.tar.gz && \ + tar -zxvf v1.20.tar.gz && \ + cd leveldb-1.20/ && \ + make && \ + sudo scp -r out-static/lib* out-shared/lib* /usr/local/lib/ && \ + cd include/ && \ + sudo scp -r leveldb /usr/local/include/ && \ + sudo ldconfig && \ + rm -f v1.20.tar.gz ``` Set database backend to cleveldb: @@ -105,5 +107,5 @@ db_backend = "cleveldb" To build Tendermint, run ``` -CGO_ENABLED=1 CGO_CXXFLAGS_ALLOW="(-fno-builtin-memcmp|-lpthread)" CGO_CFLAGS_ALLOW="-fno-builtin-memcmp" go build -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`" -tags "tendermint gcc" -o build/tendermint ./cmd/tendermint/ +CGO_LDFLAGS="-lsnappy" go build -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`" -tags "tendermint gcc" -o build/tendermint ./cmd/tendermint/ ``` diff --git a/libs/db/Makefile b/libs/db/Makefile deleted file mode 100644 index e0cd45b0a..000000000 --- a/libs/db/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -test_gcc: - CGO_CXXFLAGS_ALLOW="(-fno-builtin-memcmp|-lpthread)" CGO_CFLAGS_ALLOW="-fno-builtin-memcmp" go test -tags gcc - -.PHONY: test_gcc diff --git a/libs/db/c_level_db.go b/libs/db/c_level_db.go index 10f03aa0c..307461261 100644 --- a/libs/db/c_level_db.go +++ b/libs/db/c_level_db.go @@ -7,7 +7,7 @@ import ( "fmt" "path/filepath" - levigo "github.com/DataDog/leveldb" + "github.com/jmhodges/levigo" ) func init() { diff --git a/state/txindex/kv/kv_test.go b/state/txindex/kv/kv_test.go index f6ebe822c..78a76168d 100644 --- a/state/txindex/kv/kv_test.go +++ b/state/txindex/kv/kv_test.go @@ -196,7 +196,7 @@ func benchmarkTxIndex(txsCount int64, b *testing.B) { } defer os.RemoveAll(dir) // nolint: errcheck - store := db.NewDB("tx_index", "bboltdb", dir) + store := db.NewDB("tx_index", "leveldb", dir) indexer := NewTxIndex(store) batch := txindex.NewBatch(txsCount) From 2fbf810cd832922d113a888f0c9ecbfbdafe8916 Mon Sep 17 00:00:00 2001 From: Zarko Milosevic Date: Tue, 18 Sep 2018 11:16:50 +0200 Subject: [PATCH 21/47] Delay starting node until Genesis time (#2389) --- CHANGELOG_PENDING.md | 1 + node/node.go | 9 +++++++++ node/node_test.go | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index bf4f3348b..c4b776246 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -24,3 +24,4 @@ IMPROVEMENTS: - [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) BUG FIXES: +- [node] \#2294 Delay starting node until Genesis time diff --git a/node/node.go b/node/node.go index 7f288fe4c..c623e620f 100644 --- a/node/node.go +++ b/node/node.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "net/http" + "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -37,6 +38,7 @@ import ( "github.com/tendermint/tendermint/state/txindex/kv" "github.com/tendermint/tendermint/state/txindex/null" "github.com/tendermint/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" _ "net/http/pprof" @@ -427,6 +429,13 @@ func NewNode(config *cfg.Config, // OnStart starts the Node. It implements cmn.Service. func (n *Node) OnStart() error { + now := tmtime.Now() + genTime := n.genesisDoc.GenesisTime + if genTime.After(now) { + n.Logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime) + time.Sleep(genTime.Sub(now)) + } + err := n.eventBus.Start() if err != nil { return err diff --git a/node/node_test.go b/node/node_test.go index d4e35f735..f4c1f6a16 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -14,6 +14,8 @@ import ( cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/types" + + tmtime "github.com/tendermint/tendermint/types/time" ) func TestNodeStartStop(t *testing.T) { @@ -75,3 +77,17 @@ func TestSplitAndTrimEmpty(t *testing.T) { assert.Equal(t, tc.expected, splitAndTrimEmpty(tc.s, tc.sep, tc.cutset), "%s", tc.s) } } + +func TestNodeDelayedStop(t *testing.T) { + config := cfg.ResetTestRoot("node_delayed_node_test") + now := tmtime.Now() + + // create & start node + n, err := DefaultNewNode(config, log.TestingLogger()) + n.GenesisDoc().GenesisTime = now.Add(5 * time.Second) + assert.NoError(t, err) + + n.Start() + startTime := tmtime.Now() + assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime)) +} From 89462c52d9fa9d9a52ee6d7995a777a1bcc1f51d Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 18 Sep 2018 13:28:32 +0400 Subject: [PATCH 22/47] spec: add missing field to NodeInfoOther (#2426) and fix formatting Refs https://github.com/tendermint/tendermint/pull/2417#discussion_r218080500 --- docs/spec/p2p/peer.md | 1 + p2p/node_info.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/spec/p2p/peer.md b/docs/spec/p2p/peer.md index eb344c291..8f8f12b13 100644 --- a/docs/spec/p2p/peer.md +++ b/docs/spec/p2p/peer.md @@ -92,6 +92,7 @@ type NodeInfoOther struct { ConsensusVersion string RPCVersion string TxIndex string + RPCAddress string } ``` diff --git a/p2p/node_info.go b/p2p/node_info.go index c0718deee..a0df3d374 100644 --- a/p2p/node_info.go +++ b/p2p/node_info.go @@ -83,7 +83,8 @@ func (info NodeInfo) Validate() error { // Sanitize versions // XXX: Should we be more strict about version and address formats? other := info.Other - versions := []string{other.AminoVersion, + versions := []string{ + other.AminoVersion, other.AminoVersion, other.P2PVersion, other.ConsensusVersion, From be5d68ea4fd5ea249d4598f82fd4a35c2d84cace Mon Sep 17 00:00:00 2001 From: Alexander Simmerl Date: Tue, 18 Sep 2018 22:11:54 +0200 Subject: [PATCH 23/47] p2p: Implement PeerTransport This is the implementation for the design described in ADR 12[0]. It's the first step of a larger refactor of the p2p package as tracked in interface bundling all concerns of low-level connection handling and isolating the rest of peer lifecycle management from the specifics of the low-level internet protocols. Even if the swappable implementation will never be utilised, already the isolation of conn related code in one place will help with the reasoning about execution path and addressation of security sensitive issues surfaced through bounty programs and audits. We deliberately decided to not have Peer filtering and other management in the Transport, its sole responsibility is the translation of connections to Peers, handing those to the caller fully setup. It's the responsibility of the caller to reject those and or keep track. Peer filtering will take place in the Switch and can be inspected in a the following commit. This changeset additionally is an exercise in clean separation of logic and other infrastructural concerns like logging and instrumentation. By leveraging a clean and minimal interface. How this looks can be seen in a follow-up change. Design #2069[2] Refs #2067[3] Fixes #2047[4] Fixes #2046[5] changes: * describe Transport interface * implement new default Transport: MultiplexTransport * test MultiplexTransport with new constraints * implement ConnSet for concurrent management of net.Conn, synchronous to PeerSet * implement and expose duplicate IP filter * implemnt TransportOption for optional parametirisation [0] https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-012-peer-transport.md [1] https://github.com/tendermint/tendermint/issues/2067 [2] https://github.com/tendermint/tendermint/pull/2069 [3] https://github.com/tendermint/tendermint/issues/2067 [4] https://github.com/tendermint/tendermint/issues/2047 [5] https://github.com/tendermint/tendermint/issues/2046 --- p2p/conn_set.go | 73 +++++ p2p/transport.go | 494 ++++++++++++++++++++++++++++++++ p2p/transport_test.go | 636 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1203 insertions(+) create mode 100644 p2p/conn_set.go create mode 100644 p2p/transport.go create mode 100644 p2p/transport_test.go diff --git a/p2p/conn_set.go b/p2p/conn_set.go new file mode 100644 index 000000000..f960c0e88 --- /dev/null +++ b/p2p/conn_set.go @@ -0,0 +1,73 @@ +package p2p + +import ( + "net" + "sync" +) + +// ConnSet is a lookup table for connections and all their ips. +type ConnSet interface { + Has(net.Conn) bool + HasIP(net.IP) bool + Set(net.Conn, []net.IP) + Remove(net.Conn) +} + +type connSetItem struct { + conn net.Conn + ips []net.IP +} + +type connSet struct { + sync.RWMutex + + conns map[string]connSetItem +} + +// NewConnSet returns a ConnSet implementation. +func NewConnSet() *connSet { + return &connSet{ + conns: map[string]connSetItem{}, + } +} + +func (cs *connSet) Has(c net.Conn) bool { + cs.RLock() + defer cs.RUnlock() + + _, ok := cs.conns[c.RemoteAddr().String()] + + return ok +} + +func (cs *connSet) HasIP(ip net.IP) bool { + cs.RLock() + defer cs.RUnlock() + + for _, c := range cs.conns { + for _, known := range c.ips { + if known.Equal(ip) { + return true + } + } + } + + return false +} + +func (cs *connSet) Remove(c net.Conn) { + cs.Lock() + defer cs.Unlock() + + delete(cs.conns, c.RemoteAddr().String()) +} + +func (cs *connSet) Set(c net.Conn, ips []net.IP) { + cs.Lock() + defer cs.Unlock() + + cs.conns[c.RemoteAddr().String()] = connSetItem{ + conn: c, + ips: ips, + } +} diff --git a/p2p/transport.go b/p2p/transport.go new file mode 100644 index 000000000..61cff55d9 --- /dev/null +++ b/p2p/transport.go @@ -0,0 +1,494 @@ +package p2p + +import ( + "context" + "fmt" + "net" + "time" + + "github.com/tendermint/tendermint/config" + crypto "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/p2p/conn" +) + +const ( + defaultDialTimeout = time.Second + defaultFilterTimeout = 5 * time.Second + defaultHandshakeTimeout = 3 * time.Second +) + +// IPResolver is a behaviour subset of net.Resolver. +type IPResolver interface { + LookupIPAddr(context.Context, string) ([]net.IPAddr, error) +} + +// accept is the container to carry the upgraded connection and NodeInfo from an +// asynchronously running routine to the Accept method. +type accept struct { + conn net.Conn + nodeInfo NodeInfo + err error +} + +// peerConfig is used to bundle data we need to fully setup a Peer with an +// MConn, provided by the caller of Accept and Dial (currently the Switch). This +// a temporary measure until reactor setup is less dynamic and we introduce the +// concept of PeerBehaviour to communicate about significant Peer lifecycle +// events. +// TODO(xla): Refactor out with more static Reactor setup and PeerBehaviour. +type peerConfig struct { + chDescs []*conn.ChannelDescriptor + onPeerError func(Peer, interface{}) + outbound, persistent bool + reactorsByCh map[byte]Reactor +} + +// Transport emits and connects to Peers. The implementation of Peer is left to +// the transport. Each transport is also responsible to filter establishing +// peers specific to its domain. +type Transport interface { + // Accept returns a newly connected Peer. + Accept(peerConfig) (Peer, error) + + // Dial connects to the Peer for the address. + Dial(NetAddress, peerConfig) (Peer, error) +} + +// transportLifecycle bundles the methods for callers to control start and stop +// behaviour. +type transportLifecycle interface { + Close() error + Listen(NetAddress) error +} + +// ConnFilterFunc to be implemented by filter hooks after a new connection has +// been established. The set of exisiting connections is passed along together +// with all resolved IPs for the new connection. +type ConnFilterFunc func(ConnSet, net.Conn, []net.IP) error + +// ConnDuplicateIPFilter resolves and keeps all ips for an incoming connection +// and refuses new ones if they come from a known ip. +func ConnDuplicateIPFilter() ConnFilterFunc { + return func(cs ConnSet, c net.Conn, ips []net.IP) error { + for _, ip := range ips { + if cs.HasIP(ip) { + return ErrRejected{ + conn: c, + err: fmt.Errorf("IP<%v> already connected", ip), + isDuplicate: true, + } + } + } + + return nil + } +} + +// MultiplexTransportOption sets an optional parameter on the +// MultiplexTransport. +type MultiplexTransportOption func(*MultiplexTransport) + +// MultiplexTransportConnFilters sets the filters for rejection new connections. +func MultiplexTransportConnFilters( + filters ...ConnFilterFunc, +) MultiplexTransportOption { + return func(mt *MultiplexTransport) { mt.connFilters = filters } +} + +// MultiplexTransportFilterTimeout sets the timeout waited for filter calls to +// return. +func MultiplexTransportFilterTimeout( + timeout time.Duration, +) MultiplexTransportOption { + return func(mt *MultiplexTransport) { mt.filterTimeout = timeout } +} + +// MultiplexTransportResolver sets the Resolver used for ip lokkups, defaults to +// net.DefaultResolver. +func MultiplexTransportResolver(resolver IPResolver) MultiplexTransportOption { + return func(mt *MultiplexTransport) { mt.resolver = resolver } +} + +// MultiplexTransport accepts and dials tcp connections and upgrades them to +// multiplexed peers. +type MultiplexTransport struct { + listener net.Listener + + acceptc chan accept + closec chan struct{} + + // Lookup table for duplicate ip and id checks. + conns ConnSet + connFilters []ConnFilterFunc + + dialTimeout time.Duration + filterTimeout time.Duration + handshakeTimeout time.Duration + nodeInfo NodeInfo + nodeKey NodeKey + resolver IPResolver + + // TODO(xla): Those configs are still needed as we parameterise peerConn and + // peer currently. All relevant configuration should be refactored into options + // with sane defaults. + mConfig conn.MConnConfig + p2pConfig config.P2PConfig +} + +// Test multiplexTransport for interface completeness. +var _ Transport = (*MultiplexTransport)(nil) +var _ transportLifecycle = (*MultiplexTransport)(nil) + +// NewMultiplexTransport returns a tcp connected multiplexed peer. +func NewMultiplexTransport( + nodeInfo NodeInfo, + nodeKey NodeKey, +) *MultiplexTransport { + return &MultiplexTransport{ + acceptc: make(chan accept), + closec: make(chan struct{}), + dialTimeout: defaultDialTimeout, + filterTimeout: defaultFilterTimeout, + handshakeTimeout: defaultHandshakeTimeout, + mConfig: conn.DefaultMConnConfig(), + nodeInfo: nodeInfo, + nodeKey: nodeKey, + conns: NewConnSet(), + resolver: net.DefaultResolver, + } +} + +// Accept implements Transport. +func (mt *MultiplexTransport) Accept(cfg peerConfig) (Peer, error) { + select { + // This case should never have any side-effectful/blocking operations to + // ensure that quality peers are ready to be used. + case a := <-mt.acceptc: + if a.err != nil { + return nil, a.err + } + + cfg.outbound = false + + return mt.wrapPeer(a.conn, a.nodeInfo, cfg), nil + case <-mt.closec: + return nil, &ErrTransportClosed{} + } +} + +// Dial implements Transport. +func (mt *MultiplexTransport) Dial( + addr NetAddress, + cfg peerConfig, +) (Peer, error) { + c, err := addr.DialTimeout(mt.dialTimeout) + if err != nil { + return nil, err + } + + // TODO(xla): Evaluate if we should apply filters if we explicitly dial. + if err := mt.filterConn(c); err != nil { + return nil, err + } + + secretConn, nodeInfo, err := mt.upgrade(c) + if err != nil { + return nil, err + } + + cfg.outbound = true + + p := mt.wrapPeer(secretConn, nodeInfo, cfg) + + return p, nil +} + +// Close implements transportLifecycle. +func (mt *MultiplexTransport) Close() error { + close(mt.closec) + + return mt.listener.Close() +} + +// Listen implements transportLifecycle. +func (mt *MultiplexTransport) Listen(addr NetAddress) error { + ln, err := net.Listen("tcp", addr.DialString()) + if err != nil { + return err + } + + mt.listener = ln + + go mt.acceptPeers() + + return nil +} + +func (mt *MultiplexTransport) acceptPeers() { + for { + c, err := mt.listener.Accept() + if err != nil { + // If Close() has been called, silently exit. + select { + case _, ok := <-mt.closec: + if !ok { + return + } + default: + // Transport is not closed + } + + mt.acceptc <- accept{err: err} + return + } + + // Connection upgrade and filtering should be asynchronous to avoid + // Head-of-line blocking[0]. + // Reference: https://github.com/tendermint/tendermint/issues/2047 + // + // [0] https://en.wikipedia.org/wiki/Head-of-line_blocking + go func(c net.Conn) { + var ( + nodeInfo NodeInfo + secretConn *conn.SecretConnection + ) + + err := mt.filterConn(c) + if err == nil { + secretConn, nodeInfo, err = mt.upgrade(c) + } + + select { + case mt.acceptc <- accept{secretConn, nodeInfo, err}: + // Make the upgraded peer available. + case <-mt.closec: + // Give up if the transport was closed. + _ = c.Close() + return + } + }(c) + } +} + +func (mt *MultiplexTransport) cleanup(c net.Conn) error { + mt.conns.Remove(c) + + return c.Close() +} + +func (mt *MultiplexTransport) filterConn(c net.Conn) (err error) { + defer func() { + if err != nil { + _ = c.Close() + } + }() + + // Reject if connection is already present. + if mt.conns.Has(c) { + return ErrRejected{conn: c, isDuplicate: true} + } + + // Resolve ips for incoming conn. + ips, err := resolveIPs(mt.resolver, c) + if err != nil { + return err + } + + errc := make(chan error, len(mt.connFilters)) + + for _, f := range mt.connFilters { + go func(f ConnFilterFunc, c net.Conn, ips []net.IP, errc chan<- error) { + errc <- f(mt.conns, c, ips) + }(f, c, ips, errc) + } + + for i := 0; i < cap(errc); i++ { + select { + case err := <-errc: + if err != nil { + return ErrRejected{conn: c, err: err, isFiltered: true} + } + case <-time.After(mt.filterTimeout): + return ErrFilterTimeout{} + } + + } + + mt.conns.Set(c, ips) + + return nil +} + +func (mt *MultiplexTransport) upgrade( + c net.Conn, +) (secretConn *conn.SecretConnection, nodeInfo NodeInfo, err error) { + defer func() { + if err != nil { + _ = mt.cleanup(c) + } + }() + + secretConn, err = upgradeSecretConn(c, mt.handshakeTimeout, mt.nodeKey.PrivKey) + if err != nil { + return nil, NodeInfo{}, ErrRejected{ + conn: c, + err: fmt.Errorf("secrect conn failed: %v", err), + isAuthFailure: true, + } + } + + nodeInfo, err = handshake(secretConn, mt.handshakeTimeout, mt.nodeInfo) + if err != nil { + return nil, NodeInfo{}, ErrRejected{ + conn: c, + err: fmt.Errorf("handshake failed: %v", err), + isAuthFailure: true, + } + } + + if err := nodeInfo.Validate(); err != nil { + return nil, NodeInfo{}, ErrRejected{ + conn: c, + err: err, + isNodeInfoInvalid: true, + } + } + + // Ensure connection key matches self reported key. + if connID := PubKeyToID(secretConn.RemotePubKey()); connID != nodeInfo.ID { + return nil, NodeInfo{}, ErrRejected{ + conn: c, + id: connID, + err: fmt.Errorf( + "conn.ID (%v) NodeInfo.ID (%v) missmatch", + connID, + nodeInfo.ID, + ), + isAuthFailure: true, + } + } + + // Reject self. + if mt.nodeInfo.ID == nodeInfo.ID { + return nil, NodeInfo{}, ErrRejected{ + addr: *NewNetAddress(nodeInfo.ID, c.RemoteAddr()), + conn: c, + id: nodeInfo.ID, + isSelf: true, + } + } + + if err := mt.nodeInfo.CompatibleWith(nodeInfo); err != nil { + return nil, NodeInfo{}, ErrRejected{ + conn: c, + err: err, + id: nodeInfo.ID, + isIncompatible: true, + } + } + + return secretConn, nodeInfo, nil +} + +func (mt *MultiplexTransport) wrapPeer( + c net.Conn, + ni NodeInfo, + cfg peerConfig, +) Peer { + p := newPeer( + peerConn{ + conn: c, + config: &mt.p2pConfig, + outbound: cfg.outbound, + persistent: cfg.persistent, + }, + mt.mConfig, + ni, + cfg.reactorsByCh, + cfg.chDescs, + cfg.onPeerError, + ) + + // Wait for Peer to Stop so we can cleanup. + go func(c net.Conn) { + <-p.Quit() + _ = mt.cleanup(c) + }(c) + + return p +} + +func handshake( + c net.Conn, + timeout time.Duration, + nodeInfo NodeInfo, +) (NodeInfo, error) { + if err := c.SetDeadline(time.Now().Add(timeout)); err != nil { + return NodeInfo{}, err + } + + var ( + errc = make(chan error, 2) + + peerNodeInfo NodeInfo + ) + + go func(errc chan<- error, c net.Conn) { + _, err := cdc.MarshalBinaryWriter(c, nodeInfo) + errc <- err + }(errc, c) + go func(errc chan<- error, c net.Conn) { + _, err := cdc.UnmarshalBinaryReader( + c, + &peerNodeInfo, + int64(MaxNodeInfoSize()), + ) + errc <- err + }(errc, c) + + for i := 0; i < cap(errc); i++ { + err := <-errc + if err != nil { + return NodeInfo{}, err + } + } + + return peerNodeInfo, c.SetDeadline(time.Time{}) +} + +func upgradeSecretConn( + c net.Conn, + timeout time.Duration, + privKey crypto.PrivKey, +) (*conn.SecretConnection, error) { + if err := c.SetDeadline(time.Now().Add(timeout)); err != nil { + return nil, err + } + + sc, err := conn.MakeSecretConnection(c, privKey) + if err != nil { + return nil, err + } + + return sc, sc.SetDeadline(time.Time{}) +} + +func resolveIPs(resolver IPResolver, c net.Conn) ([]net.IP, error) { + host, _, err := net.SplitHostPort(c.RemoteAddr().String()) + if err != nil { + return nil, err + } + + addrs, err := resolver.LookupIPAddr(context.Background(), host) + if err != nil { + return nil, err + } + + ips := []net.IP{} + + for _, addr := range addrs { + ips = append(ips, addr.IP) + } + + return ips, nil +} diff --git a/p2p/transport_test.go b/p2p/transport_test.go new file mode 100644 index 000000000..9e3cc467f --- /dev/null +++ b/p2p/transport_test.go @@ -0,0 +1,636 @@ +package p2p + +import ( + "fmt" + "math/rand" + "net" + "reflect" + "testing" + "time" + + "github.com/tendermint/tendermint/crypto/ed25519" +) + +func TestTransportMultiplexConnFilter(t *testing.T) { + mt := NewMultiplexTransport( + NodeInfo{}, + NodeKey{ + PrivKey: ed25519.GenPrivKey(), + }, + ) + + MultiplexTransportConnFilters( + func(_ ConnSet, _ net.Conn, _ []net.IP) error { return nil }, + func(_ ConnSet, _ net.Conn, _ []net.IP) error { return nil }, + func(_ ConnSet, _ net.Conn, _ []net.IP) error { + return fmt.Errorf("rejected") + }, + )(mt) + + addr, err := NewNetAddressStringWithOptionalID("127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + if err := mt.Listen(*addr); err != nil { + t.Fatal(err) + } + + errc := make(chan error) + + go func() { + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = addr.Dial() + if err != nil { + errc <- err + return + } + + close(errc) + }() + + if err := <-errc; err != nil { + t.Errorf("connection failed: %v", err) + } + + _, err = mt.Accept(peerConfig{}) + if err, ok := err.(ErrRejected); ok { + if !err.IsFiltered() { + t.Errorf("expected peer to be filtered") + } + } else { + t.Errorf("expected ErrRejected") + } +} + +func TestTransportMultiplexConnFilterTimeout(t *testing.T) { + mt := NewMultiplexTransport( + NodeInfo{}, + NodeKey{ + PrivKey: ed25519.GenPrivKey(), + }, + ) + + MultiplexTransportFilterTimeout(5 * time.Millisecond)(mt) + MultiplexTransportConnFilters( + func(_ ConnSet, _ net.Conn, _ []net.IP) error { + time.Sleep(10 * time.Millisecond) + return nil + }, + )(mt) + + addr, err := NewNetAddressStringWithOptionalID("127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + if err := mt.Listen(*addr); err != nil { + t.Fatal(err) + } + + errc := make(chan error) + + go func() { + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = addr.Dial() + if err != nil { + errc <- err + return + } + + close(errc) + }() + + if err := <-errc; err != nil { + t.Errorf("connection failed: %v", err) + } + + _, err = mt.Accept(peerConfig{}) + if _, ok := err.(ErrFilterTimeout); !ok { + t.Errorf("expected ErrFilterTimeout") + } +} +func TestTransportMultiplexAcceptMultiple(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + var ( + seed = rand.New(rand.NewSource(time.Now().UnixNano())) + errc = make(chan error, seed.Intn(64)+64) + ) + + // Setup dialers. + for i := 0; i < cap(errc); i++ { + go func() { + var ( + pv = ed25519.GenPrivKey() + dialer = NewMultiplexTransport( + NodeInfo{ + ID: PubKeyToID(pv.PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "dialer", + Version: "1.0.0", + }, + NodeKey{ + PrivKey: pv, + }, + ) + ) + + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = dialer.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + // Signal that the connection was established. + errc <- nil + }() + } + + // Catch connection errors. + for i := 0; i < cap(errc); i++ { + if err := <-errc; err != nil { + t.Fatal(err) + } + } + + ps := []Peer{} + + // Accept all peers. + for i := 0; i < cap(errc); i++ { + p, err := mt.Accept(peerConfig{}) + if err != nil { + t.Fatal(err) + } + + if err := p.Start(); err != nil { + t.Fatal(err) + } + + ps = append(ps, p) + } + + if have, want := len(ps), cap(errc); have != want { + t.Errorf("have %v, want %v", have, want) + } + + // Stop all peers. + for _, p := range ps { + if err := p.Stop(); err != nil { + t.Fatal(err) + } + } + + if err := mt.Close(); err != nil { + t.Errorf("close errored: %v", err) + } +} + +func TestTransportMultiplexAcceptNonBlocking(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + var ( + fastNodePV = ed25519.GenPrivKey() + fastNodeInfo = NodeInfo{ + ID: PubKeyToID(fastNodePV.PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "fastNode", + Version: "1.0.0", + } + errc = make(chan error) + fastc = make(chan struct{}) + slowc = make(chan struct{}) + ) + + // Simulate slow Peer. + go func() { + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + c, err := addr.Dial() + if err != nil { + errc <- err + return + } + + close(slowc) + + select { + case <-fastc: + // Fast peer connected. + case <-time.After(50 * time.Millisecond): + // We error if the fast peer didn't succeed. + errc <- fmt.Errorf("Fast peer timed out") + } + + sc, err := upgradeSecretConn(c, 20*time.Millisecond, ed25519.GenPrivKey()) + if err != nil { + errc <- err + return + } + + _, err = handshake(sc, 20*time.Millisecond, NodeInfo{ + ID: PubKeyToID(ed25519.GenPrivKey().PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "slow_peer", + }) + if err != nil { + errc <- err + return + } + }() + + // Simulate fast Peer. + go func() { + <-slowc + + var ( + dialer = NewMultiplexTransport( + fastNodeInfo, + NodeKey{ + PrivKey: fastNodePV, + }, + ) + ) + + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = dialer.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + close(errc) + close(fastc) + }() + + if err := <-errc; err != nil { + t.Errorf("connection failed: %v", err) + } + + p, err := mt.Accept(peerConfig{}) + if err != nil { + t.Fatal(err) + } + + if have, want := p.NodeInfo(), fastNodeInfo; !reflect.DeepEqual(have, want) { + t.Errorf("have %v, want %v", have, want) + } +} + +func TestTransportMultiplexValidateNodeInfo(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + errc := make(chan error) + + go func() { + var ( + pv = ed25519.GenPrivKey() + dialer = NewMultiplexTransport( + NodeInfo{ + ID: PubKeyToID(pv.PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "", // Should not be empty. + Version: "1.0.0", + }, + NodeKey{ + PrivKey: pv, + }, + ) + ) + + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = dialer.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + close(errc) + }() + + if err := <-errc; err != nil { + t.Errorf("connection failed: %v", err) + } + + _, err := mt.Accept(peerConfig{}) + if err, ok := err.(ErrRejected); ok { + if !err.IsNodeInfoInvalid() { + t.Errorf("expected NodeInfo to be invalid") + } + } else { + t.Errorf("expected ErrRejected") + } +} + +func TestTransportMultiplexRejectMissmatchID(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + errc := make(chan error) + + go func() { + dialer := NewMultiplexTransport( + NodeInfo{ + ID: PubKeyToID(ed25519.GenPrivKey().PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "dialer", + Version: "1.0.0", + }, + NodeKey{ + PrivKey: ed25519.GenPrivKey(), + }, + ) + + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = dialer.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + close(errc) + }() + + if err := <-errc; err != nil { + t.Errorf("connection failed: %v", err) + } + + _, err := mt.Accept(peerConfig{}) + if err, ok := err.(ErrRejected); ok { + if !err.IsAuthFailure() { + t.Errorf("expected auth failure") + } + } else { + t.Errorf("expected ErrRejected") + } +} + +func TestTransportMultiplexRejectIncompatible(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + errc := make(chan error) + + go func() { + var ( + pv = ed25519.GenPrivKey() + dialer = NewMultiplexTransport( + NodeInfo{ + ID: PubKeyToID(pv.PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "dialer", + Version: "2.0.0", + }, + NodeKey{ + PrivKey: pv, + }, + ) + ) + + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = dialer.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + close(errc) + }() + + _, err := mt.Accept(peerConfig{}) + if err, ok := err.(ErrRejected); ok { + if !err.IsIncompatible() { + t.Errorf("expected to reject incompatible") + } + } else { + t.Errorf("expected ErrRejected") + } +} + +func TestTransportMultiplexRejectSelf(t *testing.T) { + mt := testSetupMultiplexTransport(t) + + errc := make(chan error) + + go func() { + addr, err := NewNetAddressStringWithOptionalID(mt.listener.Addr().String()) + if err != nil { + errc <- err + return + } + + _, err = mt.Dial(*addr, peerConfig{}) + if err != nil { + errc <- err + return + } + + close(errc) + }() + + if err := <-errc; err != nil { + if err, ok := err.(ErrRejected); ok { + if !err.IsSelf() { + t.Errorf("expected to reject self") + } + } else { + t.Errorf("expected ErrRejected") + } + } else { + t.Errorf("expected connection failure") + } + + _, err := mt.Accept(peerConfig{}) + if err, ok := err.(ErrRejected); ok { + if !err.IsSelf() { + t.Errorf("expected to reject self") + } + } else { + t.Errorf("expected ErrRejected") + } +} + +func TestTransportConnDuplicateIPFilter(t *testing.T) { + filter := ConnDuplicateIPFilter() + + if err := filter(nil, &testTransportConn{}, nil); err != nil { + t.Fatal(err) + } + + var ( + c = &testTransportConn{} + cs = NewConnSet() + ) + + cs.Set(c, []net.IP{ + net.IP{10, 0, 10, 1}, + net.IP{10, 0, 10, 2}, + net.IP{10, 0, 10, 3}, + }) + + if err := filter(cs, c, []net.IP{ + net.IP{10, 0, 10, 2}, + }); err == nil { + t.Errorf("expected Peer to be rejected as duplicate") + } +} + +func TestTransportHandshake(t *testing.T) { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + var ( + peerPV = ed25519.GenPrivKey() + peerNodeInfo = NodeInfo{ + ID: PubKeyToID(peerPV.PubKey()), + } + ) + + go func() { + c, err := net.Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Error(err) + return + } + + go func(c net.Conn) { + _, err := cdc.MarshalBinaryWriter(c, peerNodeInfo) + if err != nil { + t.Error(err) + } + }(c) + go func(c net.Conn) { + ni := NodeInfo{} + + _, err := cdc.UnmarshalBinaryReader( + c, + &ni, + int64(MaxNodeInfoSize()), + ) + if err != nil { + t.Error(err) + } + }(c) + }() + + c, err := ln.Accept() + if err != nil { + t.Fatal(err) + } + + ni, err := handshake(c, 20*time.Millisecond, NodeInfo{}) + if err != nil { + t.Fatal(err) + } + + if have, want := ni, peerNodeInfo; !reflect.DeepEqual(have, want) { + t.Errorf("have %v, want %v", have, want) + } +} + +func testSetupMultiplexTransport(t *testing.T) *MultiplexTransport { + var ( + pv = ed25519.GenPrivKey() + mt = NewMultiplexTransport( + NodeInfo{ + ID: PubKeyToID(pv.PubKey()), + ListenAddr: "127.0.0.1:0", + Moniker: "transport", + Version: "1.0.0", + }, + NodeKey{ + PrivKey: pv, + }, + ) + ) + + addr, err := NewNetAddressStringWithOptionalID("127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + if err := mt.Listen(*addr); err != nil { + t.Fatal(err) + } + + return mt +} + +type testTransportAddr struct{} + +func (a *testTransportAddr) Network() string { return "tcp" } +func (a *testTransportAddr) String() string { return "test.local:1234" } + +type testTransportConn struct{} + +func (c *testTransportConn) Close() error { + return fmt.Errorf("Close() not implemented") +} + +func (c *testTransportConn) LocalAddr() net.Addr { + return &testTransportAddr{} +} + +func (c *testTransportConn) RemoteAddr() net.Addr { + return &testTransportAddr{} +} + +func (c *testTransportConn) Read(_ []byte) (int, error) { + return -1, fmt.Errorf("Read() not implemented") +} + +func (c *testTransportConn) SetDeadline(_ time.Time) error { + return fmt.Errorf("SetDeadline() not implemented") +} + +func (c *testTransportConn) SetReadDeadline(_ time.Time) error { + return fmt.Errorf("SetReadDeadline() not implemented") +} + +func (c *testTransportConn) SetWriteDeadline(_ time.Time) error { + return fmt.Errorf("SetWriteDeadline() not implemented") +} + +func (c *testTransportConn) Write(_ []byte) (int, error) { + return -1, fmt.Errorf("Write() not implemented") +} From bdd01310a01bee07f505778506760c2ce9381122 Mon Sep 17 00:00:00 2001 From: Alexander Simmerl Date: Tue, 18 Sep 2018 22:14:40 +0200 Subject: [PATCH 24/47] p2p: Integrate new Transport We are swapping the exisiting listener implementation with the newly introduced Transport and its default implementation MultiplexTransport, removing a large chunk of old connection setup and handling scattered over the Peer and Switch code. The Switch requires a Transport now and handles externally passed Peer filters. --- blockchain/reactor_test.go | 2 +- consensus/byzantine_test.go | 8 +- node/node.go | 270 +++++++++++++++++----------- p2p/errors.go | 99 +++++++++++ p2p/listener.go | 286 ------------------------------ p2p/listener_test.go | 79 --------- p2p/peer.go | 94 ---------- p2p/peer_test.go | 51 +++++- p2p/pex/pex_reactor_test.go | 10 +- p2p/switch.go | 340 ++++++++++++++++-------------------- p2p/switch_test.go | 213 ++++++++++++++-------- p2p/test_util.go | 136 ++++++++++++--- rpc/core/consensus.go | 2 +- rpc/core/net.go | 15 +- rpc/core/pipe.go | 24 ++- rpc/core/status.go | 2 +- 16 files changed, 743 insertions(+), 888 deletions(-) delete mode 100644 p2p/listener.go delete mode 100644 p2p/listener_test.go diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index 0ef38a6c4..b63a057e1 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -42,7 +42,7 @@ func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainRe bcReactor.SetLogger(logger.With("module", "blockchain")) // Next: we need to set a switch in order for peers to be added in - bcReactor.Switch = p2p.NewSwitch(cfg.DefaultP2PConfig()) + bcReactor.Switch = p2p.NewSwitch(cfg.DefaultP2PConfig(), nil) // Lastly: let's add some blocks in for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index 0aba77432..3903e6b9e 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -39,7 +39,13 @@ func TestByzantine(t *testing.T) { switches := make([]*p2p.Switch, N) p2pLogger := logger.With("module", "p2p") for i := 0; i < N; i++ { - switches[i] = p2p.NewSwitch(config.P2P) + switches[i] = p2p.MakeSwitch( + config.P2P, + i, + "foo", "1.0.0", + func(i int, sw *p2p.Switch) *p2p.Switch { + return sw + }) switches[i].SetLogger(p2pLogger.With("validator", i)) } diff --git a/node/node.go b/node/node.go index c623e620f..995d1c889 100644 --- a/node/node.go +++ b/node/node.go @@ -126,9 +126,12 @@ type Node struct { privValidator types.PrivValidator // local node's validator key // network - sw *p2p.Switch // p2p connections - addrBook pex.AddrBook // known peers - nodeKey *p2p.NodeKey // our node privkey + transport *p2p.MultiplexTransport + sw *p2p.Switch // p2p connections + addrBook pex.AddrBook // known peers + nodeInfo p2p.NodeInfo + nodeKey *p2p.NodeKey // our node privkey + isListening bool // services eventBus *types.EventBus // pub/sub for services @@ -301,14 +304,109 @@ func NewNode(config *cfg.Config, consensusReactor := cs.NewConsensusReactor(consensusState, fastSync) consensusReactor.SetLogger(consensusLogger) - p2pLogger := logger.With("module", "p2p") + eventBus := types.NewEventBus() + eventBus.SetLogger(logger.With("module", "events")) + + // services which will be publishing and/or subscribing for messages (events) + // consensusReactor will set it on consensusState and blockExecutor + consensusReactor.SetEventBus(eventBus) - sw := p2p.NewSwitch(config.P2P, p2p.WithMetrics(p2pMetrics)) + // Transaction indexing + var txIndexer txindex.TxIndexer + switch config.TxIndex.Indexer { + case "kv": + store, err := dbProvider(&DBContext{"tx_index", config}) + if err != nil { + return nil, err + } + if config.TxIndex.IndexTags != "" { + txIndexer = kv.NewTxIndex(store, kv.IndexTags(splitAndTrimEmpty(config.TxIndex.IndexTags, ",", " "))) + } else if config.TxIndex.IndexAllTags { + txIndexer = kv.NewTxIndex(store, kv.IndexAllTags()) + } else { + txIndexer = kv.NewTxIndex(store) + } + default: + txIndexer = &null.TxIndex{} + } + + indexerService := txindex.NewIndexerService(txIndexer, eventBus) + indexerService.SetLogger(logger.With("module", "txindex")) + + var ( + p2pLogger = logger.With("module", "p2p") + nodeInfo = makeNodeInfo(config, nodeKey.ID(), txIndexer, genDoc.ChainID) + ) + + // Setup Transport. + var ( + transport = p2p.NewMultiplexTransport(nodeInfo, *nodeKey) + connFilters = []p2p.ConnFilterFunc{} + peerFilters = []p2p.PeerFilterFunc{} + ) + + if !config.P2P.AllowDuplicateIP { + connFilters = append(connFilters, p2p.ConnDuplicateIPFilter()) + } + + // Filter peers by addr or pubkey with an ABCI query. + // If the query return code is OK, add peer. + // XXX: Query format subject to change + if config.FilterPeers { + connFilters = append( + connFilters, + // ABCI query for address filtering. + func(_ p2p.ConnSet, c net.Conn, _ []net.IP) error { + res, err := proxyApp.Query().QuerySync(abci.RequestQuery{ + Path: fmt.Sprintf("/p2p/filter/addr/%s", c.RemoteAddr().String()), + }) + if err != nil { + return err + } + if res.IsErr() { + return fmt.Errorf("Error querying abci app: %v", res) + } + + return nil + }, + ) + + peerFilters = append( + peerFilters, + // ABCI query for ID filtering. + func(_ p2p.IPeerSet, p p2p.Peer) error { + res, err := proxyApp.Query().QuerySync(abci.RequestQuery{ + Path: fmt.Sprintf("/p2p/filter/id/%s", p.ID()), + }) + if err != nil { + return err + } + if res.IsErr() { + return fmt.Errorf("Error querying abci app: %v", res) + } + + return nil + }, + ) + } + + p2p.MultiplexTransportConnFilters(connFilters...)(transport) + + // Setup Switch. + sw := p2p.NewSwitch( + config.P2P, + transport, + p2p.WithMetrics(p2pMetrics), + p2p.SwitchPeerFilters(peerFilters...), + ) sw.SetLogger(p2pLogger) sw.AddReactor("MEMPOOL", mempoolReactor) sw.AddReactor("BLOCKCHAIN", bcReactor) sw.AddReactor("CONSENSUS", consensusReactor) sw.AddReactor("EVIDENCE", evidenceReactor) + sw.SetNodeInfo(nodeInfo) + sw.SetNodeKey(nodeKey) + p2pLogger.Info("P2P Node ID", "ID", nodeKey.ID(), "file", config.NodeKeyFile()) // Optionally, start the pex reactor @@ -324,6 +422,10 @@ func NewNode(config *cfg.Config, // If PEX is on, it should handle dialing the seeds. Otherwise the switch does it. // Note we currently use the addrBook regardless at least for AddOurAddress addrBook := pex.NewAddrBook(config.P2P.AddrBookFile(), config.P2P.AddrBookStrict) + + // Add ourselves to addrbook to prevent dialing ourselves + addrBook.AddOurAddress(nodeInfo.NetAddress()) + addrBook.SetLogger(p2pLogger.With("book", config.P2P.AddrBookFile())) if config.P2P.PexReactor { // TODO persistent peers ? so we can have their DNS addrs saved @@ -338,62 +440,6 @@ func NewNode(config *cfg.Config, sw.SetAddrBook(addrBook) - // Filter peers by addr or pubkey with an ABCI query. - // If the query return code is OK, add peer. - // XXX: Query format subject to change - if config.FilterPeers { - // NOTE: addr is ip:port - sw.SetAddrFilter(func(addr net.Addr) error { - resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: fmt.Sprintf("/p2p/filter/addr/%s", addr.String())}) - if err != nil { - return err - } - if resQuery.IsErr() { - return fmt.Errorf("Error querying abci app: %v", resQuery) - } - return nil - }) - sw.SetIDFilter(func(id p2p.ID) error { - resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: fmt.Sprintf("/p2p/filter/id/%s", id)}) - if err != nil { - return err - } - if resQuery.IsErr() { - return fmt.Errorf("Error querying abci app: %v", resQuery) - } - return nil - }) - } - - eventBus := types.NewEventBus() - eventBus.SetLogger(logger.With("module", "events")) - - // services which will be publishing and/or subscribing for messages (events) - // consensusReactor will set it on consensusState and blockExecutor - consensusReactor.SetEventBus(eventBus) - - // Transaction indexing - var txIndexer txindex.TxIndexer - switch config.TxIndex.Indexer { - case "kv": - store, err := dbProvider(&DBContext{"tx_index", config}) - if err != nil { - return nil, err - } - if config.TxIndex.IndexTags != "" { - txIndexer = kv.NewTxIndex(store, kv.IndexTags(splitAndTrimEmpty(config.TxIndex.IndexTags, ",", " "))) - } else if config.TxIndex.IndexAllTags { - txIndexer = kv.NewTxIndex(store, kv.IndexAllTags()) - } else { - txIndexer = kv.NewTxIndex(store) - } - default: - txIndexer = &null.TxIndex{} - } - - indexerService := txindex.NewIndexerService(txIndexer, eventBus) - indexerService.SetLogger(logger.With("module", "txindex")) - // run the profile server profileHost := config.ProfListenAddress if profileHost != "" { @@ -407,9 +453,11 @@ func NewNode(config *cfg.Config, genesisDoc: genDoc, privValidator: privValidator, - sw: sw, - addrBook: addrBook, - nodeKey: nodeKey, + transport: transport, + sw: sw, + addrBook: addrBook, + nodeInfo: nodeInfo, + nodeKey: nodeKey, stateDB: stateDB, blockStore: blockStore, @@ -441,21 +489,6 @@ func (n *Node) OnStart() error { return err } - // Create & add listener - l := p2p.NewDefaultListener( - n.config.P2P.ListenAddress, - n.config.P2P.ExternalAddress, - n.config.P2P.UPNP, - n.Logger.With("module", "p2p")) - n.sw.AddListener(l) - - nodeInfo := n.makeNodeInfo(n.nodeKey.ID()) - n.sw.SetNodeInfo(nodeInfo) - n.sw.SetNodeKey(n.nodeKey) - - // Add ourselves to addrbook to prevent dialing ourselves - n.addrBook.AddOurAddress(nodeInfo.NetAddress()) - // Add private IDs to addrbook to block those peers being added n.addrBook.AddPrivateIDs(splitAndTrimEmpty(n.config.P2P.PrivatePeerIDs, ",", " ")) @@ -474,6 +507,17 @@ func (n *Node) OnStart() error { n.prometheusSrv = n.startPrometheusServer(n.config.Instrumentation.PrometheusListenAddr) } + // Start the transport. + addr, err := p2p.NewNetAddressStringWithOptionalID(n.config.P2P.ListenAddress) + if err != nil { + return err + } + if err := n.transport.Listen(*addr); err != nil { + return err + } + + n.isListening = true + // Start the switch (the P2P server). err = n.sw.Start() if err != nil { @@ -506,6 +550,12 @@ func (n *Node) OnStop() { // TODO: gracefully disconnect from peers. n.sw.Stop() + if err := n.transport.Close(); err != nil { + n.Logger.Error("Error closing transport", "err", err) + } + + n.isListening = false + // finally stop the listeners / external services for _, l := range n.rpcListeners { n.Logger.Info("Closing rpc listener", "listener", l) @@ -536,13 +586,6 @@ func (n *Node) RunForever() { }) } -// AddListener adds a listener to accept inbound peer connections. -// It should be called before starting the Node. -// The first listener is the primary listener (in NodeInfo) -func (n *Node) AddListener(l p2p.Listener) { - n.sw.AddListener(l) -} - // ConfigureRPC sets all variables in rpccore so they will serve // rpc calls from this node func (n *Node) ConfigureRPC() { @@ -551,7 +594,8 @@ func (n *Node) ConfigureRPC() { rpccore.SetConsensusState(n.consensusState) rpccore.SetMempool(n.mempoolReactor.Mempool) rpccore.SetEvidencePool(n.evidencePool) - rpccore.SetSwitch(n.sw) + rpccore.SetP2PPeers(n.sw) + rpccore.SetP2PTransport(n) rpccore.SetPubKey(n.privValidator.GetPubKey()) rpccore.SetGenesisDoc(n.genesisDoc) rpccore.SetAddrBook(n.addrBook) @@ -683,14 +727,36 @@ func (n *Node) ProxyApp() proxy.AppConns { return n.proxyApp } -func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo { +//------------------------------------------------------------------------------ + +func (n *Node) Listeners() []string { + return []string{ + fmt.Sprintf("Listener(@%v)", n.config.P2P.ExternalAddress), + } +} + +func (n *Node) IsListening() bool { + return n.isListening +} + +// NodeInfo returns the Node's Info from the Switch. +func (n *Node) NodeInfo() p2p.NodeInfo { + return n.nodeInfo +} + +func makeNodeInfo( + config *cfg.Config, + nodeID p2p.ID, + txIndexer txindex.TxIndexer, + chainID string, +) p2p.NodeInfo { txIndexerStatus := "on" - if _, ok := n.txIndexer.(*null.TxIndex); ok { + if _, ok := txIndexer.(*null.TxIndex); ok { txIndexerStatus = "off" } nodeInfo := p2p.NodeInfo{ ID: nodeID, - Network: n.genesisDoc.ChainID, + Network: chainID, Version: version.Version, Channels: []byte{ bc.BlockchainChannel, @@ -698,7 +764,7 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo { mempl.MempoolChannel, evidence.EvidenceChannel, }, - Moniker: n.config.Moniker, + Moniker: config.Moniker, Other: p2p.NodeInfoOther{ AminoVersion: amino.Version, P2PVersion: p2p.Version, @@ -708,34 +774,26 @@ func (n *Node) makeNodeInfo(nodeID p2p.ID) p2p.NodeInfo { }, } - if n.config.P2P.PexReactor { + if config.P2P.PexReactor { nodeInfo.Channels = append(nodeInfo.Channels, pex.PexChannel) } - rpcListenAddr := n.config.RPC.ListenAddress + rpcListenAddr := config.RPC.ListenAddress nodeInfo.Other.RPCAddress = rpcListenAddr - if !n.sw.IsListening() { - return nodeInfo + lAddr := config.P2P.ExternalAddress + + if lAddr == "" { + lAddr = config.P2P.ListenAddress } - p2pListener := n.sw.Listeners()[0] - p2pHost := p2pListener.ExternalAddressHost() - p2pPort := p2pListener.ExternalAddress().Port - nodeInfo.ListenAddr = fmt.Sprintf("%v:%v", p2pHost, p2pPort) + nodeInfo.ListenAddr = lAddr return nodeInfo } //------------------------------------------------------------------------------ -// NodeInfo returns the Node's Info from the Switch. -func (n *Node) NodeInfo() p2p.NodeInfo { - return n.sw.NodeInfo() -} - -//------------------------------------------------------------------------------ - var ( genesisDocKey = []byte("genesisDoc") ) diff --git a/p2p/errors.go b/p2p/errors.go index fc477d1c2..902d22034 100644 --- a/p2p/errors.go +++ b/p2p/errors.go @@ -5,6 +5,98 @@ import ( "net" ) +// ErrFilterTimeout indicates that a filter operation timed out. +type ErrFilterTimeout struct{} + +func (e ErrFilterTimeout) Error() string { + return "filter timed out" +} + +// ErrRejected indicates that a Peer was rejected carrying additional +// information as to the reason. +type ErrRejected struct { + addr NetAddress + conn net.Conn + err error + id ID + isAuthFailure bool + isDuplicate bool + isFiltered bool + isIncompatible bool + isNodeInfoInvalid bool + isSelf bool +} + +// Addr returns the NetAddress for the rejected Peer. +func (e ErrRejected) Addr() NetAddress { + return e.addr +} + +func (e ErrRejected) Error() string { + if e.isAuthFailure { + return fmt.Sprintf("auth failure: %s", e.err) + } + + if e.isDuplicate { + if e.conn != nil { + return fmt.Sprintf( + "duplicate CONN<%s>: %s", + e.conn.RemoteAddr().String(), + e.err, + ) + } + if e.id != "" { + return fmt.Sprintf("duplicate ID<%v>: %s", e.id, e.err) + } + } + + if e.isFiltered { + if e.conn != nil { + return fmt.Sprintf( + "filtered CONN<%s>: %s", + e.conn.RemoteAddr().String(), + e.err, + ) + } + + if e.id != "" { + return fmt.Sprintf("filtered ID<%v>: %s", e.id, e.err) + } + } + + if e.isIncompatible { + return fmt.Sprintf("incompatible: %s", e.err) + } + + if e.isNodeInfoInvalid { + return fmt.Sprintf("invalid NodeInfo: %s", e.err) + } + + if e.isSelf { + return fmt.Sprintf("self ID<%v>", e.id) + } + + return fmt.Sprintf("%s", e.err) +} + +// IsAuthFailure when Peer authentication was unsuccessful. +func (e ErrRejected) IsAuthFailure() bool { return e.isAuthFailure } + +// IsDuplicate when Peer ID or IP are present already. +func (e ErrRejected) IsDuplicate() bool { return e.isDuplicate } + +// IsFiltered when Peer ID or IP was filtered. +func (e ErrRejected) IsFiltered() bool { return e.isFiltered } + +// IsIncompatible when Peer NodeInfo is not compatible with our own. +func (e ErrRejected) IsIncompatible() bool { return e.isIncompatible } + +// IsNodeInfoInvalid when the sent NodeInfo is not valid. +func (e ErrRejected) IsNodeInfoInvalid() bool { return e.isNodeInfoInvalid } + +// IsSelf when Peer is our own node. +func (e ErrRejected) IsSelf() bool { return e.isSelf } + // ErrSwitchDuplicatePeerID to be raised when a peer is connecting with a known // ID. type ErrSwitchDuplicatePeerID struct { @@ -47,6 +139,13 @@ func (e ErrSwitchAuthenticationFailure) Error() string { ) } +// ErrTransportClosed is raised when the Transport has been closed. +type ErrTransportClosed struct{} + +func (e ErrTransportClosed) Error() string { + return "transport has been closed" +} + //------------------------------------------------------------------- type ErrNetAddressNoID struct { diff --git a/p2p/listener.go b/p2p/listener.go deleted file mode 100644 index d0dd3f42a..000000000 --- a/p2p/listener.go +++ /dev/null @@ -1,286 +0,0 @@ -package p2p - -import ( - "fmt" - "net" - "strconv" - "strings" - "time" - - cmn "github.com/tendermint/tendermint/libs/common" - "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/p2p/upnp" -) - -// Listener is a network listener for stream-oriented protocols, providing -// convenient methods to get listener's internal and external addresses. -// Clients are supposed to read incoming connections from a channel, returned -// by Connections() method. -type Listener interface { - Connections() <-chan net.Conn - InternalAddress() *NetAddress - ExternalAddress() *NetAddress - ExternalAddressHost() string - String() string - Stop() error -} - -// DefaultListener is a cmn.Service, running net.Listener underneath. -// Optionally, UPnP is used upon calling NewDefaultListener to resolve external -// address. -type DefaultListener struct { - cmn.BaseService - - listener net.Listener - intAddr *NetAddress - extAddr *NetAddress - connections chan net.Conn -} - -var _ Listener = (*DefaultListener)(nil) - -const ( - numBufferedConnections = 10 - defaultExternalPort = 8770 - tryListenSeconds = 5 -) - -func splitHostPort(addr string) (host string, port int) { - host, portStr, err := net.SplitHostPort(addr) - if err != nil { - panic(err) - } - port, err = strconv.Atoi(portStr) - if err != nil { - panic(err) - } - return host, port -} - -// NewDefaultListener creates a new DefaultListener on lAddr, optionally trying -// to determine external address using UPnP. -func NewDefaultListener( - fullListenAddrString string, - externalAddrString string, - useUPnP bool, - logger log.Logger) Listener { - - // Split protocol, address, and port. - protocol, lAddr := cmn.ProtocolAndAddress(fullListenAddrString) - lAddrIP, lAddrPort := splitHostPort(lAddr) - - // Create listener - var listener net.Listener - var err error - for i := 0; i < tryListenSeconds; i++ { - listener, err = net.Listen(protocol, lAddr) - if err == nil { - break - } else if i < tryListenSeconds-1 { - time.Sleep(time.Second * 1) - } - } - if err != nil { - panic(err) - } - // Actual listener local IP & port - listenerIP, listenerPort := splitHostPort(listener.Addr().String()) - logger.Info("Local listener", "ip", listenerIP, "port", listenerPort) - - // Determine internal address... - var intAddr *NetAddress - intAddr, err = NewNetAddressStringWithOptionalID(lAddr) - if err != nil { - panic(err) - } - - inAddrAny := lAddrIP == "" || lAddrIP == "0.0.0.0" - - // Determine external address. - var extAddr *NetAddress - - if externalAddrString != "" { - var err error - extAddr, err = NewNetAddressStringWithOptionalID(externalAddrString) - if err != nil { - panic(fmt.Sprintf("Error in ExternalAddress: %v", err)) - } - } - - // If the lAddrIP is INADDR_ANY, try UPnP. - if extAddr == nil && useUPnP && inAddrAny { - extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger) - } - - // Otherwise just use the local address. - if extAddr == nil { - defaultToIPv4 := inAddrAny - extAddr = getNaiveExternalAddress(defaultToIPv4, listenerPort, false, logger) - } - if extAddr == nil { - panic("Could not determine external address!") - } - - dl := &DefaultListener{ - listener: listener, - intAddr: intAddr, - extAddr: extAddr, - connections: make(chan net.Conn, numBufferedConnections), - } - dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl) - err = dl.Start() // Started upon construction - if err != nil { - logger.Error("Error starting base service", "err", err) - } - return dl -} - -// OnStart implements cmn.Service by spinning a goroutine, listening for new -// connections. -func (l *DefaultListener) OnStart() error { - if err := l.BaseService.OnStart(); err != nil { - return err - } - go l.listenRoutine() - return nil -} - -// OnStop implements cmn.Service by closing the listener. -func (l *DefaultListener) OnStop() { - l.BaseService.OnStop() - l.listener.Close() // nolint: errcheck -} - -// Accept connections and pass on the channel. -func (l *DefaultListener) listenRoutine() { - for { - conn, err := l.listener.Accept() - - if !l.IsRunning() { - break // Go to cleanup - } - - // listener wasn't stopped, - // yet we encountered an error. - if err != nil { - panic(err) - } - - l.connections <- conn - } - - // Cleanup - close(l.connections) - for range l.connections { - // Drain - } -} - -// Connections returns a channel of inbound connections. -// It gets closed when the listener closes. -// It is the callers responsibility to close any connections received -// over this channel. -func (l *DefaultListener) Connections() <-chan net.Conn { - return l.connections -} - -// InternalAddress returns the internal NetAddress (address used for -// listening). -func (l *DefaultListener) InternalAddress() *NetAddress { - return l.intAddr -} - -// ExternalAddress returns the external NetAddress (publicly available, -// determined using either UPnP or local resolver). -func (l *DefaultListener) ExternalAddress() *NetAddress { - return l.extAddr -} - -// ExternalAddressHost returns the external NetAddress IP string. If an IP is -// IPv6, it's wrapped in brackets ("[2001:db8:1f70::999:de8:7648:6e8]"). -func (l *DefaultListener) ExternalAddressHost() string { - ip := l.ExternalAddress().IP - if isIpv6(ip) { - // Means it's ipv6, so format it with brackets - return "[" + ip.String() + "]" - } - return ip.String() -} - -func (l *DefaultListener) String() string { - return fmt.Sprintf("Listener(@%v)", l.extAddr) -} - -/* external address helpers */ - -// UPNP external address discovery & port mapping -func getUPNPExternalAddress(externalPort, internalPort int, logger log.Logger) *NetAddress { - logger.Info("Getting UPNP external address") - nat, err := upnp.Discover() - if err != nil { - logger.Info("Could not perform UPNP discover", "err", err) - return nil - } - - ext, err := nat.GetExternalAddress() - if err != nil { - logger.Info("Could not get UPNP external address", "err", err) - return nil - } - - // UPnP can't seem to get the external port, so let's just be explicit. - if externalPort == 0 { - externalPort = defaultExternalPort - } - - externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0) - if err != nil { - logger.Info("Could not add UPNP port mapping", "err", err) - return nil - } - - logger.Info("Got UPNP external address", "address", ext) - return NewNetAddressIPPort(ext, uint16(externalPort)) -} - -func isIpv6(ip net.IP) bool { - v4 := ip.To4() - if v4 != nil { - return false - } - - ipString := ip.String() - - // Extra check just to be sure it's IPv6 - return (strings.Contains(ipString, ":") && !strings.Contains(ipString, ".")) -} - -// TODO: use syscalls: see issue #712 -func getNaiveExternalAddress(defaultToIPv4 bool, port int, settleForLocal bool, logger log.Logger) *NetAddress { - addrs, err := net.InterfaceAddrs() - if err != nil { - panic(fmt.Sprintf("Could not fetch interface addresses: %v", err)) - } - - for _, a := range addrs { - ipnet, ok := a.(*net.IPNet) - if !ok { - continue - } - if defaultToIPv4 || !isIpv6(ipnet.IP) { - v4 := ipnet.IP.To4() - if v4 == nil || (!settleForLocal && v4[0] == 127) { - // loopback - continue - } - } else if !settleForLocal && ipnet.IP.IsLoopback() { - // IPv6, check for loopback - continue - } - return NewNetAddressIPPort(ipnet.IP, uint16(port)) - } - - // try again, but settle for local - logger.Info("Node may not be connected to internet. Settling for local address") - return getNaiveExternalAddress(defaultToIPv4, port, true, logger) -} diff --git a/p2p/listener_test.go b/p2p/listener_test.go deleted file mode 100644 index f87b5d6f5..000000000 --- a/p2p/listener_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package p2p - -import ( - "bytes" - "net" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" -) - -func TestListener(t *testing.T) { - // Create a listener - l := NewDefaultListener("tcp://:8001", "", false, log.TestingLogger()) - - // Dial the listener - lAddr := l.ExternalAddress() - connOut, err := lAddr.Dial() - if err != nil { - t.Fatalf("Could not connect to listener address %v", lAddr) - } else { - t.Logf("Created a connection to listener address %v", lAddr) - } - connIn, ok := <-l.Connections() - if !ok { - t.Fatalf("Could not get inbound connection from listener") - } - - msg := []byte("hi!") - go func() { - _, err := connIn.Write(msg) - if err != nil { - t.Error(err) - } - }() - b := make([]byte, 32) - n, err := connOut.Read(b) - if err != nil { - t.Fatalf("Error reading off connection: %v", err) - } - - b = b[:n] - if !bytes.Equal(msg, b) { - t.Fatalf("Got %s, expected %s", b, msg) - } - - // Close the server, no longer needed. - l.Stop() -} - -func TestExternalAddress(t *testing.T) { - { - // Create a listener with no external addr. Should default - // to local ipv4. - l := NewDefaultListener("tcp://:8001", "", false, log.TestingLogger()) - lAddr := l.ExternalAddress().String() - _, _, err := net.SplitHostPort(lAddr) - require.Nil(t, err) - spl := strings.Split(lAddr, ".") - require.Equal(t, len(spl), 4) - l.Stop() - } - - { - // Create a listener with set external ipv4 addr. - setExAddr := "8.8.8.8:8080" - l := NewDefaultListener("tcp://:8001", setExAddr, false, log.TestingLogger()) - lAddr := l.ExternalAddress().String() - require.Equal(t, lAddr, setExAddr) - l.Stop() - } - - { - // Invalid external addr causes panic - setExAddr := "awrlsckjnal:8080" - require.Panics(t, func() { NewDefaultListener("tcp://:8001", setExAddr, false, log.TestingLogger()) }) - } -} diff --git a/p2p/peer.go b/p2p/peer.go index a5f0bbbd8..5dbc582c0 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -6,7 +6,6 @@ import ( "sync/atomic" "time" - crypto "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" @@ -130,87 +129,6 @@ func newPeer( return p } -func newOutboundPeerConn( - addr *NetAddress, - config *config.P2PConfig, - persistent bool, - ourNodePrivKey crypto.PrivKey, -) (peerConn, error) { - conn, err := dial(addr, config) - if err != nil { - return peerConn{}, cmn.ErrorWrap(err, "Error creating peer") - } - - pc, err := newPeerConn(conn, config, true, persistent, ourNodePrivKey, addr) - if err != nil { - if cerr := conn.Close(); cerr != nil { - return peerConn{}, cmn.ErrorWrap(err, cerr.Error()) - } - return peerConn{}, err - } - - // ensure dialed ID matches connection ID - if addr.ID != pc.ID() { - if cerr := conn.Close(); cerr != nil { - return peerConn{}, cmn.ErrorWrap(err, cerr.Error()) - } - return peerConn{}, ErrSwitchAuthenticationFailure{addr, pc.ID()} - } - - return pc, nil -} - -func newInboundPeerConn( - conn net.Conn, - config *config.P2PConfig, - ourNodePrivKey crypto.PrivKey, -) (peerConn, error) { - - // TODO: issue PoW challenge - - return newPeerConn(conn, config, false, false, ourNodePrivKey, nil) -} - -func newPeerConn( - rawConn net.Conn, - cfg *config.P2PConfig, - outbound, persistent bool, - ourNodePrivKey crypto.PrivKey, - originalAddr *NetAddress, -) (pc peerConn, err error) { - conn := rawConn - - // Fuzz connection - if cfg.TestFuzz { - // so we have time to do peer handshakes and get set up - conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig) - } - - // Set deadline for secret handshake - dl := time.Now().Add(cfg.HandshakeTimeout) - if err := conn.SetDeadline(dl); err != nil { - return pc, cmn.ErrorWrap( - err, - "Error setting deadline while encrypting connection", - ) - } - - // Encrypt connection - conn, err = tmconn.MakeSecretConnection(conn, ourNodePrivKey) - if err != nil { - return pc, cmn.ErrorWrap(err, "Error creating peer") - } - - // Only the information we already have - return peerConn{ - config: cfg, - outbound: outbound, - persistent: persistent, - conn: conn, - originalAddr: originalAddr, - }, nil -} - //--------------------------------------------------- // Implements cmn.Service @@ -399,18 +317,6 @@ func (p *peer) String() string { //------------------------------------------------------------------ // helper funcs -func dial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) { - if cfg.TestDialFail { - return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)") - } - - conn, err := addr.DialTimeout(cfg.DialTimeout) - if err != nil { - return nil, err - } - return conn, nil -} - func createMConnection( conn net.Conn, p *peer, diff --git a/p2p/peer_test.go b/p2p/peer_test.go index f0e915328..a2a2946a1 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -1,6 +1,7 @@ package p2p import ( + "fmt" golog "log" "net" "testing" @@ -76,7 +77,7 @@ func createOutboundPeerAndPerformHandshake( } reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)} pk := ed25519.GenPrivKey() - pc, err := newOutboundPeerConn(addr, config, false, pk) + pc, err := testOutboundPeerConn(addr, config, false, pk) if err != nil { return nil, err } @@ -96,6 +97,48 @@ func createOutboundPeerAndPerformHandshake( return p, nil } +func testDial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) { + if cfg.TestDialFail { + return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)") + } + + conn, err := addr.DialTimeout(cfg.DialTimeout) + if err != nil { + return nil, err + } + return conn, nil +} + +func testOutboundPeerConn( + addr *NetAddress, + config *config.P2PConfig, + persistent bool, + ourNodePrivKey crypto.PrivKey, +) (peerConn, error) { + conn, err := testDial(addr, config) + if err != nil { + return peerConn{}, cmn.ErrorWrap(err, "Error creating peer") + } + + pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr) + if err != nil { + if cerr := conn.Close(); cerr != nil { + return peerConn{}, cmn.ErrorWrap(err, cerr.Error()) + } + return peerConn{}, err + } + + // ensure dialed ID matches connection ID + if addr.ID != pc.ID() { + if cerr := conn.Close(); cerr != nil { + return peerConn{}, cmn.ErrorWrap(err, cerr.Error()) + } + return peerConn{}, ErrSwitchAuthenticationFailure{addr, pc.ID()} + } + + return pc, nil +} + type remotePeer struct { PrivKey crypto.PrivKey Config *config.P2PConfig @@ -143,19 +186,19 @@ func (rp *remotePeer) accept(l net.Listener) { golog.Fatalf("Failed to accept conn: %+v", err) } - pc, err := newInboundPeerConn(conn, rp.Config, rp.PrivKey) + pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey) if err != nil { golog.Fatalf("Failed to create a peer: %+v", err) } - _, err = pc.HandshakeTimeout(NodeInfo{ + _, err = handshake(pc.conn, time.Second, NodeInfo{ ID: rp.Addr().ID, Moniker: "remote_peer", Network: "testing", Version: "123.123.123", ListenAddr: l.Addr().String(), Channels: rp.channels, - }, 1*time.Second) + }) if err != nil { golog.Fatalf("Failed to perform handshake: %+v", err) } diff --git a/p2p/pex/pex_reactor_test.go b/p2p/pex/pex_reactor_test.go index f72f81e06..c22eabdc1 100644 --- a/p2p/pex/pex_reactor_test.go +++ b/p2p/pex/pex_reactor_test.go @@ -109,9 +109,7 @@ func TestPEXReactorRunning(t *testing.T) { addOtherNodeAddrToAddrBook(1, 0) addOtherNodeAddrToAddrBook(2, 1) - for i, sw := range switches { - sw.AddListener(p2p.NewDefaultListener("tcp://"+sw.NodeInfo().ListenAddr, "", false, logger.With("pex", i))) - + for _, sw := range switches { err := sw.Start() // start switch and reactors require.Nil(t, err) } @@ -474,9 +472,6 @@ func testCreatePeerWithConfig(dir string, id int, config *PEXReactorConfig) *p2p return sw }, ) - peer.AddListener( - p2p.NewDefaultListener("tcp://"+peer.NodeInfo().ListenAddr, "", false, log.TestingLogger()), - ) return peer } @@ -510,9 +505,6 @@ func testCreateSeed(dir string, id int, knownAddrs, srcAddrs []*p2p.NetAddress) return sw }, ) - seed.AddListener( - p2p.NewDefaultListener("tcp://"+seed.NodeInfo().ListenAddr, "", false, log.TestingLogger()), - ) return seed } diff --git a/p2p/switch.go b/p2p/switch.go index b5413dabf..57077e07d 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -3,7 +3,6 @@ package p2p import ( "fmt" "math" - "net" "sync" "time" @@ -42,6 +41,10 @@ type AddrBook interface { Save() } +// PeerFilterFunc to be implemented by filter hooks after a new Peer has been +// fully setup. +type PeerFilterFunc func(IPeerSet, Peer) error + //----------------------------------------------------------------------------- // Switch handles peer connections and exposes an API to receive incoming messages @@ -52,7 +55,6 @@ type Switch struct { cmn.BaseService config *config.P2PConfig - listeners []Listener reactors map[string]Reactor chDescs []*conn.ChannelDescriptor reactorsByCh map[byte]Reactor @@ -63,8 +65,10 @@ type Switch struct { nodeKey *NodeKey // our node privkey addrBook AddrBook - filterConnByAddr func(net.Addr) error - filterConnByID func(ID) error + transport Transport + + filterTimeout time.Duration + peerFilters []PeerFilterFunc mConfig conn.MConnConfig @@ -77,16 +81,22 @@ type Switch struct { type SwitchOption func(*Switch) // NewSwitch creates a new Switch with the given config. -func NewSwitch(cfg *config.P2PConfig, options ...SwitchOption) *Switch { +func NewSwitch( + cfg *config.P2PConfig, + transport Transport, + options ...SwitchOption, +) *Switch { sw := &Switch{ - config: cfg, - reactors: make(map[string]Reactor), - chDescs: make([]*conn.ChannelDescriptor, 0), - reactorsByCh: make(map[byte]Reactor), - peers: NewPeerSet(), - dialing: cmn.NewCMap(), - reconnecting: cmn.NewCMap(), - metrics: NopMetrics(), + config: cfg, + reactors: make(map[string]Reactor), + chDescs: make([]*conn.ChannelDescriptor, 0), + reactorsByCh: make(map[byte]Reactor), + peers: NewPeerSet(), + dialing: cmn.NewCMap(), + reconnecting: cmn.NewCMap(), + metrics: NopMetrics(), + transport: transport, + filterTimeout: defaultFilterTimeout, } // Ensure we have a completely undeterministic PRNG. @@ -109,6 +119,16 @@ func NewSwitch(cfg *config.P2PConfig, options ...SwitchOption) *Switch { return sw } +// SwitchFilterTimeout sets the timeout used for peer filters. +func SwitchFilterTimeout(timeout time.Duration) SwitchOption { + return func(sw *Switch) { sw.filterTimeout = timeout } +} + +// SwitchPeerFilters sets the filters for rejection of new peers. +func SwitchPeerFilters(filters ...PeerFilterFunc) SwitchOption { + return func(sw *Switch) { sw.peerFilters = filters } +} + // WithMetrics sets the metrics. func WithMetrics(metrics *Metrics) SwitchOption { return func(sw *Switch) { sw.metrics = metrics } @@ -148,24 +168,6 @@ func (sw *Switch) Reactor(name string) Reactor { return sw.reactors[name] } -// AddListener adds the given listener to the switch for listening to incoming peer connections. -// NOTE: Not goroutine safe. -func (sw *Switch) AddListener(l Listener) { - sw.listeners = append(sw.listeners, l) -} - -// Listeners returns the list of listeners the switch listens on. -// NOTE: Not goroutine safe. -func (sw *Switch) Listeners() []Listener { - return sw.listeners -} - -// IsListening returns true if the switch has at least one listener. -// NOTE: Not goroutine safe. -func (sw *Switch) IsListening() bool { - return len(sw.listeners) > 0 -} - // SetNodeInfo sets the switch's NodeInfo for checking compatibility and handshaking with other nodes. // NOTE: Not goroutine safe. func (sw *Switch) SetNodeInfo(nodeInfo NodeInfo) { @@ -187,7 +189,7 @@ func (sw *Switch) SetNodeKey(nodeKey *NodeKey) { //--------------------------------------------------------------------- // Service start/stop -// OnStart implements BaseService. It starts all the reactors, peers, and listeners. +// OnStart implements BaseService. It starts all the reactors and peers. func (sw *Switch) OnStart() error { // Start reactors for _, reactor := range sw.reactors { @@ -196,25 +198,21 @@ func (sw *Switch) OnStart() error { return cmn.ErrorWrap(err, "failed to start %v", reactor) } } - // Start listeners - for _, listener := range sw.listeners { - go sw.listenerRoutine(listener) - } + + // Start accepting Peers. + go sw.acceptRoutine() + return nil } -// OnStop implements BaseService. It stops all listeners, peers, and reactors. +// OnStop implements BaseService. It stops all peers and reactors. func (sw *Switch) OnStop() { - // Stop listeners - for _, listener := range sw.listeners { - listener.Stop() - } - sw.listeners = nil // Stop peers - for _, peer := range sw.peers.List() { - peer.Stop() - sw.peers.Remove(peer) + for _, p := range sw.peers.List() { + p.Stop() + sw.peers.Remove(p) } + // Stop reactors sw.Logger.Debug("Switch: Stopping reactors") for _, reactor := range sw.reactors { @@ -459,42 +457,46 @@ func (sw *Switch) IsDialingOrExistingAddress(addr *NetAddress) bool { (!sw.config.AllowDuplicateIP && sw.peers.HasIP(addr.IP)) } -//------------------------------------------------------------------------------------ -// Connection filtering - -// FilterConnByAddr returns an error if connecting to the given address is forbidden. -func (sw *Switch) FilterConnByAddr(addr net.Addr) error { - if sw.filterConnByAddr != nil { - return sw.filterConnByAddr(addr) - } - return nil -} - -// FilterConnByID returns an error if connecting to the given peer ID is forbidden. -func (sw *Switch) FilterConnByID(id ID) error { - if sw.filterConnByID != nil { - return sw.filterConnByID(id) - } - return nil - -} - -// SetAddrFilter sets the function for filtering connections by address. -func (sw *Switch) SetAddrFilter(f func(net.Addr) error) { - sw.filterConnByAddr = f -} - -// SetIDFilter sets the function for filtering connections by peer ID. -func (sw *Switch) SetIDFilter(f func(ID) error) { - sw.filterConnByID = f -} +func (sw *Switch) acceptRoutine() { + for { + p, err := sw.transport.Accept(peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + reactorsByCh: sw.reactorsByCh, + }) + if err != nil { + switch err.(type) { + case ErrRejected: + rErr := err.(ErrRejected) + + if rErr.IsSelf() { + // Remove the given address from the address book and add to our addresses + // to avoid dialing in the future. + addr := rErr.Addr() + sw.addrBook.RemoveAddress(&addr) + sw.addrBook.AddOurAddress(&addr) + } -//------------------------------------------------------------------------------------ + sw.Logger.Info( + "Inbound Peer rejected", + "err", err, + "numPeers", sw.peers.Size(), + ) + + continue + case *ErrTransportClosed: + sw.Logger.Error( + "Stopped accept routine, as transport is closed", + "numPeers", sw.peers.Size(), + ) + default: + sw.Logger.Error( + "Accept on transport errored", + "err", err, + "numPeers", sw.peers.Size(), + ) + } -func (sw *Switch) listenerRoutine(l Listener) { - for { - inConn, ok := <-l.Connections() - if !ok { break } @@ -503,41 +505,25 @@ func (sw *Switch) listenerRoutine(l Listener) { if in >= sw.config.MaxNumInboundPeers { sw.Logger.Info( "Ignoring inbound connection: already have enough inbound peers", - "address", inConn.RemoteAddr().String(), + "address", p.NodeInfo().NetAddress().String(), "have", in, "max", sw.config.MaxNumInboundPeers, ) - inConn.Close() - continue - } - // New inbound connection! - err := sw.addInboundPeerWithConfig(inConn, sw.config) - if err != nil { - sw.Logger.Info("Ignoring inbound connection: error while adding peer", "address", inConn.RemoteAddr().String(), "err", err) + _ = p.Stop() + continue } - } - - // cleanup -} -// closes conn if err is returned -func (sw *Switch) addInboundPeerWithConfig( - conn net.Conn, - config *config.P2PConfig, -) error { - peerConn, err := newInboundPeerConn(conn, config, sw.nodeKey.PrivKey) - if err != nil { - conn.Close() // peer is nil - return err - } - if err = sw.addPeer(peerConn); err != nil { - peerConn.CloseConn() - return err + if err := sw.addPeer(p); err != nil { + _ = p.Stop() + sw.Logger.Info( + "Ignoring inbound connection: error while adding peer", + "err", err, + "id", p.ID(), + ) + } } - - return nil } // dial the peer; make secret connection; authenticate against the dialed ID; @@ -547,109 +533,88 @@ func (sw *Switch) addInboundPeerWithConfig( // StopPeerForError is called func (sw *Switch) addOutboundPeerWithConfig( addr *NetAddress, - config *config.P2PConfig, + cfg *config.P2PConfig, persistent bool, ) error { sw.Logger.Info("Dialing peer", "address", addr) - peerConn, err := newOutboundPeerConn( - addr, - config, - persistent, - sw.nodeKey.PrivKey, - ) + + // XXX(xla): Remove the leakage of test concerns in implementation. + if cfg.TestDialFail { + go sw.reconnectToPeer(addr) + return fmt.Errorf("dial err (peerConfig.DialFail == true)") + } + + p, err := sw.transport.Dial(*addr, peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + persistent: persistent, + reactorsByCh: sw.reactorsByCh, + }) if err != nil { + switch e := err.(type) { + case ErrRejected: + if e.IsSelf() { + // Remove the given address from the address book and add to our addresses + // to avoid dialing in the future. + sw.addrBook.RemoveAddress(addr) + sw.addrBook.AddOurAddress(addr) + } + } + if persistent { go sw.reconnectToPeer(addr) } + return err } - if err := sw.addPeer(peerConn); err != nil { - peerConn.CloseConn() + if err := sw.addPeer(p); err != nil { + _ = p.Stop() return err } + return nil } -// addPeer performs the Tendermint P2P handshake with a peer -// that already has a SecretConnection. If all goes well, -// it starts the peer and adds it to the switch. -// NOTE: This performs a blocking handshake before the peer is added. -// NOTE: If error is returned, caller is responsible for calling -// peer.CloseConn() -func (sw *Switch) addPeer(pc peerConn) error { - - addr := pc.conn.RemoteAddr() - if err := sw.FilterConnByAddr(addr); err != nil { - return err - } - - // Exchange NodeInfo on the conn - peerNodeInfo, err := pc.HandshakeTimeout(sw.nodeInfo, time.Duration(sw.config.HandshakeTimeout)) - if err != nil { - return err +func (sw *Switch) filterPeer(p Peer) error { + // Avoid duplicate + if sw.peers.Has(p.ID()) { + return ErrRejected{id: p.ID(), isDuplicate: true} } - peerID := peerNodeInfo.ID + errc := make(chan error, len(sw.peerFilters)) - // ensure connection key matches self reported key - connID := pc.ID() - - if peerID != connID { - return fmt.Errorf( - "nodeInfo.ID() (%v) doesn't match conn.ID() (%v)", - peerID, - connID, - ) + for _, f := range sw.peerFilters { + go func(f PeerFilterFunc, p Peer, errc chan<- error) { + errc <- f(sw.peers, p) + }(f, p, errc) } - // Validate the peers nodeInfo - if err := peerNodeInfo.Validate(); err != nil { - return err - } - - // Avoid self - if sw.nodeKey.ID() == peerID { - addr := peerNodeInfo.NetAddress() - // remove the given address from the address book - // and add to our addresses to avoid dialing again - if sw.addrBook != nil { - sw.addrBook.RemoveAddress(addr) - sw.addrBook.AddOurAddress(addr) + for i := 0; i < cap(errc); i++ { + select { + case err := <-errc: + if err != nil { + return ErrRejected{id: p.ID(), err: err, isFiltered: true} + } + case <-time.After(sw.filterTimeout): + return ErrFilterTimeout{} } - return ErrSwitchConnectToSelf{addr} - } - - // Avoid duplicate - if sw.peers.Has(peerID) { - return ErrSwitchDuplicatePeerID{peerID} - } - - // Check for duplicate connection or peer info IP. - if !sw.config.AllowDuplicateIP && - (sw.peers.HasIP(pc.RemoteIP()) || - sw.peers.HasIP(peerNodeInfo.NetAddress().IP)) { - return ErrSwitchDuplicatePeerIP{pc.RemoteIP()} } - // Filter peer against ID white list - if err := sw.FilterConnByID(peerID); err != nil { - return err - } + return nil +} - // Check version, chain id - if err := sw.nodeInfo.CompatibleWith(peerNodeInfo); err != nil { +// addPeer starts up the Peer and adds it to the Switch. +func (sw *Switch) addPeer(p Peer) error { + if err := sw.filterPeer(p); err != nil { return err } - peer := newPeer(pc, sw.mConfig, peerNodeInfo, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError) - peer.SetLogger(sw.Logger.With("peer", addr)) - - peer.Logger.Info("Successful handshake with peer", "peerNodeInfo", peerNodeInfo) + p.SetLogger(sw.Logger.With("peer", p.NodeInfo().NetAddress().String)) // All good. Start peer if sw.IsRunning() { - if err = sw.startInitPeer(peer); err != nil { + if err := sw.startInitPeer(p); err != nil { return err } } @@ -657,25 +622,30 @@ func (sw *Switch) addPeer(pc peerConn) error { // Add the peer to .peers. // We start it first so that a peer in the list is safe to Stop. // It should not err since we already checked peers.Has(). - if err := sw.peers.Add(peer); err != nil { + if err := sw.peers.Add(p); err != nil { return err } + + sw.Logger.Info("Added peer", "peer", p) sw.metrics.Peers.Add(float64(1)) - sw.Logger.Info("Added peer", "peer", peer) return nil } -func (sw *Switch) startInitPeer(peer *peer) error { - err := peer.Start() // spawn send/recv routines +func (sw *Switch) startInitPeer(p Peer) error { + err := p.Start() // spawn send/recv routines if err != nil { // Should never happen - sw.Logger.Error("Error starting peer", "peer", peer, "err", err) + sw.Logger.Error( + "Error starting peer", + "err", err, + "peer", p, + ) return err } for _, reactor := range sw.reactors { - reactor.AddPeer(peer) + reactor.AddPeer(p) } return nil diff --git a/p2p/switch_test.go b/p2p/switch_test.go index 2ce297761..4fea3cfe0 100644 --- a/p2p/switch_test.go +++ b/p2p/switch_test.go @@ -3,7 +3,6 @@ package p2p import ( "bytes" "fmt" - "net" "sync" "testing" "time" @@ -11,10 +10,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" - - "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/p2p/conn" ) @@ -151,35 +149,6 @@ func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, r } } -func TestConnAddrFilter(t *testing.T) { - s1 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc) - s2 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc) - defer s1.Stop() - defer s2.Stop() - - c1, c2 := conn.NetPipe() - - s1.SetAddrFilter(func(addr net.Addr) error { - if addr.String() == c1.RemoteAddr().String() { - return fmt.Errorf("Error: pipe is blacklisted") - } - return nil - }) - - // connect to good peer - go func() { - err := s1.addPeerWithConnection(c1) - assert.NotNil(t, err, "expected err") - }() - go func() { - err := s2.addPeerWithConnection(c2) - assert.NotNil(t, err, "expected err") - }() - - assertNoPeersAfterTimeout(t, s1, 400*time.Millisecond) - assertNoPeersAfterTimeout(t, s2, 400*time.Millisecond) -} - func TestSwitchFiltersOutItself(t *testing.T) { s1 := MakeSwitch(cfg, 1, "127.0.0.1", "123.123.123", initSwitchFunc) // addr := s1.NodeInfo().NetAddress() @@ -194,11 +163,16 @@ func TestSwitchFiltersOutItself(t *testing.T) { // addr should be rejected in addPeer based on the same ID err := s1.DialPeerWithAddress(rp.Addr(), false) if assert.Error(t, err) { - assert.Equal(t, ErrSwitchConnectToSelf{rp.Addr()}.Error(), err.Error()) + if err, ok := err.(ErrRejected); ok { + if !err.IsSelf() { + t.Errorf("expected self to be rejected") + } + } else { + t.Errorf("expected ErrRejected") + } } assert.True(t, s1.addrBook.OurAddress(rp.Addr())) - assert.False(t, s1.addrBook.HasAddress(rp.Addr())) rp.Stop() @@ -206,46 +180,124 @@ func TestSwitchFiltersOutItself(t *testing.T) { assertNoPeersAfterTimeout(t, s1, 100*time.Millisecond) } -func assertNoPeersAfterTimeout(t *testing.T, sw *Switch, timeout time.Duration) { - time.Sleep(timeout) - if sw.Peers().Size() != 0 { - t.Fatalf("Expected %v to not connect to some peers, got %d", sw, sw.Peers().Size()) +func TestSwitchPeerFilter(t *testing.T) { + var ( + filters = []PeerFilterFunc{ + func(_ IPeerSet, _ Peer) error { return nil }, + func(_ IPeerSet, _ Peer) error { return fmt.Errorf("denied!") }, + func(_ IPeerSet, _ Peer) error { return nil }, + } + sw = MakeSwitch( + cfg, + 1, + "testing", + "123.123.123", + initSwitchFunc, + SwitchPeerFilters(filters...), + ) + ) + defer sw.Stop() + + // simulate remote peer + rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg} + rp.Start() + defer rp.Stop() + + p, err := sw.transport.Dial(*rp.Addr(), peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + reactorsByCh: sw.reactorsByCh, + }) + if err != nil { + t.Fatal(err) + } + + err = sw.addPeer(p) + if err, ok := err.(ErrRejected); ok { + if !err.IsFiltered() { + t.Errorf("expected peer to be filtered") + } + } else { + t.Errorf("expected ErrRejected") } } -func TestConnIDFilter(t *testing.T) { - s1 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc) - s2 := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc) - defer s1.Stop() - defer s2.Stop() +func TestSwitchPeerFilterTimeout(t *testing.T) { + var ( + filters = []PeerFilterFunc{ + func(_ IPeerSet, _ Peer) error { + time.Sleep(10 * time.Millisecond) + return nil + }, + } + sw = MakeSwitch( + cfg, + 1, + "testing", + "123.123.123", + initSwitchFunc, + SwitchFilterTimeout(5*time.Millisecond), + SwitchPeerFilters(filters...), + ) + ) + defer sw.Stop() - c1, c2 := conn.NetPipe() + // simulate remote peer + rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg} + rp.Start() + defer rp.Stop() - s1.SetIDFilter(func(id ID) error { - if id == s2.nodeInfo.ID { - return fmt.Errorf("Error: pipe is blacklisted") - } - return nil + p, err := sw.transport.Dial(*rp.Addr(), peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + reactorsByCh: sw.reactorsByCh, }) + if err != nil { + t.Fatal(err) + } - s2.SetIDFilter(func(id ID) error { - if id == s1.nodeInfo.ID { - return fmt.Errorf("Error: pipe is blacklisted") - } - return nil + err = sw.addPeer(p) + if _, ok := err.(ErrFilterTimeout); !ok { + t.Errorf("expected ErrFilterTimeout") + } +} + +func TestSwitchPeerFilterDuplicate(t *testing.T) { + sw := MakeSwitch(cfg, 1, "testing", "123.123.123", initSwitchFunc) + + // simulate remote peer + rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg} + rp.Start() + defer rp.Stop() + + p, err := sw.transport.Dial(*rp.Addr(), peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + reactorsByCh: sw.reactorsByCh, }) + if err != nil { + t.Fatal(err) + } - go func() { - err := s1.addPeerWithConnection(c1) - assert.NotNil(t, err, "expected error") - }() - go func() { - err := s2.addPeerWithConnection(c2) - assert.NotNil(t, err, "expected error") - }() + if err := sw.addPeer(p); err != nil { + t.Fatal(err) + } + + err = sw.addPeer(p) + if err, ok := err.(ErrRejected); ok { + if !err.IsDuplicate() { + t.Errorf("expected peer to be duplicate") + } + } else { + t.Errorf("expected ErrRejected") + } +} - assertNoPeersAfterTimeout(t, s1, 400*time.Millisecond) - assertNoPeersAfterTimeout(t, s2, 400*time.Millisecond) +func assertNoPeersAfterTimeout(t *testing.T, sw *Switch, timeout time.Duration) { + time.Sleep(timeout) + if sw.Peers().Size() != 0 { + t.Fatalf("Expected %v to not connect to some peers, got %d", sw, sw.Peers().Size()) + } } func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) { @@ -263,19 +315,23 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) { rp.Start() defer rp.Stop() - pc, err := newOutboundPeerConn(rp.Addr(), cfg, false, sw.nodeKey.PrivKey) + p, err := sw.transport.Dial(*rp.Addr(), peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + reactorsByCh: sw.reactorsByCh, + }) require.Nil(err) - err = sw.addPeer(pc) + + err = sw.addPeer(p) require.Nil(err) - peer := sw.Peers().Get(rp.ID()) - require.NotNil(peer) + require.NotNil(sw.Peers().Get(rp.ID())) // simulate failure by closing connection - pc.CloseConn() + p.(*peer).CloseConn() assertNoPeersAfterTimeout(t, sw, 100*time.Millisecond) - assert.False(peer.IsRunning()) + assert.False(p.IsRunning()) } func TestSwitchReconnectsToPersistentPeer(t *testing.T) { @@ -293,17 +349,20 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) { rp.Start() defer rp.Stop() - pc, err := newOutboundPeerConn(rp.Addr(), cfg, true, sw.nodeKey.PrivKey) - // sw.reactorsByCh, sw.chDescs, sw.StopPeerForError, sw.nodeKey.PrivKey, + p, err := sw.transport.Dial(*rp.Addr(), peerConfig{ + chDescs: sw.chDescs, + onPeerError: sw.StopPeerForError, + persistent: true, + reactorsByCh: sw.reactorsByCh, + }) require.Nil(err) - require.Nil(sw.addPeer(pc)) + require.Nil(sw.addPeer(p)) - peer := sw.Peers().Get(rp.ID()) - require.NotNil(peer) + require.NotNil(sw.Peers().Get(rp.ID())) // simulate failure by closing connection - pc.CloseConn() + p.(*peer).CloseConn() // TODO: remove sleep, detect the disconnection, wait for reconnect npeers := sw.Peers().Size() @@ -315,7 +374,7 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) { } } assert.NotZero(npeers) - assert.False(peer.IsRunning()) + assert.False(p.IsRunning()) // simulate another remote peer rp = &remotePeer{ diff --git a/p2p/test_util.go b/p2p/test_util.go index b88dfb06a..64b8b215c 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -3,7 +3,9 @@ package p2p import ( "fmt" "net" + "time" + crypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" @@ -104,14 +106,32 @@ func Connect2Switches(switches []*Switch, i, j int) { } func (sw *Switch) addPeerWithConnection(conn net.Conn) error { - pc, err := newInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey) + pc, err := testInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey) if err != nil { if err := conn.Close(); err != nil { sw.Logger.Error("Error closing connection", "err", err) } return err } - if err = sw.addPeer(pc); err != nil { + + ni, err := handshake(conn, 50*time.Millisecond, sw.nodeInfo) + if err != nil { + if err := conn.Close(); err != nil { + sw.Logger.Error("Error closing connection", "err", err) + } + return err + } + + p := newPeer( + pc, + sw.mConfig, + ni, + sw.reactorsByCh, + sw.chDescs, + sw.StopPeerForError, + ) + + if err = sw.addPeer(p); err != nil { pc.CloseConn() return err } @@ -131,35 +151,99 @@ func StartSwitches(switches []*Switch) error { return nil } -func MakeSwitch(cfg *config.P2PConfig, i int, network, version string, initSwitch func(int, *Switch) *Switch) *Switch { - // new switch, add reactors - // TODO: let the config be passed in? - nodeKey := &NodeKey{ - PrivKey: ed25519.GenPrivKey(), +func MakeSwitch( + cfg *config.P2PConfig, + i int, + network, version string, + initSwitch func(int, *Switch) *Switch, + opts ...SwitchOption, +) *Switch { + var ( + nodeKey = NodeKey{ + PrivKey: ed25519.GenPrivKey(), + } + ni = NodeInfo{ + ID: nodeKey.ID(), + Moniker: fmt.Sprintf("switch%d", i), + Network: network, + Version: version, + ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023), + Other: NodeInfoOther{ + AminoVersion: "1.0", + P2PVersion: "1.0", + ConsensusVersion: "1.0", + RPCVersion: "1.0", + TxIndex: "off", + RPCAddress: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023), + }, + } + ) + + addr, err := NewNetAddressStringWithOptionalID( + IDAddressString(nodeKey.ID(), ni.ListenAddr), + ) + if err != nil { + panic(err) } - sw := NewSwitch(cfg) - sw.SetLogger(log.TestingLogger()) - sw = initSwitch(i, sw) - addr := fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023) - ni := NodeInfo{ - ID: nodeKey.ID(), - Moniker: fmt.Sprintf("switch%d", i), - Network: network, - Version: version, - ListenAddr: addr, - Other: NodeInfoOther{ - AminoVersion: "1.0", - P2PVersion: "1.0", - ConsensusVersion: "1.0", - RPCVersion: "1.0", - TxIndex: "off", - RPCAddress: addr, - }, + + t := NewMultiplexTransport(ni, nodeKey) + + if err := t.Listen(*addr); err != nil { + panic(err) } + + // TODO: let the config be passed in? + sw := initSwitch(i, NewSwitch(cfg, t, opts...)) + sw.SetLogger(log.TestingLogger()) + sw.SetNodeKey(&nodeKey) + for ch := range sw.reactorsByCh { ni.Channels = append(ni.Channels, ch) } + + // TODO: We need to setup reactors ahead of time so the NodeInfo is properly + // populated and we don't have to do those awkward overrides and setters. + t.nodeInfo = ni sw.SetNodeInfo(ni) - sw.SetNodeKey(nodeKey) + return sw } + +func testInboundPeerConn( + conn net.Conn, + config *config.P2PConfig, + ourNodePrivKey crypto.PrivKey, +) (peerConn, error) { + return testPeerConn(conn, config, false, false, ourNodePrivKey, nil) +} + +func testPeerConn( + rawConn net.Conn, + cfg *config.P2PConfig, + outbound, persistent bool, + ourNodePrivKey crypto.PrivKey, + originalAddr *NetAddress, +) (pc peerConn, err error) { + conn := rawConn + + // Fuzz connection + if cfg.TestFuzz { + // so we have time to do peer handshakes and get set up + conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig) + } + + // Encrypt connection + conn, err = upgradeSecretConn(conn, cfg.HandshakeTimeout, ourNodePrivKey) + if err != nil { + return pc, cmn.ErrorWrap(err, "Error creating peer") + } + + // Only the information we already have + return peerConn{ + config: cfg, + outbound: outbound, + persistent: persistent, + conn: conn, + originalAddr: originalAddr, + }, nil +} diff --git a/rpc/core/consensus.go b/rpc/core/consensus.go index 4e4c54dea..193fbd285 100644 --- a/rpc/core/consensus.go +++ b/rpc/core/consensus.go @@ -191,7 +191,7 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) { // ``` func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { // Get Peer consensus states. - peers := p2pSwitch.Peers().List() + peers := p2pPeers.Peers().List() peerStates := make([]ctypes.PeerStateInfo, len(peers)) for i, peer := range peers { peerState := peer.Get(types.PeerStateKey).(*cm.PeerState) diff --git a/rpc/core/net.go b/rpc/core/net.go index ba9753d81..acb18a34f 100644 --- a/rpc/core/net.go +++ b/rpc/core/net.go @@ -35,13 +35,8 @@ import ( // } // ``` func NetInfo() (*ctypes.ResultNetInfo, error) { - listening := p2pSwitch.IsListening() - listeners := []string{} - for _, listener := range p2pSwitch.Listeners() { - listeners = append(listeners, listener.String()) - } peers := []ctypes.Peer{} - for _, peer := range p2pSwitch.Peers().List() { + for _, peer := range p2pPeers.Peers().List() { peers = append(peers, ctypes.Peer{ NodeInfo: peer.NodeInfo(), IsOutbound: peer.IsOutbound(), @@ -52,8 +47,8 @@ func NetInfo() (*ctypes.ResultNetInfo, error) { // PRO: useful info // CON: privacy return &ctypes.ResultNetInfo{ - Listening: listening, - Listeners: listeners, + Listening: p2pTransport.IsListening(), + Listeners: p2pTransport.Listeners(), NPeers: len(peers), Peers: peers, }, nil @@ -65,7 +60,7 @@ func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) { } // starts go routines to dial each peer after random delays logger.Info("DialSeeds", "addrBook", addrBook, "seeds", seeds) - err := p2pSwitch.DialPeersAsync(addrBook, seeds, false) + err := p2pPeers.DialPeersAsync(addrBook, seeds, false) if err != nil { return &ctypes.ResultDialSeeds{}, err } @@ -78,7 +73,7 @@ func UnsafeDialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers, } // starts go routines to dial each peer after random delays logger.Info("DialPeers", "addrBook", addrBook, "peers", peers, "persistent", persistent) - err := p2pSwitch.DialPeersAsync(addrBook, peers, persistent) + err := p2pPeers.DialPeersAsync(addrBook, peers, persistent) if err != nil { return &ctypes.ResultDialPeers{}, err } diff --git a/rpc/core/pipe.go b/rpc/core/pipe.go index 1d1f61466..188ea1c36 100644 --- a/rpc/core/pipe.go +++ b/rpc/core/pipe.go @@ -34,13 +34,16 @@ type Consensus interface { GetRoundStateSimpleJSON() ([]byte, error) } -type P2P interface { - Listeners() []p2p.Listener - Peers() p2p.IPeerSet - NumPeers() (outbound, inbound, dialig int) - NodeInfo() p2p.NodeInfo +type transport interface { + Listeners() []string IsListening() bool + NodeInfo() p2p.NodeInfo +} + +type peers interface { DialPeersAsync(p2p.AddrBook, []string, bool) error + NumPeers() (outbound, inbound, dialig int) + Peers() p2p.IPeerSet } //---------------------------------------------- @@ -56,7 +59,8 @@ var ( blockStore sm.BlockStore evidencePool sm.EvidencePool consensusState Consensus - p2pSwitch P2P + p2pPeers peers + p2pTransport transport // objects pubKey crypto.PubKey @@ -90,8 +94,12 @@ func SetConsensusState(cs Consensus) { consensusState = cs } -func SetSwitch(sw P2P) { - p2pSwitch = sw +func SetP2PPeers(p peers) { + p2pPeers = p +} + +func SetP2PTransport(t transport) { + p2pTransport = t } func SetPubKey(pk crypto.PubKey) { diff --git a/rpc/core/status.go b/rpc/core/status.go index de8d69cce..17fb2f341 100644 --- a/rpc/core/status.go +++ b/rpc/core/status.go @@ -91,7 +91,7 @@ func Status() (*ctypes.ResultStatus, error) { } result := &ctypes.ResultStatus{ - NodeInfo: p2pSwitch.NodeInfo(), + NodeInfo: p2pTransport.NodeInfo(), SyncInfo: ctypes.SyncInfo{ LatestBlockHash: latestBlockHash, LatestAppHash: latestAppHash, From 3e099f75c7bb3ec746c6cb49321fd18501ece638 Mon Sep 17 00:00:00 2001 From: zhangzheng Date: Wed, 19 Sep 2018 17:46:37 +0800 Subject: [PATCH 25/47] minor note in indexing-transactions.md (#2443) (#2444) Fix inconsistent documents and code --- docs/app-dev/indexing-transactions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/app-dev/indexing-transactions.md b/docs/app-dev/indexing-transactions.md index 3ba097c4c..61c959ca4 100644 --- a/docs/app-dev/indexing-transactions.md +++ b/docs/app-dev/indexing-transactions.md @@ -12,8 +12,8 @@ Let's take a look at the `[tx_index]` config section: # What indexer to use for transactions # # Options: -# 1) "null" (default) -# 2) "kv" - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). indexer = "kv" # Comma-separated list of tags to index (by default the only tag is "tx.hash") From 91a8767083216b7688e869c9e1166cf4af29a8d9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 19 Sep 2018 09:35:09 -0400 Subject: [PATCH 26/47] proxy: remove Handshaker from proxy pkg (#2437) Handshaker was removed from proxy package so it can be called independently of starting the abci app connections and can return a result to the caller. --- consensus/replay_file.go | 9 +++++++-- consensus/replay_test.go | 14 ++++++++++---- consensus/wal_generator.go | 4 ++-- node/node.go | 18 +++++++++++------- proxy/multi_app_conn.go | 21 ++++----------------- state/execution_test.go | 8 ++++---- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/consensus/replay_file.go b/consensus/replay_file.go index e4b9f0196..685eb71f2 100644 --- a/consensus/replay_file.go +++ b/consensus/replay_file.go @@ -298,13 +298,18 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo // Create proxyAppConn connection (consensus, mempool, query) clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()) - proxyApp := proxy.NewAppConns(clientCreator, - NewHandshaker(stateDB, state, blockStore, gdoc)) + proxyApp := proxy.NewAppConns(clientCreator) err = proxyApp.Start() if err != nil { cmn.Exit(fmt.Sprintf("Error starting proxy app conns: %v", err)) } + handshaker := NewHandshaker(stateDB, state, blockStore, gdoc) + err = handshaker.Handshake(proxyApp) + if err != nil { + cmn.Exit(fmt.Sprintf("Error on handshake: %v", err)) + } + eventBus := types.NewEventBus() if err := eventBus.Start(); err != nil { cmn.Exit(fmt.Sprintf("Failed to start event bus: %v", err)) diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 44280f694..7a828da64 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -351,7 +351,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { if nBlocks > 0 { // run nBlocks against a new client to build up the app state. // use a throwaway tendermint state - proxyApp := proxy.NewAppConns(clientCreator2, nil) + proxyApp := proxy.NewAppConns(clientCreator2) stateDB, state, _ := stateAndStore(config, privVal.GetPubKey()) buildAppStateFromChain(proxyApp, stateDB, state, chain, nBlocks, mode) } @@ -359,11 +359,14 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { // now start the app using the handshake - it should sync genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) handshaker := NewHandshaker(stateDB, state, store, genDoc) - proxyApp := proxy.NewAppConns(clientCreator2, handshaker) + proxyApp := proxy.NewAppConns(clientCreator2) if err := proxyApp.Start(); err != nil { t.Fatalf("Error starting proxy app connections: %v", err) } defer proxyApp.Stop() + if err := handshaker.Handshake(proxyApp); err != nil { + t.Fatalf("Error on abci handshake: %v", err) + } // get the latest app hash from the app res, err := proxyApp.Query().InfoSync(abci.RequestInfo{Version: ""}) @@ -439,7 +442,7 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB, func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, chain []*types.Block, mode uint) sm.State { // run the whole chain against this client to build up the tendermint state clientCreator := proxy.NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(path.Join(config.DBDir(), "1"))) - proxyApp := proxy.NewAppConns(clientCreator, nil) // sm.NewHandshaker(config, state, store, ReplayLastBlock)) + proxyApp := proxy.NewAppConns(clientCreator) // sm.NewHandshaker(config, state, store, ReplayLastBlock)) if err := proxyApp.Start(); err != nil { panic(err) } @@ -643,11 +646,14 @@ func TestInitChainUpdateValidators(t *testing.T) { // now start the app using the handshake - it should sync genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) handshaker := NewHandshaker(stateDB, state, store, genDoc) - proxyApp := proxy.NewAppConns(clientCreator, handshaker) + proxyApp := proxy.NewAppConns(clientCreator) if err := proxyApp.Start(); err != nil { t.Fatalf("Error starting proxy app connections: %v", err) } defer proxyApp.Stop() + if err := handshaker.Handshake(proxyApp); err != nil { + t.Fatalf("Error on abci handshake: %v", err) + } // reload the state, check the validator set was updated state = sm.LoadState(stateDB) diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 6d889aa6f..cdb667edf 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -52,13 +52,13 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) { return nil, errors.Wrap(err, "failed to make genesis state") } blockStore := bc.NewBlockStore(blockStoreDB) - handshaker := NewHandshaker(stateDB, state, blockStore, genDoc) - proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker) + proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app)) proxyApp.SetLogger(logger.With("module", "proxy")) if err := proxyApp.Start(); err != nil { return nil, errors.Wrap(err, "failed to start proxy app connections") } defer proxyApp.Stop() + eventBus := types.NewEventBus() eventBus.SetLogger(logger.With("module", "events")) if err := eventBus.Start(); err != nil { diff --git a/node/node.go b/node/node.go index 995d1c889..f3dcadf9c 100644 --- a/node/node.go +++ b/node/node.go @@ -190,18 +190,22 @@ func NewNode(config *cfg.Config, return nil, err } - // Create the proxyApp, which manages connections (consensus, mempool, query) - // and sync tendermint and the app by performing a handshake - // and replaying any necessary blocks - consensusLogger := logger.With("module", "consensus") - handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc) - handshaker.SetLogger(consensusLogger) - proxyApp := proxy.NewAppConns(clientCreator, handshaker) + // Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query). + proxyApp := proxy.NewAppConns(clientCreator) proxyApp.SetLogger(logger.With("module", "proxy")) if err := proxyApp.Start(); err != nil { return nil, fmt.Errorf("Error starting proxy app connections: %v", err) } + // Create the handshaker, which calls RequestInfo and replays any blocks + // as necessary to sync tendermint with the app. + consensusLogger := logger.With("module", "consensus") + handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc) + handshaker.SetLogger(consensusLogger) + if err := handshaker.Handshake(proxyApp); err != nil { + return nil, fmt.Errorf("Error during handshake: %v", err) + } + // reload the state (it may have been updated by the handshake) state = sm.LoadState(stateDB) diff --git a/proxy/multi_app_conn.go b/proxy/multi_app_conn.go index 279fa42ee..b5897d8a5 100644 --- a/proxy/multi_app_conn.go +++ b/proxy/multi_app_conn.go @@ -17,26 +17,19 @@ type AppConns interface { Query() AppConnQuery } -func NewAppConns(clientCreator ClientCreator, handshaker Handshaker) AppConns { - return NewMultiAppConn(clientCreator, handshaker) +func NewAppConns(clientCreator ClientCreator) AppConns { + return NewMultiAppConn(clientCreator) } //----------------------------- // multiAppConn implements AppConns -type Handshaker interface { - Handshake(AppConns) error -} - // a multiAppConn is made of a few appConns (mempool, consensus, query) -// and manages their underlying abci clients, including the handshake -// which ensures the app and tendermint are synced. +// and manages their underlying abci clients // TODO: on app restart, clients must reboot together type multiAppConn struct { cmn.BaseService - handshaker Handshaker - mempoolConn *appConnMempool consensusConn *appConnConsensus queryConn *appConnQuery @@ -45,9 +38,8 @@ type multiAppConn struct { } // Make all necessary abci connections to the application -func NewMultiAppConn(clientCreator ClientCreator, handshaker Handshaker) *multiAppConn { +func NewMultiAppConn(clientCreator ClientCreator) *multiAppConn { multiAppConn := &multiAppConn{ - handshaker: handshaker, clientCreator: clientCreator, } multiAppConn.BaseService = *cmn.NewBaseService(nil, "multiAppConn", multiAppConn) @@ -103,10 +95,5 @@ func (app *multiAppConn) OnStart() error { } app.consensusConn = NewAppConnConsensus(concli) - // ensure app is synced to the latest state - if app.handshaker != nil { - return app.handshaker.Handshake(app) - } - return nil } diff --git a/state/execution_test.go b/state/execution_test.go index 02beeb9b7..e93c9bfd1 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -29,7 +29,7 @@ var ( func TestApplyBlock(t *testing.T) { cc := proxy.NewLocalClientCreator(kvstore.NewKVStoreApplication()) - proxyApp := proxy.NewAppConns(cc, nil) + proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() require.Nil(t, err) defer proxyApp.Stop() @@ -52,7 +52,7 @@ func TestApplyBlock(t *testing.T) { func TestBeginBlockValidators(t *testing.T) { app := &testApp{} cc := proxy.NewLocalClientCreator(app) - proxyApp := proxy.NewAppConns(cc, nil) + proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() require.Nil(t, err) defer proxyApp.Stop() @@ -105,7 +105,7 @@ func TestBeginBlockValidators(t *testing.T) { func TestBeginBlockByzantineValidators(t *testing.T) { app := &testApp{} cc := proxy.NewLocalClientCreator(app) - proxyApp := proxy.NewAppConns(cc, nil) + proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() require.Nil(t, err) defer proxyApp.Stop() @@ -239,7 +239,7 @@ func TestUpdateValidators(t *testing.T) { func TestEndBlockValidatorUpdates(t *testing.T) { app := &testApp{} cc := proxy.NewLocalClientCreator(app) - proxyApp := proxy.NewAppConns(cc, nil) + proxyApp := proxy.NewAppConns(cc) err := proxyApp.Start() require.Nil(t, err) defer proxyApp.Stop() From c0cdb9d4413901d015f256609070b9a760280173 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 19 Sep 2018 06:38:30 -0700 Subject: [PATCH 27/47] libs : Remove libs/common/word.go (#2431) We didn't use this code anywhere in the codebase. As such, we probably should reduce the surface area we support. In the event that we do in fact require 256 bit words inside of tendermint, we should adapt the stdlibs' internal word representations, which also handles SIMD. Inside of the SDK, a separate solution for big ints / larger words is employed, which uses big ints. This in turn does utilize the stdlibs SIMD support. --- CHANGELOG_PENDING.md | 1 + libs/common/word.go | 90 -------------------------------------------- 2 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 libs/common/word.go diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index c4b776246..35d776f6f 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -11,6 +11,7 @@ BREAKING CHANGES: * Go API * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas + * \#2431 Remove Word256 code in libs/common, due to lack of use * Blockchain Protocol * P2P Protocol diff --git a/libs/common/word.go b/libs/common/word.go deleted file mode 100644 index a5b841f55..000000000 --- a/libs/common/word.go +++ /dev/null @@ -1,90 +0,0 @@ -package common - -import ( - "bytes" - "sort" -) - -var ( - Zero256 = Word256{0} - One256 = Word256{1} -) - -type Word256 [32]byte - -func (w Word256) String() string { return string(w[:]) } -func (w Word256) TrimmedString() string { return TrimmedString(w.Bytes()) } -func (w Word256) Copy() Word256 { return w } -func (w Word256) Bytes() []byte { return w[:] } // copied. -func (w Word256) Prefix(n int) []byte { return w[:n] } -func (w Word256) Postfix(n int) []byte { return w[32-n:] } -func (w Word256) IsZero() bool { - accum := byte(0) - for _, byt := range w { - accum |= byt - } - return accum == 0 -} -func (w Word256) Compare(other Word256) int { - return bytes.Compare(w[:], other[:]) -} - -func Uint64ToWord256(i uint64) Word256 { - buf := [8]byte{} - PutUint64BE(buf[:], i) - return LeftPadWord256(buf[:]) -} - -func Int64ToWord256(i int64) Word256 { - buf := [8]byte{} - PutInt64BE(buf[:], i) - return LeftPadWord256(buf[:]) -} - -func RightPadWord256(bz []byte) (word Word256) { - copy(word[:], bz) - return -} - -func LeftPadWord256(bz []byte) (word Word256) { - copy(word[32-len(bz):], bz) - return -} - -func Uint64FromWord256(word Word256) uint64 { - buf := word.Postfix(8) - return GetUint64BE(buf) -} - -func Int64FromWord256(word Word256) int64 { - buf := word.Postfix(8) - return GetInt64BE(buf) -} - -//------------------------------------- - -type Tuple256 struct { - First Word256 - Second Word256 -} - -func (tuple Tuple256) Compare(other Tuple256) int { - firstCompare := tuple.First.Compare(other.First) - if firstCompare == 0 { - return tuple.Second.Compare(other.Second) - } - return firstCompare -} - -func Tuple256Split(t Tuple256) (Word256, Word256) { - return t.First, t.Second -} - -type Tuple256Slice []Tuple256 - -func (p Tuple256Slice) Len() int { return len(p) } -func (p Tuple256Slice) Less(i, j int) bool { - return p[i].Compare(p[j]) < 0 -} -func (p Tuple256Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p Tuple256Slice) Sort() { sort.Sort(p) } From aa5495f24e17c72d49a58ac0682d9f9011cb66d3 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 19 Sep 2018 17:54:14 +0400 Subject: [PATCH 28/47] p2p: add RPCAddress to NodeInfoOther.String() (#2442) - remove second AminoVersion from https://github.com/tendermint/tendermint/pull/2426/files#diff-f2fefc7a06ea0d1e0a910196901e50aaR86 Refs #2433 --- node/node.go | 4 +--- p2p/node_info.go | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/node/node.go b/node/node.go index f3dcadf9c..1061fbf7a 100644 --- a/node/node.go +++ b/node/node.go @@ -775,6 +775,7 @@ func makeNodeInfo( ConsensusVersion: cs.Version, RPCVersion: fmt.Sprintf("%v/%v", rpc.Version, rpccore.Version), TxIndex: txIndexerStatus, + RPCAddress: config.RPC.ListenAddress, }, } @@ -782,9 +783,6 @@ func makeNodeInfo( nodeInfo.Channels = append(nodeInfo.Channels, pex.PexChannel) } - rpcListenAddr := config.RPC.ListenAddress - nodeInfo.Other.RPCAddress = rpcListenAddr - lAddr := config.P2P.ExternalAddress if lAddr == "" { diff --git a/p2p/node_info.go b/p2p/node_info.go index a0df3d374..a16535949 100644 --- a/p2p/node_info.go +++ b/p2p/node_info.go @@ -48,12 +48,13 @@ type NodeInfoOther struct { func (o NodeInfoOther) String() string { return fmt.Sprintf( - "{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v}", + "{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v, rpc_address: %v}", o.AminoVersion, o.P2PVersion, o.ConsensusVersion, o.RPCVersion, o.TxIndex, + o.RPCAddress, ) } @@ -84,7 +85,6 @@ func (info NodeInfo) Validate() error { // XXX: Should we be more strict about version and address formats? other := info.Other versions := []string{ - other.AminoVersion, other.AminoVersion, other.P2PVersion, other.ConsensusVersion, From 26aa978456f35708e22af0b2cb752016b58840b5 Mon Sep 17 00:00:00 2001 From: bradyjoestar Date: Thu, 20 Sep 2018 01:40:22 +0800 Subject: [PATCH 29/47] Make mempool cache a proper LRU (#2407) Closes #2399 --- CHANGELOG_PENDING.md | 1 + mempool/mempool.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 35d776f6f..3a881bd28 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -21,6 +21,7 @@ FEATURES: * \#2310 Mempool is now aware of the MaxGas requirement IMPROVEMENTS: +- [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) - [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714) - [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) diff --git a/mempool/mempool.go b/mempool/mempool.go index 0e4a95361..870922627 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -577,7 +577,8 @@ func (cache *mapTxCache) Push(tx types.Tx) bool { // Use the tx hash in the cache txHash := sha256.Sum256(tx) - if _, exists := cache.map_[txHash]; exists { + if moved, exists := cache.map_[txHash]; exists { + cache.list.MoveToFront(moved) return false } From a045c562a248de3585f8041aa7974fd0984638ae Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 19 Sep 2018 18:11:11 -0400 Subject: [PATCH 30/47] update adr-016 (#2435) --- .../architecture/adr-016-protocol-versions.md | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/architecture/adr-016-protocol-versions.md b/docs/architecture/adr-016-protocol-versions.md index 4dba4e848..1ae1f467f 100644 --- a/docs/architecture/adr-016-protocol-versions.md +++ b/docs/architecture/adr-016-protocol-versions.md @@ -4,9 +4,17 @@ - How to / should we version the authenticated encryption handshake itself (ie. upfront protocol negotiation for the P2PVersion) +- How to / should we version ABCI itself? Should it just be absorbed by the + BlockVersion? ## Changelog +- 18-09-2018: Updates after working a bit on implementation + - ABCI Handshake needs to happen independently of starting the app + conns so we can see the result + - Add question about ABCI protocol version +- 16-08-2018: Updates after discussion with SDK team + - Remove signalling for next version from Header/ABCI - 03-08-2018: Updates from discussion with Jae: - ProtocolVersion contains Block/AppVersion, not Current/Next - signal upgrades to Tendermint using EndBlock fields @@ -19,18 +27,18 @@ ## Context +Here we focus on software-agnostic protocol versions. + The Software Version is covered by SemVer and described elsewhere. It is not relevant to the protocol description, suffice to say that if any protocol version changes, the software version changes, but not necessarily vice versa. -Software version shoudl be included in NodeInfo for convenience/diagnostics. +Software version should be included in NodeInfo for convenience/diagnostics. We are also interested in versioning across different blockchains in a meaningful way, for instance to differentiate branches of a contentious hard-fork. We leave that for a later ADR. -Here we focus on protocol versions. - ## Requirements We need to version components of the blockchain that may be independently upgraded. @@ -86,11 +94,9 @@ to connect to peers with older version. Each component of the software is independently versioned in a modular way and its easy to mix and match and upgrade. -Good luck pal ;) - ## Proposal -Each of BlockVersion, AppVersion, P2PVersion is a monotonically increasing int64. +Each of BlockVersion, AppVersion, P2PVersion, is a monotonically increasing int64. To use these versions, we need to update the block Header, the p2p NodeInfo, and the ABCI. @@ -100,19 +106,16 @@ Block Header should include a `Version` struct as its first field like: ``` type Version struct { - CurrentVersion ProtocolVersion - ChainID string - - NextVersion ProtocolVersion -} - -type ProtocolVersion struct { - BlockVersion int64 - AppVersion int64 + Block int64 + App int64 } ``` -Note this effectively makes BlockVersion the first field in the block Header. +Here, `Version.Block` defines the rules for the current block, while +`Version.App` defines the app version that processed the last block and computed +the `AppHash` in the current block. Together they provide a complete description +of the consensus-critical protocol. + Since we have settled on a proto3 header, the ability to read the BlockVersion out of the serialized header is unanimous. Using a Version struct gives us more flexibility to add fields without breaking @@ -120,8 +123,6 @@ the header. The ProtocolVersion struct includes both the Block and App versions - it should serve as a complete description of the consensus-critical protocol. -Using the `NextVersion` field, proposer's can signal their readiness to upgrade -to a new Block and/or App version. ### NodeInfo @@ -129,23 +130,21 @@ NodeInfo should include a Version struct as its first field like: ``` type Version struct { - P2PVersion int64 + P2P int64 + Block int64 + App int64 - ChainID string - BlockVersion int64 - AppVersion int64 - SoftwareVersion string + Other []string } ``` -Note this effectively makes P2PVersion the first field in the NodeInfo, so it +Note this effectively makes `Version.P2P` the first field in the NodeInfo, so it should be easy to read this out of the serialized header if need be to facilitate an upgrade. -The SoftwareVersion here should include the name of the software client and +The `Version.Other` here should include additional information like the name of the software client and it's SemVer version - this is for convenience only. Eg. -`tendermint-core/v0.22.8`. - -The other versions and ChainID will determine peer compatibility (described below). +`tendermint-core/v0.22.8`. It's a `[]string` so it can include information about +the version of Tendermint, of the app, of Tendermint libraries, etc. ### ABCI @@ -158,6 +157,11 @@ version information. We also need to be able to update versions in the life of a blockchain. The natural place to do this is EndBlock. +Note that currently the result of the Handshake isn't exposed anywhere, as the +handshaking happens inside the `proxy.AppConns` abstraction. We will need to +remove the handshaking from the `proxy` package so we can call it independently +and get the result, which should contain the application version. + #### Info RequestInfo should add support for protocol versions like: @@ -199,28 +203,24 @@ message ResponseEndBlock { ConsensusParams consensus_param_updates repeated common.KVPair tags - VersionUpdates version_updates -} - -message VersionUpdates { - ProtocolVersion current_version - ProtocolVersion next_version + VersionUpdate version_update } -message ProtocolVersion { - int64 block_version +message VersionUpdate { int64 app_version } ``` -Tendermint will use the information in VersionUpdates for the next block it +Tendermint will use the information in VersionUpdate for the next block it proposes. ### BlockVersion BlockVersion is included in both the Header and the NodeInfo. -Changing BlockVersion should happen quite infrequently and ideally only for extreme emergency. +Changing BlockVersion should happen quite infrequently and ideally only for +critical upgrades. For now, it is not encoded in ABCI, though it's always +possible to use tags to signal an external process to co-ordinate an upgrade. Note Ethereum has not had to make an upgrade like this (everything has been at state machine level, AFAIK). @@ -251,7 +251,7 @@ this is the first byte of a 32-byte ed25519 pubkey. AppVersion is also included in the block Header and the NodeInfo. -AppVersion essentially defines how the AppHash and Results are computed. +AppVersion essentially defines how the AppHash and LastResults are computed. ### Peer Compatibility From faa3509646cd4c5e109e6d32ce253fa60db93c3f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 19 Sep 2018 18:56:23 -0400 Subject: [PATCH 31/47] adr-021: note about tag spacers (#2362) --- docs/architecture/adr-021-abci-events.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/architecture/adr-021-abci-events.md b/docs/architecture/adr-021-abci-events.md index 7d60d45a0..45a73df1d 100644 --- a/docs/architecture/adr-021-abci-events.md +++ b/docs/architecture/adr-021-abci-events.md @@ -18,6 +18,11 @@ Since there is only one list of tags, recording data for multiple such events in a single Check/DeliverTx/Begin/EndBlock must be done using prefixes in the key space. +Alternatively, groups of tags that constitute an event can be separated by a +special tag that denotes a break between the events. This would allow +straightforward encoding of multiple events into a single list of tags without +prefixing, at the cost of these "special" tags to separate the different events. + TODO: brief description of how the indexing works ## Decision From 8aad09d9d4b29df4cee1488859ddd59e53144349 Mon Sep 17 00:00:00 2001 From: bradyjoestar Date: Thu, 20 Sep 2018 13:53:25 +0800 Subject: [PATCH 32/47] Output error instead of panic when the given db_backend is not initialised (#2411) Closes #2371 --- libs/db/db.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/libs/db/db.go b/libs/db/db.go index 869937660..789bbfbff 100644 --- a/libs/db/db.go +++ b/libs/db/db.go @@ -1,6 +1,9 @@ package db -import "fmt" +import ( + "fmt" + "strings" +) //---------------------------------------- // Main entry @@ -28,7 +31,18 @@ func registerDBCreator(backend DBBackendType, creator dbCreator, force bool) { } func NewDB(name string, backend DBBackendType, dir string) DB { - db, err := backends[backend](name, dir) + dbCreator, ok := backends[backend] + + if !ok { + var keys []string + for k, _ := range backends { + keys = append(keys, string(k)) + } + panic(fmt.Sprintf("Unknown db_backend %s, expected either %s", backend, strings.Join(keys, " or "))) + } + + db, err := dbCreator(name, dir) + if err != nil { panic(fmt.Sprintf("Error initializing DB: %v", err)) } From f76312ffe6073ddbedf89334f84f7798b0e240b7 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Wed, 19 Sep 2018 19:33:20 -0700 Subject: [PATCH 33/47] docs: Update secure-p2p doc to match the spec + current implementation Closes #2421. I am of the opinion that the spec is easier to read than this though, and we shouldn't really explain this here other than that we use a variant of station to station protocol, with X25519 for the diffie hellman, and we describe the related security properties. --- docs/tendermint-core/secure-p2p.md | 56 ++++++++++++++++-------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/docs/tendermint-core/secure-p2p.md b/docs/tendermint-core/secure-p2p.md index 01d2f22b5..ee02f3f7c 100644 --- a/docs/tendermint-core/secure-p2p.md +++ b/docs/tendermint-core/secure-p2p.md @@ -8,41 +8,43 @@ Each peer generates an ED25519 key-pair to use as a persistent (long-term) id. When two peers establish a TCP connection, they first each generate an -ephemeral ED25519 key-pair to use for this session, and send each other +ephemeral X25519 key-pair to use for this session, and send each other their respective ephemeral public keys. This happens in the clear. -They then each compute the shared secret. The shared secret is the -multiplication of the peer's ephemeral private key by the other peer's -ephemeral public key. The result is the same for both peers by the magic -of [elliptic -curves](https://en.wikipedia.org/wiki/Elliptic_curve_cryptography). The -shared secret is used as the symmetric key for the encryption algorithm. - -The two ephemeral public keys are sorted to establish a canonical order. -Then a 24-byte nonce is generated by concatenating the public keys and -hashing them with Ripemd160. Note Ripemd160 produces 20byte hashes, so -the nonce ends with four 0s. - -The nonce is used to seed the encryption - it is critical that the same -nonce never be used twice with the same private key. For convenience, -the last bit of the nonce is flipped, giving us two nonces: one for -encrypting our own messages, one for decrypting our peer's. Which ever -peer has the higher public key uses the "bit-flipped" nonce for -encryption. - -Now, a challenge is generated by concatenating the ephemeral public keys -and taking the SHA256 hash. - -Each peer signs the challenge with their persistent private key, and +They then each compute the shared secret, as done in a [diffie hellman +key exhange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange). +The shared secret is used as the symmetric key for the encryption algorithm. + +We then run [hkdf-sha256](https://en.wikipedia.org/wiki/HKDF) to expand the +shared secret to generate a symmetric key for sending data, +a symmetric key for receiving data, +a challenge to authenticate the other party. +One peer will send data with their sending key, and the other peer +would decode it using their own receiving key. +We must ensure that both parties don't try to use the same key as the sending +key, and the same key as the receiving key, as in that case nothing can be +decoded. +To ensure this, the peer with the canonically smaller ephemeral pubkey +uses the first key as their receiving key, and the second key as their sending key. +If the peer has the canonically larger ephemeral pubkey, they do the reverse. + +Each peer also keeps a received message counter and sent message counter, both +are initialized to zero. +All future communication is encrypted using chacha20poly1305. +The key used to send the message is the sending key, and the key used to decode +the message is the receiving key. +The nonce for chacha20poly1305 is the relevant message counter. +It is critical that the message counter is incremented every time you send a +message and every time you receive a message that decodes correctly. + +Each peer now signs the challenge with their persistent private key, and sends the other peer an AuthSigMsg, containing their persistent public key and the signature. On receiving an AuthSigMsg, the peer verifies the signature. The peers are now authenticated. -All future communications can now be encrypted using the shared secret -and the generated nonces, where each nonce is incremented by one each -time it is used. The communications maintain Perfect Forward Secrecy, as +The communication maintains Perfect Forward Secrecy, as the persistent key pair was not used for generating secrets - only for authenticating. From 0d6b75bd53f2e513feee3aa640025d3884473f67 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Thu, 20 Sep 2018 02:12:42 -0700 Subject: [PATCH 34/47] common: Delete unused functions (#2452) These functions were not used anywhere within tendermint, or the cosmos-sdk. (The functionality is already duplicated in the cosmos-sdk types package) * common: Delete unused functions within byteslice * remove more unused code from strings.go and int.go * Remove more unused code from int.go * Fix testcase --- CHANGELOG_PENDING.md | 5 +++ libs/common/byteslice.go | 63 ----------------------------------- libs/common/byteslice_test.go | 28 ---------------- libs/common/int.go | 54 ------------------------------ libs/common/string.go | 18 ---------- libs/common/string_test.go | 20 +---------- 6 files changed, 6 insertions(+), 182 deletions(-) delete mode 100644 libs/common/byteslice_test.go diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 3a881bd28..dd6469862 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -12,6 +12,11 @@ BREAKING CHANGES: * Go API * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas * \#2431 Remove Word256 code in libs/common, due to lack of use + * \#2452 Remove the following methods from libs/common due to lack of use: + * byteslice.go: cmn.IsZeros, cmn.RightPadBytes, cmn.LeftPadBytes, cmn.PrefixEndBytes + * strings.go: cmn.IsHex, cmn.StripHex + * int.go: Uint64Slice, all put/get int64 methods + * Blockchain Protocol * P2P Protocol diff --git a/libs/common/byteslice.go b/libs/common/byteslice.go index 57b3a8a2b..af2d7949d 100644 --- a/libs/common/byteslice.go +++ b/libs/common/byteslice.go @@ -1,9 +1,5 @@ package common -import ( - "bytes" -) - // Fingerprint returns the first 6 bytes of a byte slice. // If the slice is less than 6 bytes, the fingerprint // contains trailing zeroes. @@ -12,62 +8,3 @@ func Fingerprint(slice []byte) []byte { copy(fingerprint, slice) return fingerprint } - -func IsZeros(slice []byte) bool { - for _, byt := range slice { - if byt != byte(0) { - return false - } - } - return true -} - -func RightPadBytes(slice []byte, l int) []byte { - if l < len(slice) { - return slice - } - padded := make([]byte, l) - copy(padded[0:len(slice)], slice) - return padded -} - -func LeftPadBytes(slice []byte, l int) []byte { - if l < len(slice) { - return slice - } - padded := make([]byte, l) - copy(padded[l-len(slice):], slice) - return padded -} - -func TrimmedString(b []byte) string { - trimSet := string([]byte{0}) - return string(bytes.TrimLeft(b, trimSet)) - -} - -// PrefixEndBytes returns the end byteslice for a noninclusive range -// that would include all byte slices for which the input is the prefix -func PrefixEndBytes(prefix []byte) []byte { - if prefix == nil { - return nil - } - - end := make([]byte, len(prefix)) - copy(end, prefix) - finished := false - - for !finished { - if end[len(end)-1] != byte(255) { - end[len(end)-1]++ - finished = true - } else { - end = end[:len(end)-1] - if len(end) == 0 { - end = nil - finished = true - } - } - } - return end -} diff --git a/libs/common/byteslice_test.go b/libs/common/byteslice_test.go deleted file mode 100644 index 98085d125..000000000 --- a/libs/common/byteslice_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package common - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPrefixEndBytes(t *testing.T) { - assert := assert.New(t) - - var testCases = []struct { - prefix []byte - expected []byte - }{ - {[]byte{byte(55), byte(255), byte(255), byte(0)}, []byte{byte(55), byte(255), byte(255), byte(1)}}, - {[]byte{byte(55), byte(255), byte(255), byte(15)}, []byte{byte(55), byte(255), byte(255), byte(16)}}, - {[]byte{byte(55), byte(200), byte(255)}, []byte{byte(55), byte(201)}}, - {[]byte{byte(55), byte(255), byte(255)}, []byte{byte(56)}}, - {[]byte{byte(255), byte(255), byte(255)}, nil}, - {nil, nil}, - } - - for _, test := range testCases { - end := PrefixEndBytes(test.prefix) - assert.Equal(test.expected, end) - } -} diff --git a/libs/common/int.go b/libs/common/int.go index a8a5f1e00..845dc97f6 100644 --- a/libs/common/int.go +++ b/libs/common/int.go @@ -1,59 +1,5 @@ package common -import ( - "encoding/binary" - "sort" -) - -// Sort for []uint64 - -type Uint64Slice []uint64 - -func (p Uint64Slice) Len() int { return len(p) } -func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] } -func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p Uint64Slice) Sort() { sort.Sort(p) } - -func SearchUint64s(a []uint64, x uint64) int { - return sort.Search(len(a), func(i int) bool { return a[i] >= x }) -} - -func (p Uint64Slice) Search(x uint64) int { return SearchUint64s(p, x) } - -//-------------------------------------------------------------------------------- - -func PutUint64LE(dest []byte, i uint64) { - binary.LittleEndian.PutUint64(dest, i) -} - -func GetUint64LE(src []byte) uint64 { - return binary.LittleEndian.Uint64(src) -} - -func PutUint64BE(dest []byte, i uint64) { - binary.BigEndian.PutUint64(dest, i) -} - -func GetUint64BE(src []byte) uint64 { - return binary.BigEndian.Uint64(src) -} - -func PutInt64LE(dest []byte, i int64) { - binary.LittleEndian.PutUint64(dest, uint64(i)) -} - -func GetInt64LE(src []byte) int64 { - return int64(binary.LittleEndian.Uint64(src)) -} - -func PutInt64BE(dest []byte, i int64) { - binary.BigEndian.PutUint64(dest, uint64(i)) -} - -func GetInt64BE(src []byte) int64 { - return int64(binary.BigEndian.Uint64(src)) -} - // IntInSlice returns true if a is found in the list. func IntInSlice(a int, list []int) bool { for _, b := range list { diff --git a/libs/common/string.go b/libs/common/string.go index e341b49e8..e125043d1 100644 --- a/libs/common/string.go +++ b/libs/common/string.go @@ -1,28 +1,10 @@ package common import ( - "encoding/hex" "fmt" "strings" ) -// IsHex returns true for non-empty hex-string prefixed with "0x" -func IsHex(s string) bool { - if len(s) > 2 && strings.EqualFold(s[:2], "0x") { - _, err := hex.DecodeString(s[2:]) - return err == nil - } - return false -} - -// StripHex returns hex string without leading "0x" -func StripHex(s string) string { - if IsHex(s) { - return s[2:] - } - return s -} - // StringInSlice returns true if a is found the list. func StringInSlice(a string, list []string) bool { for _, b := range list { diff --git a/libs/common/string_test.go b/libs/common/string_test.go index 0fc677a91..5e7ae98cc 100644 --- a/libs/common/string_test.go +++ b/libs/common/string_test.go @@ -13,30 +13,12 @@ func TestStringInSlice(t *testing.T) { assert.False(t, StringInSlice("", []string{})) } -func TestIsHex(t *testing.T) { - notHex := []string{ - "", " ", "a", "x", "0", "0x", "0X", "0x ", "0X ", "0X a", - "0xf ", "0x f", "0xp", "0x-", - "0xf", "0XBED", "0xF", "0xbed", // Odd lengths - } - for _, v := range notHex { - assert.False(t, IsHex(v), "%q is not hex", v) - } - hex := []string{ - "0x00", "0x0a", "0x0F", "0xFFFFFF", "0Xdeadbeef", "0x0BED", - "0X12", "0X0A", - } - for _, v := range hex { - assert.True(t, IsHex(v), "%q is hex", v) - } -} - func TestIsASCIIText(t *testing.T) { notASCIIText := []string{ "", "\xC2", "\xC2\xA2", "\xFF", "\x80", "\xF0", "\n", "\t", } for _, v := range notASCIIText { - assert.False(t, IsHex(v), "%q is not ascii-text", v) + assert.False(t, IsASCIIText(v), "%q is not ascii-text", v) } asciiText := []string{ " ", ".", "x", "$", "_", "abcdefg;", "-", "0x00", "0", "123", From bd951171db8f2206c6b4bdb381364c6b3f80ba73 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 20 Sep 2018 13:14:02 +0400 Subject: [PATCH 35/47] docs: Add missing changelog entry and comment (#2451) Follow-up on https://github.com/tendermint/tendermint/pull/2411 --- CHANGELOG_PENDING.md | 1 + libs/db/db.go | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index dd6469862..bedd771ef 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -26,6 +26,7 @@ FEATURES: * \#2310 Mempool is now aware of the MaxGas requirement IMPROVEMENTS: +- [libs/db] \#2371 Output error instead of panic when the given db_backend is not initialised (@bradyjoestar) - [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) - [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714) - [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) diff --git a/libs/db/db.go b/libs/db/db.go index 789bbfbff..8a3975a84 100644 --- a/libs/db/db.go +++ b/libs/db/db.go @@ -30,19 +30,23 @@ func registerDBCreator(backend DBBackendType, creator dbCreator, force bool) { backends[backend] = creator } +// NewDB creates a new database of type backend with the given name. +// NOTE: function panics if: +// - backend is unknown (not registered) +// - creator function, provided during registration, returns error func NewDB(name string, backend DBBackendType, dir string) DB { dbCreator, ok := backends[backend] - if !ok { - var keys []string - for k, _ := range backends { - keys = append(keys, string(k)) + keys := make([]string, len(backends)) + i := 0 + for k := range backends { + keys[i] = string(k) + i++ } panic(fmt.Sprintf("Unknown db_backend %s, expected either %s", backend, strings.Join(keys, " or "))) } db, err := dbCreator(name, dir) - if err != nil { panic(fmt.Sprintf("Error initializing DB: %v", err)) } From 84b518b8d3dad245d2eb6131a186e1ea0fb8aa89 Mon Sep 17 00:00:00 2001 From: Aravind Date: Thu, 20 Sep 2018 18:01:20 +0530 Subject: [PATCH 36/47] rpc: Add /consensus_params endpoint (#2415) * Add /consensus_params endpoint * Incorporated change https://github.com/tendermint/tendermint/pull/2415#discussion_r219078049 * Fixed an error in pervious commit --- rpc/core/consensus.go | 46 +++++++++++++++++++++++++++++++++++++ rpc/core/routes.go | 1 + rpc/core/types/responses.go | 6 +++++ 3 files changed, 53 insertions(+) diff --git a/rpc/core/consensus.go b/rpc/core/consensus.go index 193fbd285..a4a2c667c 100644 --- a/rpc/core/consensus.go +++ b/rpc/core/consensus.go @@ -261,3 +261,49 @@ func ConsensusState() (*ctypes.ResultConsensusState, error) { bz, err := consensusState.GetRoundStateSimpleJSON() return &ctypes.ResultConsensusState{bz}, err } + +// Get the consensus parameters at the given block height. +// If no height is provided, it will fetch the current consensus params. +// +// ```shell +// curl 'localhost:26657/consensus_params' +// ``` +// +// ```go +// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket") +// state, err := client.ConsensusParams() +// ``` +// +// The above command returns JSON structured like this: +// +// ```json +// { +// "jsonrpc": "2.0", +// "id": "", +// "result": { +// "block_height": "1", +// "consensus_params": { +// "block_size_params": { +// "max_txs_bytes": "22020096", +// "max_gas": "-1" +// }, +// "evidence_params": { +// "max_age": "100000" +// } +// } +// } +// } +// ``` +func ConsensusParams(heightPtr *int64) (*ctypes.ResultConsensusParams, error) { + height := consensusState.GetState().LastBlockHeight + 1 + height, err := getHeight(height, heightPtr) + if err != nil { + return nil, err + } + + consensusparams, err := sm.LoadConsensusParams(stateDB, height) + if err != nil { + return nil, err + } + return &ctypes.ResultConsensusParams{BlockHeight: height, ConsensusParams: consensusparams}, nil +} diff --git a/rpc/core/routes.go b/rpc/core/routes.go index f26fadb62..639a2d08a 100644 --- a/rpc/core/routes.go +++ b/rpc/core/routes.go @@ -26,6 +26,7 @@ var Routes = map[string]*rpc.RPCFunc{ "validators": rpc.NewRPCFunc(Validators, "height"), "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""), "consensus_state": rpc.NewRPCFunc(ConsensusState, ""), + "consensus_params": rpc.NewRPCFunc(ConsensusParams, "height"), "unconfirmed_txs": rpc.NewRPCFunc(UnconfirmedTxs, "limit"), "num_unconfirmed_txs": rpc.NewRPCFunc(NumUnconfirmedTxs, ""), diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index 77672910f..a6dcf2b93 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -118,6 +118,12 @@ type ResultValidators struct { Validators []*types.Validator `json:"validators"` } +// ConsensusParams for given height +type ResultConsensusParams struct { + BlockHeight int64 `json:"block_height"` + ConsensusParams types.ConsensusParams `json:"consensus_params"` +} + // Info about the consensus state. // UNSTABLE type ResultDumpConsensusState struct { From 7b727bf3d0a69c81123fe2774262f5de880d0793 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 20 Sep 2018 11:55:36 -0400 Subject: [PATCH 37/47] Minor changelog fixes (#2449) * readme: add some libs to semver * changelog: some updates --- CHANGELOG_PENDING.md | 12 ++++++------ README.md | 10 +++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index bedd771ef..35a395d5f 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -5,14 +5,14 @@ Special thanks to external contributors with PRs included in this release: BREAKING CHANGES: * CLI/RPC/Config + * [rpc] [\#2391](https://github.com/tendermint/tendermint/issues/2391) /status `result.node_info.other` became a map * Apps - [rpc] /status `result.node_info.other` became a map #[2391](https://github.com/tendermint/tendermint/issues/2391) + * [mempool] \#2310 Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. * Go API - * \#2310 Mempool.ReapMaxBytes -> Mempool.ReapMaxBytesMaxGas - * \#2431 Remove Word256 code in libs/common, due to lack of use - * \#2452 Remove the following methods from libs/common due to lack of use: + * [libs/common] \#2431 Remove Word256 due to lack of use + * [libs/common] \#2452 Remove the following functions due to lack of use: * byteslice.go: cmn.IsZeros, cmn.RightPadBytes, cmn.LeftPadBytes, cmn.PrefixEndBytes * strings.go: cmn.IsHex, cmn.StripHex * int.go: Uint64Slice, all put/get int64 methods @@ -23,13 +23,13 @@ BREAKING CHANGES: FEATURES: - * \#2310 Mempool is now aware of the MaxGas requirement IMPROVEMENTS: - [libs/db] \#2371 Output error instead of panic when the given db_backend is not initialised (@bradyjoestar) - [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) -- [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714) +- [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator - [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) +- [p2p] \#2126 Introduce PeerTransport interface to improve isolation of concerns BUG FIXES: - [node] \#2294 Delay starting node until Genesis time diff --git a/README.md b/README.md index d97042008..2e4146f40 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,10 @@ develop | [![CircleCI](https://circleci.com/gh/tendermint/tendermint/tree/deve Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine - written in any programming language - and securely replicates it on many machines. -For protocol details, see [the specification](/docs/spec). For a consensus proof and detailed protocol analysis checkout our recent paper, "[The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)". +For protocol details, see [the specification](/docs/spec). + +For detailed analysis of the consensus protocol, including safety and liveness proofs, +see our recent paper, "[The latest gossip on BFT consensus](https://arxiv.org/abs/1807.04938)". ## A Note on Production Readiness @@ -115,6 +118,11 @@ CHANGELOG even if they don't lead to MINOR version bumps: - rpc/client - config - node +- libs/bech32 +- libs/common +- libs/db +- libs/errors +- libs/log Exported objects in these packages that are not covered by the versioning scheme are explicitly marked by `// UNSTABLE` in their go doc comment and may change at any From 8d50bb9dadd4f12f1011cdaecc4d4c1b8849f15a Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 21 Sep 2018 13:00:36 +0400 Subject: [PATCH 38/47] conesnsu: follow up to removing some consensus params (#2427) * follow up to removing some consensus params Refs #2382 * change args type to int64 in state#makeParams * make valsCount and evidenceCount ints again * MaxEvidenceBytesPerBlock: include magic number in godoc * [spec] creating a proposal * test state#TxFilter * panic if MaxDataBytes is less than 0 * fixes after review * use amino#UvarintSize to calculate overhead https://github.com/tendermint/go-amino/blob/0c74291f3bb61e24f8ea1d13148cece479f79d35/encoder.go#L85-L90 * avoid cyclic imports * you can do better Go, come on * remove testdouble package --- abci/types/types.pb.go | 176 +++++++++++------------ abci/types/types.proto | 2 +- consensus/mempool_test.go | 2 +- consensus/reactor_test.go | 2 +- consensus/state.go | 8 +- docs/spec/README.md | 1 + docs/spec/consensus/creating-proposal.md | 42 ++++++ evidence/pool.go | 2 +- evidence/store.go | 10 +- mempool/mempool.go | 18 +-- mempool/mempool_test.go | 2 +- node/node.go | 6 +- state/execution.go | 7 +- state/services.go | 8 +- state/state_test.go | 10 +- state/tx_filter.go | 15 ++ state/tx_filter_test.go | 47 ++++++ types/block.go | 43 ++++-- types/block_test.go | 59 +++++++- types/evidence.go | 10 +- types/evidence_test.go | 2 +- types/genesis_test.go | 1 + types/params.go | 4 +- types/params_test.go | 35 ++--- types/protobuf.go | 6 +- types/vote.go | 2 +- types/vote_test.go | 2 +- 27 files changed, 347 insertions(+), 175 deletions(-) create mode 100644 docs/spec/consensus/creating-proposal.md create mode 100644 state/tx_filter.go create mode 100644 state/tx_filter_test.go diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index e94bd93ae..3c7f81ab6 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -60,7 +60,7 @@ func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{0} + return fileDescriptor_types_8495fed925debe52, []int{0} } func (m *Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -482,7 +482,7 @@ func (m *RequestEcho) Reset() { *m = RequestEcho{} } func (m *RequestEcho) String() string { return proto.CompactTextString(m) } func (*RequestEcho) ProtoMessage() {} func (*RequestEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{1} + return fileDescriptor_types_8495fed925debe52, []int{1} } func (m *RequestEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -528,7 +528,7 @@ func (m *RequestFlush) Reset() { *m = RequestFlush{} } func (m *RequestFlush) String() string { return proto.CompactTextString(m) } func (*RequestFlush) ProtoMessage() {} func (*RequestFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{2} + return fileDescriptor_types_8495fed925debe52, []int{2} } func (m *RequestFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -568,7 +568,7 @@ func (m *RequestInfo) Reset() { *m = RequestInfo{} } func (m *RequestInfo) String() string { return proto.CompactTextString(m) } func (*RequestInfo) ProtoMessage() {} func (*RequestInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{3} + return fileDescriptor_types_8495fed925debe52, []int{3} } func (m *RequestInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -617,7 +617,7 @@ func (m *RequestSetOption) Reset() { *m = RequestSetOption{} } func (m *RequestSetOption) String() string { return proto.CompactTextString(m) } func (*RequestSetOption) ProtoMessage() {} func (*RequestSetOption) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{4} + return fileDescriptor_types_8495fed925debe52, []int{4} } func (m *RequestSetOption) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -675,7 +675,7 @@ func (m *RequestInitChain) Reset() { *m = RequestInitChain{} } func (m *RequestInitChain) String() string { return proto.CompactTextString(m) } func (*RequestInitChain) ProtoMessage() {} func (*RequestInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{5} + return fileDescriptor_types_8495fed925debe52, []int{5} } func (m *RequestInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -753,7 +753,7 @@ func (m *RequestQuery) Reset() { *m = RequestQuery{} } func (m *RequestQuery) String() string { return proto.CompactTextString(m) } func (*RequestQuery) ProtoMessage() {} func (*RequestQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{6} + return fileDescriptor_types_8495fed925debe52, []int{6} } func (m *RequestQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -825,7 +825,7 @@ func (m *RequestBeginBlock) Reset() { *m = RequestBeginBlock{} } func (m *RequestBeginBlock) String() string { return proto.CompactTextString(m) } func (*RequestBeginBlock) ProtoMessage() {} func (*RequestBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{7} + return fileDescriptor_types_8495fed925debe52, []int{7} } func (m *RequestBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -893,7 +893,7 @@ func (m *RequestCheckTx) Reset() { *m = RequestCheckTx{} } func (m *RequestCheckTx) String() string { return proto.CompactTextString(m) } func (*RequestCheckTx) ProtoMessage() {} func (*RequestCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{8} + return fileDescriptor_types_8495fed925debe52, []int{8} } func (m *RequestCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -940,7 +940,7 @@ func (m *RequestDeliverTx) Reset() { *m = RequestDeliverTx{} } func (m *RequestDeliverTx) String() string { return proto.CompactTextString(m) } func (*RequestDeliverTx) ProtoMessage() {} func (*RequestDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{9} + return fileDescriptor_types_8495fed925debe52, []int{9} } func (m *RequestDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -987,7 +987,7 @@ func (m *RequestEndBlock) Reset() { *m = RequestEndBlock{} } func (m *RequestEndBlock) String() string { return proto.CompactTextString(m) } func (*RequestEndBlock) ProtoMessage() {} func (*RequestEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{10} + return fileDescriptor_types_8495fed925debe52, []int{10} } func (m *RequestEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1033,7 +1033,7 @@ func (m *RequestCommit) Reset() { *m = RequestCommit{} } func (m *RequestCommit) String() string { return proto.CompactTextString(m) } func (*RequestCommit) ProtoMessage() {} func (*RequestCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{11} + return fileDescriptor_types_8495fed925debe52, []int{11} } func (m *RequestCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1086,7 +1086,7 @@ func (m *Response) Reset() { *m = Response{} } func (m *Response) String() string { return proto.CompactTextString(m) } func (*Response) ProtoMessage() {} func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{12} + return fileDescriptor_types_8495fed925debe52, []int{12} } func (m *Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1539,7 +1539,7 @@ func (m *ResponseException) Reset() { *m = ResponseException{} } func (m *ResponseException) String() string { return proto.CompactTextString(m) } func (*ResponseException) ProtoMessage() {} func (*ResponseException) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{13} + return fileDescriptor_types_8495fed925debe52, []int{13} } func (m *ResponseException) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1586,7 +1586,7 @@ func (m *ResponseEcho) Reset() { *m = ResponseEcho{} } func (m *ResponseEcho) String() string { return proto.CompactTextString(m) } func (*ResponseEcho) ProtoMessage() {} func (*ResponseEcho) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{14} + return fileDescriptor_types_8495fed925debe52, []int{14} } func (m *ResponseEcho) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1632,7 +1632,7 @@ func (m *ResponseFlush) Reset() { *m = ResponseFlush{} } func (m *ResponseFlush) String() string { return proto.CompactTextString(m) } func (*ResponseFlush) ProtoMessage() {} func (*ResponseFlush) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{15} + return fileDescriptor_types_8495fed925debe52, []int{15} } func (m *ResponseFlush) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1675,7 +1675,7 @@ func (m *ResponseInfo) Reset() { *m = ResponseInfo{} } func (m *ResponseInfo) String() string { return proto.CompactTextString(m) } func (*ResponseInfo) ProtoMessage() {} func (*ResponseInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{16} + return fileDescriptor_types_8495fed925debe52, []int{16} } func (m *ResponseInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1747,7 +1747,7 @@ func (m *ResponseSetOption) Reset() { *m = ResponseSetOption{} } func (m *ResponseSetOption) String() string { return proto.CompactTextString(m) } func (*ResponseSetOption) ProtoMessage() {} func (*ResponseSetOption) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{17} + return fileDescriptor_types_8495fed925debe52, []int{17} } func (m *ResponseSetOption) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1809,7 +1809,7 @@ func (m *ResponseInitChain) Reset() { *m = ResponseInitChain{} } func (m *ResponseInitChain) String() string { return proto.CompactTextString(m) } func (*ResponseInitChain) ProtoMessage() {} func (*ResponseInitChain) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{18} + return fileDescriptor_types_8495fed925debe52, []int{18} } func (m *ResponseInitChain) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1871,7 +1871,7 @@ func (m *ResponseQuery) Reset() { *m = ResponseQuery{} } func (m *ResponseQuery) String() string { return proto.CompactTextString(m) } func (*ResponseQuery) ProtoMessage() {} func (*ResponseQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{19} + return fileDescriptor_types_8495fed925debe52, []int{19} } func (m *ResponseQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1967,7 +1967,7 @@ func (m *ResponseBeginBlock) Reset() { *m = ResponseBeginBlock{} } func (m *ResponseBeginBlock) String() string { return proto.CompactTextString(m) } func (*ResponseBeginBlock) ProtoMessage() {} func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{20} + return fileDescriptor_types_8495fed925debe52, []int{20} } func (m *ResponseBeginBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2020,7 +2020,7 @@ func (m *ResponseCheckTx) Reset() { *m = ResponseCheckTx{} } func (m *ResponseCheckTx) String() string { return proto.CompactTextString(m) } func (*ResponseCheckTx) ProtoMessage() {} func (*ResponseCheckTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{21} + return fileDescriptor_types_8495fed925debe52, []int{21} } func (m *ResponseCheckTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2115,7 +2115,7 @@ func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } func (m *ResponseDeliverTx) String() string { return proto.CompactTextString(m) } func (*ResponseDeliverTx) ProtoMessage() {} func (*ResponseDeliverTx) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{22} + return fileDescriptor_types_8495fed925debe52, []int{22} } func (m *ResponseDeliverTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2206,7 +2206,7 @@ func (m *ResponseEndBlock) Reset() { *m = ResponseEndBlock{} } func (m *ResponseEndBlock) String() string { return proto.CompactTextString(m) } func (*ResponseEndBlock) ProtoMessage() {} func (*ResponseEndBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{23} + return fileDescriptor_types_8495fed925debe52, []int{23} } func (m *ResponseEndBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2268,7 +2268,7 @@ func (m *ResponseCommit) Reset() { *m = ResponseCommit{} } func (m *ResponseCommit) String() string { return proto.CompactTextString(m) } func (*ResponseCommit) ProtoMessage() {} func (*ResponseCommit) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{24} + return fileDescriptor_types_8495fed925debe52, []int{24} } func (m *ResponseCommit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2318,7 +2318,7 @@ func (m *ConsensusParams) Reset() { *m = ConsensusParams{} } func (m *ConsensusParams) String() string { return proto.CompactTextString(m) } func (*ConsensusParams) ProtoMessage() {} func (*ConsensusParams) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{25} + return fileDescriptor_types_8495fed925debe52, []int{25} } func (m *ConsensusParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2364,7 +2364,7 @@ func (m *ConsensusParams) GetEvidenceParams() *EvidenceParams { // BlockSize contains limits on the block size. type BlockSize struct { // Note: must be greater than 0 - MaxBytes int32 `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` + MaxBytes int64 `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"` // Note: must be greater or equal to -1 MaxGas int64 `protobuf:"varint,2,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -2376,7 +2376,7 @@ func (m *BlockSize) Reset() { *m = BlockSize{} } func (m *BlockSize) String() string { return proto.CompactTextString(m) } func (*BlockSize) ProtoMessage() {} func (*BlockSize) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{26} + return fileDescriptor_types_8495fed925debe52, []int{26} } func (m *BlockSize) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2405,7 +2405,7 @@ func (m *BlockSize) XXX_DiscardUnknown() { var xxx_messageInfo_BlockSize proto.InternalMessageInfo -func (m *BlockSize) GetMaxBytes() int32 { +func (m *BlockSize) GetMaxBytes() int64 { if m != nil { return m.MaxBytes } @@ -2432,7 +2432,7 @@ func (m *EvidenceParams) Reset() { *m = EvidenceParams{} } func (m *EvidenceParams) String() string { return proto.CompactTextString(m) } func (*EvidenceParams) ProtoMessage() {} func (*EvidenceParams) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{27} + return fileDescriptor_types_8495fed925debe52, []int{27} } func (m *EvidenceParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2480,7 +2480,7 @@ func (m *LastCommitInfo) Reset() { *m = LastCommitInfo{} } func (m *LastCommitInfo) String() string { return proto.CompactTextString(m) } func (*LastCommitInfo) ProtoMessage() {} func (*LastCommitInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{28} + return fileDescriptor_types_8495fed925debe52, []int{28} } func (m *LastCommitInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2553,7 +2553,7 @@ func (m *Header) Reset() { *m = Header{} } func (m *Header) String() string { return proto.CompactTextString(m) } func (*Header) ProtoMessage() {} func (*Header) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{29} + return fileDescriptor_types_8495fed925debe52, []int{29} } func (m *Header) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2699,7 +2699,7 @@ func (m *BlockID) Reset() { *m = BlockID{} } func (m *BlockID) String() string { return proto.CompactTextString(m) } func (*BlockID) ProtoMessage() {} func (*BlockID) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{30} + return fileDescriptor_types_8495fed925debe52, []int{30} } func (m *BlockID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2754,7 +2754,7 @@ func (m *PartSetHeader) Reset() { *m = PartSetHeader{} } func (m *PartSetHeader) String() string { return proto.CompactTextString(m) } func (*PartSetHeader) ProtoMessage() {} func (*PartSetHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{31} + return fileDescriptor_types_8495fed925debe52, []int{31} } func (m *PartSetHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2811,7 +2811,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{32} + return fileDescriptor_types_8495fed925debe52, []int{32} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2867,7 +2867,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{33} + return fileDescriptor_types_8495fed925debe52, []int{33} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2923,7 +2923,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{34} + return fileDescriptor_types_8495fed925debe52, []int{34} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2978,7 +2978,7 @@ func (m *PubKey) Reset() { *m = PubKey{} } func (m *PubKey) String() string { return proto.CompactTextString(m) } func (*PubKey) ProtoMessage() {} func (*PubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{35} + return fileDescriptor_types_8495fed925debe52, []int{35} } func (m *PubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3036,7 +3036,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_types_bfbaec40016cbadd, []int{36} + return fileDescriptor_types_8495fed925debe52, []int{36} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7737,7 +7737,7 @@ func NewPopulatedConsensusParams(r randyTypes, easy bool) *ConsensusParams { func NewPopulatedBlockSize(r randyTypes, easy bool) *BlockSize { this := &BlockSize{} - this.MaxBytes = int32(r.Int31()) + this.MaxBytes = int64(r.Int63()) if r.Intn(2) == 0 { this.MaxBytes *= -1 } @@ -12901,7 +12901,7 @@ func (m *BlockSize) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.MaxBytes |= (int32(b) & 0x7F) << shift + m.MaxBytes |= (int64(b) & 0x7F) << shift if b < 0x80 { break } @@ -14503,12 +14503,12 @@ var ( ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_bfbaec40016cbadd) } +func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_8495fed925debe52) } func init() { - golang_proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_bfbaec40016cbadd) + golang_proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_8495fed925debe52) } -var fileDescriptor_types_bfbaec40016cbadd = []byte{ +var fileDescriptor_types_8495fed925debe52 = []byte{ // 2062 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0x4f, 0x6f, 0x23, 0x49, 0x15, 0x4f, 0xdb, 0x8e, 0xed, 0x7e, 0x49, 0xec, 0x4c, 0x25, 0x93, 0x78, 0x0c, 0x24, 0xa3, 0x06, @@ -14595,48 +14595,48 @@ var fileDescriptor_types_bfbaec40016cbadd = []byte{ 0xbb, 0x2d, 0xeb, 0x17, 0x06, 0xb4, 0x0b, 0x87, 0x21, 0x07, 0x00, 0x32, 0xe3, 0xc5, 0xde, 0x73, 0x5d, 0x2a, 0xaf, 0xaa, 0x83, 0xa3, 0xc9, 0x1e, 0x7b, 0xcf, 0x99, 0x6d, 0xf6, 0xf5, 0x2f, 0xf9, 0x18, 0xda, 0x4c, 0x15, 0x4c, 0x3a, 0x25, 0x55, 0x72, 0xd8, 0xa1, 0xcb, 0x29, 0xa5, 0x6d, 0x8b, - 0xe5, 0xc6, 0xd6, 0x31, 0x98, 0xc9, 0xba, 0xe4, 0x6b, 0x60, 0x4e, 0xe8, 0x4c, 0x95, 0xb1, 0x62, - 0xf3, 0x45, 0xbb, 0x39, 0xa1, 0x33, 0xac, 0x60, 0xc9, 0x26, 0x34, 0x04, 0x71, 0x48, 0xe5, 0x0e, - 0x55, 0xbb, 0x3e, 0xa1, 0xb3, 0x1f, 0xd2, 0xd8, 0xda, 0x85, 0x56, 0x7e, 0x13, 0xcd, 0xaa, 0x21, - 0x45, 0xb2, 0x1e, 0x0f, 0x99, 0xf5, 0x18, 0x5a, 0xf9, 0x4a, 0x51, 0x24, 0x92, 0x28, 0x98, 0xfa, - 0xae, 0xda, 0x4e, 0x0e, 0x44, 0x9b, 0x78, 0x19, 0xc8, 0xab, 0xcb, 0x96, 0x86, 0xe7, 0x01, 0x67, - 0x99, 0xfa, 0x52, 0xf2, 0x58, 0x7f, 0xac, 0x41, 0x5d, 0x96, 0xad, 0xe4, 0xad, 0x4c, 0xa7, 0x80, - 0x98, 0xd4, 0x5b, 0xba, 0x7e, 0xb1, 0xdd, 0xc0, 0xf4, 0x7d, 0xfa, 0x30, 0x6d, 0x1b, 0xd2, 0x44, - 0x55, 0xc9, 0x55, 0xd5, 0xba, 0x47, 0xa9, 0xbe, 0x76, 0x8f, 0xb2, 0x09, 0x0d, 0x7f, 0x3a, 0x71, - 0xf8, 0x2c, 0xc6, 0x58, 0xab, 0xda, 0x75, 0x7f, 0x3a, 0x79, 0x32, 0x8b, 0x85, 0x4d, 0x79, 0xc0, - 0xe9, 0x18, 0x49, 0x32, 0xd8, 0x9a, 0x38, 0x21, 0x88, 0x47, 0xb0, 0x92, 0x41, 0x39, 0xcf, 0x55, - 0x25, 0x54, 0x2b, 0x7b, 0xe3, 0xa7, 0x0f, 0x95, 0xba, 0x4b, 0x09, 0xea, 0x9d, 0xba, 0x64, 0x27, - 0x5f, 0x92, 0x23, 0x38, 0xca, 0x0c, 0x9d, 0xa9, 0xba, 0x05, 0x34, 0x8a, 0x03, 0x08, 0x77, 0x93, - 0x2c, 0x32, 0x5d, 0x37, 0xc5, 0x04, 0x12, 0xdf, 0x86, 0x76, 0x8a, 0x2f, 0x92, 0xc5, 0x94, 0xab, - 0xa4, 0xd3, 0xc8, 0xf8, 0x1e, 0xac, 0xfb, 0x6c, 0xc6, 0x9d, 0x22, 0x37, 0x20, 0x37, 0x11, 0xb4, - 0xf3, 0xbc, 0xc4, 0xb7, 0xa1, 0x95, 0x06, 0x24, 0xf2, 0x2e, 0xc9, 0xc6, 0x28, 0x99, 0x45, 0xb6, - 0x3b, 0xd0, 0x4c, 0xd0, 0x7d, 0x19, 0x19, 0x1a, 0x54, 0x82, 0x7a, 0x52, 0x2f, 0x44, 0x2c, 0x9e, - 0x8e, 0xb9, 0x5a, 0x64, 0x05, 0x79, 0xb0, 0x5e, 0xb0, 0xe5, 0x3c, 0xf2, 0x7e, 0x13, 0x56, 0x92, - 0x38, 0x40, 0xbe, 0x16, 0xf2, 0x2d, 0xeb, 0x49, 0x64, 0xda, 0x85, 0xd5, 0x30, 0x0a, 0xc2, 0x20, - 0x66, 0x91, 0x43, 0x5d, 0x37, 0x62, 0x71, 0xdc, 0x69, 0xcb, 0xf5, 0xf4, 0xfc, 0xb1, 0x9c, 0xb6, - 0x7e, 0x0e, 0x0d, 0x65, 0xfd, 0xd2, 0xf6, 0xe9, 0xfb, 0xb0, 0x1c, 0xd2, 0x48, 0x9c, 0x29, 0xdb, - 0x44, 0xe9, 0x22, 0xf6, 0x8c, 0x46, 0xa2, 0x6b, 0xce, 0xf5, 0x52, 0x4b, 0xc8, 0x2f, 0xa7, 0xac, - 0x7b, 0xb0, 0x92, 0xe3, 0x11, 0x61, 0x80, 0x4e, 0xa1, 0xc3, 0x00, 0x07, 0xc9, 0xce, 0x95, 0x74, - 0x67, 0xeb, 0x3e, 0x98, 0x89, 0xa1, 0x45, 0xad, 0xa5, 0xf5, 0x30, 0x94, 0xed, 0xe4, 0x10, 0x01, - 0x3a, 0xf8, 0x9c, 0x45, 0xaa, 0xbe, 0x92, 0x03, 0xeb, 0x29, 0xb4, 0x0b, 0xf9, 0x94, 0xec, 0x41, - 0x23, 0x9c, 0xf6, 0x1d, 0xdd, 0xd7, 0xa7, 0x9d, 0xe0, 0xd9, 0xb4, 0xff, 0x09, 0xbb, 0xd2, 0x9d, - 0x60, 0x88, 0xa3, 0x74, 0xd9, 0x4a, 0x76, 0xd9, 0x31, 0x34, 0x75, 0x68, 0x92, 0xef, 0x82, 0x99, - 0xf8, 0x48, 0x21, 0x81, 0x25, 0x5b, 0xab, 0x45, 0x53, 0x46, 0x71, 0xd5, 0xb1, 0x37, 0xf4, 0x99, - 0xeb, 0xa4, 0xf1, 0x80, 0x7b, 0x34, 0xed, 0xb6, 0x24, 0x7c, 0xaa, 0x9d, 0xdf, 0x7a, 0x0f, 0xea, - 0xf2, 0x6c, 0xc2, 0x3e, 0x62, 0x65, 0x5d, 0x7e, 0x8a, 0xff, 0xd2, 0x4c, 0xfb, 0x27, 0x03, 0x9a, - 0x3a, 0x45, 0x95, 0x0a, 0xe5, 0x0e, 0x5d, 0x79, 0xd5, 0x43, 0xcf, 0xeb, 0xcd, 0x75, 0x16, 0xa9, - 0xbd, 0x76, 0x16, 0xd9, 0x03, 0x22, 0x93, 0xc5, 0x65, 0xc0, 0x3d, 0x7f, 0xe8, 0x48, 0x5b, 0xcb, - 0xac, 0xb1, 0x8a, 0x94, 0x73, 0x24, 0x9c, 0x89, 0xf9, 0xc3, 0x2f, 0x16, 0xa1, 0x7d, 0xdc, 0x7b, - 0x70, 0x7a, 0x1c, 0x86, 0x63, 0x6f, 0x40, 0xb1, 0xe6, 0x3d, 0x80, 0x1a, 0x56, 0xf5, 0x25, 0xef, - 0x89, 0xdd, 0xb2, 0xf6, 0x92, 0x1c, 0xc2, 0x22, 0x16, 0xf7, 0xa4, 0xec, 0x59, 0xb1, 0x5b, 0xda, - 0x65, 0x8a, 0x4d, 0x64, 0xf9, 0x7f, 0xf3, 0x75, 0xb1, 0x5b, 0xd6, 0x6a, 0x92, 0x8f, 0xc1, 0x4c, - 0xcb, 0xf2, 0x79, 0x6f, 0x8c, 0xdd, 0xb9, 0x4d, 0xa7, 0x90, 0x4f, 0xab, 0xa1, 0x79, 0x4f, 0x65, - 0xdd, 0xb9, 0xdd, 0x19, 0x39, 0x82, 0x86, 0xae, 0x12, 0xcb, 0x5f, 0x01, 0xbb, 0x73, 0x1a, 0x42, - 0x61, 0x1e, 0x59, 0x69, 0x97, 0x3d, 0x55, 0x76, 0x4b, 0xbb, 0x56, 0xf2, 0x01, 0xd4, 0x15, 0xec, - 0x97, 0xbe, 0x04, 0x76, 0xcb, 0xdb, 0x3a, 0xa1, 0x64, 0xda, 0x6b, 0xcc, 0x7b, 0x4e, 0xed, 0xce, - 0x6d, 0xaf, 0xc9, 0x31, 0x40, 0xa6, 0xba, 0x9e, 0xfb, 0x4e, 0xda, 0x9d, 0xdf, 0x36, 0x93, 0xfb, - 0xd0, 0x4c, 0x9f, 0x42, 0xca, 0x5f, 0x3e, 0xbb, 0xf3, 0x3a, 0xd9, 0xde, 0xd7, 0xff, 0xf3, 0xf7, - 0x2d, 0xe3, 0xd7, 0xd7, 0x5b, 0xc6, 0x6f, 0xaf, 0xb7, 0x8c, 0xaf, 0xae, 0xb7, 0x8c, 0x3f, 0x5c, - 0x6f, 0x19, 0x7f, 0xbb, 0xde, 0x32, 0x7e, 0xf7, 0x8f, 0x2d, 0xa3, 0x5f, 0x47, 0xf7, 0x7f, 0xff, - 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x29, 0x33, 0xce, 0x77, 0xac, 0x17, 0x00, 0x00, + 0xe5, 0xc6, 0xd6, 0x31, 0x98, 0xc9, 0xba, 0xe4, 0x6b, 0x60, 0x4e, 0xe8, 0x4c, 0x95, 0xb1, 0xb2, + 0x00, 0x6a, 0x4e, 0xe8, 0x0c, 0x2b, 0x58, 0xb2, 0x09, 0x0d, 0x41, 0x1c, 0x52, 0xb9, 0x43, 0xd5, + 0xae, 0x4f, 0xe8, 0xec, 0x87, 0x34, 0xb6, 0x76, 0xa1, 0x95, 0xdf, 0x44, 0xb3, 0x6a, 0x48, 0x91, + 0xac, 0xc7, 0x43, 0x66, 0x3d, 0x86, 0x56, 0xbe, 0x52, 0x14, 0x89, 0x24, 0x0a, 0xa6, 0xbe, 0x8b, + 0x8c, 0x8b, 0xb6, 0x1c, 0x88, 0x36, 0xf1, 0x32, 0x90, 0x57, 0x97, 0x2d, 0x0d, 0xcf, 0x03, 0xce, + 0x32, 0xf5, 0xa5, 0xe4, 0xb1, 0xfe, 0x58, 0x83, 0xba, 0x2c, 0x5b, 0xc9, 0x5b, 0x99, 0x4e, 0x01, + 0x31, 0xa9, 0xb7, 0x74, 0xfd, 0x62, 0xbb, 0x81, 0xe9, 0xfb, 0xf4, 0x61, 0xda, 0x36, 0xa4, 0x89, + 0xaa, 0x92, 0xab, 0xaa, 0x75, 0x8f, 0x52, 0x7d, 0xed, 0x1e, 0x65, 0x13, 0x1a, 0xfe, 0x74, 0xe2, + 0xf0, 0x59, 0x8c, 0xb1, 0x56, 0xb5, 0xeb, 0xfe, 0x74, 0xf2, 0x64, 0x16, 0x0b, 0x9b, 0xf2, 0x80, + 0xd3, 0x31, 0x92, 0x64, 0xb0, 0x35, 0x71, 0x42, 0x10, 0x8f, 0x60, 0x25, 0x83, 0x72, 0x9e, 0xab, + 0x4a, 0xa8, 0x56, 0xf6, 0xc6, 0x4f, 0x1f, 0x2a, 0x75, 0x97, 0x12, 0xd4, 0x3b, 0x75, 0xc9, 0x4e, + 0xbe, 0x24, 0x47, 0x70, 0x94, 0x19, 0x3a, 0x53, 0x75, 0x0b, 0x68, 0x14, 0x07, 0x10, 0xee, 0x26, + 0x59, 0x64, 0xba, 0x6e, 0x8a, 0x09, 0x24, 0xbe, 0x0d, 0xed, 0x14, 0x5f, 0x24, 0x8b, 0x29, 0x57, + 0x49, 0xa7, 0x91, 0xf1, 0x3d, 0x58, 0xf7, 0xd9, 0x8c, 0x3b, 0x45, 0x6e, 0x40, 0x6e, 0x22, 0x68, + 0xe7, 0x79, 0x89, 0x6f, 0x43, 0x2b, 0x0d, 0x48, 0xe4, 0x5d, 0x92, 0x8d, 0x51, 0x32, 0x8b, 0x6c, + 0x77, 0xa0, 0x99, 0xa0, 0xfb, 0x32, 0x32, 0x34, 0xa8, 0x04, 0xf5, 0xa4, 0x5e, 0x88, 0x58, 0x3c, + 0x1d, 0x73, 0xb5, 0xc8, 0x0a, 0xf2, 0x60, 0xbd, 0x60, 0xcb, 0x79, 0xe4, 0xfd, 0x26, 0xac, 0x24, + 0x71, 0x80, 0x7c, 0x2d, 0xe4, 0x5b, 0xd6, 0x93, 0xc8, 0xb4, 0x0b, 0xab, 0x61, 0x14, 0x84, 0x41, + 0xcc, 0x22, 0x87, 0xba, 0x6e, 0xc4, 0xe2, 0xb8, 0xd3, 0x96, 0xeb, 0xe9, 0xf9, 0x63, 0x39, 0x6d, + 0xfd, 0x1c, 0x1a, 0xca, 0xfa, 0xa5, 0xed, 0xd3, 0xf7, 0x61, 0x39, 0xa4, 0x91, 0x38, 0x53, 0xb6, + 0x89, 0xd2, 0x45, 0xec, 0x19, 0x8d, 0x44, 0xd7, 0x9c, 0xeb, 0xa5, 0x96, 0x90, 0x5f, 0x4e, 0x59, + 0xf7, 0x60, 0x25, 0xc7, 0x23, 0xc2, 0x00, 0x9d, 0x42, 0x87, 0x01, 0x0e, 0x92, 0x9d, 0x2b, 0xe9, + 0xce, 0xd6, 0x7d, 0x30, 0x13, 0x43, 0x8b, 0x5a, 0x4b, 0xeb, 0x61, 0x28, 0xdb, 0xc9, 0x21, 0x02, + 0x74, 0xf0, 0x39, 0x8b, 0x54, 0x7d, 0x25, 0x07, 0xd6, 0x53, 0x68, 0x17, 0xf2, 0x29, 0xd9, 0x83, + 0x46, 0x38, 0xed, 0x3b, 0xba, 0xaf, 0x4f, 0x3b, 0xc1, 0xb3, 0x69, 0xff, 0x13, 0x76, 0xa5, 0x3b, + 0xc1, 0x10, 0x47, 0xe9, 0xb2, 0x95, 0xec, 0xb2, 0x63, 0x68, 0xea, 0xd0, 0x24, 0xdf, 0x05, 0x33, + 0xf1, 0x91, 0x42, 0x02, 0x4b, 0xb6, 0x56, 0x8b, 0xa6, 0x8c, 0xe2, 0xaa, 0x63, 0x6f, 0xe8, 0x33, + 0xd7, 0x49, 0xe3, 0x01, 0xf7, 0x68, 0xda, 0x6d, 0x49, 0xf8, 0x54, 0x3b, 0xbf, 0xf5, 0x1e, 0xd4, + 0xe5, 0xd9, 0x84, 0x7d, 0xc4, 0xca, 0xba, 0xfc, 0x14, 0xff, 0xa5, 0x99, 0xf6, 0x4f, 0x06, 0x34, + 0x75, 0x8a, 0x2a, 0x15, 0xca, 0x1d, 0xba, 0xf2, 0xaa, 0x87, 0x9e, 0xd7, 0x9b, 0xeb, 0x2c, 0x52, + 0x7b, 0xed, 0x2c, 0xb2, 0x07, 0x44, 0x26, 0x8b, 0xcb, 0x80, 0x7b, 0xfe, 0xd0, 0x91, 0xb6, 0x96, + 0x59, 0x63, 0x15, 0x29, 0xe7, 0x48, 0x38, 0x13, 0xf3, 0x87, 0x5f, 0x2c, 0x42, 0xfb, 0xb8, 0xf7, + 0xe0, 0xf4, 0x38, 0x0c, 0xc7, 0xde, 0x80, 0x62, 0xcd, 0x7b, 0x00, 0x35, 0xac, 0xea, 0x4b, 0xde, + 0x13, 0xbb, 0x65, 0xed, 0x25, 0x39, 0x84, 0x45, 0x2c, 0xee, 0x49, 0xd9, 0xb3, 0x62, 0xb7, 0xb4, + 0xcb, 0x14, 0x9b, 0xc8, 0xf2, 0xff, 0xe6, 0xeb, 0x62, 0xb7, 0xac, 0xd5, 0x24, 0x1f, 0x83, 0x99, + 0x96, 0xe5, 0xf3, 0xde, 0x18, 0xbb, 0x73, 0x9b, 0x4e, 0x21, 0x9f, 0x56, 0x43, 0xf3, 0x9e, 0xca, + 0xba, 0x73, 0xbb, 0x33, 0x72, 0x04, 0x0d, 0x5d, 0x25, 0x96, 0xbf, 0x02, 0x76, 0xe7, 0x34, 0x84, + 0xc2, 0x3c, 0xb2, 0xd2, 0x2e, 0x7b, 0xaa, 0xec, 0x96, 0x76, 0xad, 0xe4, 0x03, 0xa8, 0x2b, 0xd8, + 0x2f, 0x7d, 0x09, 0xec, 0x96, 0xb7, 0x75, 0x42, 0xc9, 0xb4, 0xd7, 0x98, 0xf7, 0x9c, 0xda, 0x9d, + 0xdb, 0x5e, 0x93, 0x63, 0x80, 0x4c, 0x75, 0x3d, 0xf7, 0x9d, 0xb4, 0x3b, 0xbf, 0x6d, 0x26, 0xf7, + 0xa1, 0x99, 0x3e, 0x85, 0x94, 0xbf, 0x7c, 0x76, 0xe7, 0x75, 0xb2, 0xbd, 0xaf, 0xff, 0xe7, 0xef, + 0x5b, 0xc6, 0xaf, 0xaf, 0xb7, 0x8c, 0xdf, 0x5e, 0x6f, 0x19, 0x5f, 0x5d, 0x6f, 0x19, 0x7f, 0xb8, + 0xde, 0x32, 0xfe, 0x76, 0xbd, 0x65, 0xfc, 0xee, 0x1f, 0x5b, 0x46, 0xbf, 0x8e, 0xee, 0xff, 0xfe, + 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xef, 0x95, 0x6c, 0x08, 0xac, 0x17, 0x00, 0x00, } diff --git a/abci/types/types.proto b/abci/types/types.proto index eacce5442..d23ac513e 100644 --- a/abci/types/types.proto +++ b/abci/types/types.proto @@ -206,7 +206,7 @@ message ConsensusParams { // BlockSize contains limits on the block size. message BlockSize { // Note: must be greater than 0 - int32 max_bytes = 1; + int64 max_bytes = 1; // Note: must be greater or equal to -1 int64 max_gas = 2; } diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index fbf46c2da..950cf67d8 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -148,7 +148,7 @@ func TestMempoolRmBadTx(t *testing.T) { // check for the tx for { - txs := cs.mempool.ReapMaxBytesMaxGas(len(txBytes), -1) + txs := cs.mempool.ReapMaxBytesMaxGas(int64(len(txBytes)), -1) if len(txs) == 0 { emptyMempoolCh <- struct{}{} return diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 98b058b8d..2c4c4452b 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -196,7 +196,7 @@ func newMockEvidencePool(val []byte) *mockEvidencePool { } // NOTE: maxBytes is ignored -func (m *mockEvidencePool) PendingEvidence(maxBytes int) []types.Evidence { +func (m *mockEvidencePool) PendingEvidence(maxBytes int64) []types.Evidence { if m.height > 0 { return m.ev } diff --git a/consensus/state.go b/consensus/state.go index bee0f893e..3cc29b2b3 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -953,15 +953,17 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts // bound evidence to 1/10th of the block evidence := cs.evpool.PendingEvidence(types.MaxEvidenceBytesPerBlock(maxBytes)) // Mempool validated transactions - txs := cs.mempool.ReapMaxBytesMaxGas(types.MaxDataBytes(maxBytes, cs.state.Validators.Size(), len(evidence)), maxGas) - + txs := cs.mempool.ReapMaxBytesMaxGas(types.MaxDataBytes( + maxBytes, + cs.state.Validators.Size(), + len(evidence), + ), maxGas) proposerAddr := cs.privValidator.GetAddress() block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr) return block, parts } - // Enter: `timeoutPropose` after entering Propose. // Enter: proposal block and POL is ready. // Enter: any +2/3 prevotes for future round. diff --git a/docs/spec/README.md b/docs/spec/README.md index 4de5104f1..08eef489e 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -21,6 +21,7 @@ please submit them to our [bug bounty](https://tendermint.com/security)! ### Consensus Protocol - [Consensus Algorithm](/docs/spec/consensus/consensus.md) +- [Creating a proposal](/docs/spec/consensus/creating-proposal.md) - [Time](/docs/spec/consensus/bft-time.md) - [Light-Client](/docs/spec/consensus/light-client.md) diff --git a/docs/spec/consensus/creating-proposal.md b/docs/spec/consensus/creating-proposal.md new file mode 100644 index 000000000..03f5866dc --- /dev/null +++ b/docs/spec/consensus/creating-proposal.md @@ -0,0 +1,42 @@ +# Creating a proposal + +A block consists of a header, transactions, votes (the commit), +and a list of evidence of malfeasance (ie. signing conflicting votes). + +We include no more than 1/10th of the maximum block size +(`ConsensusParams.BlockSize.MaxBytes`) of evidence with each block. + +## Reaping transactions from the mempool + +When we reap transactions from the mempool, we calculate maximum data +size by subtracting maximum header size (`MaxHeaderBytes`), the maximum +amino overhead for a block (`MaxAminoOverheadForBlock`), the size of +the last commit (if present) and evidence (if present). While reaping +we account for amino overhead for each transaction. + +```go +func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 { + return maxBytes - + MaxAminoOverheadForBlock - + MaxHeaderBytes - + int64(valsCount)*MaxVoteBytes - + int64(evidenceCount)*MaxEvidenceBytes +} +``` + +## Validating transactions in the mempool + +Before we accept a transaction in the mempool, we check if it's size is no more +than {MaxDataSize}. {MaxDataSize} is calculated using the same formula as +above, except because the evidence size is unknown at the moment, we subtract +maximum evidence size (1/10th of the maximum block size). + +```go +func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 { + return maxBytes - + MaxAminoOverheadForBlock - + MaxHeaderBytes - + int64(valsCount)*MaxVoteBytes - + MaxEvidenceBytesPerBlock(maxBytes) +} +``` diff --git a/evidence/pool.go b/evidence/pool.go index 21cab5e07..0f3d482af 100644 --- a/evidence/pool.go +++ b/evidence/pool.go @@ -59,7 +59,7 @@ func (evpool *EvidencePool) PriorityEvidence() []types.Evidence { // PendingEvidence returns uncommitted evidence up to maxBytes. // If maxBytes is -1, all evidence is returned. -func (evpool *EvidencePool) PendingEvidence(maxBytes int) []types.Evidence { +func (evpool *EvidencePool) PendingEvidence(maxBytes int64) []types.Evidence { return evpool.evidenceStore.PendingEvidence(maxBytes) } diff --git a/evidence/store.go b/evidence/store.go index 60656f052..9d0010a81 100644 --- a/evidence/store.go +++ b/evidence/store.go @@ -88,23 +88,23 @@ func (store *EvidenceStore) PriorityEvidence() (evidence []types.Evidence) { // PendingEvidence returns known uncommitted evidence up to maxBytes. // If maxBytes is -1, all evidence is returned. -func (store *EvidenceStore) PendingEvidence(maxBytes int) (evidence []types.Evidence) { +func (store *EvidenceStore) PendingEvidence(maxBytes int64) (evidence []types.Evidence) { return store.listEvidence(baseKeyPending, maxBytes) } // listEvidence lists the evidence for the given prefix key up to maxBytes. // It is wrapped by PriorityEvidence and PendingEvidence for convenience. // If maxBytes is -1, there's no cap on the size of returned evidence. -func (store *EvidenceStore) listEvidence(prefixKey string, maxBytes int) (evidence []types.Evidence) { - var bytes int +func (store *EvidenceStore) listEvidence(prefixKey string, maxBytes int64) (evidence []types.Evidence) { + var bytes int64 iter := dbm.IteratePrefix(store.db, []byte(prefixKey)) for ; iter.Valid(); iter.Next() { val := iter.Value() - if maxBytes > 0 && bytes+len(val) > maxBytes { + if maxBytes > 0 && bytes+int64(len(val)) > maxBytes { return evidence } - bytes += len(val) + bytes += int64(len(val)) var ei EvidenceInfo err := cdc.UnmarshalBinaryBare(val, &ei) diff --git a/mempool/mempool.go b/mempool/mempool.go index 870922627..1bcad6fa4 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -4,7 +4,6 @@ import ( "bytes" "container/list" "crypto/sha256" - "encoding/binary" "fmt" "sync" "sync/atomic" @@ -12,13 +11,13 @@ import ( "github.com/pkg/errors" + amino "github.com/tendermint/go-amino" abci "github.com/tendermint/tendermint/abci/types" + cfg "github.com/tendermint/tendermint/config" auto "github.com/tendermint/tendermint/libs/autofile" "github.com/tendermint/tendermint/libs/clist" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" - - cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" ) @@ -385,9 +384,7 @@ func (mem *Mempool) notifyTxsAvailable() { // with the condition that the total gasWanted must be less than maxGas. // If both maxes are negative, there is no cap on the size of all returned // transactions (~ all available transactions). -func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { - var buf [binary.MaxVarintLen64]byte - +func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs { mem.proxyMtx.Lock() defer mem.proxyMtx.Unlock() @@ -396,7 +393,7 @@ func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { time.Sleep(time.Millisecond * 10) } - var totalBytes int + var totalBytes int64 var totalGas int64 // TODO: we will get a performance boost if we have a good estimate of avg // size per tx, and set the initial capacity based off of that. @@ -405,12 +402,11 @@ func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { for e := mem.txs.Front(); e != nil; e = e.Next() { memTx := e.Value.(*mempoolTx) // Check total size requirement - // amino.UvarintSize is not used here because it won't be possible to reuse buf - aminoOverhead := binary.PutUvarint(buf[:], uint64(len(memTx.tx))) - if maxBytes > -1 && totalBytes+len(memTx.tx)+aminoOverhead > maxBytes { + aminoOverhead := int64(amino.UvarintSize(uint64(len(memTx.tx)))) + if maxBytes > -1 && totalBytes+int64(len(memTx.tx))+aminoOverhead > maxBytes { return txs } - totalBytes += len(memTx.tx) + aminoOverhead + totalBytes += int64(len(memTx.tx)) + aminoOverhead // Check total gas requirement if maxGas > -1 && totalGas+memTx.gasWanted > maxGas { return txs diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index 1004421f0..dc7259dd3 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -90,7 +90,7 @@ func TestReapMaxBytesMaxGas(t *testing.T) { // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas tests := []struct { numTxsToCreate int - maxBytes int + maxBytes int64 maxGas int64 expectedNumTxs int }{ diff --git a/node/node.go b/node/node.go index 1061fbf7a..97ea8143e 100644 --- a/node/node.go +++ b/node/node.go @@ -250,16 +250,12 @@ func NewNode(config *cfg.Config, csMetrics, p2pMetrics, memplMetrics := metricsProvider() // Make MempoolReactor - maxDataBytes := types.MaxDataBytesUnknownEvidence( - state.ConsensusParams.BlockSize.MaxBytes, - state.Validators.Size(), - ) mempool := mempl.NewMempool( config.Mempool, proxyApp.Mempool(), state.LastBlockHeight, mempl.WithMetrics(memplMetrics), - mempl.WithFilter(func(tx types.Tx) bool { return len(tx) <= maxDataBytes }), + mempl.WithFilter(sm.TxFilter(state)), ) mempoolLogger := logger.With("module", "mempool") mempool.SetLogger(mempoolLogger) diff --git a/state/execution.go b/state/execution.go index b4cdb7a3e..60fa4780a 100644 --- a/state/execution.go +++ b/state/execution.go @@ -145,12 +145,7 @@ func (blockExec *BlockExecutor) Commit(state State, block *types.Block) ([]byte, "appHash", fmt.Sprintf("%X", res.Data)) // Update mempool. - maxDataBytes := types.MaxDataBytesUnknownEvidence( - state.ConsensusParams.BlockSize.MaxBytes, - state.Validators.Size(), - ) - filter := func(tx types.Tx) bool { return len(tx) <= maxDataBytes } - if err := blockExec.mempool.Update(block.Height, block.Txs, filter); err != nil { + if err := blockExec.mempool.Update(block.Height, block.Txs, TxFilter(state)); err != nil { return nil, err } diff --git a/state/services.go b/state/services.go index fd98a06c6..320b4772c 100644 --- a/state/services.go +++ b/state/services.go @@ -22,7 +22,7 @@ type Mempool interface { Size() int CheckTx(types.Tx, func(*abci.Response)) error - ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs + ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs Update(height int64, txs types.Txs, filter func(types.Tx) bool) error Flush() FlushAppConn() error @@ -40,7 +40,7 @@ func (MockMempool) Lock() func (MockMempool) Unlock() {} func (MockMempool) Size() int { return 0 } func (MockMempool) CheckTx(tx types.Tx, cb func(*abci.Response)) error { return nil } -func (MockMempool) ReapMaxBytesMaxGas(maxBytes int, maxGas int64) types.Txs { return types.Txs{} } +func (MockMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs { return types.Txs{} } func (MockMempool) Update(height int64, txs types.Txs, filter func(types.Tx) bool) error { return nil } func (MockMempool) Flush() {} func (MockMempool) FlushAppConn() error { return nil } @@ -73,7 +73,7 @@ type BlockStore interface { // EvidencePool defines the EvidencePool interface used by the ConsensusState. type EvidencePool interface { - PendingEvidence(int) []types.Evidence + PendingEvidence(int64) []types.Evidence AddEvidence(types.Evidence) error Update(*types.Block, State) } @@ -81,6 +81,6 @@ type EvidencePool interface { // MockMempool is an empty implementation of a Mempool, useful for testing. type MockEvidencePool struct{} -func (m MockEvidencePool) PendingEvidence(int) []types.Evidence { return nil } +func (m MockEvidencePool) PendingEvidence(int64) []types.Evidence { return nil } func (m MockEvidencePool) AddEvidence(types.Evidence) error { return nil } func (m MockEvidencePool) Update(*types.Block, State) {} diff --git a/state/state_test.go b/state/state_test.go index 51e98814e..1ab470b02 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -328,7 +328,7 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { params[0] = state.ConsensusParams for i := 1; i < N+1; i++ { params[i] = *types.DefaultConsensusParams() - params[i].BlockSize.MaxBytes += i + params[i].BlockSize.MaxBytes += int64(i) } // Build the params history by running updateState @@ -373,14 +373,14 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { } } -func makeParams(txsBytes, blockGas, evidenceAge int) types.ConsensusParams { +func makeParams(blockBytes, blockGas, evidenceAge int64) types.ConsensusParams { return types.ConsensusParams{ BlockSize: types.BlockSize{ - MaxBytes: txsBytes, - MaxGas: int64(blockGas), + MaxBytes: blockBytes, + MaxGas: blockGas, }, EvidenceParams: types.EvidenceParams{ - MaxAge: int64(evidenceAge), + MaxAge: evidenceAge, }, } } diff --git a/state/tx_filter.go b/state/tx_filter.go new file mode 100644 index 000000000..b8882d8ed --- /dev/null +++ b/state/tx_filter.go @@ -0,0 +1,15 @@ +package state + +import ( + "github.com/tendermint/tendermint/types" +) + +// TxFilter returns a function to filter transactions. The function limits the +// size of a transaction to the maximum block's data size. +func TxFilter(state State) func(tx types.Tx) bool { + maxDataBytes := types.MaxDataBytesUnknownEvidence( + state.ConsensusParams.BlockSize.MaxBytes, + state.Validators.Size(), + ) + return func(tx types.Tx) bool { return int64(len(tx)) <= maxDataBytes } +} diff --git a/state/tx_filter_test.go b/state/tx_filter_test.go new file mode 100644 index 000000000..e6b8999f4 --- /dev/null +++ b/state/tx_filter_test.go @@ -0,0 +1,47 @@ +package state + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/ed25519" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" +) + +func TestTxFilter(t *testing.T) { + genDoc := randomGenesisDoc() + genDoc.ConsensusParams.BlockSize.MaxBytes = 3000 + + testCases := []struct { + tx types.Tx + isTxValid bool + }{ + {types.Tx(cmn.RandBytes(250)), true}, + {types.Tx(cmn.RandBytes(3001)), false}, + } + + for i, tc := range testCases { + stateDB := dbm.NewDB("state", "memdb", os.TempDir()) + state, err := LoadStateFromDBOrGenesisDoc(stateDB, genDoc) + require.NoError(t, err) + + f := TxFilter(state) + assert.Equal(t, tc.isTxValid, f(tc.tx), "#%v", i) + } +} + +func randomGenesisDoc() *types.GenesisDoc { + pubkey := ed25519.GenPrivKey().PubKey() + return &types.GenesisDoc{ + GenesisTime: tmtime.Now(), + ChainID: "abc", + Validators: []types.GenesisValidator{{pubkey.Address(), pubkey, 10, "myval"}}, + ConsensusParams: types.DefaultConsensusParams(), + } +} diff --git a/types/block.go b/types/block.go index 951ad96fe..14f975483 100644 --- a/types/block.go +++ b/types/block.go @@ -15,7 +15,7 @@ import ( const ( // MaxHeaderBytes is a maximum header size (including amino overhead). - MaxHeaderBytes = 511 + MaxHeaderBytes int64 = 511 // MaxAminoOverheadForBlock - maximum amino overhead to encode a block (up to // MaxBlockSizeBytes in size) not including it's parts except Data. @@ -24,7 +24,7 @@ const ( // 2 fields (2 embedded): 2 bytes // Uvarint length of Data.Txs: 4 bytes // Data.Txs field: 1 byte - MaxAminoOverheadForBlock = 11 + MaxAminoOverheadForBlock int64 = 11 ) // Block defines the atomic unit of a Tendermint blockchain. @@ -205,23 +205,48 @@ func (b *Block) StringShort() string { //----------------------------------------------------------------------------- // MaxDataBytes returns the maximum size of block's data. -func MaxDataBytes(maxBytes, valsCount, evidenceCount int) int { - return maxBytes - +// +// XXX: Panics on negative result. +func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 { + maxDataBytes := maxBytes - MaxAminoOverheadForBlock - MaxHeaderBytes - - (valsCount * MaxVoteBytes) - - (evidenceCount * MaxEvidenceBytes) + int64(valsCount)*MaxVoteBytes - + int64(evidenceCount)*MaxEvidenceBytes + + if maxDataBytes < 0 { + panic(fmt.Sprintf( + "Negative MaxDataBytes. BlockSize.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", + maxBytes, + -(maxDataBytes - maxBytes), + )) + } + + return maxDataBytes + } // MaxDataBytesUnknownEvidence returns the maximum size of block's data when // evidence count is unknown. MaxEvidenceBytesPerBlock will be used as the size // of evidence. -func MaxDataBytesUnknownEvidence(maxBytes, valsCount int) int { - return maxBytes - +// +// XXX: Panics on negative result. +func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 { + maxDataBytes := maxBytes - MaxAminoOverheadForBlock - MaxHeaderBytes - - (valsCount * MaxVoteBytes) - + int64(valsCount)*MaxVoteBytes - MaxEvidenceBytesPerBlock(maxBytes) + + if maxDataBytes < 0 { + panic(fmt.Sprintf( + "Negative MaxDataBytesUnknownEvidence. BlockSize.MaxBytes=%d is too small to accommodate header&lastCommit&evidence=%d", + maxBytes, + -(maxDataBytes - maxBytes), + )) + } + + return maxDataBytes } //----------------------------------------------------------------------------- diff --git a/types/block_test.go b/types/block_test.go index c2a73bf88..ffd73eae0 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -266,7 +266,7 @@ func TestMaxHeaderBytes(t *testing.T) { bz, err := cdc.MarshalBinary(h) require.NoError(t, err) - assert.Equal(t, MaxHeaderBytes, len(bz)) + assert.EqualValues(t, MaxHeaderBytes, len(bz)) } func randCommit() *Commit { @@ -279,3 +279,60 @@ func randCommit() *Commit { } return commit } + +func TestBlockMaxDataBytes(t *testing.T) { + testCases := []struct { + maxBytes int64 + valsCount int + evidenceCount int + panics bool + result int64 + }{ + 0: {-10, 1, 0, true, 0}, + 1: {10, 1, 0, true, 0}, + 2: {721, 1, 0, true, 0}, + 3: {722, 1, 0, false, 0}, + 4: {723, 1, 0, false, 1}, + } + + for i, tc := range testCases { + if tc.panics { + assert.Panics(t, func() { + MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount) + }, "#%v", i) + } else { + assert.Equal(t, + tc.result, + MaxDataBytes(tc.maxBytes, tc.valsCount, tc.evidenceCount), + "#%v", i) + } + } +} + +func TestBlockMaxDataBytesUnknownEvidence(t *testing.T) { + testCases := []struct { + maxBytes int64 + valsCount int + panics bool + result int64 + }{ + 0: {-10, 1, true, 0}, + 1: {10, 1, true, 0}, + 2: {801, 1, true, 0}, + 3: {802, 1, false, 0}, + 4: {803, 1, false, 1}, + } + + for i, tc := range testCases { + if tc.panics { + assert.Panics(t, func() { + MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount) + }, "#%v", i) + } else { + assert.Equal(t, + tc.result, + MaxDataBytesUnknownEvidence(tc.maxBytes, tc.valsCount), + "#%v", i) + } + } +} diff --git a/types/evidence.go b/types/evidence.go index 2526a3942..836a1a597 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -12,7 +12,7 @@ import ( const ( // MaxEvidenceBytes is a maximum size of any evidence (including amino overhead). - MaxEvidenceBytes = 440 + MaxEvidenceBytes int64 = 440 ) // ErrEvidenceInvalid wraps a piece of evidence and the error denoting how or why it is invalid. @@ -52,14 +52,16 @@ func RegisterEvidences(cdc *amino.Codec) { cdc.RegisterConcrete(MockBadEvidence{}, "tendermint/MockBadEvidence", nil) } -// MaxEvidenceBytesPerBlock returns the maximum evidence size per block. -func MaxEvidenceBytesPerBlock(blockMaxBytes int) int { +// MaxEvidenceBytesPerBlock returns the maximum evidence size per block - +// 1/10th of the maximum block size. +func MaxEvidenceBytesPerBlock(blockMaxBytes int64) int64 { return blockMaxBytes / 10 } //------------------------------------------- -// DuplicateVoteEvidence contains evidence a validator signed two conflicting votes. +// DuplicateVoteEvidence contains evidence a validator signed two conflicting +// votes. type DuplicateVoteEvidence struct { PubKey crypto.PubKey VoteA *Vote diff --git a/types/evidence_test.go b/types/evidence_test.go index 68c683518..1a7e9ea5d 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -108,7 +108,7 @@ func TestMaxEvidenceBytes(t *testing.T) { bz, err := cdc.MarshalBinary(ev) require.NoError(t, err) - assert.Equal(t, MaxEvidenceBytes, len(bz)) + assert.EqualValues(t, MaxEvidenceBytes, len(bz)) } func randomDuplicatedVoteEvidence() *DuplicateVoteEvidence { diff --git a/types/genesis_test.go b/types/genesis_test.go index a0686ce0d..e7f041a85 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" tmtime "github.com/tendermint/tendermint/types/time" ) diff --git a/types/params.go b/types/params.go index 902b7873f..a7301d063 100644 --- a/types/params.go +++ b/types/params.go @@ -23,7 +23,7 @@ type ConsensusParams struct { // BlockSize contain limits on the block size. type BlockSize struct { - MaxBytes int `json:"max_txs_bytes"` + MaxBytes int64 `json:"max_bytes"` MaxGas int64 `json:"max_gas"` } @@ -102,7 +102,7 @@ func (params ConsensusParams) Update(params2 *abci.ConsensusParams) ConsensusPar // XXX: it's cast city over here. It's ok because we only do int32->int // but still, watch it champ. if params2.BlockSize != nil { - res.BlockSize.MaxBytes = int(params2.BlockSize.MaxBytes) + res.BlockSize.MaxBytes = params2.BlockSize.MaxBytes res.BlockSize.MaxGas = params2.BlockSize.MaxGas } if params2.EvidenceParams != nil { diff --git a/types/params_test.go b/types/params_test.go index ab235bc47..888b678b4 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -9,30 +9,23 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -func newConsensusParams(txsBytes, evidenceAge int) ConsensusParams { - return ConsensusParams{ - BlockSize: BlockSize{MaxBytes: txsBytes}, - EvidenceParams: EvidenceParams{MaxAge: int64(evidenceAge)}, - } -} - func TestConsensusParamsValidation(t *testing.T) { testCases := []struct { params ConsensusParams valid bool }{ // test block size - 0: {newConsensusParams(1, 1), true}, - 1: {newConsensusParams(0, 1), false}, - 2: {newConsensusParams(47*1024*1024, 1), true}, - 3: {newConsensusParams(10, 1), true}, - 4: {newConsensusParams(100*1024*1024, 1), true}, - 5: {newConsensusParams(101*1024*1024, 1), false}, - 6: {newConsensusParams(1024*1024*1024, 1), false}, - 7: {newConsensusParams(1024*1024*1024, -1), false}, + 0: {makeParams(1, 0, 1), true}, + 1: {makeParams(0, 0, 1), false}, + 2: {makeParams(47*1024*1024, 0, 1), true}, + 3: {makeParams(10, 0, 1), true}, + 4: {makeParams(100*1024*1024, 0, 1), true}, + 5: {makeParams(101*1024*1024, 0, 1), false}, + 6: {makeParams(1024*1024*1024, 0, 1), false}, + 7: {makeParams(1024*1024*1024, 0, -1), false}, // test evidence age - 8: {newConsensusParams(1, 0), false}, - 9: {newConsensusParams(1, -1), false}, + 8: {makeParams(1, 0, 0), false}, + 9: {makeParams(1, 0, -1), false}, } for i, tc := range testCases { if tc.valid { @@ -43,14 +36,14 @@ func TestConsensusParamsValidation(t *testing.T) { } } -func makeParams(txsBytes, blockGas, evidenceAge int) ConsensusParams { +func makeParams(blockBytes, blockGas, evidenceAge int64) ConsensusParams { return ConsensusParams{ BlockSize: BlockSize{ - MaxBytes: txsBytes, - MaxGas: int64(blockGas), + MaxBytes: blockBytes, + MaxGas: blockGas, }, EvidenceParams: EvidenceParams{ - MaxAge: int64(evidenceAge), + MaxAge: evidenceAge, }, } } diff --git a/types/protobuf.go b/types/protobuf.go index df19a5b55..c9c429c80 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -115,7 +115,7 @@ func (tm2pb) ValidatorUpdates(vals *ValidatorSet) []abci.ValidatorUpdate { func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams { return &abci.ConsensusParams{ BlockSize: &abci.BlockSize{ - MaxBytes: int32(params.BlockSize.MaxBytes), + MaxBytes: params.BlockSize.MaxBytes, MaxGas: params.BlockSize.MaxGas, }, EvidenceParams: &abci.EvidenceParams{ @@ -211,11 +211,11 @@ func (pb2tm) ValidatorUpdates(vals []abci.ValidatorUpdate) ([]*Validator, error) func (pb2tm) ConsensusParams(csp *abci.ConsensusParams) ConsensusParams { return ConsensusParams{ BlockSize: BlockSize{ - MaxBytes: int(csp.BlockSize.MaxBytes), // XXX + MaxBytes: csp.BlockSize.MaxBytes, MaxGas: csp.BlockSize.MaxGas, }, EvidenceParams: EvidenceParams{ - MaxAge: csp.EvidenceParams.MaxAge, // XXX + MaxAge: csp.EvidenceParams.MaxAge, }, } } diff --git a/types/vote.go b/types/vote.go index 6481f56b9..4a90a7185 100644 --- a/types/vote.go +++ b/types/vote.go @@ -12,7 +12,7 @@ import ( const ( // MaxVoteBytes is a maximum vote size (including amino overhead). - MaxVoteBytes = 200 + MaxVoteBytes int64 = 200 ) var ( diff --git a/types/vote_test.go b/types/vote_test.go index 4f5449359..dd7663e59 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -147,5 +147,5 @@ func TestMaxVoteBytes(t *testing.T) { bz, err := cdc.MarshalBinary(vote) require.NoError(t, err) - assert.Equal(t, MaxVoteBytes, len(bz)) + assert.EqualValues(t, MaxVoteBytes, len(bz)) } From 886a83dfb85b1b27f96351dec6f40a99895919f3 Mon Sep 17 00:00:00 2001 From: Zach Date: Fri, 21 Sep 2018 07:39:55 -0400 Subject: [PATCH 39/47] docs: Add assets/instructions for local docs build (#2453) * ungitignore * add docs/.vuepress to enable local builds * config.js needs to be here, one less step * docs: make spec in sidebar nicer * docs: local build instructions --- .gitignore | 3 +- docs/{ => .vuepress}/config.js | 7 +- docs/.vuepress/dist/404.html | 17 + .../dist/assets/css/1.styles.c01b7ee3.css | 1 + .../dist/assets/img/search.83621669.svg | 1 + docs/.vuepress/dist/assets/js/0.7c2695bf.js | 1 + docs/.vuepress/dist/assets/js/app.48f1ff5f.js | 8 + docs/.vuepress/dist/index.html | 17 + docs/DOCS_README.md | 35 +- docs/package-lock.json | 4670 +++++++++++++++++ docs/spec/README.md | 2 +- docs/spec/blockchain/blockchain.md | 2 +- docs/spec/blockchain/encoding.md | 2 +- docs/spec/blockchain/state.md | 2 +- docs/spec/consensus/bft-time.md | 2 +- docs/spec/consensus/light-client.md | 2 +- docs/spec/p2p/node.md | 2 +- docs/spec/p2p/peer.md | 2 +- 18 files changed, 4759 insertions(+), 17 deletions(-) rename docs/{ => .vuepress}/config.js (97%) create mode 100644 docs/.vuepress/dist/404.html create mode 100644 docs/.vuepress/dist/assets/css/1.styles.c01b7ee3.css create mode 100644 docs/.vuepress/dist/assets/img/search.83621669.svg create mode 100644 docs/.vuepress/dist/assets/js/0.7c2695bf.js create mode 100644 docs/.vuepress/dist/assets/js/app.48f1ff5f.js create mode 100644 docs/.vuepress/dist/index.html create mode 100644 docs/package-lock.json diff --git a/.gitignore b/.gitignore index f4adfcaa1..1cf9cdb90 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ test/p2p/data/ test/logs coverage.txt docs/_build -docs/.vuepress docs/dist *.log abci-cli @@ -42,4 +41,4 @@ terraform.tfstate terraform.tfstate.backup terraform.tfstate.d -.vscode \ No newline at end of file +.vscode diff --git a/docs/config.js b/docs/.vuepress/config.js similarity index 97% rename from docs/config.js rename to docs/.vuepress/config.js index 983f0c678..5b064bf82 100644 --- a/docs/config.js +++ b/docs/.vuepress/config.js @@ -66,18 +66,19 @@ module.exports = { "/app-dev/ecosystem" ] }, + { title: "Tendermint Spec", collapsable: true, children: [ - "/spec/README", + "/spec/", "/spec/blockchain/blockchain", "/spec/blockchain/encoding", "/spec/blockchain/state", - "/spec/consensus/abci", + "/spec/software/abci", "/spec/consensus/bft-time", "/spec/consensus/consensus", "/spec/consensus/light-client", - "/spec/consensus/wal", + "/spec/software/wal", "/spec/p2p/config", "/spec/p2p/connection", "/spec/p2p/node", diff --git a/docs/.vuepress/dist/404.html b/docs/.vuepress/dist/404.html new file mode 100644 index 000000000..6249309b0 --- /dev/null +++ b/docs/.vuepress/dist/404.html @@ -0,0 +1,17 @@ + + + + + + VuePress + + + + + + + +

404

Looks like we've got some broken links.
Take me home.
+ + + diff --git a/docs/.vuepress/dist/assets/css/1.styles.c01b7ee3.css b/docs/.vuepress/dist/assets/css/1.styles.c01b7ee3.css new file mode 100644 index 000000000..0df6f0be4 --- /dev/null +++ b/docs/.vuepress/dist/assets/css/1.styles.c01b7ee3.css @@ -0,0 +1 @@ +.icon.outbound{color:#aaa;display:inline-block}.badge{display:inline-block;vertical-align:top;font-size:14px;height:18px;line-height:18px;border-radius:9px;padding:0 5px;color:#fff;margin-right:5px}.badge.tip{background-color:#42b983}.badge.warn,.badge.warning{background-color:#e7c000}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto}.home .hero{text-align:center}.home .hero img{max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.sidebar-button{display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.search-box{display:inline-block;position:relative;margin-right:.5rem}.search-box input{cursor:text;width:10rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:1.5rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative;left:1rem}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper .dropdown-title{display:block}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:.45rem 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper .dropdown-title .arrow{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid #ccc;border-bottom:0}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid #ddd;border-bottom-color:#ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{cursor:pointer;position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem;position:relative}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{font-size:.9rem;position:absolute;right:1.5rem;top:.7rem}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}}.page-edit,.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit,.page-nav{padding:2rem}}@media (max-width:419px){.page-edit,.page-nav{padding:1.5rem}}.page{padding-bottom:2rem}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#aaa}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar-group:not(.first){margin-top:1em}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading{cursor:auto;color:inherit}.sidebar-heading{color:#999;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:0 1.5rem;margin-top:0;margin-bottom:.5rem}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading:.open .arrow{top:-.18em}.sidebar-group-items{transition:height .1s ease-out;overflow:hidden}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem 0}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar .sidebar-links{padding:1.5rem 0}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar .sidebar-links{padding:1rem 0}}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#3eaf7c;border-left-color:#3eaf7c;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.content pre,.content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background:transparent;overflow:auto}.content pre[class*=language-] code,.content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre{position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number,div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.content:not(.custom){padding:2rem}}@media (max-width:419px){.content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:15px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.content:not(.custom)>:first-child{margin-top:3.6rem}.content:not(.custom) a:hover{text-decoration:underline}.content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.content:not(.custom) img{max-width:100%}.content.custom{padding:0;margin:0}.content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1.2rem;color:#999;border-left:.25rem solid #dfe2e5;margin-left:0;padding-left:1rem}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.content:not(.custom)>h1,.content:not(.custom)>h2,.content:not(.custom)>h3,.content:not(.custom)>h4,.content:not(.custom)>h5,.content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.content:not(.custom)>h1:first-child,.content:not(.custom)>h2:first-child,.content:not(.custom)>h3:first-child,.content:not(.custom)>h4:first-child,.content:not(.custom)>h5:first-child,.content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.content:not(.custom)>h1:first-child+.custom-block,.content:not(.custom)>h1:first-child+p,.content:not(.custom)>h1:first-child+pre,.content:not(.custom)>h2:first-child+.custom-block,.content:not(.custom)>h2:first-child+p,.content:not(.custom)>h2:first-child+pre,.content:not(.custom)>h3:first-child+.custom-block,.content:not(.custom)>h3:first-child+p,.content:not(.custom)>h3:first-child+pre,.content:not(.custom)>h4:first-child+.custom-block,.content:not(.custom)>h4:first-child+p,.content:not(.custom)>h4:first-child+pre,.content:not(.custom)>h5:first-child+.custom-block,.content:not(.custom)>h5:first-child+p,.content:not(.custom)>h5:first-child+pre,.content:not(.custom)>h6:first-child+.custom-block,.content:not(.custom)>h6:first-child+p,.content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.custom-layout{padding-top:3.6rem}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}.theme-container.no-navbar .custom-layout{padding-top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}} \ No newline at end of file diff --git a/docs/.vuepress/dist/assets/img/search.83621669.svg b/docs/.vuepress/dist/assets/img/search.83621669.svg new file mode 100644 index 000000000..03d83913e --- /dev/null +++ b/docs/.vuepress/dist/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/docs/.vuepress/dist/assets/js/0.7c2695bf.js b/docs/.vuepress/dist/assets/js/0.7c2695bf.js new file mode 100644 index 000000000..2e3485dd0 --- /dev/null +++ b/docs/.vuepress/dist/assets/js/0.7c2695bf.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{136:function(e,t,s){"use strict";s.r(t);var n=s(0),r=Object(n.a)({},function(){this.$createElement;this._self._c;return this._m(0)},[function(){var e=this.$createElement,t=this._self._c||e;return t("div",{staticClass:"content"},[t("h1",{attrs:{id:"hello-vuepress"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#hello-vuepress","aria-hidden":"true"}},[this._v("#")]),this._v(" Hello VuePress")])])}],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/docs/.vuepress/dist/assets/js/app.48f1ff5f.js b/docs/.vuepress/dist/assets/js/app.48f1ff5f.js new file mode 100644 index 000000000..30bce60ff --- /dev/null +++ b/docs/.vuepress/dist/assets/js/app.48f1ff5f.js @@ -0,0 +1,8 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[1],[]]);!function(t){function e(e){for(var r,a,s=e[0],c=e[1],u=e[2],f=0,p=[];f=t.length?(this._t=void 0,o(1)):o(0,"keys"==e?n:"values"==e?t[n]:[n,t[n]])},"values"),i.Arguments=i.Array,r("keys"),r("values"),r("entries")},function(t,e){t.exports={}},function(t,e,n){var r=n(2),o=n(12),i=n(8),a=n(11),s=n(17),c=function(t,e,n){var u,l,f,p,h=t&c.F,d=t&c.G,v=t&c.S,m=t&c.P,g=t&c.B,y=d?r:v?r[e]||(r[e]={}):(r[e]||{}).prototype,b=d?o:o[e]||(o[e]={}),_=b.prototype||(b.prototype={});for(u in d&&(n=e),n)f=((l=!h&&y&&void 0!==y[u])?y:n)[u],p=g&&l?s(f,r):m&&"function"==typeof f?s(Function.call,f):f,y&&a(y,u,f,t&c.U),b[u]!=f&&i(b,u,p),m&&_[u]!=f&&(_[u]=f)};r.core=o,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,t.exports=c},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(25);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){n(42)("replace",2,function(t,e,n){return[function(r,o){"use strict";var i=t(this),a=void 0==r?void 0:r[e];return void 0!==a?a.call(r,i,o):n.call(String(i),r,o)},n]})},function(t,e,n){var r=n(43),o=n(22);n(52)("keys",function(){return function(t){return o(r(t))}})},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){var r=n(54),o=n(20);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(55),o=n(44);t.exports=Object.keys||function(t){return r(t,o)}},function(t,e,n){var r=n(15);r(r.S+r.F,"Object",{assign:n(121)})},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+r).toString(36))}},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){},function(t,e,n){var r,o; +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */void 0===(o="function"==typeof(r=function(){var t,e,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function o(t,e,n){return tn?n:t}function i(t){return 100*(-1+t)}n.configure=function(t){var e,n;for(e in t)void 0!==(n=t[e])&&t.hasOwnProperty(e)&&(r[e]=n);return this},n.status=null,n.set=function(t){var e=n.isStarted();t=o(t,r.minimum,1),n.status=1===t?null:t;var c=n.render(!e),u=c.querySelector(r.barSelector),l=r.speed,f=r.easing;return c.offsetWidth,a(function(e){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,function(t,e,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+i(t)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(t)+"%,0)"}:{"margin-left":i(t)+"%"}).transition="all "+e+"ms "+n,o}(t,l,f)),1===t?(s(c,{transition:"none",opacity:1}),c.offsetWidth,setTimeout(function(){s(c,{transition:"all "+l+"ms linear",opacity:0}),setTimeout(function(){n.remove(),e()},l)},l)):setTimeout(e,l)}),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var t=function(){setTimeout(function(){n.status&&(n.trickle(),t())},r.trickleSpeed)};return r.trickle&&t(),this},n.done=function(t){return t||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(t){var e=n.status;return e?("number"!=typeof t&&(t=(1-e)*o(Math.random()*e,.1,.95)),e=o(e+t,0,.994),n.set(e)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},t=0,e=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===e&&n.start(),t++,e++,r.always(function(){0==--e?(t=0,n.done()):n.set((t-e)/t)}),this):this},n.render=function(t){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var e=document.createElement("div");e.id="nprogress",e.innerHTML=r.template;var o,a=e.querySelector(r.barSelector),c=t?"-100":i(n.status||0),l=document.querySelector(r.parent);return s(a,{transition:"all 0 linear",transform:"translate3d("+c+"%,0,0)"}),r.showSpinner||(o=e.querySelector(r.spinnerSelector))&&p(o),l!=document.body&&u(l,"nprogress-custom-parent"),l.appendChild(e),e},n.remove=function(){l(document.documentElement,"nprogress-busy"),l(document.querySelector(r.parent),"nprogress-custom-parent");var t=document.getElementById("nprogress");t&&p(t)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var t=document.body.style,e="WebkitTransform"in t?"Webkit":"MozTransform"in t?"Moz":"msTransform"in t?"ms":"OTransform"in t?"O":"";return e+"Perspective"in t?"translate3d":e+"Transform"in t?"translate":"margin"};var a=function(){var t=[];function e(){var n=t.shift();n&&n(e)}return function(n){t.push(n),1==t.length&&e()}}(),s=function(){var t=["Webkit","O","Moz","ms"],e={};function n(n){return n=n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(t,e){return e.toUpperCase()}),e[n]||(e[n]=function(e){var n=document.body.style;if(e in n)return e;for(var r,o=t.length,i=e.charAt(0).toUpperCase()+e.slice(1);o--;)if((r=t[o]+i)in n)return r;return e}(n))}function r(t,e,r){e=n(e),t.style[e]=r}return function(t,e){var n,o,i=arguments;if(2==i.length)for(n in e)void 0!==(o=e[n])&&e.hasOwnProperty(n)&&r(t,n,o);else r(t,i[1],i[2])}}();function c(t,e){var n="string"==typeof t?t:f(t);return n.indexOf(" "+e+" ")>=0}function u(t,e){var n=f(t),r=n+e;c(n,e)||(t.className=r.substring(1))}function l(t,e){var n,r=f(t);c(t,e)&&(n=r.replace(" "+e+" "," "),t.className=n.substring(1,n.length-1))}function f(t){return(" "+(t.className||"")+" ").replace(/\s+/gi," ")}function p(t){t&&t.parentNode&&t.parentNode.removeChild(t)}return n})?r.call(e,n,e,t):r)||(t.exports=o)},function(t,e,n){"use strict";var r=n(8),o=n(11),i=n(5),a=n(20),s=n(1);t.exports=function(t,e,n){var c=s(t),u=n(a,c,""[t]),l=u[0],f=u[1];i(function(){var e={};return e[c]=function(){return 7},7!=""[t](e)})&&(o(String.prototype,t,l),r(RegExp.prototype,c,2==e?function(t,e){return f.call(t,this,e)}:function(t){return f.call(t,this)}))}},function(t,e,n){var r=n(20);t.exports=function(t){return Object(r(t))}},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(t,e,n){var r=n(64)("keys"),o=n(24);t.exports=function(t){return r[t]||(r[t]=o(t))}},function(t,e,n){var r=n(7).f,o=n(10),i=n(1)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r=n(3),o=n(2).document,i=r(o)&&r(o.createElement);t.exports=function(t){return i?o.createElement(t):{}}},function(t,e){t.exports=!1},function(t,e,n){n(42)("match",1,function(t,e,n){return[function(n){"use strict";var r=t(this),o=void 0==n?void 0:n[e];return void 0!==o?o.call(n,r):new RegExp(n)[e](String(r))},n]})},function(t,e,n){var r=n(3),o=n(16),i=n(1)("match");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==o(t))}},function(t,e,n){var r=n(15),o=n(12),i=n(5);t.exports=function(t,e){var n=(o.Object||{})[t]||Object[t],a={};a[t]=e(n),r(r.S+r.F*i(function(){n(1)}),"Object",a)}},function(t,e){e.f={}.propertyIsEnumerable},function(t,e,n){var r=n(16);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==r(t)?t.split(""):Object(t)}},function(t,e,n){var r=n(10),o=n(21),i=n(120)(!1),a=n(45)("IE_PROTO");t.exports=function(t,e){var n,s=o(t),c=0,u=[];for(n in s)n!=a&&r(s,n)&&u.push(n);for(;e.length>c;)r(s,n=e[c++])&&(~i(u,n)||u.push(n));return u}},function(t,e,n){"use strict";var r=n(2),o=n(7),i=n(6),a=n(1)("species");t.exports=function(t){var e=r[t];i&&e&&!e[a]&&o.f(e,a,{configurable:!0,get:function(){return this}})}},function(t,e,n){"use strict";var r=n(25);t.exports.f=function(t){return new function(t){var e,n;this.promise=new t(function(t,r){if(void 0!==e||void 0!==n)throw TypeError("Bad Promise constructor");e=t,n=r}),this.resolve=r(e),this.reject=r(n)}(t)}},function(t,e,n){var r=n(2).document;t.exports=r&&r.documentElement},function(t,e,n){var r,o,i,a=n(17),s=n(128),c=n(58),u=n(48),l=n(2),f=l.process,p=l.setImmediate,h=l.clearImmediate,d=l.MessageChannel,v=l.Dispatch,m=0,g={},y=function(){var t=+this;if(g.hasOwnProperty(t)){var e=g[t];delete g[t],e()}},b=function(t){y.call(t.data)};p&&h||(p=function(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return g[++m]=function(){s("function"==typeof t?t:Function(t),e)},r(m),m},h=function(t){delete g[t]},"process"==n(16)(f)?r=function(t){f.nextTick(a(y,t,1))}:v&&v.now?r=function(t){v.now(a(y,t,1))}:d?(i=(o=new d).port2,o.port1.onmessage=b,r=a(i.postMessage,i,1)):l.addEventListener&&"function"==typeof postMessage&&!l.importScripts?(r=function(t){l.postMessage(t+"","*")},l.addEventListener("message",b,!1)):r="onreadystatechange"in u("script")?function(t){c.appendChild(u("script")).onreadystatechange=function(){c.removeChild(this),y.call(t)}}:function(t){setTimeout(a(y,t,1),0)}),t.exports={set:p,clear:h}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e,n){var r=n(60),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(3);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){t.exports=!n(6)&&!n(5)(function(){return 7!=Object.defineProperty(n(48)("div"),"a",{get:function(){return 7}}).a})},function(t,e,n){var r=n(12),o=n(2),i=o["__core-js_shared__"]||(o["__core-js_shared__"]={});(t.exports=function(t,e){return i[t]||(i[t]=void 0!==e?e:{})})("versions",[]).push({version:r.version,mode:n(49)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},function(t,e,n){var r=n(16),o=n(1)("toStringTag"),i="Arguments"==r(function(){return arguments}());t.exports=function(t){var e,n,a;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),o))?n:i?r(e):"Object"==(a=r(e))&&"function"==typeof e.callee?"Arguments":a}},function(t,e,n){"use strict";var r,o,i,a,s=n(49),c=n(2),u=n(17),l=n(65),f=n(15),p=n(3),h=n(25),d=n(134),v=n(133),m=n(129),g=n(59).set,y=n(127)(),b=n(57),_=n(126),x=n(125),w=n(124),C=c.TypeError,k=c.process,$=k&&k.versions,O=$&&$.v8||"",S=c.Promise,A="process"==l(k),E=function(){},j=o=b.f,T=!!function(){try{var t=S.resolve(1),e=(t.constructor={})[n(1)("species")]=function(t){t(E,E)};return(A||"function"==typeof PromiseRejectionEvent)&&t.then(E)instanceof e&&0!==O.indexOf("6.6")&&-1===x.indexOf("Chrome/66")}catch(t){}}(),L=function(t){var e;return!(!p(t)||"function"!=typeof(e=t.then))&&e},P=function(t,e){if(!t._n){t._n=!0;var n=t._c;y(function(){for(var r=t._v,o=1==t._s,i=0,a=function(e){var n,i,a,s=o?e.ok:e.fail,c=e.resolve,u=e.reject,l=e.domain;try{s?(o||(2==t._h&&R(t),t._h=1),!0===s?n=r:(l&&l.enter(),n=s(r),l&&(l.exit(),a=!0)),n===e.promise?u(C("Promise-chain cycle")):(i=L(n))?i.call(n,c,u):c(n)):u(r)}catch(t){l&&!a&&l.exit(),u(t)}};n.length>i;)a(n[i++]);t._c=[],t._n=!1,e&&!t._h&&I(t)})}},I=function(t){g.call(c,function(){var e,n,r,o=t._v,i=M(t);if(i&&(e=_(function(){A?k.emit("unhandledRejection",o,t):(n=c.onunhandledrejection)?n({promise:t,reason:o}):(r=c.console)&&r.error&&r.error("Unhandled promise rejection",o)}),t._h=A||M(t)?2:1),t._a=void 0,i&&e.e)throw e.v})},M=function(t){return 1!==t._h&&0===(t._a||t._c).length},R=function(t){g.call(c,function(){var e;A?k.emit("rejectionHandled",t):(e=c.onrejectionhandled)&&e({promise:t,reason:t._v})})},N=function(t){var e=this;e._d||(e._d=!0,(e=e._w||e)._v=t,e._s=2,e._a||(e._a=e._c.slice()),P(e,!0))},D=function(t){var e,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===t)throw C("Promise can't be resolved itself");(e=L(t))?y(function(){var r={_w:n,_d:!1};try{e.call(t,u(D,r,1),u(N,r,1))}catch(t){N.call(r,t)}}):(n._v=t,n._s=1,P(n,!1))}catch(t){N.call({_w:n,_d:!1},t)}}};T||(S=function(t){d(this,S,"Promise","_h"),h(t),r.call(this);try{t(u(D,this,1),u(N,this,1))}catch(t){N.call(this,t)}},(r=function(t){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1}).prototype=n(123)(S.prototype,{then:function(t,e){var n=j(m(this,S));return n.ok="function"!=typeof t||t,n.fail="function"==typeof e&&e,n.domain=A?k.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&P(this,!1),n.promise},catch:function(t){return this.then(void 0,t)}}),i=function(){var t=new r;this.promise=t,this.resolve=u(D,t,1),this.reject=u(N,t,1)},b.f=j=function(t){return t===S||t===a?new i(t):o(t)}),f(f.G+f.W+f.F*!T,{Promise:S}),n(46)(S,"Promise"),n(56)("Promise"),a=n(12).Promise,f(f.S+f.F*!T,"Promise",{reject:function(t){var e=j(this);return(0,e.reject)(t),e.promise}}),f(f.S+f.F*(s||!T),"Promise",{resolve:function(t){return w(s&&this===a?S:this,t)}}),f(f.S+f.F*!(T&&n(122)(function(t){S.all(t).catch(E)})),"Promise",{all:function(t){var e=this,n=j(e),r=n.resolve,o=n.reject,i=_(function(){var n=[],i=0,a=1;v(t,!1,function(t){var s=i++,c=!1;n.push(void 0),a++,e.resolve(t).then(function(t){c||(c=!0,n[s]=t,--a||r(n))},o)}),--a||r(n)});return i.e&&o(i.v),n.promise},race:function(t){var e=this,n=j(e),r=n.reject,o=_(function(){v(t,!1,function(t){e.resolve(t).then(n.resolve,r)})});return o.e&&r(o.v),n.promise}})},function(t,e){var n="Expected a function",r=NaN,o="[object Symbol]",i=/^\s+|\s+$/g,a=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof global&&global&&global.Object===Object&&global,f="object"==typeof self&&self&&self.Object===Object&&self,p=l||f||Function("return this")(),h=Object.prototype.toString,d=Math.max,v=Math.min,m=function(){return p.Date.now()};function g(t,e,r){var o,i,a,s,c,u,l=0,f=!1,p=!1,h=!0;if("function"!=typeof t)throw new TypeError(n);function g(e){var n=o,r=i;return o=i=void 0,l=e,s=t.apply(r,n)}function _(t){var n=t-u;return void 0===u||n>=e||n<0||p&&t-l>=a}function x(){var t=m();if(_(t))return w(t);c=setTimeout(x,function(t){var n=e-(t-u);return p?v(n,a-(t-l)):n}(t))}function w(t){return c=void 0,h&&o?g(t):(o=i=void 0,s)}function C(){var t=m(),n=_(t);if(o=arguments,i=this,u=t,n){if(void 0===c)return function(t){return l=t,c=setTimeout(x,e),f?g(t):s}(u);if(p)return c=setTimeout(x,e),g(u)}return void 0===c&&(c=setTimeout(x,e)),s}return e=b(e)||0,y(r)&&(f=!!r.leading,a=(p="maxWait"in r)?d(b(r.maxWait)||0,e):a,h="trailing"in r?!!r.trailing:h),C.cancel=function(){void 0!==c&&clearTimeout(c),l=0,o=u=i=c=void 0},C.flush=function(){return void 0===c?s:w(m())},C}function y(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}function b(t){if("number"==typeof t)return t;if(function(t){return"symbol"==typeof t||function(t){return!!t&&"object"==typeof t}(t)&&h.call(t)==o}(t))return r;if(y(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=y(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(i,"");var n=s.test(t);return n||c.test(t)?u(t.slice(2),n?2:8):a.test(t)?r:+t}t.exports=function(t,e,r){var o=!0,i=!0;if("function"!=typeof t)throw new TypeError(n);return y(r)&&(o="leading"in r?!!r.leading:o,i="trailing"in r?!!r.trailing:i),g(t,e,{leading:o,maxWait:e,trailing:i})}},function(t,e,n){"use strict";n.r(e);n(66),n(23);var r=Object.freeze({});function o(t){return void 0===t||null===t}function i(t){return void 0!==t&&null!==t}function a(t){return!0===t}function s(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function c(t){return null!==t&&"object"==typeof t}var u=Object.prototype.toString;function l(t){return"[object Object]"===u.call(t)}function f(t){return"[object RegExp]"===u.call(t)}function p(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function h(t){return null==t?"":"object"==typeof t?JSON.stringify(t,null,2):String(t)}function d(t){var e=parseFloat(t);return isNaN(e)?t:e}function v(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(n,1)}}var y=Object.prototype.hasOwnProperty;function b(t,e){return y.call(t,e)}function _(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var x=/-(\w)/g,w=_(function(t){return t.replace(x,function(t,e){return e?e.toUpperCase():""})}),C=_(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),k=/\B([A-Z])/g,$=_(function(t){return t.replace(k,"-$1").toLowerCase()});var O=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function S(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function A(t,e){for(var n in e)t[n]=e[n];return t}function E(t){for(var e={},n=0;n0,Y=G&&G.indexOf("edge/")>0,J=(G&&G.indexOf("android"),G&&/iphone|ipad|ipod|ios/.test(G)||"ios"===W),Q=(G&&/chrome\/\d+/.test(G),{}.watch),Z=!1;if(V)try{var tt={};Object.defineProperty(tt,"passive",{get:function(){Z=!0}}),window.addEventListener("test-passive",null,tt)}catch(t){}var et=function(){return void 0===H&&(H=!V&&!z&&"undefined"!=typeof global&&"server"===global.process.env.VUE_ENV),H},nt=V&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function rt(t){return"function"==typeof t&&/native code/.test(t.toString())}var ot,it="undefined"!=typeof Symbol&&rt(Symbol)&&"undefined"!=typeof Reflect&&rt(Reflect.ownKeys);ot="undefined"!=typeof Set&&rt(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var at=j,st=0,ct=function(){this.id=st++,this.subs=[]};ct.prototype.addSub=function(t){this.subs.push(t)},ct.prototype.removeSub=function(t){g(this.subs,t)},ct.prototype.depend=function(){ct.target&&ct.target.addDep(this)},ct.prototype.notify=function(){for(var t=this.subs.slice(),e=0,n=t.length;e-1)if(i&&!b(o,"default"))a=!1;else if(""===a||a===$(t)){var c=Ft(String,o.type);(c<0||s0&&(ue((u=t(u,(n||"")+"_"+c))[0])&&ue(f)&&(r[l]=vt(f.text+u[0].text),u.shift()),r.push.apply(r,u)):s(u)?ue(f)?r[l]=vt(f.text+u):""!==u&&r.push(vt(u)):ue(u)&&ue(f)?r[l]=vt(f.text+u.text):(a(e._isVList)&&i(u.tag)&&o(u.key)&&i(n)&&(u.key="__vlist"+n+"_"+c+"__"),r.push(u)));return r}(t):void 0}function ue(t){return i(t)&&i(t.text)&&!1===t.isComment}function le(t,e){return(t.__esModule||it&&"Module"===t[Symbol.toStringTag])&&(t=t.default),c(t)?e.extend(t):t}function fe(t){return t.isComment&&t.asyncFactory}function pe(t){if(Array.isArray(t))for(var e=0;eAe&&Ce[n].id>t.id;)n--;Ce.splice(n+1,0,t)}else Ce.push(t);Oe||(Oe=!0,Zt(Ee))}}(this)},Te.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||c(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Bt(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},Te.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},Te.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Te.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||g(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var Le={enumerable:!0,configurable:!0,get:j,set:j};function Pe(t,e,n){Le.get=function(){return this[e][n]},Le.set=function(t){this[e][n]=t},Object.defineProperty(t,n,Le)}function Ie(t){t._watchers=[];var e=t.$options;e.props&&function(t,e){var n=t.$options.propsData||{},r=t._props={},o=t.$options._propKeys=[];t.$parent&&xt(!1);var i=function(i){o.push(i);var a=Nt(i,e,n,t);Ot(r,i,a),i in t||Pe(t,"_props",i)};for(var a in e)i(a);xt(!0)}(t,e.props),e.methods&&function(t,e){t.$options.props;for(var n in e)t[n]=null==e[n]?j:O(e[n],t)}(t,e.methods),e.data?function(t){var e=t.$options.data;l(e=t._data="function"==typeof e?function(t,e){lt();try{return t.call(e,e)}catch(t){return Bt(t,e,"data()"),{}}finally{ft()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props,o=(t.$options.methods,n.length);for(;o--;){var i=n[o];0,r&&b(r,i)||(void 0,36!==(a=(i+"").charCodeAt(0))&&95!==a&&Pe(t,"_data",i))}var a;$t(e,!0)}(t):$t(t._data={},!0),e.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=et();for(var o in e){var i=e[o],a="function"==typeof i?i:i.get;0,r||(n[o]=new Te(t,a||j,j,Me)),o in t||Re(t,o,i)}}(t,e.computed),e.watch&&e.watch!==Q&&function(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var o=0;o=0||n.indexOf(t[o])<0)&&r.push(t[o]);return r}return t}function fn(t){this._init(t)}function pn(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,o=t._Ctor||(t._Ctor={});if(o[r])return o[r];var i=t.name||n.options.name;var a=function(t){this._init(t)};return(a.prototype=Object.create(n.prototype)).constructor=a,a.cid=e++,a.options=Mt(n.options,t),a.super=n,a.options.props&&function(t){var e=t.options.props;for(var n in e)Pe(t.prototype,"_props",n)}(a),a.options.computed&&function(t){var e=t.options.computed;for(var n in e)Re(t.prototype,n,e[n])}(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,N.forEach(function(t){a[t]=n[t]}),i&&(a.options.components[i]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=A({},a.options),o[r]=a,a}}function hn(t){return t&&(t.Ctor.options.name||t.tag)}function dn(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!f(t)&&t.test(e)}function vn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var a=n[i];if(a){var s=hn(a.componentOptions);s&&!e(s)&&mn(n,i,r,o)}}}function mn(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,g(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=cn++,e._isVue=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r,n._parentElm=e._parentElm,n._refElm=e._refElm;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=Mt(un(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&ve(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,o=n&&n.context;t.$slots=me(e._renderChildren,o),t.$scopedSlots=r,t._c=function(e,n,r,o){return sn(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return sn(t,e,n,r,o,!0)};var i=n&&n.data;Ot(t,"$attrs",i&&i.attrs||r,null,!0),Ot(t,"$listeners",e._parentListeners||r,null,!0)}(e),we(e,"beforeCreate"),function(t){var e=Ue(t.$options.inject,t);e&&(xt(!1),Object.keys(e).forEach(function(n){Ot(t,n,e[n])}),xt(!0))}(e),Ie(e),function(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}(e),we(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(fn),function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=St,t.prototype.$delete=At,t.prototype.$watch=function(t,e,n){if(l(e))return De(this,t,e,n);(n=n||{}).user=!0;var r=new Te(this,t,e,n);return n.immediate&&e.call(this,r.value),function(){r.teardown()}}}(fn),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){if(Array.isArray(t))for(var r=0,o=t.length;r1?S(e):e;for(var n=S(arguments,1),r=0,o=e.length;rparseInt(this.max)&&mn(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return U}};Object.defineProperty(t,"config",e),t.util={warn:at,extend:A,mergeOptions:Mt,defineReactive:Ot},t.set=St,t.delete=At,t.nextTick=Zt,t.options=Object.create(null),N.forEach(function(e){t.options[e+"s"]=Object.create(null)}),t.options._base=t,A(t.options.components,yn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=S(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=Mt(this.options,t),this}}(t),pn(t),function(t){N.forEach(function(e){t[e]=function(t,n){return n?("component"===e&&l(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}})}(t)}(fn),Object.defineProperty(fn.prototype,"$isServer",{get:et}),Object.defineProperty(fn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(fn,"FunctionalRenderContext",{value:Qe}),fn.version="2.5.16";var bn=v("style,class"),_n=v("input,textarea,option,select,progress"),xn=v("contenteditable,draggable,spellcheck"),wn=v("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),Cn="http://www.w3.org/1999/xlink",kn=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},$n=function(t){return kn(t)?t.slice(6,t.length):""},On=function(t){return null==t||!1===t};function Sn(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=An(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=An(e,n.data));return function(t,e){if(i(t)||i(e))return En(t,jn(e));return""}(e.staticClass,e.class)}function An(t,e){return{staticClass:En(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function En(t,e){return t?e?t+" "+e:t:e||""}function jn(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=t.length;r-1?Zn(t,e,n):wn(e)?On(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):xn(e)?t.setAttribute(e,On(n)||"false"===n?"false":"true"):kn(e)?On(n)?t.removeAttributeNS(Cn,$n(e)):t.setAttributeNS(Cn,e,n):Zn(t,e,n)}function Zn(t,e,n){if(On(n))t.removeAttribute(e);else{if(K&&!X&&"TEXTAREA"===t.tagName&&"placeholder"===e&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var tr={create:Jn,update:Jn};function er(t,e){var n=e.elm,r=e.data,a=t.data;if(!(o(r.staticClass)&&o(r.class)&&(o(a)||o(a.staticClass)&&o(a.class)))){var s=Sn(e),c=n._transitionClasses;i(c)&&(s=En(s,jn(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}var nr,rr={create:er,update:er},or="__r",ir="__c";function ar(t,e,n,r,o){var i;e=(i=e)._withTask||(i._withTask=function(){Xt=!0;var t=i.apply(null,arguments);return Xt=!1,t}),n&&(e=function(t,e,n){var r=nr;return function o(){null!==t.apply(null,arguments)&&sr(e,o,n,r)}}(e,t,r)),nr.addEventListener(t,e,Z?{capture:r,passive:o}:r)}function sr(t,e,n,r){(r||nr).removeEventListener(t,e._withTask||e,n)}function cr(t,e){if(!o(t.data.on)||!o(e.data.on)){var n=e.data.on||{},r=t.data.on||{};nr=e.elm,function(t){if(i(t[or])){var e=K?"change":"input";t[e]=[].concat(t[or],t[e]||[]),delete t[or]}i(t[ir])&&(t.change=[].concat(t[ir],t.change||[]),delete t[ir])}(n),ie(n,r,ar,sr,e.context),nr=void 0}}var ur={create:cr,update:cr};function lr(t,e){if(!o(t.data.domProps)||!o(e.data.domProps)){var n,r,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};for(n in i(c.__ob__)&&(c=e.data.domProps=A({},c)),s)o(c[n])&&(a[n]="");for(n in c){if(r=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n){a._value=r;var u=o(r)?"":String(r);fr(a,u)&&(a.value=u)}else a[n]=r}}}function fr(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.lazy)return!1;if(r.number)return d(n)!==d(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var pr={create:lr,update:lr},hr=_(function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach(function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e});function dr(t){var e=vr(t.style);return t.staticStyle?A(t.staticStyle,e):e}function vr(t){return Array.isArray(t)?E(t):"string"==typeof t?hr(t):t}var mr,gr=/^--/,yr=/\s*!important$/,br=function(t,e,n){if(gr.test(e))t.style.setProperty(e,n);else if(yr.test(n))t.style.setProperty(e,n.replace(yr,""),"important");else{var r=xr(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(/\s+/).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function $r(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(/\s+/).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Or(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&A(e,Sr(t.name||"v")),A(e,t),e}return"string"==typeof t?Sr(t):void 0}}var Sr=_(function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}}),Ar=V&&!X,Er="transition",jr="animation",Tr="transition",Lr="transitionend",Pr="animation",Ir="animationend";Ar&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Tr="WebkitTransition",Lr="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Pr="WebkitAnimation",Ir="webkitAnimationEnd"));var Mr=V?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Rr(t){Mr(function(){Mr(t)})}function Nr(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),kr(t,e))}function Dr(t,e){t._transitionClasses&&g(t._transitionClasses,e),$r(t,e)}function Ur(t,e,n){var r=Br(t,e),o=r.type,i=r.timeout,a=r.propCount;if(!o)return n();var s=o===Er?Lr:Ir,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c0&&(n=Er,l=a,f=i.length):e===jr?u>0&&(n=jr,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Er:jr:null)?n===Er?i.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Er&&Fr.test(r[Tr+"Property"])}}function Hr(t,e){for(;t.length1}function Kr(t,e){!0!==e.data.show&&Vr(e)}var Xr=function(t){var e,n,r={},c=t.modules,u=t.nodeOps;for(e=0;ed?b(t,o(n[g+1])?null:n[g+1].elm,n,h,g,r):h>g&&x(0,e,p,d)}(c,h,d,n,s):i(d)?(i(t.text)&&u.setTextContent(c,""),b(c,null,d,0,d.length-1,n)):i(h)?x(0,h,0,h.length-1):i(t.text)&&u.setTextContent(c,""):t.text!==e.text&&u.setTextContent(c,e.text),i(p)&&i(l=p.hook)&&i(l=l.postpatch)&&l(t,e)}}}function $(t,e,n){if(a(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,a.selected!==i&&(a.selected=i);else if(P(to(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));o||(t.selectedIndex=-1)}}function Zr(t,e){return e.every(function(e){return!P(e,t)})}function to(t){return"_value"in t?t._value:t.value}function eo(t){t.target.composing=!0}function no(t){t.target.composing&&(t.target.composing=!1,ro(t.target,"input"))}function ro(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function oo(t){return!t.componentInstance||t.data&&t.data.transition?t:oo(t.componentInstance._vnode)}var io={model:Yr,show:{bind:function(t,e,n){var r=e.value,o=(n=oo(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,Vr(n,function(){t.style.display=i})):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=oo(n)).data&&n.data.transition?(n.data.show=!0,r?Vr(n,function(){t.style.display=t.__vOriginalDisplay}):zr(n,function(){t.style.display="none"})):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}}},ao={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function so(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?so(pe(e.children)):t}function co(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var i in o)e[w(i)]=o[i];return e}function uo(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var lo={name:"transition",props:ao,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(function(t){return t.tag||fe(t)})).length){0;var r=this.mode;0;var o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var i=so(o);if(!i)return o;if(this._leaving)return uo(t,o);var a="__transition-"+this._uid+"-";i.key=null==i.key?i.isComment?a+"comment":a+i.tag:s(i.key)?0===String(i.key).indexOf(a)?i.key:a+i.key:i.key;var c=(i.data||(i.data={})).transition=co(this),u=this._vnode,l=so(u);if(i.data.directives&&i.data.directives.some(function(t){return"show"===t.name})&&(i.data.show=!0),l&&l.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(i,l)&&!fe(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=A({},c);if("out-in"===r)return this._leaving=!0,ae(f,"afterLeave",function(){e._leaving=!1,e.$forceUpdate()}),uo(t,o);if("in-out"===r){if(fe(i))return u;var p,h=function(){p()};ae(c,"afterEnter",h),ae(c,"enterCancelled",h),ae(f,"delayLeave",function(t){p=t})}}return o}}},fo=A({tag:String,moveClass:String},ao);function po(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function ho(t){t.data.newPos=t.elm.getBoundingClientRect()}function vo(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform="translate("+r+"px,"+o+"px)",i.transitionDuration="0s"}}delete fo.mode;var mo={Transition:lo,TransitionGroup:{props:fo,render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],a=co(this),s=0;s-1?Mn[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Mn[t]=/HTMLUnknownElement/.test(e.toString())},A(fn.options.directives,io),A(fn.options.components,mo),fn.prototype.__patch__=V?Xr:j,fn.prototype.$mount=function(t,e){return function(t,e,n){return t.$el=e,t.$options.render||(t.$options.render=dt),we(t,"beforeMount"),new Te(t,function(){t._update(t._render(),n)},j,null,!0),n=!1,null==t.$vnode&&(t._isMounted=!0,we(t,"mounted")),t}(this,t=t&&V?function(t){if("string"==typeof t){var e=document.querySelector(t);return e||document.createElement("div")}return t}(t):void 0,e)},V&&setTimeout(function(){U.devtools&&nt&&nt.emit("init",fn)},0);var go=fn; +/** + * vue-router v3.0.1 + * (c) 2017 Evan You + * @license MIT + */function yo(t,e){0}function bo(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}var _o={name:"router-view",functional:!0,props:{name:{type:String,default:"default"}},render:function(t,e){var n=e.props,r=e.children,o=e.parent,i=e.data;i.routerView=!0;for(var a=o.$createElement,s=n.name,c=o.$route,u=o._routerViewCache||(o._routerViewCache={}),l=0,f=!1;o&&o._routerRoot!==o;)o.$vnode&&o.$vnode.data.routerView&&l++,o._inactive&&(f=!0),o=o.$parent;if(i.routerViewDepth=l,f)return a(u[s],i,r);var p=c.matched[l];if(!p)return u[s]=null,a();var h=u[s]=p.components[s];i.registerRouteInstance=function(t,e){var n=p.instances[s];(e&&n!==t||!e&&n===t)&&(p.instances[s]=e)},(i.hook||(i.hook={})).prepatch=function(t,e){p.instances[s]=e.componentInstance};var d=i.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0;default:0}}(c,p.props&&p.props[s]);if(d){d=i.props=function(t,e){for(var n in e)t[n]=e[n];return t}({},d);var v=i.attrs=i.attrs||{};for(var m in d)h.props&&m in h.props||(v[m]=d[m],delete d[m])}return a(h,i,r)}};var xo=/[!'()*]/g,wo=function(t){return"%"+t.charCodeAt(0).toString(16)},Co=/%2C/g,ko=function(t){return encodeURIComponent(t).replace(xo,wo).replace(Co,",")},$o=decodeURIComponent;function Oo(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(function(t){var n=t.replace(/\+/g," ").split("="),r=$o(n.shift()),o=n.length>0?$o(n.join("=")):null;void 0===e[r]?e[r]=o:Array.isArray(e[r])?e[r].push(o):e[r]=[e[r],o]}),e):e}function So(t){var e=t?Object.keys(t).map(function(e){var n=t[e];if(void 0===n)return"";if(null===n)return ko(e);if(Array.isArray(n)){var r=[];return n.forEach(function(t){void 0!==t&&(null===t?r.push(ko(e)):r.push(ko(e)+"="+ko(t)))}),r.join("&")}return ko(e)+"="+ko(n)}).filter(function(t){return t.length>0}).join("&"):null;return e?"?"+e:""}var Ao=/\/?$/;function Eo(t,e,n,r){var o=r&&r.options.stringifyQuery,i=e.query||{};try{i=jo(i)}catch(t){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:Lo(e,o),matched:t?function(t){var e=[];for(;t;)e.unshift(t),t=t.parent;return e}(t):[]};return n&&(a.redirectedFrom=Lo(n,o)),Object.freeze(a)}function jo(t){if(Array.isArray(t))return t.map(jo);if(t&&"object"==typeof t){var e={};for(var n in t)e[n]=jo(t[n]);return e}return t}var To=Eo(null,{path:"/"});function Lo(t,e){var n=t.path,r=t.query;void 0===r&&(r={});var o=t.hash;return void 0===o&&(o=""),(n||"/")+(e||So)(r)+o}function Po(t,e){return e===To?t===e:!!e&&(t.path&&e.path?t.path.replace(Ao,"")===e.path.replace(Ao,"")&&t.hash===e.hash&&Io(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&Io(t.query,e.query)&&Io(t.params,e.params)))}function Io(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(function(n){var r=t[n],o=e[n];return"object"==typeof r&&"object"==typeof o?Io(r,o):String(r)===String(o)})}var Mo,Ro=[String,Object],No=[String,Array],Do={name:"router-link",props:{to:{type:Ro,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:No,default:"click"}},render:function(t){var e=this,n=this.$router,r=this.$route,o=n.resolve(this.to,r,this.append),i=o.location,a=o.route,s=o.href,c={},u=n.options.linkActiveClass,l=n.options.linkExactActiveClass,f=null==u?"router-link-active":u,p=null==l?"router-link-exact-active":l,h=null==this.activeClass?f:this.activeClass,d=null==this.exactActiveClass?p:this.exactActiveClass,v=i.path?Eo(null,i,null,n):a;c[d]=Po(r,v),c[h]=this.exact?c[d]:function(t,e){return 0===t.path.replace(Ao,"/").indexOf(e.path.replace(Ao,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(var n in e)if(!(n in t))return!1;return!0}(t.query,e.query)}(r,v);var m=function(t){Uo(t)&&(e.replace?n.replace(i):n.push(i))},g={click:Uo};Array.isArray(this.event)?this.event.forEach(function(t){g[t]=m}):g[this.event]=m;var y={class:c};if("a"===this.tag)y.on=g,y.attrs={href:s};else{var b=function t(e){if(e)for(var n,r=0;r=0&&(e=t.slice(r),t=t.slice(0,r));var o=t.indexOf("?");return o>=0&&(n=t.slice(o+1),t=t.slice(0,o)),{path:t,query:n,hash:e}}(o.path||""),c=e&&e.path||"/",u=s.path?Ho(s.path,c,n||o.append):c,l=function(t,e,n){void 0===e&&(e={});var r,o=n||Oo;try{r=o(t||"")}catch(t){r={}}for(var i in e)r[i]=e[i];return r}(s.query,o.query,r&&r.options.parseQuery),f=o.hash||s.hash;return f&&"#"!==f.charAt(0)&&(f="#"+f),{_normalized:!0,path:u,query:l,hash:f}}function li(t,e){for(var n in e)t[n]=e[n];return t}function fi(t,e){var n=ci(t),r=n.pathList,o=n.pathMap,i=n.nameMap;function a(t,n,a){var s=ui(t,n,!1,e),u=s.name;if(u){var l=i[u];if(!l)return c(null,s);var f=l.regex.keys.filter(function(t){return!t.optional}).map(function(t){return t.name});if("object"!=typeof s.params&&(s.params={}),n&&"object"==typeof n.params)for(var p in n.params)!(p in s.params)&&f.indexOf(p)>-1&&(s.params[p]=n.params[p]);if(l)return s.path=si(l.path,s.params),c(l,s,a)}else if(s.path){s.params={};for(var h=0;h=t.length?n():t[o]?e(t[o],function(){r(o+1)}):r(o+1)};r(0)}function ji(t){return function(e,n,r){var o=!1,i=0,a=null;Ti(t,function(t,e,n,s){if("function"==typeof t&&void 0===t.cid){o=!0,i++;var c,u=Ii(function(e){var o;((o=e).__esModule||Pi&&"Module"===o[Symbol.toStringTag])&&(e=e.default),t.resolved="function"==typeof e?e:Mo.extend(e),n.components[s]=e,--i<=0&&r()}),l=Ii(function(t){var e="Failed to resolve async component "+s+": "+t;a||(a=bo(t)?t:new Error(e),r(a))});try{c=t(u,l)}catch(t){l(t)}if(c)if("function"==typeof c.then)c.then(u,l);else{var f=c.component;f&&"function"==typeof f.then&&f.then(u,l)}}}),o||r()}}function Ti(t,e){return Li(t.map(function(t){return Object.keys(t.components).map(function(n){return e(t.components[n],t.instances[n],t,n)})}))}function Li(t){return Array.prototype.concat.apply([],t)}var Pi="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function Ii(t){var e=!1;return function(){for(var n=[],r=arguments.length;r--;)n[r]=arguments[r];if(!e)return e=!0,t.apply(this,n)}}var Mi=function(t,e){this.router=t,this.base=function(t){if(!t)if(Bo){var e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";"/"!==t.charAt(0)&&(t="/"+t);return t.replace(/\/$/,"")}(e),this.current=To,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Ri(t,e,n,r){var o=Ti(t,function(t,r,o,i){var a=function(t,e){"function"!=typeof t&&(t=Mo.extend(t));return t.options[e]}(t,e);if(a)return Array.isArray(a)?a.map(function(t){return n(t,r,o,i)}):n(a,r,o,i)});return Li(r?o.reverse():o)}function Ni(t,e){if(e)return function(){return t.apply(e,arguments)}}Mi.prototype.listen=function(t){this.cb=t},Mi.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},Mi.prototype.onError=function(t){this.errorCbs.push(t)},Mi.prototype.transitionTo=function(t,e,n){var r=this,o=this.router.match(t,this.current);this.confirmTransition(o,function(){r.updateRoute(o),e&&e(o),r.ensureURL(),r.ready||(r.ready=!0,r.readyCbs.forEach(function(t){t(o)}))},function(t){n&&n(t),t&&!r.ready&&(r.ready=!0,r.readyErrorCbs.forEach(function(e){e(t)}))})},Mi.prototype.confirmTransition=function(t,e,n){var r=this,o=this.current,i=function(t){bo(t)&&(r.errorCbs.length?r.errorCbs.forEach(function(e){e(t)}):(yo(),console.error(t))),n&&n(t)};if(Po(t,o)&&t.matched.length===o.matched.length)return this.ensureURL(),i();var a=function(t,e){var n,r=Math.max(t.length,e.length);for(n=0;n=0?e.slice(0,n):e)+"#"+t}function Vi(t){wi?Si(qi(t)):window.location.hash=t}function zi(t){wi?Ai(qi(t)):window.location.replace(qi(t))}var Wi=function(t){function e(e,n){t.call(this,e,n),this.stack=[],this.index=-1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.push=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index+1).concat(t),r.index++,e&&e(t)},n)},e.prototype.replace=function(t,e,n){var r=this;this.transitionTo(t,function(t){r.stack=r.stack.slice(0,r.index).concat(t),e&&e(t)},n)},e.prototype.go=function(t){var e=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var r=this.stack[n];this.confirmTransition(r,function(){e.index=n,e.updateRoute(r)})}},e.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},e.prototype.ensureURL=function(){},e}(Mi),Gi=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=fi(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!wi&&!1!==t.fallback,this.fallback&&(e="hash"),Bo||(e="abstract"),this.mode=e,e){case"history":this.history=new Di(this,t.base);break;case"hash":this.history=new Fi(this,t.base,this.fallback);break;case"abstract":this.history=new Wi(this,t.base);break;default:0}},Ki={currentRoute:{configurable:!0}};function Xi(t,e){return t.push(e),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}Gi.prototype.match=function(t,e,n){return this.matcher.match(t,e,n)},Ki.currentRoute.get=function(){return this.history&&this.history.current},Gi.prototype.init=function(t){var e=this;if(this.apps.push(t),!this.app){this.app=t;var n=this.history;if(n instanceof Di)n.transitionTo(n.getCurrentLocation());else if(n instanceof Fi){var r=function(){n.setupListeners()};n.transitionTo(n.getCurrentLocation(),r,r)}n.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},Gi.prototype.beforeEach=function(t){return Xi(this.beforeHooks,t)},Gi.prototype.beforeResolve=function(t){return Xi(this.resolveHooks,t)},Gi.prototype.afterEach=function(t){return Xi(this.afterHooks,t)},Gi.prototype.onReady=function(t,e){this.history.onReady(t,e)},Gi.prototype.onError=function(t){this.history.onError(t)},Gi.prototype.push=function(t,e,n){this.history.push(t,e,n)},Gi.prototype.replace=function(t,e,n){this.history.replace(t,e,n)},Gi.prototype.go=function(t){this.history.go(t)},Gi.prototype.back=function(){this.go(-1)},Gi.prototype.forward=function(){this.go(1)},Gi.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},Gi.prototype.resolve=function(t,e,n){var r=ui(t,e||this.history.current,n,this),o=this.match(r,e),i=o.redirectedFrom||o.fullPath;return{location:r,route:o,href:function(t,e,n){var r="hash"===n?"#"+e:e;return t?qo(t+"/"+r):r}(this.history.base,i,this.mode),normalizedTo:r,resolved:o}},Gi.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==To&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(Gi.prototype,Ki),Gi.install=Fo,Gi.version="3.0.1",Bo&&window.Vue&&window.Vue.use(Gi);var Yi=Gi,Ji={functional:!0,props:{custom:{type:Boolean,default:!0}},render:function(t,e){var n=e.parent,r=e.props,o=e.data;return t(n.$page.key,{class:[r.custom?"custom":"",o.class,o.staticClass],style:o.style})}},Qi=(n(117),n(0)),Zi=Object(Qi.a)({},function(t,e){var n=e._c;return n("svg",{staticClass:"icon outbound",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"}},[n("path",{attrs:{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"}}),n("polygon",{attrs:{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"}})])},[],!0,null,null,null).exports,ta={functional:!0,props:["type","text"],render:function(t,e){var n=e.props,r=e.slots;return t("span",{class:["badge",n.type]},n.text||r().default)}},ea=(n(115),Object(Qi.a)(ta,void 0,void 0,!1,null,null,null).exports);n(113),n(13),n(19),n(9);function na(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e-1},a=[],s=0;s=r);s++){var c=n[s];if(this.getPageLocalePath(c)===o)if(i(c))a.push(c);else if(c.headers)for(var u=0;u=r);u++){var l=c.headers[u];i(l)&&a.push(Object.assign({},c,{path:c.path+"#"+l.slug,header:l}))}}return a}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})):t._e()])},[],!1,null,null,null).exports),Oa=(n(94),{name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}}),Sa=(n(88),Object(Qi.a)(Oa,function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)},[],!1,null,null,null).exports),Aa={components:{NavLink:_a,DropdownTransition:Sa},data:function(){return{open:!1}},props:{item:{required:!0}},methods:{toggle:function(){this.open=!this.open}}},Ea=(n(86),{components:{NavLink:_a,DropdownLink:Object(Qi.a)(Aa,function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("a",{staticClass:"dropdown-title",on:{click:t.toggle}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,function(e,r){return n("li",{key:e.link||r,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v(t._s(e.text))]):t._e(),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,function(t){return n("li",{key:t.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:t}})],1)})):n("NavLink",{attrs:{item:e}})],1)}))])],1)},[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,r=this.$router.options.routes,o=this.$site.themeConfig.locales||{},i={text:this.$themeLocaleConfig.selectText||"Languages",items:Object.keys(e).map(function(i){var a,s=e[i],c=o[i]&&o[i].label||s.lang;return s.lang===t.$lang?a=n:(a=n.replace(t.$localeConfig.path,i),r.some(function(t){return t.path===a})||(a=i)),{text:c,link:a}})};return na(this.userNav).concat([i])}return this.userNav},userLinks:function(){return(this.nav||[]).map(function(t){return Object.assign(ya(t),{items:(t.items||[]).map(ya)})})},repoLink:function(){var t=this.$site.themeConfig.repo;if(t)return/^https?:/.test(t)?t:"https://github.com/".concat(t)},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;n5&&void 0!==arguments[5]?arguments[5]:1;return!e||i>o?null:t("ul",{class:"sidebar-sub-headers"},e.map(function(e){var a=da(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[Ra(t,"#"+e.slug,e.title,a),Na(t,e.children,n,r,o,i+1)])}))}var Da={functional:!0,props:["item"],render:function(t,e){var n=e.parent,r=n.$page,o=n.$site,i=n.$route,a=e.props.item,s=da(i,a.path),c="auto"===a.type?s||a.children.some(function(t){return da(i,a.basePath+"#"+t.slug)}):s,u=Ra(t,a.path,a.title||a.path,c),l=null!=r.frontmatter.sidebarDepth?r.frontmatter.sidebarDepth:o.themeConfig.sidebarDepth,f=null==l?1:l;return"auto"===a.type?[u,Na(t,a.children,a.basePath,i,f)]:c&&a.headers&&!sa.test(a.path)?[u,Na(t,ga(a.headers),a.path,i,f)]:u}},Ua=(n(78),Object(Qi.a)(Da,void 0,void 0,!1,null,null,null).exports),Fa={name:"SidebarGroup",props:["item","first","open","collapsable"],components:{SidebarLink:Ua,DropdownTransition:Sa}};n(76);var Ba={components:{SidebarGroup:Object(Qi.a)(Fa,function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-group",class:{first:t.first,collapsable:t.collapsable}},[n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),n("DropdownTransition",[t.open||!t.collapsable?n("ul",{ref:"items",staticClass:"sidebar-group-items"},t._l(t.item.children,function(t){return n("li",[n("SidebarLink",{attrs:{item:t}})],1)})):t._e()])],1)},[],!1,null,null,null).exports,SidebarLink:Ua,NavLinks:ja},props:["items"],data:function(){return{openGroupIndex:0}},created:function(){this.refreshIndex()},watch:{$route:function(){this.refreshIndex()}},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return da(this.$route,t.path)}}},Ha=(n(74),{components:{Home:wa,Page:Ma,Sidebar:Object(Qi.a)(Ba,function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar"},[n("NavLinks"),t._t("top"),t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,function(e,r){return n("li",{key:r},["group"===e.type?n("SidebarGroup",{attrs:{item:e,first:0===r,open:r===t.openGroupIndex,collapsable:e.collapsable},on:{toggle:function(e){t.toggleGroup(r)}}}):n("SidebarLink",{attrs:{item:e}})],1)})):t._e(),t._t("bottom")],2)},[],!1,null,null,null).exports,Navbar:La},data:function(){return{isSidebarOpen:!1}},computed:{shouldShowNavbar:function(){var t=this.$site.themeConfig;return!1!==this.$page.frontmatter.navbar&&!1!==t.navbar&&(this.$title||t.logo||t.repo||t.nav||this.$themeLocaleConfig.nav)},shouldShowSidebar:function(){var t=this.$page.frontmatter;return!t.layout&&!t.home&&!1!==t.sidebar&&this.sidebarItems.length},sidebarItems:function(){return ma(this.$page,this.$route,this.$site,this.$localePath)},pageClasses:function(){var t=this.$page.frontmatter.pageClass;return[{"no-navbar":!this.shouldShowNavbar,"sidebar-open":this.isSidebarOpen,"no-sidebar":!this.shouldShowSidebar},t]}},mounted:function(){var t=this;window.addEventListener("scroll",this.onScroll),aa.a.configure({showSpinner:!1}),this.$router.beforeEach(function(t,e,n){t.path===e.path||go.component(t.name)||aa.a.start(),n()}),this.$router.afterEach(function(){aa.a.done(),t.isSidebarOpen=!1})},methods:{toggleSidebar:function(t){this.isSidebarOpen="boolean"==typeof t?t:!this.isSidebarOpen},onTouchStart:function(t){this.touchStart={x:t.changedTouches[0].clientX,y:t.changedTouches[0].clientY}},onTouchEnd:function(t){var e=t.changedTouches[0].clientX-this.touchStart.x,n=t.changedTouches[0].clientY-this.touchStart.y;Math.abs(e)>Math.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),qa=(n(72),n(70),Object(Qi.a)(Ha,function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),n("div",{staticClass:"sidebar-mask",on:{click:function(e){t.toggleSidebar(!1)}}}),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar}},[t._t("sidebar-top",null,{slot:"top"}),t._t("sidebar-bottom",null,{slot:"bottom"})],2),t.$page.frontmatter.layout?n("div",{staticClass:"custom-layout"},[n(t.$page.frontmatter.layout,{tag:"component"})],1):t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems}},[t._t("page-top",null,{slot:"top"}),t._t("page-bottom",null,{slot:"bottom"})],2)],1)},[],!1,null,null,null).exports),Va=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],za={methods:{getMsg:function(){return Va[Math.floor(Math.random()*Va.length)]}}},Wa=Object(Qi.a)(za,function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"content"},[e("h1",[this._v("404")]),e("blockquote",[this._v(this._s(this.getMsg()))]),e("router-link",{attrs:{to:"/"}},[this._v("Take me home.")])],1)])},[],!1,null,null,null).exports,Ga={created:function(){this.$ssrContext&&(this.$ssrContext.title=this.$title,this.$ssrContext.lang=this.$lang,this.$ssrContext.description=this.$page.description||this.$description)},mounted:function(){var t=this;this.currentMetaTags=[];var e=function(){document.title=t.$title,document.documentElement.lang=t.$lang;var e=[{name:"description",content:t.$description}].concat(na(t.$page.frontmatter.meta||[]));t.currentMetaTags=Ka(e,t.currentMetaTags)};this.$watch("$page",e),e()},beforeDestroy:function(){Ka(null,this.currentMetaTags)}};function Ka(t,e){if(e&&e.forEach(function(t){document.head.removeChild(t)}),t)return t.map(function(t){var e=document.createElement("meta");return Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])}),document.head.appendChild(e),e})}var Xa=n(67),Ya=[Ga,{mounted:function(){window.addEventListener("scroll",this.onScroll)},methods:{onScroll:n.n(Xa)()(function(){this.setActiveHash()},300),setActiveHash:function(){for(var t=this,e=[].slice.call(document.querySelectorAll(".sidebar-link")),n=[].slice.call(document.querySelectorAll(".header-anchor")).filter(function(t){return e.some(function(e){return e.hash===t.hash})}),r=Math.max(window.pageYOffset,document.documentElement.scrollTop,document.body.scrollTop),o=0;o=i.parentElement.offsetTop+10&&(!a||rg;)v(m[g++]);f.constructor=u,u.prototype=f,n(11)(r,"RegExp",u)}n(56)("RegExp")},,function(t,e,n){"use strict";var r=n(36);n.n(r).a},,function(t,e,n){"use strict";var r=n(37);n.n(r).a},,function(t,e,n){"use strict";var r=n(38);n.n(r).a},function(t,e,n){n(42)("split",2,function(t,e,r){"use strict";var o=n(51),i=r,a=[].push;if("c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length){var s=void 0===/()??/.exec("")[1];r=function(t,e){var n=String(this);if(void 0===t&&0===e)return[];if(!o(t))return i.call(n,t,e);var r,c,u,l,f,p=[],h=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),d=0,v=void 0===e?4294967295:e>>>0,m=new RegExp(t.source,h+"g");for(s||(r=new RegExp("^"+m.source+"$(?!\\s)",h));(c=m.exec(n))&&!((u=c.index+c[0].length)>d&&(p.push(n.slice(d,c.index)),!s&&c.length>1&&c[0].replace(r,function(){for(f=1;f1&&c.index=v));)m.lastIndex===c.index&&m.lastIndex++;return d===n.length?!l&&m.test("")||p.push(""):p.push(n.slice(d)),p.length>v?p.slice(0,v):p}}else"0".split(void 0,0).length&&(r=function(t,e){return void 0===t&&0===e?[]:i.call(this,t,e)});return[function(n,o){var i=t(this),a=void 0==n?void 0:n[e];return void 0!==a?a.call(n,i,o):r.call(String(i),n,o)},r]})},function(t,e,n){var r=n(15),o=n(5),i=n(20),a=/"/g,s=function(t,e,n,r){var o=String(i(t)),s="<"+e;return""!==n&&(s+=" "+n+'="'+String(r).replace(a,""")+'"'),s+">"+o+""};t.exports=function(t,e){var n={};n[t]=e(s),r(r.P+r.F*o(function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}),"String",n)}},function(t,e,n){"use strict";n(102)("link",function(t){return function(e){return t(this,"a","href",e)}})},function(t,e,n){var r=n(7).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(6)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(t){return""}}})},function(t,e,n){var r=n(10),o=n(43),i=n(45)("IE_PROTO"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=o(t),r(t,i)?t[i]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},function(t,e,n){var r=n(7),o=n(4),i=n(22);t.exports=n(6)?Object.defineProperties:function(t,e){o(t);for(var n,a=i(e),s=a.length,c=0;s>c;)r.f(t,n=a[c++],e[n]);return t}},function(t,e,n){var r=n(4),o=n(106),i=n(44),a=n(45)("IE_PROTO"),s=function(){},c=function(){var t,e=n(48)("iframe"),r=i.length;for(e.style.display="none",n(58).appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write(" + + diff --git a/docs/DOCS_README.md b/docs/DOCS_README.md index 0d1e3f979..e87ef23df 100644 --- a/docs/DOCS_README.md +++ b/docs/DOCS_README.md @@ -24,7 +24,7 @@ on the website. ## Config.js -The [config.js](./config.js) generates the sidebar and Table of Contents +The [config.js](./.vuepress/config.js) generates the sidebar and Table of Contents on the website docs. Note the use of relative links and the omission of file extensions. Additional features are available to improve the look of the sidebar. @@ -59,9 +59,36 @@ to send users to the GitHub. ## Building Locally -Not currently possible but coming soon! Doing so requires -assets held in the (private) website repo, installing -[VuePress](https://vuepress.vuejs.org/), and modifying the `config.js`. +To build and serve the documentation locally, run: + +``` +# from this directory +npm install +npm install -g vuepress +``` + +then change the following line in the `config.js`: + +``` +base: "/docs/", +``` + +to: + +``` +base: "/", +``` + +Finally, go up one directory to the root of the repo and run: + +``` +# from root of repo +vuepress build docs +cd dist/docs +python -m SimpleHTTPServer 8080 +``` + +then navigate to localhost:8080 in your browser. ## Consistency diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 000000000..3449eda1a --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,4670 @@ +{ + "name": "tendermint", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@azu/format-text": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.1.tgz", + "integrity": "sha1-aWc1CpRkD2sChVFpvYl85U1s6+I=" + }, + "@azu/style-format": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.0.tgz", + "integrity": "sha1-5wGH+Khi4ZGxvObAJo8TrNOlayA=", + "requires": { + "@azu/format-text": "^1.0.1" + } + }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" + }, + "@textlint/ast-node-types": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-4.0.3.tgz", + "integrity": "sha512-mkkqbuxZkCESmMCrVN5QEgmFqBJAcoAGIaZaQfziqKAyCQBLLgKVJzeFuup9mDm9mvCTKekhLk9yIaEFc8EFxA==" + }, + "@textlint/ast-traverse": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@textlint/ast-traverse/-/ast-traverse-2.0.9.tgz", + "integrity": "sha512-E2neVj65wyadt3hr9R+DHW01dG4dNOMmFRab7Bph/rkDDeK85w/6RNJgIt9vBCPtt7a4bndTj1oZrK6wDZAEtQ==", + "requires": { + "@textlint/ast-node-types": "^4.0.3" + } + }, + "@textlint/feature-flag": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@textlint/feature-flag/-/feature-flag-3.0.5.tgz", + "integrity": "sha512-hXTDGvltgiUtJs7QhALSILNE+g0cdY4CyqHR2r5+EmiYbS3NuqWVLn3GZYUPWXl9rVDky/IpR+6DF0uLJF8m8Q==", + "requires": { + "map-like": "^2.0.0" + } + }, + "@textlint/fixer-formatter": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@textlint/fixer-formatter/-/fixer-formatter-3.0.8.tgz", + "integrity": "sha512-LTHcCLTyESdz90NGYzrYC0juSqLzGBc5VMMRO8Xvz3fapBya/Sn5ncgvsHqnKY0OIbV/IdOT54G2F46D8R6P9Q==", + "requires": { + "@textlint/kernel": "^3.0.0", + "chalk": "^1.1.3", + "debug": "^2.1.0", + "diff": "^2.2.2", + "interop-require": "^1.0.0", + "is-file": "^1.0.0", + "string-width": "^1.0.1", + "text-table": "^0.2.0", + "try-resolve": "^1.0.1" + }, + "dependencies": { + "@textlint/kernel": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-3.0.0.tgz", + "integrity": "sha512-SxHWr6VAD/SdqTCy1uB03bFLbGYbhZeQTeUuIJE6s1pD7wtQ1+Y1n8nx9I9m7nqGZi5eYuVA6WnpvCq10USz+w==", + "requires": { + "@textlint/ast-node-types": "^4.0.3", + "@textlint/ast-traverse": "^2.0.9", + "@textlint/feature-flag": "^3.0.5", + "@types/bluebird": "^3.5.18", + "bluebird": "^3.5.1", + "debug": "^2.6.6", + "deep-equal": "^1.0.1", + "map-like": "^2.0.0", + "object-assign": "^4.1.1", + "structured-source": "^3.0.2" + } + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "@textlint/kernel": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-2.0.9.tgz", + "integrity": "sha512-0237/9yDIlSVaH0pcVAxm0rV1xF96UpjXUXoBRdciWnf2+O0tWQEeBC9B2/B2jLw9Ha0zGlK+q+bLREpXB97Cw==", + "requires": { + "@textlint/ast-node-types": "^4.0.2", + "@textlint/ast-traverse": "^2.0.8", + "@textlint/feature-flag": "^3.0.4", + "@types/bluebird": "^3.5.18", + "bluebird": "^3.5.1", + "debug": "^2.6.6", + "deep-equal": "^1.0.1", + "object-assign": "^4.1.1", + "structured-source": "^3.0.2" + } + }, + "@textlint/linter-formatter": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-3.0.8.tgz", + "integrity": "sha512-hayZi4ybj01Km9Soi34cT8EkmEcqGgQKHu1tvPQVd8S2zaE3m/8nmf6qhwAo/HAwMzbIj0XxdV8nVuiUfz8ADQ==", + "requires": { + "@azu/format-text": "^1.0.1", + "@azu/style-format": "^1.0.0", + "@textlint/kernel": "^3.0.0", + "chalk": "^1.0.0", + "concat-stream": "^1.5.1", + "js-yaml": "^3.2.4", + "optionator": "^0.8.1", + "pluralize": "^2.0.0", + "string-width": "^1.0.1", + "string.prototype.padstart": "^3.0.0", + "strip-ansi": "^3.0.1", + "table": "^3.7.8", + "text-table": "^0.2.0", + "try-resolve": "^1.0.1", + "xml-escape": "^1.0.0" + }, + "dependencies": { + "@textlint/kernel": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-3.0.0.tgz", + "integrity": "sha512-SxHWr6VAD/SdqTCy1uB03bFLbGYbhZeQTeUuIJE6s1pD7wtQ1+Y1n8nx9I9m7nqGZi5eYuVA6WnpvCq10USz+w==", + "requires": { + "@textlint/ast-node-types": "^4.0.3", + "@textlint/ast-traverse": "^2.0.9", + "@textlint/feature-flag": "^3.0.5", + "@types/bluebird": "^3.5.18", + "bluebird": "^3.5.1", + "debug": "^2.6.6", + "deep-equal": "^1.0.1", + "map-like": "^2.0.0", + "object-assign": "^4.1.1", + "structured-source": "^3.0.2" + } + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "@textlint/markdown-to-ast": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-6.0.9.tgz", + "integrity": "sha512-hfAWBvTeUGh5t5kTn2U3uP3qOSM1BSrxzl1jF3nn0ywfZXpRBZr5yRjXnl4DzIYawCtZOshmRi/tI3/x4TE1jQ==", + "requires": { + "@textlint/ast-node-types": "^4.0.3", + "debug": "^2.1.3", + "remark-frontmatter": "^1.2.0", + "remark-parse": "^5.0.0", + "structured-source": "^3.0.2", + "traverse": "^0.6.6", + "unified": "^6.1.6" + } + }, + "@textlint/text-to-ast": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@textlint/text-to-ast/-/text-to-ast-3.0.9.tgz", + "integrity": "sha512-0Vycl2XtGv3pUtUNkBn9M/e3jBAtmlh7STUa3GuiyATXg49PsqqX7c8NxGPrNqMvDYCJ3ZubBx8GSEyra6ZWFw==", + "requires": { + "@textlint/ast-node-types": "^4.0.3" + } + }, + "@textlint/textlint-plugin-markdown": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-markdown/-/textlint-plugin-markdown-4.0.10.tgz", + "integrity": "sha512-HIV2UAhjnt9/tJQbuXkrD3CRiEFRtNpYoQEZCNCwd1nBMWUypAFthL9jT1KJ8tagOF7wEiGMB19QfDxiNQ+6mw==", + "requires": { + "@textlint/markdown-to-ast": "^6.0.8" + } + }, + "@textlint/textlint-plugin-text": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-text/-/textlint-plugin-text-3.0.10.tgz", + "integrity": "sha512-GSw9vsuKt7E85jDSFEXT0VYZo4C3e8XFFrSWYqXlwPKl/oQ/WHQfMg7GM288uGoEaMzbKEfBtpdwdZqTjGHOQA==", + "requires": { + "@textlint/text-to-ast": "^3.0.8" + } + }, + "@types/bluebird": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.24.tgz", + "integrity": "sha512-YeQoDpq4Lm8ppSBqAnAeF/xy1cYp/dMTif2JFcvmAbETMRlvKHT2iLcWu+WyYiJO3b3Ivokwo7EQca/xfLVJmg==" + }, + "adverb-where": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/adverb-where/-/adverb-where-0.0.9.tgz", + "integrity": "sha1-CcXN3Y1QO5/l924LjcXHCo8ZPjQ=" + }, + "aggregate-error": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", + "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", + "requires": { + "clean-stack": "^1.0.0", + "indent-string": "^3.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "bail": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.3.tgz", + "integrity": "sha512-1X8CnjFVQ+a+KW36uBNMTU5s8+v5FzeqrP7hTG5aTb4aPreSbZJlhwPon9VKMuEVgV++JM+SQrALY3kr7eswdg==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", + "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==" + }, + "bluebird": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", + "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==" + }, + "boundary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-1.0.1.tgz", + "integrity": "sha1-TWfcJgLAzBbdm85+v4fpSCkPWBI=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + } + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "ccount": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.3.tgz", + "integrity": "sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw==" + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "character-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.2.tgz", + "integrity": "sha512-sMoHX6/nBiy3KKfC78dnEalnpn0Az0oSNvqUWYTtYrhRI5iUIYsROU48G+E+kMFQzqXaJ8kHJZ85n7y6/PHgwQ==" + }, + "character-entities-html4": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.2.tgz", + "integrity": "sha512-sIrXwyna2+5b0eB9W149izTPJk/KkJTg6mEzDGibwBUkyH1SbDa+nf515Ppdi3MaH35lW0JFJDWeq9Luzes1Iw==" + }, + "character-entities-legacy": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.2.tgz", + "integrity": "sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA==" + }, + "character-reference-invalid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz", + "integrity": "sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==" + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collapse-white-space": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz", + "integrity": "sha512-YfQ1tAUZm561vpYD+5eyWN8+UsceQbSrqqlc/6zDY2gtAE+uZLSdkkovhnGpmCThsvKBFakq4EdY/FF93E8XIw==" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz", + "integrity": "sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-socket": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-1.6.3.tgz", + "integrity": "sha512-/mUy3VGqIP69dAZjh2xxHXcpK9wk2Len1Dxz8mWAdrIgFC8tnR/aQAyU4a+UTXzOcTvEvGBdp1zFiwnpWKaXng==", + "requires": { + "dns-packet": "^1.1.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "e-prime": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/e-prime/-/e-prime-0.10.2.tgz", + "integrity": "sha1-6pN165hWNt6IATx6n7EprZ4V7/g=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "requires": { + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "^2.1.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "fault": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.2.tgz", + "integrity": "sha512-o2eo/X2syzzERAtN5LcGbiVQ0WwZSlN3qLtadwAz3X8Bu+XWD16dja/KMsjZLiQr+BLGPDnHGkc4yUJf1Xpkpw==", + "requires": { + "format": "^0.2.2" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "^0.3.1", + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "write": "^0.2.1" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "~1.0.0" + } + } + } + }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=" + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "^2.0.0" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "got": { + "version": "6.7.1", + "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "interop-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/interop-require/-/interop-require-1.0.0.tgz", + "integrity": "sha1-5TEDZ5lEyI1+YQW2Kp9EdceDlx4=" + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-alphabetical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.2.tgz", + "integrity": "sha512-V0xN4BYezDHcBSKb1QHUFMlR4as/XEuCZBzMJUU4n7+Cbt33SmUnSol+pnXFvLxSHNq2CemUXNdaXV6Flg7+xg==" + }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=" + }, + "is-alphanumerical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz", + "integrity": "sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg==", + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-decimal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.2.tgz", + "integrity": "sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-empty": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-empty/-/is-empty-1.2.0.tgz", + "integrity": "sha1-3pu1snhzigWgsJpX4ftNSjQan2s=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-file/-/is-file-1.0.0.tgz", + "integrity": "sha1-KKRM+9nT2xkwRfIrZfzo7fliBZY=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-hexadecimal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz", + "integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==" + }, + "is-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-hidden/-/is-hidden-1.1.1.tgz", + "integrity": "sha512-175UKecS8+U4hh2PSY0j4xnm2GKYzvSKnbh+naC93JjuBA7LgIo6YxlbcsSo6seFBdQO3RuIcH980yvqqD/2cA==" + }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "requires": { + "ip-regex": "^2.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "is-online": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-online/-/is-online-7.0.0.tgz", + "integrity": "sha1-fiQIwK4efje6jVC9sjcmDTK/2W4=", + "requires": { + "got": "^6.7.1", + "p-any": "^1.0.0", + "p-timeout": "^1.0.0", + "public-ip": "^2.3.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, + "is-relative-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-relative-url/-/is-relative-url-2.0.0.tgz", + "integrity": "sha1-cpAtf+BLPUeS59sV+duEtyBMnO8=", + "requires": { + "is-absolute-url": "^2.0.0" + } + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-whitespace-character": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz", + "integrity": "sha512-SzM+T5GKUCtLhlHFKt2SDAX2RFzfS6joT91F2/WSi9LxgFdsnhfPK/UIA+JhRR2xuyLdrCys2PiFDrtn1fU5hQ==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-word-character": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.2.tgz", + "integrity": "sha512-T3FlsX8rCHAH8e7RE7PfOPZVFQlcV3XRF9eOOBQ1uf70OxO7CjjSOjeImMPCADBdYWcStAbVbYvJ1m2D3tb+EA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isemail": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz", + "integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==", + "requires": { + "punycode": "2.x.x" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "link-check": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/link-check/-/link-check-4.4.4.tgz", + "integrity": "sha512-yvowNBZEMOFH9nGLiJ5/YV68PBMVTo4opC2SzcACO8g4gSPTB9Rwa5GIziOX9Z5Er3Yf01DHoOyVV2LeApIw8w==", + "requires": { + "is-relative-url": "^2.0.0", + "isemail": "^3.1.2", + "ms": "^2.1.1", + "request": "^2.87.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "load-plugin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/load-plugin/-/load-plugin-2.2.2.tgz", + "integrity": "sha512-FYzamtURIJefQykZGtiClYuZkJBUKzmx8Tc74y8JGAulDzbzVm/C+w/MbAljHRr+REL0cRzy3WgnHE+T8gce5g==", + "requires": { + "npm-prefix": "^1.2.0", + "resolve-from": "^4.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "requires": { + "chalk": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "longest-streak": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.2.tgz", + "integrity": "sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA==" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-like": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-like/-/map-like-2.0.0.tgz", + "integrity": "sha1-lEltSa0zPA3DI0snrbvR6FNZU7Q=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-escapes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.2.tgz", + "integrity": "sha512-lbRZ2mE3Q9RtLjxZBZ9+IMl68DKIXaVAhwvwn9pmjnPLS0h/6kyBMgNhqi1xFJ/2yv6cSyv0jbiZavZv93JkkA==" + }, + "markdown-extensions": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz", + "integrity": "sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==" + }, + "markdown-table": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.2.tgz", + "integrity": "sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw==" + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=" + }, + "md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "requires": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, + "mdast-util-compact": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.2.tgz", + "integrity": "sha512-d2WS98JSDVbpSsBfVvD9TaDMlqPRz7ohM/11G0rp5jOBb5q96RJ6YLszQ/09AAixyzh23FeIpCGqfaamEADtWg==", + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz", + "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "nlcst-to-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-2.0.2.tgz", + "integrity": "sha512-DV7wVvMcAsmZ5qEwvX1JUNF4lKkAAKbChwNlIH7NLsPR7LWWoeIt53YlZ5CQH5KDXEXQ9Xa3mw0PbPewymrtew==" + }, + "no-cliches": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/no-cliches/-/no-cliches-0.1.0.tgz", + "integrity": "sha1-9OuBpVH+zegT+MYR415kpRGNw4w=" + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + }, + "dependencies": { + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + } + } + }, + "npm-prefix": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/npm-prefix/-/npm-prefix-1.2.0.tgz", + "integrity": "sha1-5hlFX3B0ulTMZtbQ033Z8b5ry8A=", + "requires": { + "rc": "^1.1.0", + "shellsubstitute": "^1.1.0", + "untildify": "^2.1.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "p-any": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", + "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "requires": { + "p-some": "^2.0.0" + } + }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-some": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", + "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", + "requires": { + "aggregate-error": "^1.0.0" + } + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.1.2.tgz", + "integrity": "sha512-5N9lmQ7tmxfXf+hO3X6KRG6w7uYO/HL9fHalSySTdyn63C3WNvTM/1R8tn1u1larNcEbo3Slcy2bsVDQqvEpUg==", + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "passive-voice": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/passive-voice/-/passive-voice-0.1.0.tgz", + "integrity": "sha1-Fv+RrkC6DpLEPmcXY/3IQqcCcLE=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-to-glob-pattern": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-to-glob-pattern/-/path-to-glob-pattern-1.0.2.tgz", + "integrity": "sha1-Rz5qOikqnRP7rj7czuctO6uoxhk=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha1-crcmqm+sHt7uQiVsfY3CVrM1Z38=" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "prettier": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz", + "integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + }, + "public-ip": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/public-ip/-/public-ip-2.4.0.tgz", + "integrity": "sha512-74cIy+T2cDmt+Z71AfVipH2q6qqZITPyNGszKV86OGDYIRvti1m8zg4GOaiTPCLgEIWnToKYXbhEnMiZWHPEUA==", + "requires": { + "dns-socket": "^1.6.2", + "got": "^8.0.0", + "is-ip": "^2.0.0", + "pify": "^3.0.0" + }, + "dependencies": { + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "requires": { + "p-finally": "^1.0.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "randomatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", + "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "rc-config-loader": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-2.0.2.tgz", + "integrity": "sha512-Nx9SNM47eNRqe0TdntOY600qWb8NDh+xU9sv5WnTscEtzfTB0ukihlqwuCLPteyJksvZ0sEVPoySNE01TKrmTQ==", + "requires": { + "debug": "^3.1.0", + "js-yaml": "^3.12.0", + "json5": "^1.0.1", + "object-assign": "^4.1.0", + "object-keys": "^1.0.12", + "path-exists": "^3.0.0", + "require-from-string": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remark": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz", + "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", + "requires": { + "remark-parse": "^5.0.0", + "remark-stringify": "^5.0.0", + "unified": "^6.0.0" + } + }, + "remark-cli": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-cli/-/remark-cli-5.0.0.tgz", + "integrity": "sha512-+j0tza5XZ/XHfity3mg5GJFezRt5hS+ybC7/LDItmOAA8u8gRgB51B+/m5U3yT6RLlhefdqkMGKZnZMcamnvsQ==", + "requires": { + "markdown-extensions": "^1.1.0", + "remark": "^9.0.0", + "unified-args": "^5.0.0" + } + }, + "remark-frontmatter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.2.1.tgz", + "integrity": "sha512-PEXZFO3jrB+E0G6ZIsV8GOED1gPHQF5hgedJQJ8SbsLRQv4KKrFj3A+huaeu0qtzTScdxPeDTacQ9gkV4vIarA==", + "requires": { + "fault": "^1.0.1", + "xtend": "^4.0.1" + } + }, + "remark-lint-no-dead-urls": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/remark-lint-no-dead-urls/-/remark-lint-no-dead-urls-0.3.0.tgz", + "integrity": "sha512-eG+vVrNui7zeBmU6fsjIi8rwXriuyNhNcmJDQ7M5oaxCluWbH5bt6Yi/JNsabYE39dFdlVbw9JM3cLjaJv2hQw==", + "requires": { + "is-online": "^7.0.0", + "is-relative-url": "^2.0.0", + "link-check": "^4.1.0", + "unified-lint-rule": "^1.0.1", + "unist-util-visit": "^1.1.3" + } + }, + "remark-lint-write-good": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-lint-write-good/-/remark-lint-write-good-1.0.3.tgz", + "integrity": "sha512-d4D4VrAklAx2ONhpXoQnt0YrJFpJBE5XEeCyDGjPhm4DkIoLOmHWZEjxl1HvdrpGXLb/KfYU4lJPeyxlKiDhVA==", + "requires": { + "nlcst-to-string": "^2.0.0", + "unified-lint-rule": "^1.0.1", + "unist-util-visit": "^1.1.1", + "write-good": "^0.11.1" + } + }, + "remark-parse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", + "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-stringify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-5.0.0.tgz", + "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^1.0.1", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shellsubstitute": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shellsubstitute/-/shellsubstitute-1.2.0.tgz", + "integrity": "sha1-5PcCpQxRiw9v6YRRiQ1wWvKba3A=" + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=" + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", + "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==" + }, + "split-lines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/split-lines/-/split-lines-2.0.0.tgz", + "integrity": "sha512-gaIdhbqxkB5/VflPXsJwZvEzh/kdwiRPF9iqpkxX4us+lzB8INedFwjCyo6vwuz5x2Ddlnav2zh270CEjCG8mA==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "state-toggle": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.1.tgz", + "integrity": "sha512-Qe8QntFrrpWTnHwvwj2FZTgv+PKIsp0B9VxLzLLbSpPXWOgRgc5LVj/aTiSfK1RqIeF9jeC1UeOH8Q8y60A7og==" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string.prototype.padstart": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.0.0.tgz", + "integrity": "sha1-W8+tOfRkm7LQMSkuGbzwtRDUskI=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-entities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", + "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "structured-source": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-3.0.2.tgz", + "integrity": "sha1-3YAkJeD1PcSm56yjdSkBoczaevU=", + "requires": { + "boundary": "^1.0.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "3.8.3", + "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "textlint": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/textlint/-/textlint-10.2.1.tgz", + "integrity": "sha512-tjSvxRZ7iewPmw0ShIA5IIZNJM9m157K1hGXE9wGxALcSb+xOZ0oLPv1HN7z0UzqOuMNqYyeN7mi4N0IplLkYA==", + "requires": { + "@textlint/ast-node-types": "^4.0.2", + "@textlint/ast-traverse": "^2.0.8", + "@textlint/feature-flag": "^3.0.4", + "@textlint/fixer-formatter": "^3.0.7", + "@textlint/kernel": "^2.0.9", + "@textlint/linter-formatter": "^3.0.7", + "@textlint/textlint-plugin-markdown": "^4.0.10", + "@textlint/textlint-plugin-text": "^3.0.10", + "@types/bluebird": "^3.5.18", + "bluebird": "^3.0.5", + "debug": "^2.1.0", + "deep-equal": "^1.0.1", + "file-entry-cache": "^2.0.0", + "get-stdin": "^5.0.1", + "glob": "^7.1.1", + "interop-require": "^1.0.0", + "is-file": "^1.0.0", + "log-symbols": "^1.0.2", + "map-like": "^2.0.0", + "md5": "^2.2.1", + "mkdirp": "^0.5.0", + "object-assign": "^4.0.1", + "optionator": "^0.8.0", + "path-to-glob-pattern": "^1.0.2", + "rc-config-loader": "^2.0.1", + "read-pkg": "^1.1.0", + "read-pkg-up": "^3.0.0", + "structured-source": "^3.0.2", + "try-resolve": "^1.0.1", + "unique-concat": "^0.2.2" + } + }, + "textlint-rule-helper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/textlint-rule-helper/-/textlint-rule-helper-2.0.0.tgz", + "integrity": "sha1-lctGlslcQljS4zienmS4SflyE4I=", + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "textlint-rule-stop-words": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/textlint-rule-stop-words/-/textlint-rule-stop-words-1.0.5.tgz", + "integrity": "sha512-sttfqpFX3ji4AD4eF3gpiCH+csqsaztO0V2koWVYhrHyPjUL4cPlB1I/H4Fa7G3Ik35dBA0q5Tf+88A0vO9erQ==", + "requires": { + "lodash": "^4.17.10", + "split-lines": "^2.0.0", + "textlint-rule-helper": "^2.0.0" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "to-vfile": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-2.2.0.tgz", + "integrity": "sha512-saGC8/lWdGrEoBMLUtgzhRHWAkQMP8gdldA3MOAUhBwTGEb1RSMVcflHGSx4ZJsdEZ9o1qDBCPp47LCPrbZWow==", + "requires": { + "is-buffer": "^1.1.4", + "vfile": "^2.0.0", + "x-is-function": "^1.0.4" + } + }, + "too-wordy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/too-wordy/-/too-wordy-0.1.4.tgz", + "integrity": "sha1-jnsgp7ek2Pw3WfTgDEkpmT0bEvA=" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" + }, + "trim-trailing-lines": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz", + "integrity": "sha512-bWLv9BbWbbd7mlqqs2oQYnLD/U/ZqeJeJwbO0FG2zA1aTq+HTvxfHNKFa/HGCVyJpDiioUYaBhfiT6rgk+l4mg==" + }, + "trough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.3.tgz", + "integrity": "sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw==" + }, + "try-resolve": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz", + "integrity": "sha1-z95vq9ctY+V5fPqrhzq76OcA6RI=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "unherit": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.1.tgz", + "integrity": "sha512-+XZuV691Cn4zHsK0vkKYwBEwB74T3IZIcxrgn2E4rKwTfFyI1zCh7X7grwh9Re08fdPlarIdyWgI8aVB3F5A5g==", + "requires": { + "inherits": "^2.0.1", + "xtend": "^4.0.1" + } + }, + "unified": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", + "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^1.1.0", + "trough": "^1.0.0", + "vfile": "^2.0.0", + "x-is-string": "^0.1.0" + } + }, + "unified-args": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unified-args/-/unified-args-5.1.0.tgz", + "integrity": "sha512-IR8bS/qrfOMuIYrLlaXt+3L6cvDHv5YbBfYNVGBLbShUjE9vpbnUiPFMc/XKtH6oAGrD/m8lvVwCHDsFGBBzJA==", + "requires": { + "camelcase": "^4.0.0", + "chalk": "^2.0.0", + "chokidar": "^1.5.1", + "json5": "^0.5.1", + "minimist": "^1.2.0", + "text-table": "^0.2.0", + "unified-engine": "^5.1.0" + } + }, + "unified-engine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unified-engine/-/unified-engine-5.1.0.tgz", + "integrity": "sha512-N7b7HG6doQUtkWr+kH35tfUhfc9QiYeiZGG6TcZlexSURf4xRUpYKBbc2f67qJF5oPmn6mMkImkdhr31Q6saoA==", + "requires": { + "concat-stream": "^1.5.1", + "debug": "^3.1.0", + "fault": "^1.0.0", + "fn-name": "^2.0.1", + "glob": "^7.0.3", + "ignore": "^3.2.0", + "is-empty": "^1.0.0", + "is-hidden": "^1.0.1", + "is-object": "^1.0.1", + "js-yaml": "^3.6.1", + "load-plugin": "^2.0.0", + "parse-json": "^4.0.0", + "to-vfile": "^2.0.0", + "trough": "^1.0.0", + "unist-util-inspect": "^4.1.2", + "vfile-reporter": "^4.0.0", + "vfile-statistics": "^1.1.0", + "x-is-function": "^1.0.4", + "x-is-string": "^0.1.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "unified-lint-rule": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/unified-lint-rule/-/unified-lint-rule-1.0.3.tgz", + "integrity": "sha512-6z+HH3mtlFdj/w3MaQpObrZAd9KRiro370GxBFh13qkV8LYR21lLozA4iQiZPhe7KuX/lHewoGOEgQ4AWrAR3Q==", + "requires": { + "wrapped": "^1.0.1" + } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unique-concat": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/unique-concat/-/unique-concat-0.2.2.tgz", + "integrity": "sha1-khD5vcqsxeHjkpSQ18AZ35bxhxI=" + }, + "unist-util-inspect": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/unist-util-inspect/-/unist-util-inspect-4.1.3.tgz", + "integrity": "sha512-Fv9R88ZBbDp7mHN+wsbxS1r8VW3unyhZh/F18dcJRQsg0+g3DxNQnMS+AEG/uotB8Md+HMK/TfzSU5lUDWxkZg==", + "requires": { + "is-empty": "^1.0.0" + } + }, + "unist-util-is": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.2.tgz", + "integrity": "sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw==" + }, + "unist-util-remove-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.2.tgz", + "integrity": "sha512-XxoNOBvq1WXRKXxgnSYbtCF76TJrRoe5++pD4cCBsssSiWSnPEktyFrFLE8LTk3JW5mt9hB0Sk5zn4x/JeWY7Q==", + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==" + }, + "unist-util-visit": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.0.tgz", + "integrity": "sha512-FiGu34ziNsZA3ZUteZxSFaczIjGmksfSgdKqBfOejrrfzyUy5b7YrlzT1Bcvi+djkYDituJDy2XB7tGTeBieKw==", + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.0.1.tgz", + "integrity": "sha512-6B0UTiMfdWql4cQ03gDTCSns+64Zkfo2OCbK31Ov0uMizEz+CJeAp0cgZVb5Fhmcd7Bct2iRNywejT0orpbqUA==", + "requires": { + "unist-util-is": "^2.1.2" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "untildify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", + "integrity": "sha1-F+soB5h/dpUunASF/DEdBqgmouA=", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vfile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", + "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", + "requires": { + "is-buffer": "^1.1.4", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^1.0.0", + "vfile-message": "^1.0.0" + } + }, + "vfile-location": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.3.tgz", + "integrity": "sha512-zM5/l4lfw1CBoPx3Jimxoc5RNDAHHpk6AM6LM0pTIkm5SUSsx8ZekZ0PVdf0WEZ7kjlhSt7ZlqbRL6Cd6dBs6A==" + }, + "vfile-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.0.1.tgz", + "integrity": "sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug==", + "requires": { + "unist-util-stringify-position": "^1.1.1" + } + }, + "vfile-reporter": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-4.0.0.tgz", + "integrity": "sha1-6m8K4TQvSEFXOYXgX5QXNvJ96do=", + "requires": { + "repeat-string": "^1.5.0", + "string-width": "^1.0.0", + "supports-color": "^4.1.0", + "unist-util-stringify-position": "^1.0.0", + "vfile-statistics": "^1.1.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "vfile-statistics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-1.1.1.tgz", + "integrity": "sha512-dxUM6IYvGChHuwMT3dseyU5BHprNRXzAV0OHx1A769lVGsTiT50kU7BbpRFV+IE6oWmU+PwHdsTKfXhnDIRIgQ==" + }, + "weasel-words": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/weasel-words/-/weasel-words-0.1.1.tgz", + "integrity": "sha1-cTeUZYXHP+RIggE4U70ADF1oek4=" + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "wrapped": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wrapped/-/wrapped-1.0.1.tgz", + "integrity": "sha1-x4PZ2Aeyc+mwHoUWgKk4yHyQckI=", + "requires": { + "co": "3.1.0", + "sliced": "^1.0.1" + }, + "dependencies": { + "co": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", + "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-good": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/write-good/-/write-good-0.11.3.tgz", + "integrity": "sha512-fDKIHO5wCzTLCOGNJl1rzzJrZlTIzfZl8msOoJQZzRhYo0X/tFTm4+2B1zTibFYK01Nnd1kLZBjj4xjcFLePNQ==", + "requires": { + "adverb-where": "0.0.9", + "e-prime": "^0.10.2", + "no-cliches": "^0.1.0", + "object.assign": "^4.0.4", + "passive-voice": "^0.1.0", + "too-wordy": "^0.1.4", + "weasel-words": "^0.1.1" + } + }, + "x-is-function": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/x-is-function/-/x-is-function-1.0.4.tgz", + "integrity": "sha1-XSlNw9Joy90GJYDgxd93o5HR+h4=" + }, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=" + }, + "xml-escape": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.1.0.tgz", + "integrity": "sha1-OQTBQ/qOs6ADDsZG0pAqLxtwbEQ=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } +} diff --git a/docs/spec/README.md b/docs/spec/README.md index 08eef489e..3e2c2bcd4 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -1,4 +1,4 @@ -# Tendermint Specification +# Overview This is a markdown specification of the Tendermint blockchain. It defines the base data structures, how they are validated, diff --git a/docs/spec/blockchain/blockchain.md b/docs/spec/blockchain/blockchain.md index 795a22926..bd4d8ddd2 100644 --- a/docs/spec/blockchain/blockchain.md +++ b/docs/spec/blockchain/blockchain.md @@ -1,4 +1,4 @@ -# Tendermint Blockchain +# Blockchain Here we describe the data structures in the Tendermint blockchain and the rules for validating them. diff --git a/docs/spec/blockchain/encoding.md b/docs/spec/blockchain/encoding.md index 38e27e7e0..4ad30df6b 100644 --- a/docs/spec/blockchain/encoding.md +++ b/docs/spec/blockchain/encoding.md @@ -1,4 +1,4 @@ -# Tendermint Encoding +# Encoding ## Amino diff --git a/docs/spec/blockchain/state.md b/docs/spec/blockchain/state.md index e9da53b50..349fd4223 100644 --- a/docs/spec/blockchain/state.md +++ b/docs/spec/blockchain/state.md @@ -1,4 +1,4 @@ -# Tendermint State +# State ## State diff --git a/docs/spec/consensus/bft-time.md b/docs/spec/consensus/bft-time.md index 06e66dbfc..8e02f6abe 100644 --- a/docs/spec/consensus/bft-time.md +++ b/docs/spec/consensus/bft-time.md @@ -1,4 +1,4 @@ -# BFT time in Tendermint +# BFT Time Tendermint provides a deterministic, Byzantine fault-tolerant, source of time. Time in Tendermint is defined with the Time field of the block header. diff --git a/docs/spec/consensus/light-client.md b/docs/spec/consensus/light-client.md index 1b608627c..4b683b9a6 100644 --- a/docs/spec/consensus/light-client.md +++ b/docs/spec/consensus/light-client.md @@ -1,4 +1,4 @@ -# Light client +# Light Client A light client is a process that connects to the Tendermint Full Node(s) and then tries to verify the Merkle proofs about the blockchain application. In this document we describe mechanisms that ensures that the Tendermint light client diff --git a/docs/spec/p2p/node.md b/docs/spec/p2p/node.md index 2771356af..6d37eeb78 100644 --- a/docs/spec/p2p/node.md +++ b/docs/spec/p2p/node.md @@ -1,4 +1,4 @@ -# Tendermint Peer Discovery +# Peer Discovery A Tendermint P2P network has different kinds of nodes with different requirements for connectivity to one another. This document describes what kind of nodes Tendermint should enable and how they should work. diff --git a/docs/spec/p2p/peer.md b/docs/spec/p2p/peer.md index 8f8f12b13..a1ff25d8b 100644 --- a/docs/spec/p2p/peer.md +++ b/docs/spec/p2p/peer.md @@ -1,4 +1,4 @@ -# Tendermint Peers +# Peers This document explains how Tendermint Peers are identified and how they connect to one another. From f11db8c1b02bdbdd738d18e7c56f818e48db8c91 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 21 Sep 2018 17:12:29 +0100 Subject: [PATCH 40/47] Pass http.ServeTLS() errors back to the caller (#2461) Closes: #2460 * Pass http.ServeTLS() errors back to the caller * Update CHANGELOG * Amend StartHTTPServer() too for consistency's sake * Revert "Amend StartHTTPServer() too for consistency's sake" This reverts commit 23bfb4c2e917f581702291fe3ea69fce23f8c89d. --- CHANGELOG_PENDING.md | 1 + rpc/lib/server/http_server.go | 17 +++++++++-------- rpc/lib/server/http_server_test.go | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 35a395d5f..d471b2fde 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -33,3 +33,4 @@ IMPROVEMENTS: BUG FIXES: - [node] \#2294 Delay starting node until Genesis time +- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. diff --git a/rpc/lib/server/http_server.go b/rpc/lib/server/http_server.go index ff7173a10..8069a81d4 100644 --- a/rpc/lib/server/http_server.go +++ b/rpc/lib/server/http_server.go @@ -102,15 +102,16 @@ func StartHTTPAndTLSServer( listener = netutil.LimitListener(listener, config.MaxOpenConnections) } - go func() { - err := http.ServeTLS( - listener, - RecoverAndLogHandler(maxBytesHandler{h: handler, n: maxBodyBytes}, logger), - certFile, - keyFile, - ) + err = http.ServeTLS( + listener, + RecoverAndLogHandler(maxBytesHandler{h: handler, n: maxBodyBytes}, logger), + certFile, + keyFile, + ) + if err != nil { logger.Error("RPC HTTPS server stopped", "err", err) - }() + return nil, err + } return listener, nil } diff --git a/rpc/lib/server/http_server_test.go b/rpc/lib/server/http_server_test.go index 3cbe0d906..73ebc2e7e 100644 --- a/rpc/lib/server/http_server_test.go +++ b/rpc/lib/server/http_server_test.go @@ -5,11 +5,14 @@ import ( "io" "io/ioutil" "net/http" + "os" "sync" "sync/atomic" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" ) @@ -60,3 +63,15 @@ func TestMaxOpenConnections(t *testing.T) { t.Errorf("%d requests failed within %d attempts", failed, attempts) } } + +func TestStartHTTPAndTLSServer(t *testing.T) { + // set up fixtures + listenerAddr := "tcp://0.0.0.0:0" + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {}) + + // test failure + gotListener, err := StartHTTPAndTLSServer(listenerAddr, mux, "", "", log.TestingLogger(), Config{MaxOpenConnections: 1}) + require.Nil(t, gotListener) + require.IsType(t, (*os.PathError)(nil), err) +} From f99e4010f2bfdd7d0624e0d9be8428a9b435235e Mon Sep 17 00:00:00 2001 From: Zarko Milosevic Date: Fri, 21 Sep 2018 20:36:48 +0200 Subject: [PATCH 41/47] Add stats related channel between consensus state and reactor (#2388) --- CHANGELOG_PENDING.md | 3 +- cmd/tendermint/commands/init.go | 4 +- cmd/tendermint/commands/testnet.go | 6 +- consensus/metrics.go | 1 - consensus/reactor.go | 86 +++++++++++-------- consensus/reactor_test.go | 127 +++++------------------------ consensus/state.go | 35 +++++--- consensus/state_test.go | 78 ++++++++++++++++++ 8 files changed, 182 insertions(+), 158 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index d471b2fde..52d90ec77 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -33,4 +33,5 @@ IMPROVEMENTS: BUG FIXES: - [node] \#2294 Delay starting node until Genesis time -- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. +- [consensus] \#2048 Correct peer statistics for marking peer as good +- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. \ No newline at end of file diff --git a/cmd/tendermint/commands/init.go b/cmd/tendermint/commands/init.go index 5136ded3c..85ee44916 100644 --- a/cmd/tendermint/commands/init.go +++ b/cmd/tendermint/commands/init.go @@ -59,8 +59,8 @@ func initFilesWithConfig(config *cfg.Config) error { } genDoc.Validators = []types.GenesisValidator{{ Address: pv.GetPubKey().Address(), - PubKey: pv.GetPubKey(), - Power: 10, + PubKey: pv.GetPubKey(), + Power: 10, }} if err := genDoc.SaveAs(genFile); err != nil { diff --git a/cmd/tendermint/commands/testnet.go b/cmd/tendermint/commands/testnet.go index 19f137e4e..0f7dd79a4 100644 --- a/cmd/tendermint/commands/testnet.go +++ b/cmd/tendermint/commands/testnet.go @@ -92,9 +92,9 @@ func testnetFiles(cmd *cobra.Command, args []string) error { pv := privval.LoadFilePV(pvFile) genVals[i] = types.GenesisValidator{ Address: pv.GetPubKey().Address(), - PubKey: pv.GetPubKey(), - Power: 1, - Name: nodeDirName, + PubKey: pv.GetPubKey(), + Power: 1, + Name: nodeDirName, } } diff --git a/consensus/metrics.go b/consensus/metrics.go index 91ae738d5..68d065ec6 100644 --- a/consensus/metrics.go +++ b/consensus/metrics.go @@ -85,7 +85,6 @@ func PrometheusMetrics() *Metrics { Help: "Total power of the byzantine validators.", }, []string{}), - BlockIntervalSeconds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ Subsystem: "consensus", Name: "block_interval_seconds", diff --git a/consensus/reactor.go b/consensus/reactor.go index 6ba817264..4a915ace1 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -29,6 +29,7 @@ const ( maxMsgSize = 1048576 // 1MB; NOTE/TODO: keep in sync with types.PartSet sizes. blocksToContributeToBecomeGoodPeer = 10000 + votesToContributeToBecomeGoodPeer = 10000 ) //----------------------------------------------------------------------------- @@ -60,6 +61,9 @@ func NewConsensusReactor(consensusState *ConsensusState, fastSync bool) *Consens func (conR *ConsensusReactor) OnStart() error { conR.Logger.Info("ConsensusReactor ", "fastSync", conR.FastSync()) + // start routine that computes peer statistics for evaluating peer quality + go conR.peerStatsRoutine() + conR.subscribeToBroadcastEvents() if !conR.FastSync() { @@ -258,9 +262,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) ps.ApplyProposalPOLMessage(msg) case *BlockPartMessage: ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Index) - if numBlocks := ps.RecordBlockPart(msg); numBlocks%blocksToContributeToBecomeGoodPeer == 0 { - conR.Switch.MarkPeerAsGood(src) - } + conR.conS.peerMsgQueue <- msgInfo{msg, src.ID()} default: conR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) @@ -280,9 +282,6 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) ps.EnsureVoteBitArrays(height, valSize) ps.EnsureVoteBitArrays(height-1, lastCommitSize) ps.SetHasVote(msg.Vote) - if blocks := ps.RecordVote(msg.Vote); blocks%blocksToContributeToBecomeGoodPeer == 0 { - conR.Switch.MarkPeerAsGood(src) - } cs.peerMsgQueue <- msgInfo{msg, src.ID()} @@ -794,6 +793,43 @@ OUTER_LOOP: } } +func (conR *ConsensusReactor) peerStatsRoutine() { + for { + if !conR.IsRunning() { + conR.Logger.Info("Stopping peerStatsRoutine") + return + } + + select { + case msg := <-conR.conS.statsMsgQueue: + // Get peer + peer := conR.Switch.Peers().Get(msg.PeerID) + if peer == nil { + conR.Logger.Debug("Attempt to update stats for non-existent peer", + "peer", msg.PeerID) + continue + } + // Get peer state + ps := peer.Get(types.PeerStateKey).(*PeerState) + switch msg.Msg.(type) { + case *VoteMessage: + if numVotes := ps.RecordVote(); numVotes%votesToContributeToBecomeGoodPeer == 0 { + conR.Switch.MarkPeerAsGood(peer) + } + case *BlockPartMessage: + if numParts := ps.RecordBlockPart(); numParts%blocksToContributeToBecomeGoodPeer == 0 { + conR.Switch.MarkPeerAsGood(peer) + } + } + case <-conR.conS.Quit(): + return + + case <-conR.Quit(): + return + } + } +} + // String returns a string representation of the ConsensusReactor. // NOTE: For now, it is just a hard-coded string to avoid accessing unprotected shared variables. // TODO: improve! @@ -836,15 +872,13 @@ type PeerState struct { // peerStateStats holds internal statistics for a peer. type peerStateStats struct { - LastVoteHeight int64 `json:"last_vote_height"` - Votes int `json:"votes"` - LastBlockPartHeight int64 `json:"last_block_part_height"` - BlockParts int `json:"block_parts"` + Votes int `json:"votes"` + BlockParts int `json:"block_parts"` } func (pss peerStateStats) String() string { - return fmt.Sprintf("peerStateStats{lvh: %d, votes: %d, lbph: %d, blockParts: %d}", - pss.LastVoteHeight, pss.Votes, pss.LastBlockPartHeight, pss.BlockParts) + return fmt.Sprintf("peerStateStats{votes: %d, blockParts: %d}", + pss.Votes, pss.BlockParts) } // NewPeerState returns a new PeerState for the given Peer @@ -1080,18 +1114,14 @@ func (ps *PeerState) ensureVoteBitArrays(height int64, numValidators int) { } } -// RecordVote updates internal statistics for this peer by recording the vote. -// It returns the total number of votes (1 per block). This essentially means -// the number of blocks for which peer has been sending us votes. -func (ps *PeerState) RecordVote(vote *types.Vote) int { +// RecordVote increments internal votes related statistics for this peer. +// It returns the total number of added votes. +func (ps *PeerState) RecordVote() int { ps.mtx.Lock() defer ps.mtx.Unlock() - if ps.Stats.LastVoteHeight >= vote.Height { - return ps.Stats.Votes - } - ps.Stats.LastVoteHeight = vote.Height ps.Stats.Votes++ + return ps.Stats.Votes } @@ -1104,25 +1134,17 @@ func (ps *PeerState) VotesSent() int { return ps.Stats.Votes } -// RecordBlockPart updates internal statistics for this peer by recording the -// block part. It returns the total number of block parts (1 per block). This -// essentially means the number of blocks for which peer has been sending us -// block parts. -func (ps *PeerState) RecordBlockPart(bp *BlockPartMessage) int { +// RecordBlockPart increments internal block part related statistics for this peer. +// It returns the total number of added block parts. +func (ps *PeerState) RecordBlockPart() int { ps.mtx.Lock() defer ps.mtx.Unlock() - if ps.Stats.LastBlockPartHeight >= bp.Height { - return ps.Stats.BlockParts - } - - ps.Stats.LastBlockPartHeight = bp.Height ps.Stats.BlockParts++ return ps.Stats.BlockParts } -// BlockPartsSent returns the number of blocks for which peer has been sending -// us block parts. +// BlockPartsSent returns the number of useful block parts the peer has sent us. func (ps *PeerState) BlockPartsSent() int { ps.mtx.Lock() defer ps.mtx.Unlock() diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 2c4c4452b..41bddbd68 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -11,20 +11,16 @@ import ( "testing" "time" - abcicli "github.com/tendermint/tendermint/abci/client" + "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/kvstore" abci "github.com/tendermint/tendermint/abci/types" bc "github.com/tendermint/tendermint/blockchain" - cmn "github.com/tendermint/tendermint/libs/common" + cfg "github.com/tendermint/tendermint/config" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" mempl "github.com/tendermint/tendermint/mempool" - sm "github.com/tendermint/tendermint/state" - tmtime "github.com/tendermint/tendermint/types/time" - - cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/p2p" - p2pdummy "github.com/tendermint/tendermint/p2p/dummy" + sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" "github.com/stretchr/testify/assert" @@ -246,110 +242,25 @@ func TestReactorProposalHeartbeats(t *testing.T) { }, css) } -// Test we record block parts from other peers -func TestReactorRecordsBlockParts(t *testing.T) { - // create dummy peer - peer := p2pdummy.NewPeer() - ps := NewPeerState(peer).SetLogger(log.TestingLogger()) - peer.Set(types.PeerStateKey, ps) - - // create reactor - css := randConsensusNet(1, "consensus_reactor_records_block_parts_test", newMockTickerFunc(true), newPersistentKVStore) - reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states - reactor.SetEventBus(css[0].eventBus) - reactor.SetLogger(log.TestingLogger()) - sw := p2p.MakeSwitch(cfg.DefaultP2PConfig(), 1, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw }) - reactor.SetSwitch(sw) - err := reactor.Start() - require.NoError(t, err) - defer reactor.Stop() - - // 1) new block part - parts := types.NewPartSetFromData(cmn.RandBytes(100), 10) - msg := &BlockPartMessage{ - Height: 2, - Round: 0, - Part: parts.GetPart(0), - } - bz, err := cdc.MarshalBinaryBare(msg) - require.NoError(t, err) - - reactor.Receive(DataChannel, peer, bz) - require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should have increased by 1") - - // 2) block part with the same height, but different round - msg.Round = 1 - - bz, err = cdc.MarshalBinaryBare(msg) - require.NoError(t, err) - - reactor.Receive(DataChannel, peer, bz) - require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same") - - // 3) block part from earlier height - msg.Height = 1 - msg.Round = 0 - - bz, err = cdc.MarshalBinaryBare(msg) - require.NoError(t, err) - - reactor.Receive(DataChannel, peer, bz) - require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same") -} - -// Test we record votes from other peers. -func TestReactorRecordsVotes(t *testing.T) { - // Create dummy peer. - peer := p2pdummy.NewPeer() - ps := NewPeerState(peer).SetLogger(log.TestingLogger()) - peer.Set(types.PeerStateKey, ps) - - // Create reactor. - css := randConsensusNet(1, "consensus_reactor_records_votes_test", newMockTickerFunc(true), newPersistentKVStore) - reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states - reactor.SetEventBus(css[0].eventBus) - reactor.SetLogger(log.TestingLogger()) - sw := p2p.MakeSwitch(cfg.DefaultP2PConfig(), 1, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw }) - reactor.SetSwitch(sw) - err := reactor.Start() - require.NoError(t, err) - defer reactor.Stop() - _, val := css[0].state.Validators.GetByIndex(0) - - // 1) new vote - vote := &types.Vote{ - ValidatorIndex: 0, - ValidatorAddress: val.Address, - Height: 2, - Round: 0, - Timestamp: tmtime.Now(), - Type: types.VoteTypePrevote, - BlockID: types.BlockID{}, - } - bz, err := cdc.MarshalBinaryBare(&VoteMessage{vote}) - require.NoError(t, err) - - reactor.Receive(VoteChannel, peer, bz) - assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should have increased by 1") - - // 2) vote with the same height, but different round - vote.Round = 1 - - bz, err = cdc.MarshalBinaryBare(&VoteMessage{vote}) - require.NoError(t, err) - - reactor.Receive(VoteChannel, peer, bz) - assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should stay the same") +// Test we record stats about votes and block parts from other peers. +func TestReactorRecordsVotesAndBlockParts(t *testing.T) { + N := 4 + css := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) + reactors, eventChans, eventBuses := startConsensusNet(t, css, N) + defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) - // 3) vote from earlier height - vote.Height = 1 - vote.Round = 0 + // wait till everyone makes the first new block + timeoutWaitGroup(t, N, func(j int) { + <-eventChans[j] + }, css) - bz, err = cdc.MarshalBinaryBare(&VoteMessage{vote}) - require.NoError(t, err) + // Get peer + peer := reactors[1].Switch.Peers().List()[0] + // Get peer state + ps := peer.Get(types.PeerStateKey).(*PeerState) - reactor.Receive(VoteChannel, peer, bz) - assert.Equal(t, 1, ps.VotesSent(), "number of votes sent should stay the same") + assert.Equal(t, true, ps.VotesSent() > 0, "number of votes sent should have increased") + assert.Equal(t, true, ps.BlockPartsSent() > 0, "number of votes sent should have increased") } //------------------------------------------------------------- diff --git a/consensus/state.go b/consensus/state.go index 3cc29b2b3..3ee1cfbf1 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -91,6 +91,10 @@ type ConsensusState struct { internalMsgQueue chan msgInfo timeoutTicker TimeoutTicker + // information about about added votes and block parts are written on this channel + // so statistics can be computed by reactor + statsMsgQueue chan msgInfo + // we use eventBus to trigger msg broadcasts in the reactor, // and to notify external subscribers, eg. through a websocket eventBus *types.EventBus @@ -141,6 +145,7 @@ func NewConsensusState( peerMsgQueue: make(chan msgInfo, msgQueueSize), internalMsgQueue: make(chan msgInfo, msgQueueSize), timeoutTicker: NewTimeoutTicker(), + statsMsgQueue: make(chan msgInfo, msgQueueSize), done: make(chan struct{}), doWALCatchup: true, wal: nilWAL{}, @@ -639,7 +644,11 @@ func (cs *ConsensusState) handleMsg(mi msgInfo) { err = cs.setProposal(msg.Proposal) case *BlockPartMessage: // if the proposal is complete, we'll enterPrevote or tryFinalizeCommit - _, err = cs.addProposalBlockPart(msg, peerID) + added, err := cs.addProposalBlockPart(msg, peerID) + if added { + cs.statsMsgQueue <- mi + } + if err != nil && msg.Round != cs.Round { cs.Logger.Debug("Received block part from wrong round", "height", cs.Height, "csRound", cs.Round, "blockRound", msg.Round) err = nil @@ -647,7 +656,11 @@ func (cs *ConsensusState) handleMsg(mi msgInfo) { case *VoteMessage: // attempt to add the vote and dupeout the validator if its a duplicate signature // if the vote gives us a 2/3-any or 2/3-one, we transition - err := cs.tryAddVote(msg.Vote, peerID) + added, err := cs.tryAddVote(msg.Vote, peerID) + if added { + cs.statsMsgQueue <- mi + } + if err == ErrAddingVote { // TODO: punish peer // We probably don't want to stop the peer here. The vote does not @@ -1454,7 +1467,7 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p int64(cs.state.ConsensusParams.BlockSize.MaxBytes), ) if err != nil { - return true, err + return added, err } // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) @@ -1484,35 +1497,35 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p // If we're waiting on the proposal block... cs.tryFinalizeCommit(height) } - return true, nil + return added, nil } return added, nil } // Attempt to add the vote. if its a duplicate signature, dupeout the validator -func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) error { - _, err := cs.addVote(vote, peerID) +func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) { + added, err := cs.addVote(vote, peerID) if err != nil { // If the vote height is off, we'll just ignore it, // But if it's a conflicting sig, add it to the cs.evpool. // If it's otherwise invalid, punish peer. if err == ErrVoteHeightMismatch { - return err + return added, err } else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok { if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) { cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type) - return err + return added, err } cs.evpool.AddEvidence(voteErr.DuplicateVoteEvidence) - return err + return added, err } else { // Probably an invalid signature / Bad peer. // Seems this can also err sometimes with "Unexpected step" - perhaps not from a bad peer ? cs.Logger.Error("Error attempting to add vote", "err", err) - return ErrAddingVote + return added, ErrAddingVote } } - return nil + return added, nil } //----------------------------------------------------------------------------- diff --git a/consensus/state_test.go b/consensus/state_test.go index 9c3631504..32fc5fd6a 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -7,9 +7,13 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + cstypes "github.com/tendermint/tendermint/consensus/types" + cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" + p2pdummy "github.com/tendermint/tendermint/p2p/dummy" "github.com/tendermint/tendermint/types" ) @@ -1081,6 +1085,80 @@ func TestStateHalt1(t *testing.T) { } } +func TestStateOutputsBlockPartsStats(t *testing.T) { + // create dummy peer + cs, _ := randConsensusState(1) + peer := p2pdummy.NewPeer() + + // 1) new block part + parts := types.NewPartSetFromData(cmn.RandBytes(100), 10) + msg := &BlockPartMessage{ + Height: 1, + Round: 0, + Part: parts.GetPart(0), + } + + cs.ProposalBlockParts = types.NewPartSetFromHeader(parts.Header()) + cs.handleMsg(msgInfo{msg, peer.ID()}) + + statsMessage := <-cs.statsMsgQueue + require.Equal(t, msg, statsMessage.Msg, "") + require.Equal(t, peer.ID(), statsMessage.PeerID, "") + + // sending the same part from different peer + cs.handleMsg(msgInfo{msg, "peer2"}) + + // sending the part with the same height, but different round + msg.Round = 1 + cs.handleMsg(msgInfo{msg, peer.ID()}) + + // sending the part from the smaller height + msg.Height = 0 + cs.handleMsg(msgInfo{msg, peer.ID()}) + + // sending the part from the bigger height + msg.Height = 3 + cs.handleMsg(msgInfo{msg, peer.ID()}) + + select { + case <-cs.statsMsgQueue: + t.Errorf("Should not output stats message after receiving the known block part!") + case <-time.After(50 * time.Millisecond): + } + +} + +func TestStateOutputVoteStats(t *testing.T) { + cs, vss := randConsensusState(2) + // create dummy peer + peer := p2pdummy.NewPeer() + + vote := signVote(vss[1], types.VoteTypePrecommit, []byte("test"), types.PartSetHeader{}) + + voteMessage := &VoteMessage{vote} + cs.handleMsg(msgInfo{voteMessage, peer.ID()}) + + statsMessage := <-cs.statsMsgQueue + require.Equal(t, voteMessage, statsMessage.Msg, "") + require.Equal(t, peer.ID(), statsMessage.PeerID, "") + + // sending the same part from different peer + cs.handleMsg(msgInfo{&VoteMessage{vote}, "peer2"}) + + // sending the vote for the bigger height + incrementHeight(vss[1]) + vote = signVote(vss[1], types.VoteTypePrecommit, []byte("test"), types.PartSetHeader{}) + + cs.handleMsg(msgInfo{&VoteMessage{vote}, peer.ID()}) + + select { + case <-cs.statsMsgQueue: + t.Errorf("Should not output stats message after receiving the known vote or vote from bigger height") + case <-time.After(50 * time.Millisecond): + } + +} + // subscribe subscribes test client to the given query and returns a channel with cap = 1. func subscribe(eventBus *types.EventBus, q tmpubsub.Query) <-chan interface{} { out := make(chan interface{}, 1) From 2dfde37f448486df142b07327672ba52f603b410 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 21 Sep 2018 16:45:00 -0400 Subject: [PATCH 42/47] update changelog and upgrading --- CHANGELOG_PENDING.md | 35 ++++++++++++++++++++++++----------- UPGRADING.md | 6 ++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 52d90ec77..803f91ca6 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,14 +1,25 @@ # Pending -Special thanks to external contributors with PRs included in this release: +Special thanks to external contributors on this release: +@scriptionist, @bradyjoestar, @WALL-E + +This release is mostly about the ConsensusParams - removing fields and enforcing MaxGas. +It also addresses some issues found via security audit, removes various unused +functions from `libs/common`, and implements +[ADR-012](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-012-peer-transport.md). + +Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint). BREAKING CHANGES: * CLI/RPC/Config * [rpc] [\#2391](https://github.com/tendermint/tendermint/issues/2391) /status `result.node_info.other` became a map + * [types] \#2364 Remove `TxSize` and `BlockGossip` from `ConsensusParams` + * Maximum tx size is now set implicitly via the `BlockSize.MaxBytes` + * The size of block parts in the consensus is now fixed to 64kB * Apps - * [mempool] \#2310 Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. + * [mempool] \#2360 Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. * Go API * [libs/common] \#2431 Remove Word256 due to lack of use @@ -17,21 +28,23 @@ BREAKING CHANGES: * strings.go: cmn.IsHex, cmn.StripHex * int.go: Uint64Slice, all put/get int64 methods -* Blockchain Protocol - -* P2P Protocol - - FEATURES: +- [rpc] \#2415 New `/consensus_params?height=X` endpoint to query the consensus + params at any height (@scriptonist) +- [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator +- [metrics] \#2337 `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) IMPROVEMENTS: -- [libs/db] \#2371 Output error instead of panic when the given db_backend is not initialised (@bradyjoestar) +- [libs/db] \#2371 Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) +- [libs] \#2286 Enforce 0600 permissions on `autofile` and `db/fsdb` + - [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) -- [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator -- [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) - [p2p] \#2126 Introduce PeerTransport interface to improve isolation of concerns +- [libs/common] \#2326 Service returns ErrNotStarted BUG FIXES: - [node] \#2294 Delay starting node until Genesis time - [consensus] \#2048 Correct peer statistics for marking peer as good -- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. \ No newline at end of file +- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. +- [p2p] \#2047 Accept new connections asynchronously +- [tm-bench] \#2410 Enforce minimum transaction size (@WALL-E) diff --git a/UPGRADING.md b/UPGRADING.md index 16e397b22..81e56e588 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -3,6 +3,12 @@ This guide provides steps to be followed when you upgrade your applications to a newer version of Tendermint Core. +## v0.25.0 + +This release has minimal impact. + +If you use GasWanted in ABCI and want to enforce it, set the MaxGas in the genesis file (default is no max). + ## v0.24.0 New 0.24.0 release contains a lot of changes to the state and types. It's not From dde0936fb87256750e0ac0578ded063fabde392e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 21 Sep 2018 17:37:40 -0400 Subject: [PATCH 43/47] linkify changelog --- CHANGELOG_PENDING.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 803f91ca6..f2a2a2574 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -14,37 +14,37 @@ BREAKING CHANGES: * CLI/RPC/Config * [rpc] [\#2391](https://github.com/tendermint/tendermint/issues/2391) /status `result.node_info.other` became a map - * [types] \#2364 Remove `TxSize` and `BlockGossip` from `ConsensusParams` + * [types] [\#2364](https://github.com/tendermint/tendermint/issues/2364) Remove `TxSize` and `BlockGossip` from `ConsensusParams` * Maximum tx size is now set implicitly via the `BlockSize.MaxBytes` * The size of block parts in the consensus is now fixed to 64kB * Apps - * [mempool] \#2360 Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. + * [mempool] [\#2360](https://github.com/tendermint/tendermint/issues/2360) Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. * Go API - * [libs/common] \#2431 Remove Word256 due to lack of use - * [libs/common] \#2452 Remove the following functions due to lack of use: + * [libs/common] [\#2431](https://github.com/tendermint/tendermint/issues/2431) Remove Word256 due to lack of use + * [libs/common] [\#2452](https://github.com/tendermint/tendermint/issues/2452) Remove the following functions due to lack of use: * byteslice.go: cmn.IsZeros, cmn.RightPadBytes, cmn.LeftPadBytes, cmn.PrefixEndBytes * strings.go: cmn.IsHex, cmn.StripHex * int.go: Uint64Slice, all put/get int64 methods FEATURES: -- [rpc] \#2415 New `/consensus_params?height=X` endpoint to query the consensus +- [rpc] [\#2415](https://github.com/tendermint/tendermint/issues/2415) New `/consensus_params?height=X` endpoint to query the consensus params at any height (@scriptonist) - [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator -- [metrics] \#2337 `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) +- [metrics] [\#2337](https://github.com/tendermint/tendermint/issues/2337) `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) IMPROVEMENTS: -- [libs/db] \#2371 Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) -- [libs] \#2286 Enforce 0600 permissions on `autofile` and `db/fsdb` +- [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) +- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Enforce 0600 permissions on `autofile` and `db/fsdb` - [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) -- [p2p] \#2126 Introduce PeerTransport interface to improve isolation of concerns -- [libs/common] \#2326 Service returns ErrNotStarted +- [p2p] [\#2126](https://github.com/tendermint/tendermint/issues/2126) Introduce PeerTransport interface to improve isolation of concerns +- [libs/common] [\#2326](https://github.com/tendermint/tendermint/issues/2326) Service returns ErrNotStarted BUG FIXES: -- [node] \#2294 Delay starting node until Genesis time -- [consensus] \#2048 Correct peer statistics for marking peer as good -- [rpc] \#2460 StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. -- [p2p] \#2047 Accept new connections asynchronously -- [tm-bench] \#2410 Enforce minimum transaction size (@WALL-E) +- [node] [\#2294](https://github.com/tendermint/tendermint/issues/2294) Delay starting node until Genesis time +- [consensus] [\#2048](https://github.com/tendermint/tendermint/issues/2048) Correct peer statistics for marking peer as good +- [rpc] [\#2460](https://github.com/tendermint/tendermint/issues/2460) StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. +- [p2p] [\#2047](https://github.com/tendermint/tendermint/issues/2047) Accept new connections asynchronously +- [tm-bench] [\#2410](https://github.com/tendermint/tendermint/issues/2410) Enforce minimum transaction size (@WALL-E) From ee8b8bbefb2855ff3076d9ba7830cba2dbf335be Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 21 Sep 2018 17:41:02 -0400 Subject: [PATCH 44/47] flush changelog pending, bump version --- CHANGELOG.md | 53 ++++++++++++++++++++++++++++++++++++++++++++ CHANGELOG_PENDING.md | 33 --------------------------- version/version.go | 4 ++-- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 726ca9aed..989f0d14a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,58 @@ # Changelog +## v0.25.0 + +*September 22, 2018* + +Special thanks to external contributors on this release: +@scriptionist, @bradyjoestar, @WALL-E + +This release is mostly about the ConsensusParams - removing fields and enforcing MaxGas. +It also addresses some issues found via security audit, removes various unused +functions from `libs/common`, and implements +[ADR-012](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-012-peer-transport.md). + +Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint). + +BREAKING CHANGES: + +* CLI/RPC/Config + * [rpc] [\#2391](https://github.com/tendermint/tendermint/issues/2391) /status `result.node_info.other` became a map + * [types] [\#2364](https://github.com/tendermint/tendermint/issues/2364) Remove `TxSize` and `BlockGossip` from `ConsensusParams` + * Maximum tx size is now set implicitly via the `BlockSize.MaxBytes` + * The size of block parts in the consensus is now fixed to 64kB + +* Apps + * [mempool] [\#2360](https://github.com/tendermint/tendermint/issues/2360) Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. + +* Go API + * [libs/common] [\#2431](https://github.com/tendermint/tendermint/issues/2431) Remove Word256 due to lack of use + * [libs/common] [\#2452](https://github.com/tendermint/tendermint/issues/2452) Remove the following functions due to lack of use: + * byteslice.go: cmn.IsZeros, cmn.RightPadBytes, cmn.LeftPadBytes, cmn.PrefixEndBytes + * strings.go: cmn.IsHex, cmn.StripHex + * int.go: Uint64Slice, all put/get int64 methods + +FEATURES: +- [rpc] [\#2415](https://github.com/tendermint/tendermint/issues/2415) New `/consensus_params?height=X` endpoint to query the consensus + params at any height (@scriptonist) +- [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator +- [metrics] [\#2337](https://github.com/tendermint/tendermint/issues/2337) `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) + +IMPROVEMENTS: +- [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) +- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Enforce 0600 permissions on `autofile` and `db/fsdb` + +- [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) +- [p2p] [\#2126](https://github.com/tendermint/tendermint/issues/2126) Introduce PeerTransport interface to improve isolation of concerns +- [libs/common] [\#2326](https://github.com/tendermint/tendermint/issues/2326) Service returns ErrNotStarted + +BUG FIXES: +- [node] [\#2294](https://github.com/tendermint/tendermint/issues/2294) Delay starting node until Genesis time +- [consensus] [\#2048](https://github.com/tendermint/tendermint/issues/2048) Correct peer statistics for marking peer as good +- [rpc] [\#2460](https://github.com/tendermint/tendermint/issues/2460) StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. +- [p2p] [\#2047](https://github.com/tendermint/tendermint/issues/2047) Accept new connections asynchronously +- [tm-bench] [\#2410](https://github.com/tendermint/tendermint/issues/2410) Enforce minimum transaction size (@WALL-E) + ## 0.24.0 *September 6th, 2018* diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index f2a2a2574..81c7a3a29 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,50 +1,17 @@ # Pending Special thanks to external contributors on this release: -@scriptionist, @bradyjoestar, @WALL-E - -This release is mostly about the ConsensusParams - removing fields and enforcing MaxGas. -It also addresses some issues found via security audit, removes various unused -functions from `libs/common`, and implements -[ADR-012](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-012-peer-transport.md). - -Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint). BREAKING CHANGES: * CLI/RPC/Config - * [rpc] [\#2391](https://github.com/tendermint/tendermint/issues/2391) /status `result.node_info.other` became a map - * [types] [\#2364](https://github.com/tendermint/tendermint/issues/2364) Remove `TxSize` and `BlockGossip` from `ConsensusParams` - * Maximum tx size is now set implicitly via the `BlockSize.MaxBytes` - * The size of block parts in the consensus is now fixed to 64kB * Apps - * [mempool] [\#2360](https://github.com/tendermint/tendermint/issues/2360) Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. * Go API - * [libs/common] [\#2431](https://github.com/tendermint/tendermint/issues/2431) Remove Word256 due to lack of use - * [libs/common] [\#2452](https://github.com/tendermint/tendermint/issues/2452) Remove the following functions due to lack of use: - * byteslice.go: cmn.IsZeros, cmn.RightPadBytes, cmn.LeftPadBytes, cmn.PrefixEndBytes - * strings.go: cmn.IsHex, cmn.StripHex - * int.go: Uint64Slice, all put/get int64 methods FEATURES: -- [rpc] [\#2415](https://github.com/tendermint/tendermint/issues/2415) New `/consensus_params?height=X` endpoint to query the consensus - params at any height (@scriptonist) -- [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator -- [metrics] [\#2337](https://github.com/tendermint/tendermint/issues/2337) `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) IMPROVEMENTS: -- [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) -- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Enforce 0600 permissions on `autofile` and `db/fsdb` - -- [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) -- [p2p] [\#2126](https://github.com/tendermint/tendermint/issues/2126) Introduce PeerTransport interface to improve isolation of concerns -- [libs/common] [\#2326](https://github.com/tendermint/tendermint/issues/2326) Service returns ErrNotStarted BUG FIXES: -- [node] [\#2294](https://github.com/tendermint/tendermint/issues/2294) Delay starting node until Genesis time -- [consensus] [\#2048](https://github.com/tendermint/tendermint/issues/2048) Correct peer statistics for marking peer as good -- [rpc] [\#2460](https://github.com/tendermint/tendermint/issues/2460) StartHTTPAndTLSServer() now passes StartTLS() errors back to the caller rather than hanging forever. -- [p2p] [\#2047](https://github.com/tendermint/tendermint/issues/2047) Accept new connections asynchronously -- [tm-bench] [\#2410](https://github.com/tendermint/tendermint/issues/2410) Enforce minimum transaction size (@WALL-E) diff --git a/version/version.go b/version/version.go index 337ce4ead..d8bab5772 100644 --- a/version/version.go +++ b/version/version.go @@ -3,14 +3,14 @@ package version // Version components const ( Maj = "0" - Min = "24" + Min = "25" Fix = "0" ) var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.24.0" + Version = "0.25.0" // GitCommit is the current HEAD set using ldflags. GitCommit string From 111e62703707d9898c3287bcff487fe40b9f50de Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 21 Sep 2018 17:50:06 -0700 Subject: [PATCH 45/47] mempool: Filter new txs if they have insufficient gas (#2385) This also refactors the prior mempool to filter to be known as "precheck filter" and this new filter is called "postcheck filter" This PR also fixes a bug where the precheck filter previously didn't account for the amino overhead, which could a maliciously sized tx to halt blocks from getting any txs in them. * Move maxGas outside of function definition to avoid race condition * Type filter funcs and make public * Use helper method for post check * Remove superfluous Filter suffix * Move default pre/post checks into package * Fix broken references * Fix typos * Expand on examples for checks --- mempool/mempool.go | 83 ++++++++++++++++++++++++++++++++++------- mempool/mempool_test.go | 63 +++++++++++++++++++++++++++++-- node/node.go | 28 +++++++++----- state/execution.go | 43 +++++++++++++++------ state/services.go | 34 ++++++++++------- 5 files changed, 199 insertions(+), 52 deletions(-) diff --git a/mempool/mempool.go b/mempool/mempool.go index 1bcad6fa4..543c274de 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -22,6 +22,16 @@ import ( "github.com/tendermint/tendermint/types" ) +// PreCheckFunc is an optional filter to determine if a transaction should be +// rejected. Invoked before CheckTx. An example would be to ensure that a +// transaction isn't exceeded the block size. +type PreCheckFunc func(types.Tx) bool + +// PostCheckFunc is an optional filter executed after CheckTx and rejects +// transaction if false is returned. An example would be to ensure a +// transaction doesn't require more gas than available. +type PostCheckFunc func(types.Tx, *abci.ResponseCheckTx) bool + /* The mempool pushes new txs onto the proxyAppConn. @@ -58,6 +68,27 @@ var ( ErrMempoolIsFull = errors.New("Mempool is full") ) +// PreCheckAminoMaxBytes checks that the size of the transaction plus the amino +// overhead is smaller or equal to the expected maxBytes. +func PreCheckAminoMaxBytes(maxBytes int64) PreCheckFunc { + return func(tx types.Tx) bool { + // We have to account for the amino overhead in the tx size as well + aminoOverhead := amino.UvarintSize(uint64(len(tx))) + return int64(len(tx)+aminoOverhead) <= maxBytes + } +} + +// PostCheckMaxGas checks that the wanted gas is smaller or equal to the passed +// maxGas. Returns true if maxGas is -1. +func PostCheckMaxGas(maxGas int64) PostCheckFunc { + return func(tx types.Tx, res *abci.ResponseCheckTx) bool { + if maxGas == -1 { + return true + } + return res.GasWanted <= maxGas + } +} + // TxID is the hex encoded hash of the bytes as a types.Tx. func TxID(tx []byte) string { return fmt.Sprintf("%X", types.Tx(tx).Hash()) @@ -80,8 +111,8 @@ type Mempool struct { recheckEnd *clist.CElement // re-checking stops here notifiedTxsAvailable bool txsAvailable chan struct{} // fires once for each height, when the mempool is not empty - // Filter mempool to only accept txs for which filter(tx) returns true. - filter func(types.Tx) bool + preCheck PreCheckFunc + postCheck PostCheckFunc // Keep a cache of already-seen txs. // This reduces the pressure on the proxyApp. @@ -141,10 +172,16 @@ func (mem *Mempool) SetLogger(l log.Logger) { mem.logger = l } -// WithFilter sets a filter for mempool to only accept txs for which f(tx) -// returns true. -func WithFilter(f func(types.Tx) bool) MempoolOption { - return func(mem *Mempool) { mem.filter = f } +// WithPreCheck sets a filter for the mempool to reject a tx if f(tx) returns +// false. This is ran before CheckTx. +func WithPreCheck(f PreCheckFunc) MempoolOption { + return func(mem *Mempool) { mem.preCheck = f } +} + +// WithPostCheck sets a filter for the mempool to reject a tx if f(tx) returns +// false. This is ran after CheckTx. +func WithPostCheck(f PostCheckFunc) MempoolOption { + return func(mem *Mempool) { mem.postCheck = f } } // WithMetrics sets the metrics. @@ -248,7 +285,7 @@ func (mem *Mempool) CheckTx(tx types.Tx, cb func(*abci.Response)) (err error) { return ErrMempoolIsFull } - if mem.filter != nil && !mem.filter(tx) { + if mem.preCheck != nil && !mem.preCheck(tx) { return } @@ -298,7 +335,8 @@ func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) { switch r := res.Value.(type) { case *abci.Response_CheckTx: tx := req.GetCheckTx().Tx - if r.CheckTx.Code == abci.CodeTypeOK { + if (r.CheckTx.Code == abci.CodeTypeOK) && + mem.isPostCheckPass(tx, r.CheckTx) { mem.counter++ memTx := &mempoolTx{ counter: mem.counter, @@ -326,10 +364,15 @@ func (mem *Mempool) resCbRecheck(req *abci.Request, res *abci.Response) { case *abci.Response_CheckTx: memTx := mem.recheckCursor.Value.(*mempoolTx) if !bytes.Equal(req.GetCheckTx().Tx, memTx.tx) { - cmn.PanicSanity(fmt.Sprintf("Unexpected tx response from proxy during recheck\n"+ - "Expected %X, got %X", r.CheckTx.Data, memTx.tx)) + cmn.PanicSanity( + fmt.Sprintf( + "Unexpected tx response from proxy during recheck\nExpected %X, got %X", + r.CheckTx.Data, + memTx.tx, + ), + ) } - if r.CheckTx.Code == abci.CodeTypeOK { + if (r.CheckTx.Code == abci.CodeTypeOK) && mem.isPostCheckPass(memTx.tx, r.CheckTx) { // Good, nothing to do. } else { // Tx became invalidated due to newly committed block. @@ -444,7 +487,12 @@ func (mem *Mempool) ReapMaxTxs(max int) types.Txs { // Update informs the mempool that the given txs were committed and can be discarded. // NOTE: this should be called *after* block is committed by consensus. // NOTE: unsafe; Lock/Unlock must be managed by caller -func (mem *Mempool) Update(height int64, txs types.Txs, filter func(types.Tx) bool) error { +func (mem *Mempool) Update( + height int64, + txs types.Txs, + preCheck PreCheckFunc, + postCheck PostCheckFunc, +) error { // First, create a lookup map of txns in new txs. txsMap := make(map[string]struct{}, len(txs)) for _, tx := range txs { @@ -455,8 +503,11 @@ func (mem *Mempool) Update(height int64, txs types.Txs, filter func(types.Tx) bo mem.height = height mem.notifiedTxsAvailable = false - if filter != nil { - mem.filter = filter + if preCheck != nil { + mem.preCheck = preCheck + } + if postCheck != nil { + mem.postCheck = postCheck } // Remove transactions that are already in txs. @@ -514,6 +565,10 @@ func (mem *Mempool) recheckTxs(goodTxs []types.Tx) { mem.proxyAppConn.FlushAsync() } +func (mem *Mempool) isPostCheckPass(tx types.Tx, r *abci.ResponseCheckTx) bool { + return mem.postCheck == nil || mem.postCheck(tx, r) +} + //-------------------------------------------------------------------------------- // mempoolTx is a transaction that successfully ran diff --git a/mempool/mempool_test.go b/mempool/mempool_test.go index dc7259dd3..4f66da36c 100644 --- a/mempool/mempool_test.go +++ b/mempool/mempool_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + amino "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/abci/example/counter" "github.com/tendermint/tendermint/abci/example/kvstore" abci "github.com/tendermint/tendermint/abci/types" @@ -119,6 +120,62 @@ func TestReapMaxBytesMaxGas(t *testing.T) { } } +func TestMempoolFilters(t *testing.T) { + app := kvstore.NewKVStoreApplication() + cc := proxy.NewLocalClientCreator(app) + mempool := newMempoolWithApp(cc) + emptyTxArr := []types.Tx{[]byte{}} + + nopPreFilter := func(tx types.Tx) bool { return true } + nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) bool { return true } + + // This is the same filter we expect to be used within node/node.go and state/execution.go + nBytePreFilter := func(n int) func(tx types.Tx) bool { + return func(tx types.Tx) bool { + // We have to account for the amino overhead in the tx size as well + aminoOverhead := amino.UvarintSize(uint64(len(tx))) + return (len(tx) + aminoOverhead) <= n + } + } + + nGasPostFilter := func(n int64) func(tx types.Tx, res *abci.ResponseCheckTx) bool { + return func(tx types.Tx, res *abci.ResponseCheckTx) bool { + if n == -1 { + return true + } + return res.GasWanted <= n + } + } + + // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. + // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas + tests := []struct { + numTxsToCreate int + preFilter func(tx types.Tx) bool + postFilter func(tx types.Tx, res *abci.ResponseCheckTx) bool + expectedNumTxs int + }{ + {10, nopPreFilter, nopPostFilter, 10}, + {10, nBytePreFilter(10), nopPostFilter, 0}, + {10, nBytePreFilter(20), nopPostFilter, 0}, + {10, nBytePreFilter(21), nopPostFilter, 10}, + {10, nopPreFilter, nGasPostFilter(-1), 10}, + {10, nopPreFilter, nGasPostFilter(0), 0}, + {10, nopPreFilter, nGasPostFilter(1), 10}, + {10, nopPreFilter, nGasPostFilter(3000), 10}, + {10, nBytePreFilter(10), nGasPostFilter(20), 0}, + {10, nBytePreFilter(30), nGasPostFilter(20), 10}, + {10, nBytePreFilter(21), nGasPostFilter(1), 10}, + {10, nBytePreFilter(21), nGasPostFilter(0), 0}, + } + for tcIndex, tt := range tests { + mempool.Update(1, emptyTxArr, tt.preFilter, tt.postFilter) + checkTxs(t, mempool, tt.numTxsToCreate) + require.Equal(t, tt.expectedNumTxs, mempool.Size(), "mempool had the incorrect size, on test case %d", tcIndex) + mempool.Flush() + } +} + func TestTxsAvailable(t *testing.T) { app := kvstore.NewKVStoreApplication() cc := proxy.NewLocalClientCreator(app) @@ -139,7 +196,7 @@ func TestTxsAvailable(t *testing.T) { // it should fire once now for the new height // since there are still txs left committedTxs, txs := txs[:50], txs[50:] - if err := mempool.Update(1, committedTxs, nil); err != nil { + if err := mempool.Update(1, committedTxs, nil, nil); err != nil { t.Error(err) } ensureFire(t, mempool.TxsAvailable(), timeoutMS) @@ -151,7 +208,7 @@ func TestTxsAvailable(t *testing.T) { // now call update with all the txs. it should not fire as there are no txs left committedTxs = append(txs, moreTxs...) - if err := mempool.Update(2, committedTxs, nil); err != nil { + if err := mempool.Update(2, committedTxs, nil, nil); err != nil { t.Error(err) } ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) @@ -208,7 +265,7 @@ func TestSerialReap(t *testing.T) { binary.BigEndian.PutUint64(txBytes, uint64(i)) txs = append(txs, txBytes) } - if err := mempool.Update(0, txs, nil); err != nil { + if err := mempool.Update(0, txs, nil, nil); err != nil { t.Error(err) } } diff --git a/node/node.go b/node/node.go index 97ea8143e..0e5581a56 100644 --- a/node/node.go +++ b/node/node.go @@ -7,22 +7,23 @@ import ( "fmt" "net" "net/http" + _ "net/http/pprof" + "strings" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - amino "github.com/tendermint/go-amino" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/ed25519" - cmn "github.com/tendermint/tendermint/libs/common" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" + abci "github.com/tendermint/tendermint/abci/types" bc "github.com/tendermint/tendermint/blockchain" cfg "github.com/tendermint/tendermint/config" cs "github.com/tendermint/tendermint/consensus" + "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/evidence" + cmn "github.com/tendermint/tendermint/libs/common" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" mempl "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p/pex" @@ -40,9 +41,6 @@ import ( "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" - - _ "net/http/pprof" - "strings" ) //------------------------------------------------------------------------------ @@ -255,7 +253,17 @@ func NewNode(config *cfg.Config, proxyApp.Mempool(), state.LastBlockHeight, mempl.WithMetrics(memplMetrics), - mempl.WithFilter(sm.TxFilter(state)), + mempl.WithPreCheck( + mempl.PreCheckAminoMaxBytes( + types.MaxDataBytesUnknownEvidence( + state.ConsensusParams.BlockSize.MaxBytes, + state.Validators.Size(), + ), + ), + ), + mempl.WithPostCheck( + mempl.PostCheckMaxGas(state.ConsensusParams.BlockSize.MaxGas), + ), ) mempoolLogger := logger.With("module", "mempool") mempool.SetLogger(mempoolLogger) diff --git a/state/execution.go b/state/execution.go index 60fa4780a..c6d5ce0a1 100644 --- a/state/execution.go +++ b/state/execution.go @@ -7,6 +7,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" ) @@ -115,11 +116,16 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b return state, nil } -// Commit locks the mempool, runs the ABCI Commit message, and updates the mempool. +// Commit locks the mempool, runs the ABCI Commit message, and updates the +// mempool. // It returns the result of calling abci.Commit (the AppHash), and an error. -// The Mempool must be locked during commit and update because state is typically reset on Commit and old txs must be replayed -// against committed state before new txs are run in the mempool, lest they be invalid. -func (blockExec *BlockExecutor) Commit(state State, block *types.Block) ([]byte, error) { +// The Mempool must be locked during commit and update because state is +// typically reset on Commit and old txs must be replayed against committed +// state before new txs are run in the mempool, lest they be invalid. +func (blockExec *BlockExecutor) Commit( + state State, + block *types.Block, +) ([]byte, error) { blockExec.mempool.Lock() defer blockExec.mempool.Unlock() @@ -134,22 +140,35 @@ func (blockExec *BlockExecutor) Commit(state State, block *types.Block) ([]byte, // Commit block, get hash back res, err := blockExec.proxyApp.CommitSync() if err != nil { - blockExec.logger.Error("Client error during proxyAppConn.CommitSync", "err", err) + blockExec.logger.Error( + "Client error during proxyAppConn.CommitSync", + "err", err, + ) return nil, err } // ResponseCommit has no error code - just data - blockExec.logger.Info("Committed state", + blockExec.logger.Info( + "Committed state", "height", block.Height, "txs", block.NumTxs, - "appHash", fmt.Sprintf("%X", res.Data)) + "appHash", fmt.Sprintf("%X", res.Data), + ) // Update mempool. - if err := blockExec.mempool.Update(block.Height, block.Txs, TxFilter(state)); err != nil { - return nil, err - } - - return res.Data, nil + err = blockExec.mempool.Update( + block.Height, + block.Txs, + mempool.PreCheckAminoMaxBytes( + types.MaxDataBytesUnknownEvidence( + state.ConsensusParams.BlockSize.MaxBytes, + state.Validators.Size(), + ), + ), + mempool.PostCheckMaxGas(state.ConsensusParams.MaxGas), + ) + + return res.Data, err } //--------------------------------------------------------- diff --git a/state/services.go b/state/services.go index 320b4772c..b8f1febe1 100644 --- a/state/services.go +++ b/state/services.go @@ -2,6 +2,7 @@ package state import ( abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/types" ) @@ -23,7 +24,7 @@ type Mempool interface { Size() int CheckTx(types.Tx, func(*abci.Response)) error ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs - Update(height int64, txs types.Txs, filter func(types.Tx) bool) error + Update(int64, types.Txs, mempool.PreCheckFunc, mempool.PostCheckFunc) error Flush() FlushAppConn() error @@ -36,16 +37,23 @@ type MockMempool struct{} var _ Mempool = MockMempool{} -func (MockMempool) Lock() {} -func (MockMempool) Unlock() {} -func (MockMempool) Size() int { return 0 } -func (MockMempool) CheckTx(tx types.Tx, cb func(*abci.Response)) error { return nil } -func (MockMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs { return types.Txs{} } -func (MockMempool) Update(height int64, txs types.Txs, filter func(types.Tx) bool) error { return nil } -func (MockMempool) Flush() {} -func (MockMempool) FlushAppConn() error { return nil } -func (MockMempool) TxsAvailable() <-chan struct{} { return make(chan struct{}) } -func (MockMempool) EnableTxsAvailable() {} +func (MockMempool) Lock() {} +func (MockMempool) Unlock() {} +func (MockMempool) Size() int { return 0 } +func (MockMempool) CheckTx(_ types.Tx, _ func(*abci.Response)) error { return nil } +func (MockMempool) ReapMaxBytesMaxGas(_, _ int64) types.Txs { return types.Txs{} } +func (MockMempool) Update( + _ int64, + _ types.Txs, + _ mempool.PreCheckFunc, + _ mempool.PostCheckFunc, +) error { + return nil +} +func (MockMempool) Flush() {} +func (MockMempool) FlushAppConn() error { return nil } +func (MockMempool) TxsAvailable() <-chan struct{} { return make(chan struct{}) } +func (MockMempool) EnableTxsAvailable() {} //------------------------------------------------------ // blockstore @@ -82,5 +90,5 @@ type EvidencePool interface { type MockEvidencePool struct{} func (m MockEvidencePool) PendingEvidence(int64) []types.Evidence { return nil } -func (m MockEvidencePool) AddEvidence(types.Evidence) error { return nil } -func (m MockEvidencePool) Update(*types.Block, State) {} +func (m MockEvidencePool) AddEvidence(types.Evidence) error { return nil } +func (m MockEvidencePool) Update(*types.Block, State) {} From f5824bc83760ba2f7e4fbee32f82d711aaf39792 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 23 Sep 2018 01:14:05 -0400 Subject: [PATCH 46/47] Update abci and app docs (#2470) * mempool: update some comments * make build_c * docs: notes about databases and WAL files * docs: determinism. closes #1279 * docs: small note about query paths. closes #2090 * docs: gas * docs: abci consensus params --- Makefile | 5 +- docs/introduction/install.md | 9 +- docs/spec/abci/abci.md | 50 +++++-- docs/spec/abci/apps.md | 126 ++++++++++++++++-- docs/tendermint-core/running-in-production.md | 59 ++++++++ mempool/mempool.go | 8 +- 6 files changed, 228 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 1fb3eacb3..ffc72c465 100644 --- a/Makefile +++ b/Makefile @@ -23,11 +23,14 @@ check: check_tools get_vendor_deps build: CGO_ENABLED=0 go build $(BUILD_FLAGS) -tags $(BUILD_TAGS) -o build/tendermint ./cmd/tendermint/ +build_c: + CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags "$(BUILD_TAGS) gcc" -o build/tendermint ./cmd/tendermint/ + build_race: CGO_ENABLED=0 go build -race $(BUILD_FLAGS) -tags $(BUILD_TAGS) -o build/tendermint ./cmd/tendermint install: - CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags $(BUILD_TAGS) ./cmd/tendermint + CGO_ENABLED=0 go install $(BUILD_FLAGS) -tags $(BUILD_TAGS) ./cmd/tendermint ######################################## ### Protobuf diff --git a/docs/introduction/install.md b/docs/introduction/install.md index c7b83b03c..f7d78aba3 100644 --- a/docs/introduction/install.md +++ b/docs/introduction/install.md @@ -77,8 +77,13 @@ make install ## Compile with CLevelDB support -Install [LevelDB](https://github.com/google/leveldb) (minimum version is 1.7) -with snappy. Example for Ubuntu: +Install [LevelDB](https://github.com/google/leveldb) (minimum version is 1.7). + +Build Tendermint with C libraries: `make build_c`. + +### Ubuntu + +Install LevelDB with snappy: ``` sudo apt-get update diff --git a/docs/spec/abci/abci.md b/docs/spec/abci/abci.md index 287406b76..a12170981 100644 --- a/docs/spec/abci/abci.md +++ b/docs/spec/abci/abci.md @@ -48,16 +48,50 @@ Keys and values in tags must be UTF-8 encoded strings (e.g. ## Determinism -Some methods (`SetOption, Query, CheckTx, DeliverTx`) return -non-deterministic data in the form of `Info` and `Log`. The `Log` is -intended for the literal output from the application's logger, while the -`Info` is any additional info that should be returned. - -All other fields in the `Response*` of all methods must be strictly deterministic. +ABCI applications must implement deterministic finite-state machines to be +securely replicated by the Tendermint consensus. This means block execution +over the Consensus Connection must be strictly deterministic: given the same +ordered set of requests, all nodes will compute identical responses, for all +BeginBlock, DeliverTx, EndBlock, and Commit. This is critical, because the +responses are included in the header of the next block, either via a Merkle root +or directly, so all nodes must agree on exactly what they are. For this reason, it is recommended that applications not be exposed to any external user or process except via the ABCI connections to a consensus engine -like Tendermint Core. +like Tendermint Core. The application must only change its state based on input +from block execution (BeginBlock, DeliverTx, EndBlock, Commit), and not through +any other kind of request. This is the only way to ensure all nodes see the same +transactions and compute the same results. + +If there is some non-determinism in the state machine, consensus will eventually +fail as nodes disagree over the correct values for the block header. The +non-determinism must be fixed and the nodes restarted. + +Sources of non-determinism in applications may include: + +- Hardware failures + - Cosmic rays, overheating, etc. +- Node-dependent state + - Random numbers + - Time +- Underspecification + - Library version changes + - Race conditions + - Floating point numbers + - JSON serialization + - Iterating through hash-tables/maps/dictionaries +- External Sources + - Filesystem + - Network calls (eg. some external REST API service) + +See [#56](https://github.com/tendermint/abci/issues/56) for original discussion. + +Note that some methods (`SetOption, Query, CheckTx, DeliverTx`) return +explicitly non-deterministic data in the form of `Info` and `Log` fields. The `Log` is +intended for the literal output from the application's logger, while the +`Info` is any additional info that should be returned. These are the only fields +that are not included in block header computations, so we don't need agreement +on them. All other fields in the `Response*` must be strictly deterministic. ## Block Execution @@ -217,7 +251,7 @@ Commit are included in the header of the next block. be non-deterministic. - `Info (string)`: Additional information. May be non-deterministic. - - `GasWanted (int64)`: Amount of gas request for transaction. + - `GasWanted (int64)`: Amount of gas requested for transaction. - `GasUsed (int64)`: Amount of gas consumed by transaction. - `Tags ([]cmn.KVPair)`: Key-Value tags for filtering and indexing transactions (eg. by account). diff --git a/docs/spec/abci/apps.md b/docs/spec/abci/apps.md index ac0736161..cd88c685e 100644 --- a/docs/spec/abci/apps.md +++ b/docs/spec/abci/apps.md @@ -86,18 +86,50 @@ Otherwise it should never be modified. ## Transaction Results -`ResponseCheckTx` and `ResponseDeliverTx` contain the same fields, though they -have slightly different effects. +`ResponseCheckTx` and `ResponseDeliverTx` contain the same fields. -In both cases, `Info` and `Log` are non-deterministic values for debugging/convenience purposes +The `Info` and `Log` fields are non-deterministic values for debugging/convenience purposes that are otherwise ignored. -In both cases, `GasWanted` and `GasUsed` parameters are currently ignored, -though see issues -[#1861](https://github.com/tendermint/tendermint/issues/1861), -[#2299](https://github.com/tendermint/tendermint/issues/2299) and -[#2310](https://github.com/tendermint/tendermint/issues/2310) for how this may -soon change. +The `Data` field must be strictly deterministic, but can be arbitrary data. + +### Gas + +Ethereum introduced the notion of `gas` as an absract representation of the +cost of resources used by nodes when processing transactions. Every operation in the +Ethereum Virtual Machine uses some amount of gas, and gas can be accepted at a market-variable price. +Users propose a maximum amount of gas for their transaction; if the tx uses less, they get +the difference credited back. Tendermint adopts a similar abstraction, +though uses it only optionally and weakly, allowing applications to define +their own sense of the cost of execution. + +In Tendermint, the `ConsensusParams.BlockSize.MaxGas` limits the amount of `gas` that can be used in a block. +The default value is `-1`, meaning no limit, or that the concept of gas is +meaningless. + +Responses contain a `GasWanted` and `GasUsed` field. The former is the maximum +amount of gas the sender of a tx is willing to use, and the later is how much it actually +used. Applications should enforce that `GasUsed <= GasWanted` - ie. tx execution +should halt before it can use more resources than it requested. + +When `MaxGas > -1`, Tendermint enforces the following rules: + + - `GasWanted <= MaxGas` for all txs in the mempool + - `(sum of GasWanted in a block) <= MaxGas` when proposing a block + +If `MaxGas == -1`, no rules about gas are enforced. + +Note that Tendermint does not currently enforce anything about Gas in the consensus, only the mempool. +This means it does not guarantee that committed blocks satisfy these rules! +It is the application's responsibility to return non-zero response codes when gas limits are exceeded. + +The `GasUsed` field is ignored compltely by Tendermint. That said, applications should enforce: + - `GasUsed <= GasWanted` for any given transaction + - `(sum of GasUsed in a block) <= MaxGas` for every block + +In the future, we intend to add a `Priority` field to the responses that can be +used to explicitly prioritize txs in the mempool for inclusion in a block +proposal. See [#1861](https://github.com/tendermint/tendermint/issues/1861). ### CheckTx @@ -142,9 +174,6 @@ If the list is not empty, Tendermint will use it for the validator set. This way the application can determine the initial validator set for the blockchain. -ResponseInitChain also includes ConsensusParams, but these are presently -ignored. - ### EndBlock Updates to the Tendermint validator set can be made by returning @@ -179,14 +208,74 @@ following rules: Note the updates returned in block `H` will only take effect at block `H+2`. +## Consensus Parameters + +ConsensusParams enforce certain limits in the blockchain, like the maximum size +of blocks, amount of gas used in a block, and the maximum acceptable age of +evidence. They can be set in InitChain and updated in EndBlock. + +### BlockSize.MaxBytes + +The maximum size of a complete Amino encoded block. +This is enforced by Tendermint consensus. + +This implies a maximum tx size that is this MaxBytes, less the expected size of +the header, the validator set, and any included evidence in the block. + +Must have `0 < MaxBytes < 100 MB`. + +### BlockSize.MaxGas + +The maximum of the sum of `GasWanted` in a proposed block. +This is *not* enforced by Tendermint consensus. +It is left to the app to enforce (ie. if txs are included past the +limit, they should return non-zero codes). It is used by Tendermint to limit the +txs included in a proposed block. + +Must have `MaxGas >= -1`. +If `MaxGas == -1`, no limit is enforced. + +### EvidenceParams.MaxAge + +This is the maximum age of evidence. +This is enforced by Tendermint consensus. +If a block includes evidence older than this, the block will be rejected +(validators won't vote for it). + +Must have `0 < MaxAge`. + +### Updates + +The application may set the consensus params during InitChain, and update them during +EndBlock. + +#### InitChain + +ResponseInitChain includes a ConsensusParams. +If its nil, Tendermint will use the params loaded in the genesis +file. If it's not nil, Tendermint will use it. +This way the application can determine the initial consensus params for the +blockchain. + +#### EndBlock + +ResponseEndBlock includes a ConsensusParams. +If its nil, Tendermint will do nothing. +If it's not nil, Tendermint will use it. +This way the application can update the consensus params over time. + +Note the updates returned in block `H` will take effect right away for block +`H+1`. + ## Query Query is a generic method with lots of flexibility to enable diverse sets of queries on application state. Tendermint makes use of Query to filter new peers based on ID and IP, and exposes Query to the user over RPC. + Note that calls to Query are not replicated across nodes, but rather query the -local node's state - hence they may provide stale reads. For reads that require -consensus, a transaction is required. +local node's state - hence they may return stale reads. For reads that require +consensus, use a transaction. The most important use of Query is to return Merkle proofs of the application state at some height that can be used for efficient application-specific lite-clients. @@ -235,6 +324,15 @@ using the following paths, with no additional data: If either of these queries return a non-zero ABCI code, Tendermint will refuse to connect to the peer. +### Paths + +Queries are directed at paths, and may optionally include additional data. + +The expectation is for there to be some number of high level paths +differentiating concerns, like `/p2p`, `/store`, and `/app`. Currently, +Tendermint only uses `/p2p`, for filtering peers. For more advanced use, see the +implementation of +[Query in the Cosmos-SDK](https://github.com/cosmos/cosmos-sdk/blob/v0.23.1/baseapp/baseapp.go#L333). ## Crash Recovery diff --git a/docs/tendermint-core/running-in-production.md b/docs/tendermint-core/running-in-production.md index f647bd9b0..cd55be538 100644 --- a/docs/tendermint-core/running-in-production.md +++ b/docs/tendermint-core/running-in-production.md @@ -1,5 +1,41 @@ # Running in production +## Database + +By default, Tendermint uses the `syndtr/goleveldb` package for it's in-process +key-value database. Unfortunately, this implementation of LevelDB seems to suffer under heavy load (see +[#226](https://github.com/syndtr/goleveldb/issues/226)). It may be best to +install the real C-implementaiton of LevelDB and compile Tendermint to use +that using `make build_c`. See the [install instructions](../introduction/install) for details. + +Tendermint keeps multiple distinct LevelDB databases in the `$TMROOT/data`: + +- `blockstore.db`: Keeps the entire blockchain - stores blocks, + block commits, and block meta data, each indexed by height. Used to sync new + peers. +- `evidence.db`: Stores all verified evidence of misbehaviour. +- `state.db`: Stores the current blockchain state (ie. height, validators, + consensus params). Only grows if consensus params or validators change. Also + used to temporarily store intermediate results during block processing. +- `tx_index.db`: Indexes txs (and their results) by tx hash and by DeliverTx result tags. + +By default, Tendermint will only index txs by their hash, not by their DeliverTx +result tags. See [indexing transactions](../app-dev/indexing-transactions) for +details. + +There is no current strategy for pruning the databases. Consider reducing +block production by [controlling empty blocks](../tendermint-core/using-tendermint#No-Empty-Blocks) +or by increasing the `consensus.timeout_commit` param. Note both of these are +local settings and not enforced by the consensus. + +We're working on [state +syncing](https://github.com/tendermint/tendermint/issues/828), +which will enable history to be thrown away +and recent application state to be directly synced. We'll need to develop solutions +for archival nodes that allow queries on historical transactions and states. +The Cosmos project has had much success just dumping the latest state of a +blockchain to disk and starting a new chain from that state. + ## Logging Default logging level (`main:info,state:info,*:`) should suffice for @@ -11,6 +47,29 @@ you're trying to debug Tendermint or asked to provide logs with debug logging level, you can do so by running tendermint with `--log_level="*:debug"`. +## Write Ahead Logs (WAL) + +Tendermint uses write ahead logs for the consensus (`cs.wal`) and the mempool +(`mempool.wal`). Both WALs have a max size of 1GB and are automatically rotated.. + +The `consensus.wal` is used to ensure we can recover from a crash at any point +in the consensus state machine. +It writes all consensus messages (timeouts, proposals, block part, or vote) +to a single file, flushing to disk before processing messages from its own +validator. Since Tendermint validators are expected to never sign a conflicting vote, the +WAL ensures we can always recover deterministically to the latest state of the consensus without +using the network or re-signing any consensus messages. + +If your `consensus.wal` is corrupted, see [below](#WAL-Corruption). + +The `mempool.wal` logs all incoming txs before running CheckTx, but is +otherwise not used in any programmatic way. It's just a kind of manual +safe guard. Note the mempool provides no durability guarantees - a tx sent to one or many nodes +may never make it into the blockchain if those nodes crash before being able to +propose it. Clients must monitor their txs by subscribing over websockets, +polling for them, or using `/broadcast_tx_commit`. In the worst case, txs can be +resent from the mempool WAL manually. + ## DOS Exposure and Mitigation Validators are supposed to setup [Sentry Node diff --git a/mempool/mempool.go b/mempool/mempool.go index 543c274de..2096912f5 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -22,14 +22,14 @@ import ( "github.com/tendermint/tendermint/types" ) -// PreCheckFunc is an optional filter to determine if a transaction should be -// rejected. Invoked before CheckTx. An example would be to ensure that a -// transaction isn't exceeded the block size. +// PreCheckFunc is an optional filter executed before CheckTx and rejects +// transaction if false is returned. An example would be to ensure that a +// transaction doesn't exceeded the block size. type PreCheckFunc func(types.Tx) bool // PostCheckFunc is an optional filter executed after CheckTx and rejects // transaction if false is returned. An example would be to ensure a -// transaction doesn't require more gas than available. +// transaction doesn't require more gas than available for the block. type PostCheckFunc func(types.Tx, *abci.ResponseCheckTx) bool /* From 97b43d875ae8ef1d8e177964fa296ea5800c4448 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 23 Sep 2018 01:23:31 -0400 Subject: [PATCH 47/47] update changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 989f0d14a..6032fc204 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,10 @@ BREAKING CHANGES: * The size of block parts in the consensus is now fixed to 64kB * Apps - * [mempool] [\#2360](https://github.com/tendermint/tendermint/issues/2360) Mempool tracks the `ResponseCheckTx.GasWanted` and enforces `ConsensusParams.BlockSize.MaxGas` on proposals. + * [mempool] [\#2360](https://github.com/tendermint/tendermint/issues/2360) Mempool tracks the `ResponseCheckTx.GasWanted` and + `ConsensusParams.BlockSize.MaxGas` and enforces: + - `GasWanted <= MaxGas` for every tx + - `(sum of GasWanted in block) <= MaxGas` for block proposal * Go API * [libs/common] [\#2431](https://github.com/tendermint/tendermint/issues/2431) Remove Word256 due to lack of use @@ -37,11 +40,10 @@ FEATURES: params at any height (@scriptonist) - [types] [\#1714](https://github.com/tendermint/tendermint/issues/1714) Add Address to GenesisValidator - [metrics] [\#2337](https://github.com/tendermint/tendermint/issues/2337) `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any) +- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Panic if `autofile` or `db/fsdb` permissions change from 0600. IMPROVEMENTS: - [libs/db] [\#2371](https://github.com/tendermint/tendermint/issues/2371) Output error instead of panic when the given `db_backend` is not initialised (@bradyjoestar) -- [libs] [\#2286](https://github.com/tendermint/tendermint/issues/2286) Enforce 0600 permissions on `autofile` and `db/fsdb` - - [mempool] [\#2399](https://github.com/tendermint/tendermint/issues/2399) Make mempool cache a proper LRU (@bradyjoestar) - [p2p] [\#2126](https://github.com/tendermint/tendermint/issues/2126) Introduce PeerTransport interface to improve isolation of concerns - [libs/common] [\#2326](https://github.com/tendermint/tendermint/issues/2326) Service returns ErrNotStarted