diff --git a/.circleci/config.yml b/.circleci/config.yml
index 1e463aaa4d2b43e5dc466543a54ec13b0c1522e3..8e588a7f6869bb2dc525d22843354e07d82b2686 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -58,24 +58,8 @@ jobs:
           <<: *setup_docker
         # build docker image and tag the docker image(s) depending on branch/tag
       - run: make docker_build
-      - run: docker save $DOCKER_REPO > db-images.tar
-      - persist_to_workspace:
-          root: .
-          paths:
-            - .
-
-  # Simple smoke test to ensure burrow binary has been provisioned to container
-  test_docker_smoke:
-    <<: *defaults
-    steps:
-      - attach_workspace:
-          at: .
-      - setup_remote_docker:
-          <<: *setup_docker
-      - run: docker load -i db-images.tar
-      - run: docker run $DOCKER_REPO:$(./scripts/local_version.sh) -h
 
-  push_docker:
+  push_docker_dev:
     <<: *defaults
     steps:
       - attach_workspace:
@@ -83,7 +67,7 @@ jobs:
       - setup_remote_docker:
           <<: *setup_docker
       # Only run on non-pull requests
-      - run: "[[ -n \"$CIRCLE_PULL_REQUESTS\" ]] || (docker login -u $DOCKER_USER -p $DOCKER_PASS && docker load -i db-images.tar && docker push $DOCKER_REPO)"
+      - run: "[[ -n \"$CIRCLE_PULL_REQUESTS\" ]] || (docker login -u $DOCKER_USER_DEV -p $DOCKER_PASS_DEV && docker push $DOCKER_REPO_DEV)"
 
   release:
     <<: *defaults
@@ -114,26 +98,18 @@ workflows:
             <<: *tags_filters
 
       - build_docker:
-          filters:
-            <<: *tags_filters
-
-      - test_docker_smoke:
-          requires:
-            - build_docker
-          filters:
-            <<: *tags_filters
-
-      - push_docker:
-          requires:
-            - test
-            - test_integration
-            - test_integration_bosmarmot
-            - test_docker_smoke
           filters:
             # tags filters and branch filters are applied disjunctively, so we
             # will still build tags not on develop (i.e. including tagged
             # releases on master that we specifically want to build)
             <<: *tags_filters
+
+      - push_docker_dev:
+          requires:
+          - test
+          - test_integration
+          - test_integration_bosmarmot
+          filters:
             branches:
               only: develop
 
@@ -142,7 +118,6 @@ workflows:
           - test
           - test_integration
           - test_integration_bosmarmot
-          - test_docker_smoke
           filters:
             <<: *tags_filters
             branches:
diff --git a/.dockerignore b/.dockerignore
index a29b1c4a1f89ee9b79bbe7ab3a251721e9b85d62..8342b8f141eb07d137d8d0bae55a104a32e1ccab 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -10,4 +10,5 @@ CHANGELOG.md
 README.md
 .circleci
 docs
-bin
\ No newline at end of file
+bin
+scripts
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa90b222cbb11a7778e3cf03bba57fd03dcbee51..91e8aa257dd40117311bffcd738b142ab597aa46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,19 @@
 # [Hyperledger Burrow](https://github.com/hyperledger/burrow) Changelog
+## [0.21.0] - 2018-08-21
+### Changed
+- Upgraded to Tendermint 0.23.0
+- Validator Set Power now takes Address
+- RPC/TM config renamed to RPC/Info
+
+### Added
+- Burrow deploy creates devdoc
+- Docker image has org.label-schema labels
+
+### Fixed
+- Upgrade to IAVL 0.10.0 and load previous versions immutably on boot - for chains with a long history > 20 minute load times could be observed because every previous root was being loaded from DB rather than lightweight version references as was intended
+- Metrics server does not panic on empty block metas and recovers from other panics
+
+
 ## [0.20.1] - 2018-08-17
 ### Changed
 - The snatives functions have new signatures; string arguments are now string, not byte32.
@@ -7,6 +22,7 @@
 ### Fixed
 - TxExecutions that were exceptions (for example those that were REVERTed) will no longer have their events emitted from ExecutionEventsServer.GetEvents. They remain stored in state for the time being.
 - CallTxSim and CallCodeSim now take same code path as real transactions (via CallContext)
+- Release our mempool signing lock once transactions have been CheckTx'd' to massively increase throughput.
 
 ### Added
 - Upgraded to Tendermint [0.22.8](https://github.com/tendermint/tendermint/compare/v0.22.4...v0.22.8) (from 0.22.4).
@@ -18,10 +34,6 @@
 - Exposed Tendermint SeedMode option
 
 
-### Fixed
-- Release our mempool signing lock once transactions have been CheckTx'd' to massively increase throughput.
-
-
 ## [0.20.0] - 2018-07-24
 This is a major (pre-1.0.0) release that introduces the ability to change the validator set through GovTx, transaction execution history, and fuller GRPC endpoint.
 
@@ -254,6 +266,7 @@ This release marks the start of Eris-DB as the full permissioned blockchain node
   - [Blockchain] Fix getBlocks to respect block height cap.
 
 
+[0.21.0]: https://github.com/hyperledger/burrow/compare/v0.20.1...v0.21.0
 [0.20.1]: https://github.com/hyperledger/burrow/compare/v0.20.0...v0.20.1
 [0.20.0]: https://github.com/hyperledger/burrow/compare/v0.19.0...v0.20.0
 [0.19.0]: https://github.com/hyperledger/burrow/compare/v0.18.1...v0.19.0
diff --git a/Dockerfile b/Dockerfile
index 0749a7a0c33b86af2231985a7723dbb07cd0619e..68ed1ceec187480ce56af025b69c9a92830d780b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,5 @@
 # We use a multistage build to avoid bloating our deployment image with build dependencies
 FROM golang:1.10.3-alpine3.8 as builder
-MAINTAINER Monax <support@monax.io>
 
 RUN apk add --no-cache --update git bash make
 
@@ -14,21 +13,35 @@ RUN make build
 # This will be our base container image
 FROM alpine:3.8
 
-ARG REPO=/go/src/github.com/hyperledger/burrow
-
-ENV USER monax
-ENV MONAX_PATH /home/$USER/.monax
+# Variable arguments to populate labels
+ARG VERSION
+ARG VCS_REF=master
+ARG BUILD_DATE
+
+# Fixed labels according to container label-schema
+LABEL org.label-schema.schema-version="1.0"
+LABEL org.label-schema.name = "Burrow"
+LABEL org.label-schema.vendor="Hyperledger Burrow Authors"
+LABEL org.label-schema.description="Hyperledger Burrow is a permissioned Ethereum smart-contract blockchain node."
+LABEL org.label-schema.license="Apache-2.0"
+LABEL org.label-schema.version=$VERSION
+LABEL org.label-schema.vcs-url="https://github.com/hyperledger/burrow"
+LABEL org.label-schema.vcs-ref=$VCS_REF
+LABEL org.label-schema.build-date=$BUILD_DATE
+
+# Run burrow as burrow user; not as root user
+ENV USER burrow
+ENV BURROW_PATH /home/$USER
 RUN addgroup -g 101 -S $USER && adduser -S -D -u 1000 $USER $USER
-WORKDIR $MONAX_PATH
-USER $USER:$USER
+WORKDIR $BURROW_PATH
 
 # Copy binaries built in previous stage
-COPY --from=builder $REPO/bin/* /usr/local/bin/
-#RUN chown $USER:$USER /usr/local/bin/burrow*
+COPY --from=builder /go/src/github.com/hyperledger/burrow/bin/burrow /usr/local/bin/
 
-# Expose ports for 26656:tendermint-peer; 26658: tm; 10997 GRPC
+# Expose ports for 26656:peer; 26658:info; 10997:grpc
 EXPOSE 26656
 EXPOSE 26658
 EXPOSE 10997
 
+USER $USER:$USER
 ENTRYPOINT [ "burrow" ]
diff --git a/Gopkg.lock b/Gopkg.lock
index 6839e35eda685de59760984f46ecbd7ffb7902c9..39bc61be055d7c67415bddc349cbad63666cebbc 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -2,7 +2,7 @@
 
 
 [[projects]]
-  digest = "1:e0499b93857a1b91efbdc0c21e26f1130685de98035008f3b01eeeb0713798cb"
+  digest = "1:167b6f65a6656de568092189ae791253939f076df60231fdd64588ac703892a1"
   name = "github.com/BurntSushi/toml"
   packages = ["."]
   pruneopts = "NUT"
@@ -35,7 +35,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:ad87504ef74b1c36880f9287126dbc8dc4146d86acf902dd776ac6064cc75396"
+  digest = "1:5150d33e061d3af9440f2fdad3f82456cb142b3200ce77e0bc2ffef90eef0b0c"
   name = "github.com/btcsuite/btcd"
   packages = ["btcec"]
   pruneopts = "NUT"
@@ -105,7 +105,7 @@
   version = "v1.4.7"
 
 [[projects]]
-  digest = "1:2c03593aec9fa7d6969dc7295c636b46369ec2dd45dcf4acfb298281d62528ff"
+  digest = "1:4956b2f82cd1045ccded4db070821b3b6b8fbc8628d4d63de90128ea56efcdfb"
   name = "github.com/go-kit/kit"
   packages = [
     "log",
@@ -129,7 +129,7 @@
   version = "v0.3.0"
 
 [[projects]]
-  digest = "1:a82caecb6d771d89e452ddf2721e3e37cb247d72202ed983cbcbab4152d9324b"
+  digest = "1:4c59c7d491a28441d9f8b1c78d861021b13562e7e6cb3a8f258cc6703b244a31"
   name = "github.com/go-ozzo/ozzo-validation"
   packages = [
     ".",
@@ -148,7 +148,7 @@
   version = "v1.7.0"
 
 [[projects]]
-  digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45"
+  digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
   name = "github.com/gogo/protobuf"
   packages = [
     "gogoproto",
@@ -163,7 +163,7 @@
   version = "v1.1.1"
 
 [[projects]]
-  digest = "1:713cc7628304d027a7e9edcb52da888a8912d6405250a8d9c8eff6f41dd54398"
+  digest = "1:03e14cff610a8a58b774e36bd337fa979482be86aab01be81fb8bbd6d0f07fc8"
   name = "github.com/golang/protobuf"
   packages = [
     "proto",
@@ -194,7 +194,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:02e4365951e1bc55bd6505938ea88e12b5a9d5dfedcb1ae35d5a3833e502833e"
+  digest = "1:11c6c696067d3127ecf332b10f89394d386d9083f82baf71f40f2da31841a009"
   name = "github.com/hashicorp/hcl"
   packages = [
     ".",
@@ -236,7 +236,7 @@
   version = "v0.3.6"
 
 [[projects]]
-  digest = "1:fa8175fc1639f717d9462d6c507d92b174662db600997f1b4a92aae0571c23de"
+  digest = "1:c7ef3ee638cc1e5d39c2b1d9874183ecc62e4822c9524360bc8fbdc3139ab4c3"
   name = "github.com/jawher/mow.cli"
   packages = [
     ".",
@@ -325,7 +325,7 @@
   version = "v1.0.0"
 
 [[projects]]
-  digest = "1:76463f8d9f141bb3673ccece5fb0d1d0f9588395e94d01253667db733f865b18"
+  digest = "1:a16a1797cf7077c68a7a312ab68f1349b5ba2ca926a383d4b17c272b6ee97e15"
   name = "github.com/prometheus/client_golang"
   packages = [
     "prometheus",
@@ -336,7 +336,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a"
+  digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
   name = "github.com/prometheus/client_model"
   packages = ["go"]
   pruneopts = "NUT"
@@ -344,7 +344,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:edddf4ceb3a45778dfbb9364f128fffd92ea9bd6abd70edf1474f56565832682"
+  digest = "1:fad5a35eea6a1a33d6c8f949fbc146f24275ca809ece854248187683f52cc30b"
   name = "github.com/prometheus/common"
   packages = [
     "expfmt",
@@ -356,7 +356,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:37e418257b05a9e9fabbf836df2d8f3613313e80a909da6b9597b759ebca61cd"
+  digest = "1:6621142cd60b7150ab66f38ff36303ca55843dc5a635c1f9a28f95ecddab72b4"
   name = "github.com/prometheus/procfs"
   packages = [
     ".",
@@ -384,7 +384,7 @@
   version = "v1.0.6"
 
 [[projects]]
-  digest = "1:a36d61943d51cd4a1d7ecaf6993190527535a57382114ebf6549956b3e4cb612"
+  digest = "1:330e9062b308ac597e28485699c02223bd052437a6eed32a173c9227dcb9d95a"
   name = "github.com/spf13/afero"
   packages = [
     ".",
@@ -435,7 +435,7 @@
   revision = "6617b501e485b77e61b98cd533aefff9e258b5a7"
 
 [[projects]]
-  digest = "1:a7cb71e7cef4a320ae6d91424df8f991ed4161aede6dea7ba8d8f3af1b589a6c"
+  digest = "1:0331452965d8695c0a5633e0f509012987681a654f388f2ad0c3b2d7f7004b1c"
   name = "github.com/stretchr/testify"
   packages = [
     "assert",
@@ -447,7 +447,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65"
+  digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
   name = "github.com/syndtr/goleveldb"
   packages = [
     "leveldb",
@@ -468,7 +468,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232"
+  digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722"
   name = "github.com/tendermint/ed25519"
   packages = [
     ".",
@@ -487,15 +487,15 @@
   version = "0.10.1"
 
 [[projects]]
-  digest = "1:5a2904670bdaf13e71cd3a726795b2d0ee65a0862d499a1440799bd62618efac"
+  digest = "1:76c7684f6ff9b92dd8f934ad853838e207ab4b7d68927f95f5ba785d8bea56d2"
   name = "github.com/tendermint/iavl"
   packages = ["."]
   pruneopts = "NUT"
-  revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
-  version = "v0.9.2"
+  revision = "e5726c0066ccdd299a2ec9262f93c7896cdfcd87"
+  version = "v0.10.0"
 
 [[projects]]
-  digest = "1:eeaef9ab6a6bc08d1a5b9d1184caf2471b5511c1a8f0d4106b46325ec97bd588"
+  digest = "1:77fa9bc72848b93790fdad4f728f4ae36a905a51d6056dc72752889157fc37c0"
   name = "github.com/tendermint/tendermint"
   packages = [
     "abci/client",
@@ -544,8 +544,8 @@
     "version",
   ]
   pruneopts = "UT"
-  revision = "d542d2c3945116697f60451e6a407082c41c3cc9"
-  version = "v0.22.8"
+  revision = "013b9cef642f875634c614019ab13b17570778ad"
+  version = "v0.23.0"
 
 [[projects]]
   branch = "master"
@@ -565,12 +565,15 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:d5ffbaa51e280341d8ae252ac4b08b1de5daaa9373542e6a44437866a6d5bcc5"
+  digest = "1:fda2fde01556c582685ab0a5cf270ea0bd657f572fbdfc89b9acc31e1d48dc8a"
   name = "golang.org/x/crypto"
   packages = [
+    "chacha20poly1305",
     "curve25519",
     "ed25519",
     "ed25519/internal/edwards25519",
+    "hkdf",
+    "internal/chacha20",
     "internal/subtle",
     "nacl/box",
     "nacl/secretbox",
@@ -585,7 +588,7 @@
   revision = "de0752318171da717af4ce24d0a2e8626afaeb11"
 
 [[projects]]
-  digest = "1:15dbe437d38eb2103f6b55348758958a6f85a400ecc16fcb53b3f271d38cd8ea"
+  digest = "1:2822b75330f8a787dca2f7d861788811676b2c50cea125851bbe32e9fd31624c"
   name = "golang.org/x/net"
   packages = [
     "context",
@@ -602,7 +605,7 @@
 
 [[projects]]
   branch = "master"
-  digest = "1:8e423261417f9a621f0977b216f435619e72cca646191f6194fb5541f7dd849a"
+  digest = "1:60bc8320b223dd61541ea3d359a4dc241817695c826d571e2da23ae79f5521b7"
   name = "golang.org/x/sys"
   packages = [
     "cpu",
@@ -613,7 +616,7 @@
   revision = "1c9583448a9c3aa0f9a6a5241bf73c0bd8aafded"
 
 [[projects]]
-  digest = "1:a0f29009397dc27c9dc8440f0945d49e5cbb9b72d0b0fc745474d9bfdea2d9f8"
+  digest = "1:e7071ed636b5422cc51c0e3a6cebc229d6c9fffc528814b519a980641422d619"
   name = "golang.org/x/text"
   packages = [
     "collate",
@@ -644,7 +647,7 @@
   revision = "d0a8f471bba2dbb160885b0000d814ee5d559bad"
 
 [[projects]]
-  digest = "1:f778941d5c2e46da5e0f5d553d3e80bf70eb40d2e80bb4c649b625b9133f3d5f"
+  digest = "1:d0e5846da58e4e20d1bbd7502b24f31d37e3ac1e02a9042d95bd93c2d0c139dd"
   name = "google.golang.org/grpc"
   packages = [
     ".",
diff --git a/Gopkg.toml b/Gopkg.toml
index 578b1cade9e07a7c77e244c15248c1df0f7a37c6..6b27396f3916bd79b9cef92f69777ba7e76fd5e1 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -16,15 +16,11 @@
 # overriding here because of IAVL
 [[override]]
   name = "github.com/tendermint/tendermint"
-  version = "=0.22.8"
+  version = "=0.23.0"
 
-[[override]]
+[[constraint]]
   name = "github.com/tendermint/iavl"
-  version = "=0.9.2"
-
-#[[constraint]]
-#  name = "github.com/prometheus/client_golang"
-#  branch = "master"
+  version = "=0.10.0"
 
 # Haven't made a release since 2016.
 [[constraint]]
diff --git a/Makefile b/Makefile
index 9a8a744cb19fbe024a3ebb94583daa9ec07e7f37..60c4db3e90bae3442ca0e7d0b69d9485f70db81e 100644
--- a/Makefile
+++ b/Makefile
@@ -115,21 +115,21 @@ commit_hash:
 
 # build all targets in github.com/hyperledger/burrow
 .PHONY: build
-build:	check build_db
+build:	check build_burrow
 
 # build all targets in github.com/hyperledger/burrow with checks for race conditions
 .PHONY: build_race
 build_race:	check build_race_db
 
 # build burrow
-.PHONY: build_db
-build_db: commit_hash
+.PHONY: build_burrow
+build_burrow: commit_hash
 	go build -ldflags "-extldflags '-static' \
 	-X github.com/hyperledger/burrow/project.commit=$(shell cat commit_hash.txt)" \
 	-o ${REPO}/bin/burrow ./cmd/burrow
 
-.PHONY: install_db
-install_db: build_db
+.PHONY: install_burrow
+install_burrow: build_burrow
 	cp ${REPO}/bin/burrow ${GOPATH}/bin/burrow
 
 # build burrow with checks for race conditions
@@ -168,7 +168,7 @@ test: check bin/solc
 	@tests/scripts/bin_wrapper.sh go test ./... ${GOPACKAGES_NOVENDOR}
 
 .PHONY: test_keys
-test_keys: build_db
+test_keys: build_burrow
 	burrow_bin="${REPO}/bin/burrow" keys/test.sh
 
 rpc/test/strange_loop.go: integration/rpctest
@@ -186,7 +186,7 @@ test_deploy: bin/solc
 # Run integration test from bosmarmot (separated from other integration tests so we can
 # make exception when this test fails when we make a breaking change in Burrow)
 .PHONY: test_integration_bosmarmot
-test_integration_bosmarmot: bos build_db
+test_integration_bosmarmot: bos build_burrow
 	cd "${BOSMARMOT_CHECKOUT}" &&\
 	make npm_install && \
 	GOPATH="${BOSMARMOT_GOPATH}" \
@@ -235,7 +235,7 @@ tag_release: test check CHANGELOG.md NOTES.md build
 	@scripts/tag_release.sh
 
 .PHONY: release
-release: docs check test
+release: docs check test docker_build
 	@scripts/is_checkout_dirty.sh || (echo "checkout is dirty so not releasing!" && exit 1)
 	@scripts/release.sh
 
diff --git a/NOTES.md b/NOTES.md
index a8b5c487f5632087fe377735ff55ccb598e0a10e..433102bc2379b725805f6a663690a31edadb6ad8 100644
--- a/NOTES.md
+++ b/NOTES.md
@@ -1,21 +1,13 @@
 ### Changed
-- The snatives functions have new signatures; string arguments are now string, not byte32.
-- The Solidity interface contracts can be generated using the "burrow snatives" command, and the make snatives target is gone.
-
-### Fixed
-- TxExecutions that were exceptions (for example those that were REVERTed) will no longer have their events emitted from ExecutionEventsServer.GetEvents. They remain stored in state for the time being.
-- CallTxSim and CallCodeSim now take same code path as real transactions (via CallContext)
+- Upgraded to Tendermint 0.23.0
+- Validator Set Power now takes Address
+- RPC/TM config renamed to RPC/Info
 
 ### Added
-- Upgraded to Tendermint [0.22.8](https://github.com/tendermint/tendermint/compare/v0.22.4...v0.22.8) (from 0.22.4).
-- Support mempool signing for BroadcastTxAsync.
-- Reload log file (e.g. for logrotate) on SIGHUP and dump capture logs on SIGUSR1 and on shutdown (e.g. for debug).
-- File logger accepts {{.Timestamp}} in file names to generate a log file per run.
-- Ability to set --external-address on burrow configure and burrow start
-- Ability to set various command line options on burrow configure and burrow start and by BURROW_ prefixed environment variables
-- Exposed Tendermint SeedMode option
-
+- Burrow deploy creates devdoc
+- Docker image has org.label-schema labels
 
 ### Fixed
-- Release our mempool signing lock once transactions have been CheckTx'd' to massively increase throughput.
+- Upgrade to IAVL 0.10.0 and load previous versions immutably on boot - for chains with a long history > 20 minute load times could be observed because every previous root was being loaded from DB rather than lightweight version references as was intended
+- Metrics server does not panic on empty block metas and recovers from other panics
 
diff --git a/acm/validator/ring.go b/acm/validator/ring.go
index 81a0ab45e9860d27d1d9f9811404126718c1818e..635caed51296c89c6873bba2b329347970488b67 100644
--- a/acm/validator/ring.go
+++ b/acm/validator/ring.go
@@ -50,7 +50,7 @@ func NewRing(initialSet Iterable, windowSize int) *Ring {
 
 // Implement Reader
 // Get power at index from the delta bucket then falling through to the cumulative
-func (vc *Ring) PowerAt(index int64, id crypto.PublicKey) *big.Int {
+func (vc *Ring) PowerAt(index int64, id crypto.Address) *big.Int {
 	power := vc.Head().MaybePower(id)
 	if power != nil {
 		return power
@@ -58,7 +58,7 @@ func (vc *Ring) PowerAt(index int64, id crypto.PublicKey) *big.Int {
 	return vc.Cum().Power(id)
 }
 
-func (vc *Ring) Power(id crypto.PublicKey) *big.Int {
+func (vc *Ring) Power(id crypto.Address) *big.Int {
 	return vc.PowerAt(vc.head, id)
 }
 
@@ -87,7 +87,7 @@ func (vc *Ring) AlterPower(id crypto.PublicKey, power *big.Int) (*big.Int, error
 			"does not", power)
 	}
 	// if flow > maxflow then we cannot alter the power
-	flow := vc.Flow(id, power)
+	flow := vc.Flow(id.Address(), power)
 	maxFlow := vc.MaxFlow()
 	// Set flow for this id to update flow.totalPower (total flow) for comparison below, keep track of flow for each id
 	// so that we only count flow once for each id
@@ -95,13 +95,13 @@ func (vc *Ring) AlterPower(id crypto.PublicKey, power *big.Int) (*big.Int, error
 	// The totalPower of the Flow Set is the absolute value of all power changes made so far
 	if vc.flow.totalPower.Cmp(maxFlow) == 1 {
 		// Reset flow to previous value to undo update above
-		prevFlow := vc.Flow(id, vc.Head().Power(id))
+		prevFlow := vc.Flow(id.Address(), vc.Head().Power(id.Address()))
 		vc.flow.ChangePower(id, prevFlow)
 		allowable := new(big.Int).Sub(maxFlow, vc.flow.totalPower)
 		return nil, fmt.Errorf("cannot change validator power of %v from %v to %v because that would result in a flow "+
 			"greater than or equal to 1/3 of total power for the next commit: flow induced by change: %v, "+
 			"current total flow: %v/%v (cumulative/max), remaining allowable flow: %v",
-			id.Address(), vc.Cum().Power(id), power, flow, vc.flow.totalPower, maxFlow, allowable)
+			id.Address(), vc.Cum().Power(id.Address()), power, flow, vc.flow.totalPower, maxFlow, allowable)
 	}
 	// Add to total power
 	vc.Head().ChangePower(id, power)
@@ -109,7 +109,7 @@ func (vc *Ring) AlterPower(id crypto.PublicKey, power *big.Int) (*big.Int, error
 }
 
 // Returns the flow that would be induced by a validator change by comparing the head accumulater with the current set
-func (vc *Ring) Flow(id crypto.PublicKey, power *big.Int) *big.Int {
+func (vc *Ring) Flow(id crypto.Address, power *big.Int) *big.Int {
 	flow := new(big.Int)
 	return flow.Abs(flow.Sub(power, vc.Cum().Power(id)))
 }
diff --git a/acm/validator/set.go b/acm/validator/set.go
index 52bd7c83fc69bc601364ba9a68f2a77cb4a1ff24..24b68ea2604fa36b55ca5e8cfa515599d64d1619 100644
--- a/acm/validator/set.go
+++ b/acm/validator/set.go
@@ -49,7 +49,7 @@ func (vs *Set) AlterPower(id crypto.PublicKey, power *big.Int) (flow *big.Int, e
 func (vs *Set) ChangePower(id crypto.PublicKey, power *big.Int) *big.Int {
 	address := id.Address()
 	// Calculcate flow into this validator (postive means in, negative means out)
-	flow := new(big.Int).Sub(power, vs.Power(id))
+	flow := new(big.Int).Sub(power, vs.Power(id.Address()))
 	vs.totalPower.Add(vs.totalPower, flow)
 
 	if vs.trim && power.Sign() == 0 {
@@ -67,18 +67,18 @@ func (vs *Set) TotalPower() *big.Int {
 }
 
 // Returns the power of id but only if it is set
-func (vs *Set) MaybePower(id crypto.PublicKey) *big.Int {
-	if vs.powers[id.Address()] == nil {
+func (vs *Set) MaybePower(id crypto.Address) *big.Int {
+	if vs.powers[id] == nil {
 		return nil
 	}
-	return new(big.Int).Set(vs.powers[id.Address()])
+	return new(big.Int).Set(vs.powers[id])
 }
 
-func (vs *Set) Power(id crypto.PublicKey) *big.Int {
-	if vs.powers[id.Address()] == nil {
+func (vs *Set) Power(id crypto.Address) *big.Int {
+	if vs.powers[id] == nil {
 		return new(big.Int)
 	}
-	return new(big.Int).Set(vs.powers[id.Address()])
+	return new(big.Int).Set(vs.powers[id])
 }
 
 func (vs *Set) Equal(vsOther *Set) bool {
@@ -87,7 +87,7 @@ func (vs *Set) Equal(vsOther *Set) bool {
 	}
 	// Stop iteration IFF we find a non-matching validator
 	return !vs.Iterate(func(id crypto.Addressable, power *big.Int) (stop bool) {
-		otherPower := vsOther.Power(id.PublicKey())
+		otherPower := vsOther.Power(id.Address())
 		if otherPower.Cmp(power) != 0 {
 			return true
 		}
diff --git a/acm/validator/validators.go b/acm/validator/validators.go
index dece3c6677d632f33de4fdc35a86c924f7ffdaa9..efaa64f7e2cc6d940a0f613ada506944969fc4cb 100644
--- a/acm/validator/validators.go
+++ b/acm/validator/validators.go
@@ -13,7 +13,7 @@ type Writer interface {
 }
 
 type Reader interface {
-	Power(id crypto.PublicKey) *big.Int
+	Power(id crypto.Address) *big.Int
 }
 
 type Iterable interface {
@@ -51,12 +51,12 @@ func (wf WriterFunc) AlterPower(id crypto.PublicKey, power *big.Int) (flow *big.
 
 func AddPower(vs ReaderWriter, id crypto.PublicKey, power *big.Int) error {
 	// Current power + power
-	_, err := vs.AlterPower(id, new(big.Int).Add(vs.Power(id), power))
+	_, err := vs.AlterPower(id, new(big.Int).Add(vs.Power(id.Address()), power))
 	return err
 }
 
 func SubtractPower(vs ReaderWriter, id crypto.PublicKey, power *big.Int) error {
-	_, err := vs.AlterPower(id, new(big.Int).Sub(vs.Power(id), power))
+	_, err := vs.AlterPower(id, new(big.Int).Sub(vs.Power(id.Address()), power))
 	return err
 }
 
diff --git a/bcm/blockchain_test.go b/bcm/blockchain_test.go
index c5f5bc62761a1d4cbd06b1613849dad90682dc16..c2807566e19e9388799bfefdf9d2ee6a73536dbe 100644
--- a/bcm/blockchain_test.go
+++ b/bcm/blockchain_test.go
@@ -44,7 +44,7 @@ func TestBlockchain_Encode(t *testing.T) {
 
 	// Should have exponentially decayed to 0
 	assertZero(t, flow)
-	assertZero(t, bc.validatorCache.Power(id1))
+	assertZero(t, bc.validatorCache.Power(id1.Address()))
 }
 
 // Since we have -0 and 0 with big.Int due to its representation with a neg flag
diff --git a/consensus/tendermint/abci/app.go b/consensus/tendermint/abci/app.go
index cbacbc94ed70f77d13623b312376535d7173b201..6afb9b96a09f38d9a62fa4983365f876c5105b43 100644
--- a/consensus/tendermint/abci/app.go
+++ b/consensus/tendermint/abci/app.go
@@ -3,10 +3,8 @@ package abci
 import (
 	"fmt"
 	"math/big"
-	"sync"
-	"time"
-
 	"runtime/debug"
+	"sync"
 
 	"github.com/hyperledger/burrow/acm/validator"
 	"github.com/hyperledger/burrow/bcm"
@@ -116,12 +114,12 @@ func (app *App) BeginBlock(block abciTypes.RequestBeginBlock) (respBeginBlock ab
 		var err error
 		// Tendermint runs a block behind with the validators passed in here
 		previousValidators := app.blockchain.PreviousValidators()
-		if len(block.Validators) != previousValidators.Count() {
+		if len(block.LastCommitInfo.Validators) != previousValidators.Count() {
 			err = fmt.Errorf("Tendermint passes %d validators to BeginBlock but Burrow's Blockchain has %d",
-				len(block.Validators), previousValidators.Count())
+				len(block.LastCommitInfo.Validators), previousValidators.Count())
 			panic(err)
 		}
-		for _, v := range block.Validators {
+		for _, v := range block.LastCommitInfo.Validators {
 			err = app.checkValidatorMatches(previousValidators, v.Validator)
 			if err != nil {
 				panic(err)
@@ -132,14 +130,14 @@ func (app *App) BeginBlock(block abciTypes.RequestBeginBlock) (respBeginBlock ab
 }
 
 func (app *App) checkValidatorMatches(ours validator.Reader, v abciTypes.Validator) error {
-	publicKey, err := crypto.PublicKeyFromABCIPubKey(v.PubKey)
+	address, err := crypto.AddressFromBytes(v.Address)
 	if err != nil {
 		return err
 	}
-	power := ours.Power(publicKey)
+	power := ours.Power(address)
 	if power.Cmp(big.NewInt(v.Power)) != 0 {
 		return fmt.Errorf("validator %v has power %d from Tendermint but power %d from Burrow",
-			publicKey.Address(), v.Power, power)
+			address, v.Power, power)
 	}
 	return nil
 }
@@ -167,7 +165,6 @@ func (app *App) DeliverTx(txBytes []byte) abciTypes.ResponseDeliverTx {
 		Log:       ctr.Log,
 		Data:      ctr.Data,
 		Tags:      ctr.Tags,
-		Fee:       ctr.Fee,
 		GasUsed:   ctr.GasUsed,
 		GasWanted: ctr.GasWanted,
 		Info:      ctr.Info,
@@ -241,7 +238,7 @@ func (app *App) Commit() abciTypes.ResponseCommit {
 			app.panicFunc(fmt.Errorf("panic occurred in abci.App/Commit: %v\n%s", r, debug.Stack()))
 		}
 	}()
-	blockTime := time.Unix(app.block.Header.Time, 0)
+	blockTime := app.block.Header.Time
 	app.logger.InfoMsg("Committing block",
 		"tag", "Commit",
 		structure.ScopeKey, "Commit()",
diff --git a/consensus/tendermint/priv_validator_memory.go b/consensus/tendermint/priv_validator_memory.go
index 5c2c965133227083491404427b74edc8627c2e74..eda6a312a29244f65d5164eef7cfa5f24e2ee087 100644
--- a/consensus/tendermint/priv_validator_memory.go
+++ b/consensus/tendermint/priv_validator_memory.go
@@ -8,7 +8,7 @@ import (
 
 type privValidatorMemory struct {
 	crypto.Addressable
-	signer         func(msg []byte) tmCrypto.Signature
+	signer         func(msg []byte) []byte
 	lastSignedInfo *LastSignedInfo
 }
 
@@ -24,8 +24,8 @@ func NewPrivValidatorMemory(addressable crypto.Addressable, signer crypto.Signer
 	}
 }
 
-func asTendermintSigner(signer crypto.Signer) func(msg []byte) tmCrypto.Signature {
-	return func(msg []byte) tmCrypto.Signature {
+func asTendermintSigner(signer crypto.Signer) func(msg []byte) []byte {
+	return func(msg []byte) []byte {
 		sig, err := signer.Sign(msg)
 		if err != nil {
 			return nil
diff --git a/consensus/tendermint/sign_info.go b/consensus/tendermint/sign_info.go
index 1cc075ed99b73622170371b6b3946542d74b8fd0..1fce0718ad486c66cf2cb469269d514f9a58c470 100644
--- a/consensus/tendermint/sign_info.go
+++ b/consensus/tendermint/sign_info.go
@@ -8,7 +8,6 @@ import (
 	"time"
 
 	"github.com/hyperledger/burrow/binary"
-	"github.com/tendermint/tendermint/crypto"
 	"github.com/tendermint/tendermint/types"
 )
 
@@ -36,11 +35,11 @@ func voteToStep(vote *types.Vote) int8 {
 // data signed by a validator to help prevent double signing.
 type LastSignedInfo struct {
 	sync.Mutex
-	Height    int64            `json:"height"`
-	Round     int              `json:"round"`
-	Step      int8             `json:"step"`
-	Signature crypto.Signature `json:"signature,omitempty"` // so we dont lose signatures
-	SignBytes binary.HexBytes  `json:"signbytes,omitempty"` // so we dont lose signatures
+	Height    int64           `json:"height"`
+	Round     int             `json:"round"`
+	Step      int8            `json:"step"`
+	Signature []byte          `json:"signature,omitempty"` // so we dont lose signatures
+	SignBytes binary.HexBytes `json:"signbytes,omitempty"` // so we dont lose signatures
 }
 
 func NewLastSignedInfo() *LastSignedInfo {
@@ -49,7 +48,7 @@ func NewLastSignedInfo() *LastSignedInfo {
 	}
 }
 
-type tmCryptoSigner func(msg []byte) crypto.Signature
+type tmCryptoSigner func(msg []byte) []byte
 
 // SignVote signs a canonical representation of the vote, along with the
 // chainID. Implements PrivValidator.
@@ -175,7 +174,7 @@ func (lsi *LastSignedInfo) signProposal(sign tmCryptoSigner, chainID string, pro
 
 // Persist height/round/step and signature
 func (lsi *LastSignedInfo) saveSigned(height int64, round int, step int8,
-	signBytes []byte, sig crypto.Signature) {
+	signBytes []byte, sig []byte) {
 
 	lsi.Height = height
 	lsi.Round = round
diff --git a/core/kernel.go b/core/kernel.go
index f73125f64232d05e3cd0c18084c4c51ed4c6499e..4f7df7cc69365987e7c6f3895c5ea99c2e9417ce 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -125,7 +125,10 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tmTy
 	app := abci.NewApp(kern.nodeInfo, kern.Blockchain, checker, committer, txCodec, kern.Panic, logger)
 	// We could use this to provide/register our own metrics (though this will register them with us). Unfortunately
 	// Tendermint currently ignores the metrics passed unless its own server is turned on.
-	metricsProvider := node.DefaultMetricsProvider
+	metricsProvider := node.DefaultMetricsProvider(&tmConfig.InstrumentationConfig{
+		Prometheus:           false,
+		PrometheusListenAddr: "",
+	})
 	kern.Node, err = tendermint.NewNode(tmConf, privValidator, tmGenesisDoc, app, metricsProvider, tmLogger)
 	if err != nil {
 		return nil, err
@@ -197,10 +200,10 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tmTy
 			},
 		},
 		{
-			Name:    "RPC/tm",
-			Enabled: rpcConfig.TM.Enabled,
+			Name:    "RPC/info",
+			Enabled: rpcConfig.Info.Enabled,
 			Launch: func() (process.Process, error) {
-				server, err := rpcinfo.StartServer(kern.Service, "/websocket", rpcConfig.TM.ListenAddress, kern.Logger)
+				server, err := rpcinfo.StartServer(kern.Service, "/websocket", rpcConfig.Info.ListenAddress, kern.Logger)
 				if err != nil {
 					return nil, err
 				}
diff --git a/crypto/tendermint.go b/crypto/tendermint.go
index a886880391134411be47bc4d80161b99ca63b77f..f7265ba684fe11f2e0f2a5e9a790e1b29c4b616c 100644
--- a/crypto/tendermint.go
+++ b/crypto/tendermint.go
@@ -63,17 +63,6 @@ func (p PublicKey) TendermintPubKey() tmCrypto.PubKey {
 
 // Signature extensions
 
-func (sig Signature) TendermintSignature() tmCrypto.Signature {
-	switch sig.CurveType {
-	case CurveTypeEd25519:
-		s := tmEd25519.SignatureEd25519{}
-		copy(s[:], sig.Signature)
-		return s
-	case CurveTypeSecp256k1:
-		s := tmSecp256k1.SignatureSecp256k1{}
-		copy(s[:], sig.Signature)
-		return s
-	default:
-		return nil
-	}
+func (sig Signature) TendermintSignature() []byte {
+	return sig.Signature
 }
diff --git a/deploy/def/jobs.go b/deploy/def/jobs.go
index 4f4ba4c00fb3e0cff56563c5707d3d4e60ee5892..a3bbe5f1eaf140d73ea6c50c07185c2357ffaf57 100644
--- a/deploy/def/jobs.go
+++ b/deploy/def/jobs.go
@@ -213,6 +213,16 @@ type Build struct {
 	// compilers but rather will just be sent to the chain. Note, if you use a "call" job after deploying
 	// a binary contract then you will be **required** to utilize an abi field in the call job.
 	Contract string `mapstructure:"contract" json:"contract" yaml:"contract" toml:"contract"`
+	// (Optional) where to save the result of the compilation
+	BinPath string `mapstructure:"binpath" json:"binpath" yaml:"binpath" toml:"binpath"`
+	// (Optional) the name of contract to instantiate (it has to be one of the contracts present)
+	// in the file defined in Contract above.
+	// When none is provided, the system will choose the contract with the same name as that file.
+	// use "all" to override and deploy all contracts in order. if "all" is selected the result
+	// of the job will default to the address of the contract which was deployed that matches
+	// the name of the file (or the last one deployed if there are no matching names; not the "last"
+	// one deployed" strategy is non-deterministic and should not be used).
+	Instance string `mapstructure:"instance" json:"instance" yaml:"instance" toml:"instance"`
 }
 
 func (job *Build) Validate() error {
diff --git a/deploy/jobs/job_manager.go b/deploy/jobs/job_manager.go
index 151f89bde567607dd0f832c86fd1cedd035b7d1c..1cd15befd7de9ae6eaa0c444c350f57fe2db0832 100644
--- a/deploy/jobs/job_manager.go
+++ b/deploy/jobs/job_manager.go
@@ -10,12 +10,20 @@ import (
 )
 
 func RunJobs(do *def.Packages) error {
-	// Dial the chain
-	err := do.Dial()
+
+	// Dial the chain if needed
+	err, needed := burrowConnectionNeeded(do)
 	if err != nil {
 		return err
 	}
 
+	if needed {
+		err = do.Dial()
+		if err != nil {
+			return err
+		}
+	}
+
 	// ADD DefaultAddr and DefaultSet to jobs array....
 	// These work in reverse order and the addendums to the
 	// the ordering from the loading process is lifo
@@ -205,3 +213,23 @@ func postProcess(do *def.Packages) error {
 	log.Warn(fmt.Sprintf("Writing [%s] to current directory", do.DefaultOutput))
 	return WriteJobResultJSON(results, do.DefaultOutput)
 }
+
+func burrowConnectionNeeded(do *def.Packages) (error, bool) {
+	// Dial the chain if needed
+	for _, job := range do.Package.Jobs {
+		payload, err := job.Payload()
+		if err != nil {
+			return fmt.Errorf("could not get Job payload: %v", payload), false
+		}
+		switch payload.(type) {
+		case *def.Build:
+			continue
+		case *def.Set:
+			continue
+		default:
+			return nil, true
+		}
+	}
+
+	return nil, false
+}
diff --git a/deploy/jobs/jobs_contracts.go b/deploy/jobs/jobs_contracts.go
index f3f462938501d9c65f74e9b4e7314a7e71bc158f..ce6427418cf1519e83556318d67843862b8131af 100644
--- a/deploy/jobs/jobs_contracts.go
+++ b/deploy/jobs/jobs_contracts.go
@@ -40,25 +40,39 @@ func BuildJob(build *def.Build, do *def.Packages) (result string, err error) {
 	}
 
 	// Save
-	if _, err := os.Stat(do.BinPath); os.IsNotExist(err) {
-		if err := os.Mkdir(do.BinPath, 0775); err != nil {
+	binPath := build.BinPath
+	if binPath == "" {
+		binPath = do.BinPath
+	}
+	if _, err := os.Stat(binPath); os.IsNotExist(err) {
+		if err := os.Mkdir(binPath, 0775); err != nil {
 			return "", err
 		}
 	}
 
 	for _, res := range resp.Objects {
-		if res.Filename == contractPath {
-			// saving binary
-			b, err := json.Marshal(res.Binary)
-			if err != nil {
-				return "", err
+		switch build.Instance {
+		case "":
+			if res.Filename != contractPath {
+				continue
 			}
-			contractName := filepath.Join(do.BinPath, fmt.Sprintf("%s.bin", res.Objectname))
-			log.WithField("=>", contractName).Warn("Saving Binary")
-			if err := ioutil.WriteFile(contractName, b, 0664); err != nil {
-				return "", err
+		case "all":
+		default:
+			if res.Objectname != build.Instance {
+				continue
 			}
 		}
+
+		// saving binary
+		b, err := json.Marshal(res.Binary)
+		if err != nil {
+			return "", err
+		}
+		contractName := filepath.Join(binPath, fmt.Sprintf("%s.bin", res.Objectname))
+		log.WithField("=>", contractName).Warn("Saving Binary")
+		if err := ioutil.WriteFile(contractName, b, 0664); err != nil {
+			return "", err
+		}
 	}
 
 	return "", nil
diff --git a/event/pubsub/pubsub_test.go b/event/pubsub/pubsub_test.go
index d9275e0080ac53908f11682da62c4f379ee9fdd1..76525243da18aae49abbc244a93981e203c380d4 100644
--- a/event/pubsub/pubsub_test.go
+++ b/event/pubsub/pubsub_test.go
@@ -111,11 +111,11 @@ func TestResubscribe(t *testing.T) {
 	defer s.Stop()
 
 	ctx := context.Background()
-	ch, err := s.Subscribe(ctx, clientID, query.Empty{}, 0)
+	ch, err := s.Subscribe(ctx, clientID, query.Empty{}, 1)
 	require.NoError(t, err)
 	err = s.Unsubscribe(ctx, clientID, query.Empty{})
 	require.NoError(t, err)
-	ch, err = s.Subscribe(ctx, clientID, query.Empty{}, 0)
+	ch, err = s.Subscribe(ctx, clientID, query.Empty{}, 1)
 	require.NoError(t, err)
 
 	err = s.Publish(ctx, "Cable")
diff --git a/execution/state.go b/execution/state.go
index b9717ef11d636297968783a758bdae0dac0455db..5cec4b7c856bf446f5a42b5636f22b18794fae6f 100644
--- a/execution/state.go
+++ b/execution/state.go
@@ -79,12 +79,12 @@ type State struct {
 	sync.RWMutex
 	writeState *writeState
 	db         dbm.DB
-	tree       *iavl.VersionedTree
+	tree       *iavl.MutableTree
 	logger     *logging.Logger
 
 	// Values may be reassigned (mutex protected)
 	// Previous version of IAVL tree for concurrent read-only access
-	readTree *iavl.Tree
+	readTree *iavl.ImmutableTree
 	// Last state hash
 	hash []byte
 }
@@ -93,7 +93,7 @@ type State struct {
 func NewState(db dbm.DB) *State {
 	s := &State{
 		db:   db,
-		tree: iavl.NewVersionedTree(db, defaultCacheCapacity),
+		tree: iavl.NewMutableTree(db, defaultCacheCapacity),
 	}
 	s.writeState = &writeState{state: s}
 	return s
@@ -168,15 +168,7 @@ func LoadState(db dbm.DB, hash []byte) (*State, error) {
 	if version <= 0 {
 		return nil, fmt.Errorf("trying to load state from non-positive version: version %v, hash: %X", version, hash)
 	}
-	// Load previous version for readTree
-	treeVersion, err := s.tree.LoadVersion(version - 1)
-	if err != nil {
-		return nil, fmt.Errorf("could not load previous version of state tree: %v", version-1)
-	}
-	// Set readTree
-	s.readTree = s.tree.Tree()
-	// Load previous version for readTree
-	treeVersion, err = s.tree.LoadVersion(version)
+	treeVersion, err := s.tree.LoadVersion(version)
 	if err != nil {
 		return nil, fmt.Errorf("could not load current version of state tree: version %v, hash: %X", version, hash)
 	}
@@ -184,6 +176,9 @@ func LoadState(db dbm.DB, hash []byte) (*State, error) {
 		return nil, fmt.Errorf("tried to load state version %v for state hash %X but loaded version %v",
 			version, hash, treeVersion)
 	}
+	// Load previous version for readTree
+	// Set readTree
+	s.readTree, err = s.tree.GetImmutable(version - 1)
 	return s, nil
 }
 
@@ -200,16 +195,16 @@ func (s *State) Update(updater func(up Updatable) error) ([]byte, error) {
 }
 
 func (ws *writeState) save() ([]byte, error) {
-	// Grab the current orphaning tree and save it for reads against committed state. Note that this tree will lazy
-	// load nodes from database (in-memory nodes are cleared when a version is saved - see SaveBranch in IAVL), however
-	// they are not cleared unless SaveBranch is called - and only LoadVersion/SaveVersion could do that which is a hack
-	ws.state.readTree = ws.state.tree.Tree()
-
 	// save state at a new version may still be orphaned before we save the version against the hash
 	hash, treeVersion, err := ws.state.tree.SaveVersion()
 	if err != nil {
 		return nil, err
 	}
+	// Take an immutable reference to the tree we just saved for querying
+	ws.state.readTree, err = ws.state.tree.GetImmutable(treeVersion)
+	if err != nil {
+		return nil, err
+	}
 
 	// Provide a reference to load this version in the future from the state hash
 	ws.SetVersion(hash, treeVersion)
diff --git a/integration/governance/governance_test.go b/integration/governance/governance_test.go
index dfa0928b7025b313120bd8cddcceda09c2527219..8be3036e998434dbb6aea0e605e78ca01502b8f1 100644
--- a/integration/governance/governance_test.go
+++ b/integration/governance/governance_test.go
@@ -175,7 +175,7 @@ func TestChangePowerByAddress(t *testing.T) {
 	vs, err := qcli.GetValidatorSet(context.Background(), &rpcquery.GetValidatorSetParam{})
 	require.NoError(t, err)
 	set := validator.UnpersistSet(vs.Set)
-	assert.Equal(t, new(big.Int).SetUint64(power), set.Power(acc.PublicKey()))
+	assert.Equal(t, new(big.Int).SetUint64(power), set.Power(acc.Address()))
 }
 
 func TestInvalidSequenceNumber(t *testing.T) {
diff --git a/integration/integration.go b/integration/integration.go
index 7c136f8ad9648ef1901add2894c48f599c5385da..883afde425dc66ea9e047267f500b2099ab59996 100644
--- a/integration/integration.go
+++ b/integration/integration.go
@@ -170,7 +170,7 @@ func NewTestConfig(genesisDoc *genesis.GenesisDoc) *config.BurrowConfig {
 	cnf.Tendermint.ExternalAddress = cnf.Tendermint.ListenAddress
 	cnf.RPC.GRPC.ListenAddress = GetLocalAddress()
 	cnf.RPC.Metrics.ListenAddress = GetTCPLocalAddress()
-	cnf.RPC.TM.ListenAddress = GetTCPLocalAddress()
+	cnf.RPC.Info.ListenAddress = GetTCPLocalAddress()
 	cnf.Keys.RemoteAddress = ""
 	return cnf
 }
diff --git a/integration/rpcinfo/main_test.go b/integration/rpcinfo/main_test.go
index 29f3f4749c79b13150830d69f0b10dab1b0fdfe9..dfd581c97302c84e644f9e46c76bb7ea26832d31 100644
--- a/integration/rpcinfo/main_test.go
+++ b/integration/rpcinfo/main_test.go
@@ -32,8 +32,8 @@ import (
 var kern *core.Kernel
 var _ = integration.ClaimPorts()
 var testConfig = integration.NewTestConfig(rpctest.GenesisDoc)
-var jsonRpcClient = rpcClient.NewJSONRPCClient(testConfig.RPC.TM.ListenAddress)
-var httpClient = rpcClient.NewURIClient(testConfig.RPC.TM.ListenAddress)
+var jsonRpcClient = rpcClient.NewJSONRPCClient(testConfig.RPC.Info.ListenAddress)
+var httpClient = rpcClient.NewURIClient(testConfig.RPC.Info.ListenAddress)
 var clients = map[string]tmClient.RPCClient{
 	"JSONRPC": jsonRpcClient,
 	"HTTP":    httpClient,
diff --git a/project/history.go b/project/history.go
index 160e215bce6f7a0d6ccdf52b8997aebb7885deb6..0e9bce2f1289ec874a91fab5abcb0143c6913600 100644
--- a/project/history.go
+++ b/project/history.go
@@ -29,7 +29,20 @@ func FullVersion() string {
 // To cut a new release add a release to the front of this slice then run the
 // release tagging script: ./scripts/tag_release.sh
 var History relic.ImmutableHistory = relic.NewHistory("Hyperledger Burrow", "https://github.com/hyperledger/burrow").
-	MustDeclareReleases(
+	MustDeclareReleases("0.21.0 - 2018-08-21",
+		`### Changed
+- Upgraded to Tendermint 0.23.0
+- Validator Set Power now takes Address
+- RPC/TM config renamed to RPC/Info
+
+### Added
+- Burrow deploy creates devdoc
+- Docker image has org.label-schema labels
+
+### Fixed
+- Upgrade to IAVL 0.10.0 and load previous versions immutably on boot - for chains with a long history > 20 minute load times could be observed because every previous root was being loaded from DB rather than lightweight version references as was intended
+- Metrics server does not panic on empty block metas and recovers from other panics
+`,
 		"0.20.1 - 2018-08-17",
 		`### Changed
 - The snatives functions have new signatures; string arguments are now string, not byte32.
@@ -38,6 +51,7 @@ var History relic.ImmutableHistory = relic.NewHistory("Hyperledger Burrow", "htt
 ### Fixed
 - TxExecutions that were exceptions (for example those that were REVERTed) will no longer have their events emitted from ExecutionEventsServer.GetEvents. They remain stored in state for the time being.
 - CallTxSim and CallCodeSim now take same code path as real transactions (via CallContext)
+- Release our mempool signing lock once transactions have been CheckTx'd' to massively increase throughput.
 
 ### Added
 - Upgraded to Tendermint [0.22.8](https://github.com/tendermint/tendermint/compare/v0.22.4...v0.22.8) (from 0.22.4).
@@ -47,10 +61,6 @@ var History relic.ImmutableHistory = relic.NewHistory("Hyperledger Burrow", "htt
 - Ability to set --external-address on burrow configure and burrow start
 - Ability to set various command line options on burrow configure and burrow start and by BURROW_ prefixed environment variables
 - Exposed Tendermint SeedMode option
-
-
-### Fixed
-- Release our mempool signing lock once transactions have been CheckTx'd' to massively increase throughput.
 `,
 		"0.20.0 - 2018-07-24",
 		`This is a major (pre-1.0.0) release that introduces the ability to change the validator set through GovTx, transaction execution history, and fuller GRPC endpoint.
diff --git a/rpc/config.go b/rpc/config.go
index 23bfbdbb763c48fae661f22ae9d686147866b45d..3763bb7985a9e92c617e4c4076c9f435c66ea4a8 100644
--- a/rpc/config.go
+++ b/rpc/config.go
@@ -7,7 +7,7 @@ import "fmt"
 const localhost = "127.0.0.1"
 
 type RPCConfig struct {
-	TM       *ServerConfig  `json:",omitempty" toml:",omitempty"`
+	Info     *ServerConfig  `json:",omitempty" toml:",omitempty"`
 	Profiler *ServerConfig  `json:",omitempty" toml:",omitempty"`
 	GRPC     *ServerConfig  `json:",omitempty" toml:",omitempty"`
 	Metrics  *MetricsConfig `json:",omitempty" toml:",omitempty"`
@@ -37,14 +37,14 @@ type MetricsConfig struct {
 
 func DefaultRPCConfig() *RPCConfig {
 	return &RPCConfig{
-		TM:       DefaultTMConfig(),
+		Info:     DefaultInfoConfig(),
 		Profiler: DefaultProfilerConfig(),
 		GRPC:     DefaultGRPCConfig(),
 		Metrics:  DefaultMetricsConfig(),
 	}
 }
 
-func DefaultTMConfig() *ServerConfig {
+func DefaultInfoConfig() *ServerConfig {
 	return &ServerConfig{
 		Enabled:       true,
 		ListenAddress: fmt.Sprintf("tcp://%s:26658", localhost),
diff --git a/rpc/metrics/export.go b/rpc/metrics/export.go
index 2487a0f746ea56639c345c6070072f642282850d..2ea9d7b7ee80a773a0603f0f0086df7ff94ccf88 100644
--- a/rpc/metrics/export.go
+++ b/rpc/metrics/export.go
@@ -14,6 +14,7 @@
 package metrics
 
 import (
+	"fmt"
 	"math"
 
 	"github.com/hyperledger/burrow/rpc"
@@ -107,6 +108,10 @@ func (e *Exporter) getBlocks() (*rpc.ResultBlocks, error) {
 		return nil, err
 	}
 
+	if !(len(res.BlockMetas) > 0) {
+		return nil, fmt.Errorf("no blocks returned")
+	}
+
 	return res, nil
 }
 
diff --git a/rpc/metrics/server.go b/rpc/metrics/server.go
index 5eab0754c58a243ebb9c6c1bda12515c3ebcc71f..b6dbe8b1280187e02e946a91b8f99211ee870384 100644
--- a/rpc/metrics/server.go
+++ b/rpc/metrics/server.go
@@ -71,7 +71,7 @@ func StartServer(service *rpc.Service, pattern, listenAddress string, blockSampl
 	prometheus.MustRegister(&exporter)
 
 	mux := http.NewServeMux()
-	mux.Handle(pattern, prometheus.Handler())
+	mux.Handle(pattern, server.RecoverAndLogHandler(prometheus.Handler(), logger))
 
 	srv, err := server.StartHTTPServer(listenAddress, mux, logger)
 	if err != nil {
diff --git a/rpc/result_test.go b/rpc/result_test.go
index bb2967f2cdd66e6c630e85fb00a0d76f6d40ea81..f086d897eaad968d58fb91b442e3fc26855fcdda 100644
--- a/rpc/result_test.go
+++ b/rpc/result_test.go
@@ -21,7 +21,6 @@ import (
 	"github.com/hyperledger/burrow/acm"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	tmEd25519 "github.com/tendermint/tendermint/crypto/ed25519"
 	tmTypes "github.com/tendermint/tendermint/types"
 )
 
@@ -48,7 +47,7 @@ func TestResultGetBlock(t *testing.T) {
 			LastCommit: &tmTypes.Commit{
 				Precommits: []*tmTypes.Vote{
 					{
-						Signature: tmEd25519.SignatureEd25519{1, 2, 3},
+						Signature: []byte{1, 2, 3},
 					},
 				},
 			},
diff --git a/rpc/rpcinfo/info_server.go b/rpc/rpcinfo/info_server.go
index ff500e1bb96a164fbc561ac782e57588bc6fc6fb..3f51321fb80820620dfa663cbfa42724b2e1141f 100644
--- a/rpc/rpcinfo/info_server.go
+++ b/rpc/rpcinfo/info_server.go
@@ -24,7 +24,7 @@ import (
 )
 
 func StartServer(service *rpc.Service, pattern, listenAddress string, logger *logging.Logger) (*http.Server, error) {
-	logger = logger.With(structure.ComponentKey, "RPC_TM")
+	logger = logger.With(structure.ComponentKey, "RPC_Info")
 	routes := GetRoutes(service, logger)
 	mux := http.NewServeMux()
 	wm := server.NewWebsocketManager(routes, logger)
diff --git a/rpc/service.go b/rpc/service.go
index 83a0c1e3ca42edbaddb6e44fdb8f5cb8dc629386..94f03baac37959f232ac7f5855cf637139feb9d5 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -376,7 +376,7 @@ func Status(blockchain bcm.BlockchainInfo, nodeView *tendermint.NodeView, blockT
 		ValidatorInfo: &validator.Validator{
 			Address:   &address,
 			PublicKey: publicKey,
-			Power:     blockchain.Validators().Power(publicKey).Uint64(),
+			Power:     blockchain.Validators().Power(address).Uint64(),
 		},
 	}
 
diff --git a/scripts/build_tool.sh b/scripts/build_tool.sh
index 006e5b294038d9cd41e8a209beeeda5691eef06a..4340f3a8bddcbf9a1c3a908da16d75ac0b6fce5d 100755
--- a/scripts/build_tool.sh
+++ b/scripts/build_tool.sh
@@ -20,6 +20,11 @@
 
 set -e
 
+script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+# Grab date, commit, version
+. "$script_dir/local_version.sh" > /dev/null
+
 DOCKER_REPO=${DOCKER_REPO:-"hyperledger/burrow"}
 REPO=${REPO:-"$GOPATH/src/github.com/hyperledger/burrow"}
 
@@ -27,13 +32,20 @@ function log() {
     echo "$*" >> /dev/stderr
 }
 
-version=$("$REPO/scripts/local_version.sh")
-
 if [[ "$1" ]] ; then
     # If argument provided, use it as the version tag
     log "Overriding detected version $version and tagging image as $1"
     version="$1"
 fi
 
-docker build -t ${DOCKER_REPO}:${version} ${REPO}
+# Gives RFC 3339 with T instead of space
+date=$(date -Iseconds)
+
+docker build --build-arg VERSION=${version}\
+ --build-arg VCS_REF=${commit}\
+ --build-arg BUILD_DATE=${date}\
+ -t ${DOCKER_REPO}:${version} ${REPO}
+# Quick smoke test
+echo "Emitting version from docker image as smoke test..."
+docker run ${DOCKER_REPO}:${version} -v
 
diff --git a/scripts/local_version.sh b/scripts/local_version.sh
index 21f4fc2413e8f03f6788548a1a9436b95bd636b5..eb4d2d20c759074a6931b8732b7286f601246612 100755
--- a/scripts/local_version.sh
+++ b/scripts/local_version.sh
@@ -19,6 +19,10 @@ function log() {
     echo "$*" >> /dev/stderr
 }
 
+# Same as specified RFC3339 but contains the T
+date=$(date -Idate)
+commit=$(git rev-parse --short HEAD)
+
 if [[ ${tag} =~ ${VERSION_REGEX} ]] ; then
     # Only label a build as a release version when the commit is tagged
     log "Building release version (tagged $tag)..."
@@ -28,8 +32,6 @@ if [[ ${tag} =~ ${VERSION_REGEX} ]] ; then
         exit 1
     fi
 else
-    date=$(date +"%Y%m%d")
-    commit=$(git rev-parse --short HEAD)
     version="$version-dev-$date-$commit"
     log "Building non-release version $version..."
 fi
diff --git a/scripts/release.sh b/scripts/release.sh
index d54a1f00dcaea97426252bdffdd5dea25b42212e..3b7829826b0c27a30c26b58c5700043601361d74 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -2,10 +2,15 @@
 
 version_regex="^v[0-9]+\.[0-9]+\.[0-9]+$"
 
+set -e
 
 function release {
     notes="NOTES.md"
     echo "Building and releasing $tag..."
+    echo "Pushing docker image..."
+    echo ${DOCKER_PASS} | docker login --username ${DOCKER_USER} ${DOCKER_REPO} --password-stdin
+
+    echo "Building and pushing binaries"
     [[ -e "$notes" ]] && goreleaser --release-notes "$notes" || goreleaser
 }
 
@@ -30,4 +35,4 @@ if [[ ! ${tag} =~ ${version_regex} ]] ; then
     exit 0
 fi
 
-release
+release
\ No newline at end of file
diff --git a/vendor/github.com/tendermint/iavl/doc.go b/vendor/github.com/tendermint/iavl/doc.go
index 7e4891bcb2a40aa1195e35957899fe913759c494..7751bccadd24891e9727a67f18aef5341733cf43 100644
--- a/vendor/github.com/tendermint/iavl/doc.go
+++ b/vendor/github.com/tendermint/iavl/doc.go
@@ -2,13 +2,13 @@
 // for persisting key-value pairs.
 //
 //
-// Basic usage of VersionedTree.
+// Basic usage of MutableTree.
 //
 //  import "github.com/tendermint/iavl"
 //  import "github.com/tendermint/tendermint/libs/db"
 //  ...
 //
-//  tree := iavl.NewVersionedTree(db.NewMemDB(), 128)
+//  tree := iavl.NewMutableTree(db.NewMemDB(), 128)
 //
 //  tree.IsEmpty() // true
 //
diff --git a/vendor/github.com/tendermint/iavl/tree.go b/vendor/github.com/tendermint/iavl/immutable_tree.go
similarity index 55%
rename from vendor/github.com/tendermint/iavl/tree.go
rename to vendor/github.com/tendermint/iavl/immutable_tree.go
index c92901532c5c9a7630371c8989ef04d932f0c5d4..e334ef52b36b1946e65a08164a34c6e5fa2e0130 100644
--- a/vendor/github.com/tendermint/iavl/tree.go
+++ b/vendor/github.com/tendermint/iavl/immutable_tree.go
@@ -7,29 +7,29 @@ import (
 	dbm "github.com/tendermint/tendermint/libs/db"
 )
 
-// Tree is a container for an immutable AVL+ Tree. Changes are performed by
+// ImmutableTree is a container for an immutable AVL+ ImmutableTree. Changes are performed by
 // swapping the internal root with a new one, while the container is mutable.
 // Note that this tree is not thread-safe.
-type Tree struct {
+type ImmutableTree struct {
 	root    *Node
 	ndb     *nodeDB
 	version int64
 }
 
-// NewTree creates both in-memory and persistent instances
-func NewTree(db dbm.DB, cacheSize int) *Tree {
+// NewImmutableTree creates both in-memory and persistent instances
+func NewImmutableTree(db dbm.DB, cacheSize int) *ImmutableTree {
 	if db == nil {
 		// In-memory Tree.
-		return &Tree{}
+		return &ImmutableTree{}
 	}
-	return &Tree{
+	return &ImmutableTree{
 		// NodeDB-backed Tree.
 		ndb: newNodeDB(db, cacheSize),
 	}
 }
 
 // String returns a string representation of Tree.
-func (t *Tree) String() string {
+func (t *ImmutableTree) String() string {
 	leaves := []string{}
 	t.Iterate(func(key []byte, val []byte) (stop bool) {
 		leaves = append(leaves, fmt.Sprintf("%x: %x", key, val))
@@ -39,11 +39,11 @@ func (t *Tree) String() string {
 }
 
 // Size returns the number of leaf nodes in the tree.
-func (t *Tree) Size() int {
+func (t *ImmutableTree) Size() int {
 	return int(t.Size64())
 }
 
-func (t *Tree) Size64() int64 {
+func (t *ImmutableTree) Size64() int64 {
 	if t.root == nil {
 		return 0
 	}
@@ -51,20 +51,20 @@ func (t *Tree) Size64() int64 {
 }
 
 // Version returns the version of the tree.
-func (t *Tree) Version() int {
+func (t *ImmutableTree) Version() int {
 	return int(t.Version64())
 }
 
-func (t *Tree) Version64() int64 {
+func (t *ImmutableTree) Version64() int64 {
 	return t.version
 }
 
 // Height returns the height of the tree.
-func (t *Tree) Height() int {
+func (t *ImmutableTree) Height() int {
 	return int(t.Height8())
 }
 
-func (t *Tree) Height8() int8 {
+func (t *ImmutableTree) Height8() int8 {
 	if t.root == nil {
 		return 0
 	}
@@ -72,34 +72,15 @@ func (t *Tree) Height8() int8 {
 }
 
 // Has returns whether or not a key exists.
-func (t *Tree) Has(key []byte) bool {
+func (t *ImmutableTree) Has(key []byte) bool {
 	if t.root == nil {
 		return false
 	}
 	return t.root.has(t, key)
 }
 
-// Set a key. Nil values are not supported.
-func (t *Tree) Set(key []byte, value []byte) (updated bool) {
-	_, updated = t.set(key, value)
-	return updated
-}
-
-func (t *Tree) set(key []byte, value []byte) (orphaned []*Node, updated bool) {
-	if value == nil {
-		panic(fmt.Sprintf("Attempt to store nil value at key '%s'", key))
-	}
-	if t.root == nil {
-		t.root = NewNode(key, value, t.version+1)
-		return nil, false
-	}
-	t.root, updated, orphaned = t.root.set(t, key, value)
-
-	return orphaned, updated
-}
-
 // Hash returns the root hash.
-func (t *Tree) Hash() []byte {
+func (t *ImmutableTree) Hash() []byte {
 	if t.root == nil {
 		return nil
 	}
@@ -108,7 +89,7 @@ func (t *Tree) Hash() []byte {
 }
 
 // hashWithCount returns the root hash and hash count.
-func (t *Tree) hashWithCount() ([]byte, int64) {
+func (t *ImmutableTree) hashWithCount() ([]byte, int64) {
 	if t.root == nil {
 		return nil, 0
 	}
@@ -117,12 +98,12 @@ func (t *Tree) hashWithCount() ([]byte, int64) {
 
 // Get returns the index and value of the specified key if it exists, or nil
 // and the next index, if it doesn't.
-func (t *Tree) Get(key []byte) (index int, value []byte) {
+func (t *ImmutableTree) Get(key []byte) (index int, value []byte) {
 	index64, value := t.Get64(key)
 	return int(index64), value
 }
 
-func (t *Tree) Get64(key []byte) (index int64, value []byte) {
+func (t *ImmutableTree) Get64(key []byte) (index int64, value []byte) {
 	if t.root == nil {
 		return 0, nil
 	}
@@ -130,45 +111,19 @@ func (t *Tree) Get64(key []byte) (index int64, value []byte) {
 }
 
 // GetByIndex gets the key and value at the specified index.
-func (t *Tree) GetByIndex(index int) (key []byte, value []byte) {
+func (t *ImmutableTree) GetByIndex(index int) (key []byte, value []byte) {
 	return t.GetByIndex64(int64(index))
 }
 
-func (t *Tree) GetByIndex64(index int64) (key []byte, value []byte) {
+func (t *ImmutableTree) GetByIndex64(index int64) (key []byte, value []byte) {
 	if t.root == nil {
 		return nil, nil
 	}
 	return t.root.getByIndex(t, index)
 }
 
-// Remove tries to remove a key from the tree and if removed, returns its
-// value, and 'true'.
-func (t *Tree) Remove(key []byte) ([]byte, bool) {
-	value, _, removed := t.remove(key)
-	return value, removed
-}
-
-// remove tries to remove a key from the tree and if removed, returns its
-// value, nodes orphaned and 'true'.
-func (t *Tree) remove(key []byte) (value []byte, orphans []*Node, removed bool) {
-	if t.root == nil {
-		return nil, nil, false
-	}
-	newRootHash, newRoot, _, value, orphaned := t.root.remove(t, key)
-	if len(orphaned) == 0 {
-		return nil, nil, false
-	}
-
-	if newRoot == nil && newRootHash != nil {
-		t.root = t.ndb.GetNode(newRootHash)
-	} else {
-		t.root = newRoot
-	}
-	return value, orphaned, true
-}
-
 // Iterate iterates over all keys of the tree, in order.
-func (t *Tree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool) {
+func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool) {
 	if t.root == nil {
 		return false
 	}
@@ -182,7 +137,7 @@ func (t *Tree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool) {
 
 // IterateRange makes a callback for all nodes with key between start and end non-inclusive.
 // If either are nil, then it is open on that side (nil, nil is the same as Iterate)
-func (t *Tree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) {
+func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) {
 	if t.root == nil {
 		return false
 	}
@@ -196,7 +151,7 @@ func (t *Tree) IterateRange(start, end []byte, ascending bool, fn func(key []byt
 
 // IterateRangeInclusive makes a callback for all nodes with key between start and end inclusive.
 // If either are nil, then it is open on that side (nil, nil is the same as Iterate)
-func (t *Tree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool) {
+func (t *ImmutableTree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool) {
 	if t.root == nil {
 		return false
 	}
@@ -209,9 +164,9 @@ func (t *Tree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(
 }
 
 // Clone creates a clone of the tree.
-// Used internally by VersionedTree.
-func (t *Tree) clone() *Tree {
-	return &Tree{
+// Used internally by MutableTree.
+func (t *ImmutableTree) clone() *ImmutableTree {
+	return &ImmutableTree{
 		root:    t.root,
 		ndb:     t.ndb,
 		version: t.version,
@@ -219,7 +174,7 @@ func (t *Tree) clone() *Tree {
 }
 
 // nodeSize is like Size, but includes inner nodes too.
-func (t *Tree) nodeSize() int {
+func (t *ImmutableTree) nodeSize() int {
 	size := 0
 	t.root.traverse(t, true, func(n *Node) bool {
 		size++
diff --git a/vendor/github.com/tendermint/iavl/mutable_tree.go b/vendor/github.com/tendermint/iavl/mutable_tree.go
new file mode 100644
index 0000000000000000000000000000000000000000..8ad073345ce40c6957d6f5ec0c81efccb5b7cd8d
--- /dev/null
+++ b/vendor/github.com/tendermint/iavl/mutable_tree.go
@@ -0,0 +1,469 @@
+package iavl
+
+import (
+	"bytes"
+	"fmt"
+
+	cmn "github.com/tendermint/tendermint/libs/common"
+	dbm "github.com/tendermint/tendermint/libs/db"
+)
+
+// ErrVersionDoesNotExist is returned if a requested version does not exist.
+var ErrVersionDoesNotExist = fmt.Errorf("version does not exist")
+
+// MutableTree is a persistent tree which keeps track of versions.
+type MutableTree struct {
+	*ImmutableTree                  // The current, working tree.
+	lastSaved      *ImmutableTree   // The most recently saved tree.
+	orphans        map[string]int64 // Nodes removed by changes to working tree.
+	versions       map[int64]bool   // The previous, saved versions of the tree.
+	ndb            *nodeDB
+}
+
+// NewMutableTree returns a new tree with the specified cache size and datastore.
+func NewMutableTree(db dbm.DB, cacheSize int) *MutableTree {
+	ndb := newNodeDB(db, cacheSize)
+	head := &ImmutableTree{ndb: ndb}
+
+	return &MutableTree{
+		ImmutableTree: head,
+		lastSaved:     head.clone(),
+		orphans:       map[string]int64{},
+		versions:      map[int64]bool{},
+		ndb:           ndb,
+	}
+}
+
+// IsEmpty returns whether or not the tree has any keys. Only trees that are
+// not empty can be saved.
+func (tree *MutableTree) IsEmpty() bool {
+	return tree.ImmutableTree.Size() == 0
+}
+
+// VersionExists returns whether or not a version exists.
+func (tree *MutableTree) VersionExists(version int64) bool {
+	return tree.versions[version]
+}
+
+// Hash returns the hash of the latest saved version of the tree, as returned
+// by SaveVersion. If no versions have been saved, Hash returns nil.
+func (tree *MutableTree) Hash() []byte {
+	if tree.version > 0 {
+		return tree.lastSaved.Hash()
+	}
+	return nil
+}
+
+// WorkingHash returns the hash of the current working tree.
+func (tree *MutableTree) WorkingHash() []byte {
+	return tree.ImmutableTree.Hash()
+}
+
+// String returns a string representation of the tree.
+func (tree *MutableTree) String() string {
+	return tree.ndb.String()
+}
+
+// Set sets a key in the working tree. Nil values are not supported.
+func (tree *MutableTree) Set(key, value []byte) bool {
+	orphaned, updated := tree.set(key, value)
+	tree.addOrphans(orphaned)
+	return updated
+}
+
+func (tree *MutableTree) set(key []byte, value []byte) (orphaned []*Node, updated bool) {
+	if value == nil {
+		panic(fmt.Sprintf("Attempt to store nil value at key '%s'", key))
+	}
+	if tree.ImmutableTree.root == nil {
+		tree.ImmutableTree.root = NewNode(key, value, tree.version+1)
+		return nil, false
+	}
+	tree.ImmutableTree.root, updated, orphaned = tree.recursiveSet(tree.ImmutableTree.root, key, value)
+
+	return orphaned, updated
+}
+
+func (tree *MutableTree) recursiveSet(node *Node, key []byte, value []byte) (
+	newSelf *Node, updated bool, orphaned []*Node,
+) {
+	version := tree.version + 1
+
+	if node.isLeaf() {
+		switch bytes.Compare(key, node.key) {
+		case -1:
+			return &Node{
+				key:       node.key,
+				height:    1,
+				size:      2,
+				leftNode:  NewNode(key, value, version),
+				rightNode: node,
+				version:   version,
+			}, false, []*Node{}
+		case 1:
+			return &Node{
+				key:       key,
+				height:    1,
+				size:      2,
+				leftNode:  node,
+				rightNode: NewNode(key, value, version),
+				version:   version,
+			}, false, []*Node{}
+		default:
+			return NewNode(key, value, version), true, []*Node{node}
+		}
+	} else {
+		orphaned = append(orphaned, node)
+		node = node.clone(version)
+
+		if bytes.Compare(key, node.key) < 0 {
+			var leftOrphaned []*Node
+			node.leftNode, updated, leftOrphaned = tree.recursiveSet(node.getLeftNode(tree.ImmutableTree), key, value)
+			node.leftHash = nil // leftHash is yet unknown
+			orphaned = append(orphaned, leftOrphaned...)
+		} else {
+			var rightOrphaned []*Node
+			node.rightNode, updated, rightOrphaned = tree.recursiveSet(node.getRightNode(tree.ImmutableTree), key, value)
+			node.rightHash = nil // rightHash is yet unknown
+			orphaned = append(orphaned, rightOrphaned...)
+		}
+
+		if updated {
+			return node, updated, orphaned
+		}
+		node.calcHeightAndSize(tree.ImmutableTree)
+		newNode, balanceOrphaned := tree.balance(node)
+		return newNode, updated, append(orphaned, balanceOrphaned...)
+	}
+}
+
+// Remove removes a key from the working tree.
+func (tree *MutableTree) Remove(key []byte) ([]byte, bool) {
+	val, orphaned, removed := tree.remove(key)
+	tree.addOrphans(orphaned)
+	return val, removed
+}
+
+// remove tries to remove a key from the tree and if removed, returns its
+// value, nodes orphaned and 'true'.
+func (tree *MutableTree) remove(key []byte) (value []byte, orphans []*Node, removed bool) {
+	if tree.root == nil {
+		return nil, nil, false
+	}
+	newRootHash, newRoot, _, value, orphaned := tree.recursiveRemove(tree.root, key)
+	if len(orphaned) == 0 {
+		return nil, nil, false
+	}
+
+	if newRoot == nil && newRootHash != nil {
+		tree.root = tree.ndb.GetNode(newRootHash)
+	} else {
+		tree.root = newRoot
+	}
+	return value, orphaned, true
+}
+
+// removes the node corresponding to the passed key and balances the tree.
+// It returns:
+// - the hash of the new node (or nil if the node is the one removed)
+// - the node that replaces the orig. node after remove
+// - new leftmost leaf key for tree after successfully removing 'key' if changed.
+// - the removed value
+// - the orphaned nodes.
+func (tree *MutableTree) recursiveRemove(node *Node, key []byte) ([]byte, *Node, []byte, []byte, []*Node) {
+	version := tree.version + 1
+
+	if node.isLeaf() {
+		if bytes.Equal(key, node.key) {
+			return nil, nil, nil, node.value, []*Node{node}
+		}
+		return node.hash, node, nil, nil, nil
+	}
+
+	// node.key < key; we go to the left to find the key:
+	if bytes.Compare(key, node.key) < 0 {
+		newLeftHash, newLeftNode, newKey, value, orphaned := tree.recursiveRemove(node.getLeftNode(tree.ImmutableTree), key)
+
+		if len(orphaned) == 0 {
+			return node.hash, node, nil, value, orphaned
+		} else if newLeftHash == nil && newLeftNode == nil { // left node held value, was removed
+			return node.rightHash, node.rightNode, node.key, value, orphaned
+		}
+		orphaned = append(orphaned, node)
+
+		newNode := node.clone(version)
+		newNode.leftHash, newNode.leftNode = newLeftHash, newLeftNode
+		newNode.calcHeightAndSize(tree.ImmutableTree)
+		newNode, balanceOrphaned := tree.balance(newNode)
+
+		return newNode.hash, newNode, newKey, value, append(orphaned, balanceOrphaned...)
+	}
+	// node.key >= key; either found or look to the right:
+	newRightHash, newRightNode, newKey, value, orphaned := tree.recursiveRemove(node.getRightNode(tree.ImmutableTree), key)
+
+	if len(orphaned) == 0 {
+		return node.hash, node, nil, value, orphaned
+	} else if newRightHash == nil && newRightNode == nil { // right node held value, was removed
+		return node.leftHash, node.leftNode, nil, value, orphaned
+	}
+	orphaned = append(orphaned, node)
+
+	newNode := node.clone(version)
+	newNode.rightHash, newNode.rightNode = newRightHash, newRightNode
+	if newKey != nil {
+		newNode.key = newKey
+	}
+	newNode.calcHeightAndSize(tree.ImmutableTree)
+	newNode, balanceOrphaned := tree.balance(newNode)
+
+	return newNode.hash, newNode, nil, value, append(orphaned, balanceOrphaned...)
+}
+
+// Load the latest versioned tree from disk.
+func (tree *MutableTree) Load() (int64, error) {
+	return tree.LoadVersion(int64(0))
+}
+
+// Returns the version number of the latest version found
+func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) {
+	roots, err := tree.ndb.getRoots()
+	if err != nil {
+		return 0, err
+	}
+	if len(roots) == 0 {
+		return 0, nil
+	}
+	latestVersion := int64(0)
+	var latestRoot []byte
+	for version, r := range roots {
+		tree.versions[version] = true
+		if version > latestVersion &&
+			(targetVersion == 0 || version <= targetVersion) {
+			latestVersion = version
+			latestRoot = r
+		}
+	}
+
+	if !(targetVersion == 0 || latestVersion == targetVersion) {
+		return latestVersion, fmt.Errorf("wanted to load target %v but only found up to %v",
+			targetVersion, latestVersion)
+	}
+
+	t := &ImmutableTree{
+		ndb:     tree.ndb,
+		version: latestVersion,
+	}
+	if len(latestRoot) != 0 {
+		t.root = tree.ndb.GetNode(latestRoot)
+	}
+
+	tree.orphans = map[string]int64{}
+	tree.ImmutableTree = t
+	tree.lastSaved = t.clone()
+	return latestVersion, nil
+}
+
+// GetImmutable loads an ImmutableTree at a given version for querying
+func (tree *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) {
+	rootHash := tree.ndb.getRoot(version)
+	if rootHash == nil {
+		return nil, ErrVersionDoesNotExist
+	} else if len(rootHash) == 0 {
+		return &ImmutableTree{
+			ndb:     tree.ndb,
+			version: version,
+		}, nil
+	}
+	return &ImmutableTree{
+		root:    tree.ndb.GetNode(rootHash),
+		ndb:     tree.ndb,
+		version: version,
+	}, nil
+}
+
+// Rollback resets the working tree to the latest saved version, discarding
+// any unsaved modifications.
+func (tree *MutableTree) Rollback() {
+	if tree.version > 0 {
+		tree.ImmutableTree = tree.lastSaved.clone()
+	} else {
+		tree.ImmutableTree = &ImmutableTree{ndb: tree.ndb, version: 0}
+	}
+	tree.orphans = map[string]int64{}
+}
+
+// GetVersioned gets the value at the specified key and version.
+func (tree *MutableTree) GetVersioned(key []byte, version int64) (
+	index int, value []byte,
+) {
+	if tree.versions[version] {
+		t, err := tree.GetImmutable(version)
+		if err != nil {
+			return -1, nil
+		}
+		return t.Get(key)
+	}
+	return -1, nil
+}
+
+// SaveVersion saves a new tree version to disk, based on the current state of
+// the tree. Returns the hash and new version number.
+func (tree *MutableTree) SaveVersion() ([]byte, int64, error) {
+	version := tree.version + 1
+
+	if tree.versions[version] {
+		//version already exists, throw an error if attempting to overwrite
+		// Same hash means idempotent.  Return success.
+		existingHash := tree.ndb.getRoot(version)
+		var newHash = tree.WorkingHash()
+		if bytes.Equal(existingHash, newHash) {
+			tree.version = version
+			tree.ImmutableTree = tree.ImmutableTree.clone()
+			tree.lastSaved = tree.ImmutableTree.clone()
+			tree.orphans = map[string]int64{}
+			return existingHash, version, nil
+		}
+		return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)",
+			version, newHash, existingHash)
+	}
+
+	if tree.root == nil {
+		// There can still be orphans, for example if the root is the node being
+		// removed.
+		debug("SAVE EMPTY TREE %v\n", version)
+		tree.ndb.SaveOrphans(version, tree.orphans)
+		tree.ndb.SaveEmptyRoot(version)
+	} else {
+		debug("SAVE TREE %v\n", version)
+		// Save the current tree.
+		tree.ndb.SaveBranch(tree.root)
+		tree.ndb.SaveOrphans(version, tree.orphans)
+		tree.ndb.SaveRoot(tree.root, version)
+	}
+	tree.ndb.Commit()
+	tree.version = version
+	tree.versions[version] = true
+
+	// Set new working tree.
+	tree.ImmutableTree = tree.ImmutableTree.clone()
+	tree.lastSaved = tree.ImmutableTree.clone()
+	tree.orphans = map[string]int64{}
+
+	return tree.Hash(), version, nil
+}
+
+// DeleteVersion deletes a tree version from disk. The version can then no
+// longer be accessed.
+func (tree *MutableTree) DeleteVersion(version int64) error {
+	if version == 0 {
+		return cmn.NewError("version must be greater than 0")
+	}
+	if version == tree.version {
+		return cmn.NewError("cannot delete latest saved version (%d)", version)
+	}
+	if _, ok := tree.versions[version]; !ok {
+		return cmn.ErrorWrap(ErrVersionDoesNotExist, "")
+	}
+
+	tree.ndb.DeleteVersion(version)
+	tree.ndb.Commit()
+
+	delete(tree.versions, version)
+
+	return nil
+}
+
+// Rotate right and return the new node and orphan.
+func (tree *MutableTree) rotateRight(node *Node) (*Node, *Node) {
+	version := tree.version + 1
+
+	// TODO: optimize balance & rotate.
+	node = node.clone(version)
+	orphaned := node.getLeftNode(tree.ImmutableTree)
+	newNode := orphaned.clone(version)
+
+	newNoderHash, newNoderCached := newNode.rightHash, newNode.rightNode
+	newNode.rightHash, newNode.rightNode = node.hash, node
+	node.leftHash, node.leftNode = newNoderHash, newNoderCached
+
+	node.calcHeightAndSize(tree.ImmutableTree)
+	newNode.calcHeightAndSize(tree.ImmutableTree)
+
+	return newNode, orphaned
+}
+
+// Rotate left and return the new node and orphan.
+func (tree *MutableTree) rotateLeft(node *Node) (*Node, *Node) {
+	version := tree.version + 1
+
+	// TODO: optimize balance & rotate.
+	node = node.clone(version)
+	orphaned := node.getRightNode(tree.ImmutableTree)
+	newNode := orphaned.clone(version)
+
+	newNodelHash, newNodelCached := newNode.leftHash, newNode.leftNode
+	newNode.leftHash, newNode.leftNode = node.hash, node
+	node.rightHash, node.rightNode = newNodelHash, newNodelCached
+
+	node.calcHeightAndSize(tree.ImmutableTree)
+	newNode.calcHeightAndSize(tree.ImmutableTree)
+
+	return newNode, orphaned
+}
+
+// NOTE: assumes that node can be modified
+// TODO: optimize balance & rotate
+func (tree *MutableTree) balance(node *Node) (newSelf *Node, orphaned []*Node) {
+	if node.persisted {
+		panic("Unexpected balance() call on persisted node")
+	}
+	balance := node.calcBalance(tree.ImmutableTree)
+
+	if balance > 1 {
+		if node.getLeftNode(tree.ImmutableTree).calcBalance(tree.ImmutableTree) >= 0 {
+			// Left Left Case
+			newNode, orphaned := tree.rotateRight(node)
+			return newNode, []*Node{orphaned}
+		}
+		// Left Right Case
+		var leftOrphaned *Node
+
+		left := node.getLeftNode(tree.ImmutableTree)
+		node.leftHash = nil
+		node.leftNode, leftOrphaned = tree.rotateLeft(left)
+		newNode, rightOrphaned := tree.rotateRight(node)
+
+		return newNode, []*Node{left, leftOrphaned, rightOrphaned}
+	}
+	if balance < -1 {
+		if node.getRightNode(tree.ImmutableTree).calcBalance(tree.ImmutableTree) <= 0 {
+			// Right Right Case
+			newNode, orphaned := tree.rotateLeft(node)
+			return newNode, []*Node{orphaned}
+		}
+		// Right Left Case
+		var rightOrphaned *Node
+
+		right := node.getRightNode(tree.ImmutableTree)
+		node.rightHash = nil
+		node.rightNode, rightOrphaned = tree.rotateRight(right)
+		newNode, leftOrphaned := tree.rotateLeft(node)
+
+		return newNode, []*Node{right, leftOrphaned, rightOrphaned}
+	}
+	// Nothing changed
+	return node, []*Node{}
+}
+
+func (tree *MutableTree) addOrphans(orphans []*Node) {
+	for _, node := range orphans {
+		if !node.persisted {
+			// We don't need to orphan nodes that were never persisted.
+			continue
+		}
+		if len(node.hash) == 0 {
+			panic("Expected to find node hash, but was empty")
+		}
+		tree.orphans[string(node.hash)] = node.version
+	}
+}
diff --git a/vendor/github.com/tendermint/iavl/node.go b/vendor/github.com/tendermint/iavl/node.go
index 307412c338b733e4e80e07fba320ec3b9b86d556..863751b6a1dfb1188e36830e19f2dc6c2ccd6f5f 100644
--- a/vendor/github.com/tendermint/iavl/node.go
+++ b/vendor/github.com/tendermint/iavl/node.go
@@ -140,7 +140,7 @@ func (node *Node) isLeaf() bool {
 }
 
 // Check if the node has a descendant with the given key.
-func (node *Node) has(t *Tree, key []byte) (has bool) {
+func (node *Node) has(t *ImmutableTree, key []byte) (has bool) {
 	if bytes.Equal(node.key, key) {
 		return true
 	}
@@ -154,7 +154,7 @@ func (node *Node) has(t *Tree, key []byte) (has bool) {
 }
 
 // Get a key under the node.
-func (node *Node) get(t *Tree, key []byte) (index int64, value []byte) {
+func (node *Node) get(t *ImmutableTree, key []byte) (index int64, value []byte) {
 	if node.isLeaf() {
 		switch bytes.Compare(node.key, key) {
 		case -1:
@@ -175,7 +175,7 @@ func (node *Node) get(t *Tree, key []byte) (index int64, value []byte) {
 	return index, value
 }
 
-func (node *Node) getByIndex(t *Tree, index int64) (key []byte, value []byte) {
+func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value []byte) {
 	if node.isLeaf() {
 		if index == 0 {
 			return node.key, node.value
@@ -341,233 +341,42 @@ func (node *Node) writeBytes(w io.Writer) cmn.Error {
 	return nil
 }
 
-func (node *Node) set(t *Tree, key []byte, value []byte) (
-	newSelf *Node, updated bool, orphaned []*Node,
-) {
-	version := t.version + 1
-
-	if node.isLeaf() {
-		switch bytes.Compare(key, node.key) {
-		case -1:
-			return &Node{
-				key:       node.key,
-				height:    1,
-				size:      2,
-				leftNode:  NewNode(key, value, version),
-				rightNode: node,
-				version:   version,
-			}, false, []*Node{}
-		case 1:
-			return &Node{
-				key:       key,
-				height:    1,
-				size:      2,
-				leftNode:  node,
-				rightNode: NewNode(key, value, version),
-				version:   version,
-			}, false, []*Node{}
-		default:
-			return NewNode(key, value, version), true, []*Node{node}
-		}
-	} else {
-		orphaned = append(orphaned, node)
-		node = node.clone(version)
-
-		if bytes.Compare(key, node.key) < 0 {
-			var leftOrphaned []*Node
-			node.leftNode, updated, leftOrphaned = node.getLeftNode(t).set(t, key, value)
-			node.leftHash = nil // leftHash is yet unknown
-			orphaned = append(orphaned, leftOrphaned...)
-		} else {
-			var rightOrphaned []*Node
-			node.rightNode, updated, rightOrphaned = node.getRightNode(t).set(t, key, value)
-			node.rightHash = nil // rightHash is yet unknown
-			orphaned = append(orphaned, rightOrphaned...)
-		}
-
-		if updated {
-			return node, updated, orphaned
-		}
-		node.calcHeightAndSize(t)
-		newNode, balanceOrphaned := node.balance(t)
-		return newNode, updated, append(orphaned, balanceOrphaned...)
-	}
-}
-
-// removes the node corresponding to the passed key and balances the tree.
-// It returns:
-// - the hash of the new node (or nil if the node is the one removed)
-// - the node that replaces the orig. node after remove
-// - new leftmost leaf key for tree after successfully removing 'key' if changed.
-// - the removed value
-// - the orphaned nodes.
-func (node *Node) remove(t *Tree, key []byte) ([]byte, *Node, []byte, []byte, []*Node) {
-	version := t.version + 1
-
-	if node.isLeaf() {
-		if bytes.Equal(key, node.key) {
-			return nil, nil, nil, node.value, []*Node{node}
-		}
-		return node.hash, node, nil, nil, nil
-	}
-
-	// node.key < key; we go to the left to find the key:
-	if bytes.Compare(key, node.key) < 0 {
-		newLeftHash, newLeftNode, newKey, value, orphaned := node.getLeftNode(t).remove(t, key)
-
-		if len(orphaned) == 0 {
-			return node.hash, node, nil, value, orphaned
-		} else if newLeftHash == nil && newLeftNode == nil { // left node held value, was removed
-			return node.rightHash, node.rightNode, node.key, value, orphaned
-		}
-		orphaned = append(orphaned, node)
-
-		newNode := node.clone(version)
-		newNode.leftHash, newNode.leftNode = newLeftHash, newLeftNode
-		newNode.calcHeightAndSize(t)
-		newNode, balanceOrphaned := newNode.balance(t)
-
-		return newNode.hash, newNode, newKey, value, append(orphaned, balanceOrphaned...)
-	}
-	// node.key >= key; either found or look to the right:
-	newRightHash, newRightNode, newKey, value, orphaned := node.getRightNode(t).remove(t, key)
-
-	if len(orphaned) == 0 {
-		return node.hash, node, nil, value, orphaned
-	} else if newRightHash == nil && newRightNode == nil { // right node held value, was removed
-		return node.leftHash, node.leftNode, nil, value, orphaned
-	}
-	orphaned = append(orphaned, node)
-
-	newNode := node.clone(version)
-	newNode.rightHash, newNode.rightNode = newRightHash, newRightNode
-	if newKey != nil {
-		newNode.key = newKey
-	}
-	newNode.calcHeightAndSize(t)
-	newNode, balanceOrphaned := newNode.balance(t)
-
-	return newNode.hash, newNode, nil, value, append(orphaned, balanceOrphaned...)
-}
-
-func (node *Node) getLeftNode(t *Tree) *Node {
+func (node *Node) getLeftNode(t *ImmutableTree) *Node {
 	if node.leftNode != nil {
 		return node.leftNode
 	}
 	return t.ndb.GetNode(node.leftHash)
 }
 
-func (node *Node) getRightNode(t *Tree) *Node {
+func (node *Node) getRightNode(t *ImmutableTree) *Node {
 	if node.rightNode != nil {
 		return node.rightNode
 	}
 	return t.ndb.GetNode(node.rightHash)
 }
 
-// Rotate right and return the new node and orphan.
-func (node *Node) rotateRight(t *Tree) (newNode *Node, orphan *Node) {
-	version := t.version + 1
-
-	// TODO: optimize balance & rotate.
-	node = node.clone(version)
-	l := node.getLeftNode(t)
-	_l := l.clone(version)
-
-	_lrHash, _lrCached := _l.rightHash, _l.rightNode
-	_l.rightHash, _l.rightNode = node.hash, node
-	node.leftHash, node.leftNode = _lrHash, _lrCached
-
-	node.calcHeightAndSize(t)
-	_l.calcHeightAndSize(t)
-
-	return _l, l
-}
-
-// Rotate left and return the new node and orphan.
-func (node *Node) rotateLeft(t *Tree) (newNode *Node, orphan *Node) {
-	version := t.version + 1
-
-	// TODO: optimize balance & rotate.
-	node = node.clone(version)
-	r := node.getRightNode(t)
-	_r := r.clone(version)
-
-	_rlHash, _rlCached := _r.leftHash, _r.leftNode
-	_r.leftHash, _r.leftNode = node.hash, node
-	node.rightHash, node.rightNode = _rlHash, _rlCached
-
-	node.calcHeightAndSize(t)
-	_r.calcHeightAndSize(t)
-
-	return _r, r
-}
-
 // NOTE: mutates height and size
-func (node *Node) calcHeightAndSize(t *Tree) {
+func (node *Node) calcHeightAndSize(t *ImmutableTree) {
 	node.height = maxInt8(node.getLeftNode(t).height, node.getRightNode(t).height) + 1
 	node.size = node.getLeftNode(t).size + node.getRightNode(t).size
 }
 
-func (node *Node) calcBalance(t *Tree) int {
+func (node *Node) calcBalance(t *ImmutableTree) int {
 	return int(node.getLeftNode(t).height) - int(node.getRightNode(t).height)
 }
 
-// NOTE: assumes that node can be modified
-// TODO: optimize balance & rotate
-func (node *Node) balance(t *Tree) (newSelf *Node, orphaned []*Node) {
-	if node.persisted {
-		panic("Unexpected balance() call on persisted node")
-	}
-	balance := node.calcBalance(t)
-
-	if balance > 1 {
-		if node.getLeftNode(t).calcBalance(t) >= 0 {
-			// Left Left Case
-			newNode, orphaned := node.rotateRight(t)
-			return newNode, []*Node{orphaned}
-		}
-		// Left Right Case
-		var leftOrphaned *Node
-
-		left := node.getLeftNode(t)
-		node.leftHash = nil
-		node.leftNode, leftOrphaned = left.rotateLeft(t)
-		newNode, rightOrphaned := node.rotateRight(t)
-
-		return newNode, []*Node{left, leftOrphaned, rightOrphaned}
-	}
-	if balance < -1 {
-		if node.getRightNode(t).calcBalance(t) <= 0 {
-			// Right Right Case
-			newNode, orphaned := node.rotateLeft(t)
-			return newNode, []*Node{orphaned}
-		}
-		// Right Left Case
-		var rightOrphaned *Node
-
-		right := node.getRightNode(t)
-		node.rightHash = nil
-		node.rightNode, rightOrphaned = right.rotateRight(t)
-		newNode, leftOrphaned := node.rotateLeft(t)
-
-		return newNode, []*Node{right, leftOrphaned, rightOrphaned}
-	}
-	// Nothing changed
-	return node, []*Node{}
-}
-
 // traverse is a wrapper over traverseInRange when we want the whole tree
-func (node *Node) traverse(t *Tree, ascending bool, cb func(*Node) bool) bool {
+func (node *Node) traverse(t *ImmutableTree, ascending bool, cb func(*Node) bool) bool {
 	return node.traverseInRange(t, nil, nil, ascending, false, 0, func(node *Node, depth uint8) bool {
 		return cb(node)
 	})
 }
 
-func (node *Node) traverseWithDepth(t *Tree, ascending bool, cb func(*Node, uint8) bool) bool {
+func (node *Node) traverseWithDepth(t *ImmutableTree, ascending bool, cb func(*Node, uint8) bool) bool {
 	return node.traverseInRange(t, nil, nil, ascending, false, 0, cb)
 }
 
-func (node *Node) traverseInRange(t *Tree, start, end []byte, ascending bool, inclusive bool, depth uint8, cb func(*Node, uint8) bool) bool {
+func (node *Node) traverseInRange(t *ImmutableTree, start, end []byte, ascending bool, inclusive bool, depth uint8, cb func(*Node, uint8) bool) bool {
 	afterStart := start == nil || bytes.Compare(start, node.key) < 0
 	startOrAfter := start == nil || bytes.Compare(start, node.key) <= 0
 	beforeEnd := end == nil || bytes.Compare(node.key, end) < 0
@@ -615,7 +424,7 @@ func (node *Node) traverseInRange(t *Tree, start, end []byte, ascending bool, in
 }
 
 // Only used in testing...
-func (node *Node) lmd(t *Tree) *Node {
+func (node *Node) lmd(t *ImmutableTree) *Node {
 	if node.isLeaf() {
 		return node
 	}
diff --git a/vendor/github.com/tendermint/iavl/nodedb.go b/vendor/github.com/tendermint/iavl/nodedb.go
index d0d3df19c0835b5b4b16cd6f2b97dfd7472dada8..a933b26628dcbd8fbfee84f86c64e2f0048e7bf3 100644
--- a/vendor/github.com/tendermint/iavl/nodedb.go
+++ b/vendor/github.com/tendermint/iavl/nodedb.go
@@ -332,6 +332,10 @@ func (ndb *nodeDB) Commit() {
 	ndb.batch = ndb.db.NewBatch()
 }
 
+func (ndb *nodeDB) getRoot(version int64) []byte {
+	return ndb.db.Get(ndb.rootKey(version))
+}
+
 func (ndb *nodeDB) getRoots() (map[int64][]byte, error) {
 	roots := map[int64][]byte{}
 
diff --git a/vendor/github.com/tendermint/iavl/orphaning_tree.go b/vendor/github.com/tendermint/iavl/orphaning_tree.go
deleted file mode 100644
index fb7493f28a0e678e5cfa29f0a43181f824bd5ab4..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/iavl/orphaning_tree.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package iavl
-
-import (
-	"fmt"
-)
-
-// orphaningTree is a tree which keeps track of orphaned nodes.
-type orphaningTree struct {
-	*Tree
-
-	// A map of orphan hash to orphan version.
-	// The version stored here is the one at which the orphan's lifetime
-	// begins.
-	orphans map[string]int64
-}
-
-// newOrphaningTree creates a new orphaning tree from the given *Tree.
-func newOrphaningTree(t *Tree) *orphaningTree {
-	return &orphaningTree{
-		Tree:    t,
-		orphans: map[string]int64{},
-	}
-}
-
-// Set a key on the underlying tree while storing the orphaned nodes.
-func (tree *orphaningTree) Set(key, value []byte) bool {
-	orphaned, updated := tree.Tree.set(key, value)
-	tree.addOrphans(orphaned)
-	return updated
-}
-
-// Remove a key from the underlying tree while storing the orphaned nodes.
-func (tree *orphaningTree) Remove(key []byte) ([]byte, bool) {
-	val, orphaned, removed := tree.Tree.remove(key)
-	tree.addOrphans(orphaned)
-	return val, removed
-}
-
-// SaveAs saves the underlying Tree and assigns it a new version.
-// Saves orphans too.
-func (tree *orphaningTree) SaveAs(version int64) {
-	if version != tree.version+1 {
-		panic(fmt.Sprintf("Expected to save version %d but tried to save %d", tree.version+1, version))
-	}
-	if tree.root == nil {
-		// There can still be orphans, for example if the root is the node being
-		// removed.
-		debug("SAVE EMPTY TREE %v\n", version)
-		tree.ndb.SaveOrphans(version, tree.orphans)
-		tree.ndb.SaveEmptyRoot(version)
-	} else {
-		debug("SAVE TREE %v\n", version)
-		// Save the current tree.
-		tree.ndb.SaveBranch(tree.root)
-		tree.ndb.SaveOrphans(version, tree.orphans)
-		tree.ndb.SaveRoot(tree.root, version)
-	}
-	tree.ndb.Commit()
-	tree.version = version
-}
-
-// Add orphans to the orphan list. Doesn't write to disk.
-func (tree *orphaningTree) addOrphans(orphans []*Node) {
-	for _, node := range orphans {
-		if !node.persisted {
-			// We don't need to orphan nodes that were never persisted.
-			continue
-		}
-		if len(node.hash) == 0 {
-			panic("Expected to find node hash, but was empty")
-		}
-		tree.orphans[string(node.hash)] = node.version
-	}
-}
diff --git a/vendor/github.com/tendermint/iavl/proof.go b/vendor/github.com/tendermint/iavl/proof.go
index a878770484fcefbc637642de23da3fc4b0df650f..b68293ccc0072628b0d85d7005f99c6795470090 100644
--- a/vendor/github.com/tendermint/iavl/proof.go
+++ b/vendor/github.com/tendermint/iavl/proof.go
@@ -142,7 +142,7 @@ func (pln proofLeafNode) Hash() []byte {
 // If the key does not exist, returns the path to the next leaf left of key (w/
 // path), except when key is less than the least item, in which case it returns
 // a path to the least item.
-func (node *Node) PathToLeaf(t *Tree, key []byte) (PathToLeaf, *Node, error) {
+func (node *Node) PathToLeaf(t *ImmutableTree, key []byte) (PathToLeaf, *Node, error) {
 	path := new(PathToLeaf)
 	val, err := node.pathToLeaf(t, key, path)
 	return *path, val, err
@@ -151,7 +151,7 @@ func (node *Node) PathToLeaf(t *Tree, key []byte) (PathToLeaf, *Node, error) {
 // pathToLeaf is a helper which recursively constructs the PathToLeaf.
 // As an optimization the already constructed path is passed in as an argument
 // and is shared among recursive calls.
-func (node *Node) pathToLeaf(t *Tree, key []byte, path *PathToLeaf) (*Node, error) {
+func (node *Node) pathToLeaf(t *ImmutableTree, key []byte, path *PathToLeaf) (*Node, error) {
 	if node.height == 0 {
 		if bytes.Equal(node.key, key) {
 			return node, nil
diff --git a/vendor/github.com/tendermint/iavl/proof_range.go b/vendor/github.com/tendermint/iavl/proof_range.go
index cc12618f97848943a5587efe66b52a77a7f7cd03..ec438515e07f0a244daa369963208cc96e8f7a14 100644
--- a/vendor/github.com/tendermint/iavl/proof_range.go
+++ b/vendor/github.com/tendermint/iavl/proof_range.go
@@ -26,7 +26,7 @@ type RangeProof struct {
 
 // Keys returns all the keys in the RangeProof.  NOTE: The keys here may
 // include more keys than provided by tree.GetRangeWithProof or
-// VersionedTree.GetVersionedRangeWithProof.  The keys returned there are only
+// MutableTree.GetVersionedRangeWithProof.  The keys returned there are only
 // in the provided [startKey,endKey){limit} range.  The keys returned here may
 // include extra keys, such as:
 // - the key before startKey if startKey is provided and doesn't exist;
@@ -308,7 +308,7 @@ func (proof *RangeProof) _computeRootHash() (rootHash []byte, treeEnd bool, err
 // If keyEnd-1 exists, no later leaves will be included.
 // If keyStart >= keyEnd and both not nil, panics.
 // Limit is never exceeded.
-func (t *Tree) getRangeProof(keyStart, keyEnd []byte, limit int) (*RangeProof, [][]byte, [][]byte, error) {
+func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (*RangeProof, [][]byte, [][]byte, error) {
 	if keyStart != nil && keyEnd != nil && bytes.Compare(keyStart, keyEnd) >= 0 {
 		panic("if keyStart and keyEnd are present, need keyStart < keyEnd.")
 	}
@@ -365,7 +365,6 @@ func (t *Tree) getRangeProof(keyStart, keyEnd []byte, limit int) (*RangeProof, [
 	// nolint
 	var innersq = []PathToLeaf(nil)
 	var inners = PathToLeaf(nil)
-	var lastDepth uint8 = 0
 	var leafCount = 1 // from left above.
 	var pathCount = 0
 	// var keys, values [][]byte defined as function outs.
@@ -435,7 +434,6 @@ func (t *Tree) getRangeProof(keyStart, keyEnd []byte, limit int) (*RangeProof, [
 					})
 				}
 			}
-			lastDepth = depth
 			return false
 		},
 	)
@@ -451,7 +449,7 @@ func (t *Tree) getRangeProof(keyStart, keyEnd []byte, limit int) (*RangeProof, [
 
 // GetWithProof gets the value under the key if it exists, or returns nil.
 // A proof of existence or absence is returned alongside the value.
-func (t *Tree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error) {
+func (t *ImmutableTree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error) {
 	proof, _, values, err := t.getRangeProof(key, cpIncr(key), 2)
 	if err == nil {
 		if len(values) > 0 {
@@ -466,15 +464,19 @@ func (t *Tree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err er
 }
 
 // GetRangeWithProof gets key/value pairs within the specified range and limit.
-func (t *Tree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error) {
+func (t *ImmutableTree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error) {
 	proof, keys, values, err = t.getRangeProof(startKey, endKey, limit)
 	return
 }
 
 // GetVersionedWithProof gets the value under the key at the specified version
 // if it exists, or returns nil.
-func (tree *VersionedTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error) {
-	if t, ok := tree.versions[version]; ok {
+func (tree *MutableTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error) {
+	if tree.versions[version] {
+		t, err := tree.GetImmutable(version)
+		if err != nil {
+			return nil, nil, err
+		}
 		return t.GetWithProof(key)
 	}
 	return nil, nil, cmn.ErrorWrap(ErrVersionDoesNotExist, "")
@@ -482,10 +484,14 @@ func (tree *VersionedTree) GetVersionedWithProof(key []byte, version int64) ([]b
 
 // GetVersionedRangeWithProof gets key/value pairs within the specified range
 // and limit.
-func (tree *VersionedTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) (
+func (tree *MutableTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) (
 	keys, values [][]byte, proof *RangeProof, err error) {
 
-	if t, ok := tree.versions[version]; ok {
+	if tree.versions[version] {
+		t, err := tree.GetImmutable(version)
+		if err != nil {
+			return nil, nil, nil, err
+		}
 		return t.GetRangeWithProof(startKey, endKey, limit)
 	}
 	return nil, nil, nil, cmn.ErrorWrap(ErrVersionDoesNotExist, "")
diff --git a/vendor/github.com/tendermint/iavl/tree_dotgraph.go b/vendor/github.com/tendermint/iavl/tree_dotgraph.go
index 14294851ac1083e3f416ff95847bb399d69264e6..c6f50374d3991ffe9dffe1fa913f793d1f5d161a 100644
--- a/vendor/github.com/tendermint/iavl/tree_dotgraph.go
+++ b/vendor/github.com/tendermint/iavl/tree_dotgraph.go
@@ -41,7 +41,7 @@ var defaultGraphNodeAttrs = map[string]string{
 	"shape": "circle",
 }
 
-func WriteDOTGraph(w io.Writer, tree *Tree, paths []PathToLeaf) {
+func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) {
 	ctx := &graphContext{}
 
 	tree.root.hashWithCount()
diff --git a/vendor/github.com/tendermint/iavl/util.go b/vendor/github.com/tendermint/iavl/util.go
index 96f754189518f587e854e2f93e072fb568d88091..dc9f925156ce4ce250b9b4c3498e1c9c0333ee17 100644
--- a/vendor/github.com/tendermint/iavl/util.go
+++ b/vendor/github.com/tendermint/iavl/util.go
@@ -7,7 +7,7 @@ import (
 )
 
 // PrintTree prints the whole tree in an indented form.
-func PrintTree(tree *Tree) {
+func PrintTree(tree *ImmutableTree) {
 	ndb, root := tree.ndb, tree.root
 	printNode(ndb, root, 0)
 }
@@ -71,8 +71,6 @@ func cpIncr(bz []byte) (ret []byte) {
 		ret[i] = byte(0x00)
 		if i == 0 {
 			return append(ret, 0x00)
-			// Overflow
-			return nil
 		}
 	}
 	return []byte{0x00}
diff --git a/vendor/github.com/tendermint/iavl/version.go b/vendor/github.com/tendermint/iavl/version.go
index 9efd1114579c05336323ebbad17751f39f57479e..f88f00abc7e5508da298d8235043a0446fc11839 100644
--- a/vendor/github.com/tendermint/iavl/version.go
+++ b/vendor/github.com/tendermint/iavl/version.go
@@ -1,4 +1,4 @@
 package iavl
 
 // Version of iavl.
-const Version = "0.9.2"
+const Version = "0.10.0"
diff --git a/vendor/github.com/tendermint/iavl/versioned_tree.go b/vendor/github.com/tendermint/iavl/versioned_tree.go
deleted file mode 100644
index 7d8108ea85caf2cc2a4d8bd58938ed01f2e67c5d..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/iavl/versioned_tree.go
+++ /dev/null
@@ -1,197 +0,0 @@
-package iavl
-
-import (
-	"bytes"
-	"fmt"
-
-	cmn "github.com/tendermint/tendermint/libs/common"
-	dbm "github.com/tendermint/tendermint/libs/db"
-)
-
-// ErrVersionDoesNotExist is returned if a requested version does not exist.
-var ErrVersionDoesNotExist = fmt.Errorf("version does not exist")
-
-// VersionedTree is a persistent tree which keeps track of versions.
-type VersionedTree struct {
-	*orphaningTree                 // The current, working tree.
-	versions       map[int64]*Tree // The previous, saved versions of the tree.
-	ndb            *nodeDB
-}
-
-// NewVersionedTree returns a new tree with the specified cache size and datastore.
-func NewVersionedTree(db dbm.DB, cacheSize int) *VersionedTree {
-	ndb := newNodeDB(db, cacheSize)
-	head := &Tree{ndb: ndb}
-
-	return &VersionedTree{
-		orphaningTree: newOrphaningTree(head),
-		versions:      map[int64]*Tree{},
-		ndb:           ndb,
-	}
-}
-
-// IsEmpty returns whether or not the tree has any keys. Only trees that are
-// not empty can be saved.
-func (tree *VersionedTree) IsEmpty() bool {
-	return tree.orphaningTree.Size() == 0
-}
-
-// VersionExists returns whether or not a version exists.
-func (tree *VersionedTree) VersionExists(version int64) bool {
-	_, ok := tree.versions[version]
-	return ok
-}
-
-// Tree returns the current working tree.
-func (tree *VersionedTree) Tree() *Tree {
-	return tree.orphaningTree.Tree
-}
-
-// Hash returns the hash of the latest saved version of the tree, as returned
-// by SaveVersion. If no versions have been saved, Hash returns nil.
-func (tree *VersionedTree) Hash() []byte {
-	if tree.version > 0 {
-		return tree.versions[tree.version].Hash()
-	}
-	return nil
-}
-
-// String returns a string representation of the tree.
-func (tree *VersionedTree) String() string {
-	return tree.ndb.String()
-}
-
-// Set sets a key in the working tree. Nil values are not supported.
-func (tree *VersionedTree) Set(key, val []byte) bool {
-	return tree.orphaningTree.Set(key, val)
-}
-
-// Remove removes a key from the working tree.
-func (tree *VersionedTree) Remove(key []byte) ([]byte, bool) {
-	return tree.orphaningTree.Remove(key)
-}
-
-// Load the latest versioned tree from disk.
-//
-// Returns the version number of the latest version found
-func (tree *VersionedTree) Load() (int64, error) {
-	return tree.LoadVersion(0)
-}
-
-// Load a versioned tree from disk.
-//
-// If version is 0, the latest version is loaded.
-//
-// Returns the version number of the latest version found
-func (tree *VersionedTree) LoadVersion(targetVersion int64) (int64, error) {
-	roots, err := tree.ndb.getRoots()
-	if err != nil {
-		return 0, err
-	}
-	if len(roots) == 0 {
-		return 0, nil
-	}
-
-	// Load all roots from the database.
-	latestVersion := int64(0)
-	for version, root := range roots {
-
-		// Construct a tree manually.
-		t := &Tree{}
-		t.ndb = tree.ndb
-		t.version = version
-		if len(root) != 0 {
-			t.root = tree.ndb.GetNode(root)
-		}
-		tree.versions[version] = t
-
-		if version > latestVersion &&
-			(targetVersion == 0 || version <= targetVersion) {
-
-			latestVersion = version
-		}
-	}
-
-	// Validate latestVersion
-	if !(targetVersion == 0 || latestVersion == targetVersion) {
-		return latestVersion, fmt.Errorf("Wanted to load target %v but only found up to %v",
-			targetVersion, latestVersion)
-	}
-
-	// Set the working tree to a copy of the latest.
-	tree.orphaningTree = newOrphaningTree(
-		tree.versions[latestVersion].clone(),
-	)
-
-	return latestVersion, nil
-}
-
-// Rollback resets the working tree to the latest saved version, discarding
-// any unsaved modifications.
-func (tree *VersionedTree) Rollback() {
-	if tree.version > 0 {
-		tree.orphaningTree = newOrphaningTree(
-			tree.versions[tree.version].clone(),
-		)
-	} else {
-		tree.orphaningTree = newOrphaningTree(&Tree{ndb: tree.ndb, version: 0})
-	}
-}
-
-// GetVersioned gets the value at the specified key and version.
-func (tree *VersionedTree) GetVersioned(key []byte, version int64) (
-	index int, value []byte,
-) {
-	if t, ok := tree.versions[version]; ok {
-		return t.Get(key)
-	}
-	return -1, nil
-}
-
-// SaveVersion saves a new tree version to disk, based on the current state of
-// the tree. Returns the hash and new version number.
-func (tree *VersionedTree) SaveVersion() ([]byte, int64, error) {
-	version := tree.version + 1
-
-	if _, ok := tree.versions[version]; ok {
-		// Same hash means idempotent.  Return success.
-		var existingHash = tree.versions[version].Hash()
-		var newHash = tree.orphaningTree.Hash()
-		if bytes.Equal(existingHash, newHash) {
-			tree.orphaningTree = newOrphaningTree(tree.versions[version].clone())
-			return existingHash, version, nil
-		}
-		return nil, version, fmt.Errorf("version %d was already saved to different hash %X (existing hash %X)",
-			version, newHash, existingHash)
-	}
-
-	// Persist version and stash to .versions.
-	tree.orphaningTree.SaveAs(version)
-	tree.versions[version] = tree.orphaningTree.Tree
-
-	// Set new working tree.
-	tree.orphaningTree = newOrphaningTree(tree.orphaningTree.clone())
-
-	return tree.Hash(), version, nil
-}
-
-// DeleteVersion deletes a tree version from disk. The version can then no
-// longer be accessed.
-func (tree *VersionedTree) DeleteVersion(version int64) error {
-	if version == 0 {
-		return cmn.NewError("version must be greater than 0")
-	}
-	if version == tree.version {
-		return cmn.NewError("cannot delete latest saved version (%d)", version)
-	}
-	if _, ok := tree.versions[version]; !ok {
-		return cmn.ErrorWrap(ErrVersionDoesNotExist, "")
-	}
-
-	tree.ndb.DeleteVersion(version)
-	tree.ndb.Commit()
-
-	delete(tree.versions, version)
-
-	return nil
-}
diff --git a/vendor/github.com/tendermint/tendermint/abci/client/grpc_client.go b/vendor/github.com/tendermint/tendermint/abci/client/grpc_client.go
index 502ee0fcd8d54b81158ad7e39c09ac5e0b2e7276..a1f0994684fef40076e2bb42c89dc59e0fbe5ea1 100644
--- a/vendor/github.com/tendermint/tendermint/abci/client/grpc_client.go
+++ b/vendor/github.com/tendermint/tendermint/abci/client/grpc_client.go
@@ -63,7 +63,7 @@ RETRY_LOOP:
 
 	ENSURE_CONNECTED:
 		for {
-			_, err := client.Echo(context.Background(), &types.RequestEcho{"hello"}, grpc.FailFast(true))
+			_, err := client.Echo(context.Background(), &types.RequestEcho{Message: "hello"}, grpc.FailFast(true))
 			if err == nil {
 				break ENSURE_CONNECTED
 			}
@@ -129,7 +129,7 @@ func (cli *grpcClient) EchoAsync(msg string) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_Echo{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Echo{res}})
 }
 
 func (cli *grpcClient) FlushAsync() *ReqRes {
@@ -138,7 +138,7 @@ func (cli *grpcClient) FlushAsync() *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_Flush{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Flush{res}})
 }
 
 func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
@@ -147,7 +147,7 @@ func (cli *grpcClient) InfoAsync(params types.RequestInfo) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_Info{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Info{res}})
 }
 
 func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
@@ -156,7 +156,7 @@ func (cli *grpcClient) SetOptionAsync(params types.RequestSetOption) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_SetOption{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_SetOption{res}})
 }
 
 func (cli *grpcClient) DeliverTxAsync(tx []byte) *ReqRes {
@@ -165,7 +165,7 @@ func (cli *grpcClient) DeliverTxAsync(tx []byte) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_DeliverTx{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_DeliverTx{res}})
 }
 
 func (cli *grpcClient) CheckTxAsync(tx []byte) *ReqRes {
@@ -174,7 +174,7 @@ func (cli *grpcClient) CheckTxAsync(tx []byte) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_CheckTx{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_CheckTx{res}})
 }
 
 func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes {
@@ -183,7 +183,7 @@ func (cli *grpcClient) QueryAsync(params types.RequestQuery) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_Query{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Query{res}})
 }
 
 func (cli *grpcClient) CommitAsync() *ReqRes {
@@ -192,7 +192,7 @@ func (cli *grpcClient) CommitAsync() *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_Commit{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_Commit{res}})
 }
 
 func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes {
@@ -201,7 +201,7 @@ func (cli *grpcClient) InitChainAsync(params types.RequestInitChain) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_InitChain{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_InitChain{res}})
 }
 
 func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes {
@@ -210,7 +210,7 @@ func (cli *grpcClient) BeginBlockAsync(params types.RequestBeginBlock) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_BeginBlock{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_BeginBlock{res}})
 }
 
 func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes {
@@ -219,7 +219,7 @@ func (cli *grpcClient) EndBlockAsync(params types.RequestEndBlock) *ReqRes {
 	if err != nil {
 		cli.StopForError(err)
 	}
-	return cli.finishAsyncCall(req, &types.Response{&types.Response_EndBlock{res}})
+	return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_EndBlock{res}})
 }
 
 func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
diff --git a/vendor/github.com/tendermint/tendermint/abci/client/local_client.go b/vendor/github.com/tendermint/tendermint/abci/client/local_client.go
index 3d1f8d8e4162722e45d24590f6dc9e17dac29d35..3ac3b6afaded77dafd74e6b7a0b5b1ca41a6e206 100644
--- a/vendor/github.com/tendermint/tendermint/abci/client/local_client.go
+++ b/vendor/github.com/tendermint/tendermint/abci/client/local_client.go
@@ -149,7 +149,7 @@ func (app *localClient) FlushSync() error {
 }
 
 func (app *localClient) EchoSync(msg string) (*types.ResponseEcho, error) {
-	return &types.ResponseEcho{msg}, nil
+	return &types.ResponseEcho{Message: msg}, nil
 }
 
 func (app *localClient) InfoSync(req types.RequestInfo) (*types.ResponseInfo, error) {
diff --git a/vendor/github.com/tendermint/tendermint/abci/types/application.go b/vendor/github.com/tendermint/tendermint/abci/types/application.go
index ef1bc92e5e0b87537e6a867badacd3efc23f8eb6..88f8d001ec12c8a22240ed6af9303378831f847f 100644
--- a/vendor/github.com/tendermint/tendermint/abci/types/application.go
+++ b/vendor/github.com/tendermint/tendermint/abci/types/application.go
@@ -85,7 +85,7 @@ func NewGRPCApplication(app Application) *GRPCApplication {
 }
 
 func (app *GRPCApplication) Echo(ctx context.Context, req *RequestEcho) (*ResponseEcho, error) {
-	return &ResponseEcho{req.Message}, nil
+	return &ResponseEcho{Message: req.Message}, nil
 }
 
 func (app *GRPCApplication) Flush(ctx context.Context, req *RequestFlush) (*ResponseFlush, error) {
diff --git a/vendor/github.com/tendermint/tendermint/abci/types/messages.go b/vendor/github.com/tendermint/tendermint/abci/types/messages.go
index 52e4b67583de47c292a82952375a4e69c4840779..cb64a15d6973fed4bbd26d94e6ccb9fd156b57cd 100644
--- a/vendor/github.com/tendermint/tendermint/abci/types/messages.go
+++ b/vendor/github.com/tendermint/tendermint/abci/types/messages.go
@@ -71,7 +71,7 @@ func encodeVarint(w io.Writer, i int64) (err error) {
 
 func ToRequestEcho(message string) *Request {
 	return &Request{
-		Value: &Request_Echo{&RequestEcho{message}},
+		Value: &Request_Echo{&RequestEcho{Message: message}},
 	}
 }
 
@@ -95,13 +95,13 @@ func ToRequestSetOption(req RequestSetOption) *Request {
 
 func ToRequestDeliverTx(tx []byte) *Request {
 	return &Request{
-		Value: &Request_DeliverTx{&RequestDeliverTx{tx}},
+		Value: &Request_DeliverTx{&RequestDeliverTx{Tx: tx}},
 	}
 }
 
 func ToRequestCheckTx(tx []byte) *Request {
 	return &Request{
-		Value: &Request_CheckTx{&RequestCheckTx{tx}},
+		Value: &Request_CheckTx{&RequestCheckTx{Tx: tx}},
 	}
 }
 
@@ -139,13 +139,13 @@ func ToRequestEndBlock(req RequestEndBlock) *Request {
 
 func ToResponseException(errStr string) *Response {
 	return &Response{
-		Value: &Response_Exception{&ResponseException{errStr}},
+		Value: &Response_Exception{&ResponseException{Error: errStr}},
 	}
 }
 
 func ToResponseEcho(message string) *Response {
 	return &Response{
-		Value: &Response_Echo{&ResponseEcho{message}},
+		Value: &Response_Echo{&ResponseEcho{Message: message}},
 	}
 }
 
diff --git a/vendor/github.com/tendermint/tendermint/abci/types/types.pb.go b/vendor/github.com/tendermint/tendermint/abci/types/types.pb.go
index 57dd14393e9b1a67fb10641f79d9465d53532a0e..ac71d91c8f95534f2e8cd1d9f49b36cba249176b 100644
--- a/vendor/github.com/tendermint/tendermint/abci/types/types.pb.go
+++ b/vendor/github.com/tendermint/tendermint/abci/types/types.pb.go
@@ -1,48 +1,6 @@
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
 // source: abci/types/types.proto
 
-/*
-	Package types is a generated protocol buffer package.
-
-	It is generated from these files:
-		abci/types/types.proto
-
-	It has these top-level messages:
-		Request
-		RequestEcho
-		RequestFlush
-		RequestInfo
-		RequestSetOption
-		RequestInitChain
-		RequestQuery
-		RequestBeginBlock
-		RequestCheckTx
-		RequestDeliverTx
-		RequestEndBlock
-		RequestCommit
-		Response
-		ResponseException
-		ResponseEcho
-		ResponseFlush
-		ResponseInfo
-		ResponseSetOption
-		ResponseInitChain
-		ResponseQuery
-		ResponseBeginBlock
-		ResponseCheckTx
-		ResponseDeliverTx
-		ResponseEndBlock
-		ResponseCommit
-		ConsensusParams
-		BlockSize
-		TxSize
-		BlockGossip
-		Header
-		Validator
-		SigningValidator
-		PubKey
-		Evidence
-*/
 //nolint
 package types
 
@@ -51,13 +9,18 @@ import golang_proto "github.com/golang/protobuf/proto"
 import fmt "fmt"
 import math "math"
 import _ "github.com/gogo/protobuf/gogoproto"
+import _ "github.com/golang/protobuf/ptypes/timestamp"
 import common "github.com/tendermint/tendermint/libs/common"
 
+import time "time"
+
 import bytes "bytes"
 
 import context "golang.org/x/net/context"
 import grpc "google.golang.org/grpc"
 
+import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
+
 import io "io"
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -65,6 +28,7 @@ var _ = proto.Marshal
 var _ = golang_proto.Marshal
 var _ = fmt.Errorf
 var _ = math.Inf
+var _ = time.Kitchen
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the proto package it is being compiled against.
@@ -85,13 +49,44 @@ type Request struct {
 	//	*Request_DeliverTx
 	//	*Request_EndBlock
 	//	*Request_Commit
-	Value isRequest_Value `protobuf_oneof:"value"`
+	Value                isRequest_Value `protobuf_oneof:"value"`
+	XXX_NoUnkeyedLiteral struct{}        `json:"-"`
+	XXX_unrecognized     []byte          `json:"-"`
+	XXX_sizecache        int32           `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{0}
+}
+func (m *Request) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Request.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 *Request) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Request.Merge(dst, src)
+}
+func (m *Request) XXX_Size() int {
+	return m.Size()
+}
+func (m *Request) XXX_DiscardUnknown() {
+	xxx_messageInfo_Request.DiscardUnknown(m)
 }
 
-func (m *Request) Reset()                    { *m = Request{} }
-func (m *Request) String() string            { return proto.CompactTextString(m) }
-func (*Request) ProtoMessage()               {}
-func (*Request) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{0} }
+var xxx_messageInfo_Request proto.InternalMessageInfo
 
 type isRequest_Value interface {
 	isRequest_Value()
@@ -415,57 +410,57 @@ func _Request_OneofSizer(msg proto.Message) (n int) {
 	switch x := m.Value.(type) {
 	case *Request_Echo:
 		s := proto.Size(x.Echo)
-		n += proto.SizeVarint(2<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_Flush:
 		s := proto.Size(x.Flush)
-		n += proto.SizeVarint(3<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_Info:
 		s := proto.Size(x.Info)
-		n += proto.SizeVarint(4<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_SetOption:
 		s := proto.Size(x.SetOption)
-		n += proto.SizeVarint(5<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_InitChain:
 		s := proto.Size(x.InitChain)
-		n += proto.SizeVarint(6<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_Query:
 		s := proto.Size(x.Query)
-		n += proto.SizeVarint(7<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_BeginBlock:
 		s := proto.Size(x.BeginBlock)
-		n += proto.SizeVarint(8<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_CheckTx:
 		s := proto.Size(x.CheckTx)
-		n += proto.SizeVarint(9<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_DeliverTx:
 		s := proto.Size(x.DeliverTx)
-		n += proto.SizeVarint(19<<3 | proto.WireBytes)
+		n += 2 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_EndBlock:
 		s := proto.Size(x.EndBlock)
-		n += proto.SizeVarint(11<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Request_Commit:
 		s := proto.Size(x.Commit)
-		n += proto.SizeVarint(12<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case nil:
@@ -476,13 +471,44 @@ func _Request_OneofSizer(msg proto.Message) (n int) {
 }
 
 type RequestEcho struct {
-	Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{1}
+}
+func (m *RequestEcho) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestEcho) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestEcho.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 *RequestEcho) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestEcho.Merge(dst, src)
+}
+func (m *RequestEcho) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestEcho) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestEcho.DiscardUnknown(m)
 }
 
-func (m *RequestEcho) Reset()                    { *m = RequestEcho{} }
-func (m *RequestEcho) String() string            { return proto.CompactTextString(m) }
-func (*RequestEcho) ProtoMessage()               {}
-func (*RequestEcho) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{1} }
+var xxx_messageInfo_RequestEcho proto.InternalMessageInfo
 
 func (m *RequestEcho) GetMessage() string {
 	if m != nil {
@@ -492,21 +518,83 @@ func (m *RequestEcho) GetMessage() string {
 }
 
 type RequestFlush struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{2}
+}
+func (m *RequestFlush) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestFlush) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestFlush.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 *RequestFlush) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestFlush.Merge(dst, src)
+}
+func (m *RequestFlush) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestFlush) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestFlush.DiscardUnknown(m)
 }
 
-func (m *RequestFlush) Reset()                    { *m = RequestFlush{} }
-func (m *RequestFlush) String() string            { return proto.CompactTextString(m) }
-func (*RequestFlush) ProtoMessage()               {}
-func (*RequestFlush) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{2} }
+var xxx_messageInfo_RequestFlush proto.InternalMessageInfo
 
 type RequestInfo struct {
-	Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	Version              string   `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{3}
+}
+func (m *RequestInfo) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestInfo.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 *RequestInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestInfo.Merge(dst, src)
+}
+func (m *RequestInfo) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestInfo) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestInfo.DiscardUnknown(m)
 }
 
-func (m *RequestInfo) Reset()                    { *m = RequestInfo{} }
-func (m *RequestInfo) String() string            { return proto.CompactTextString(m) }
-func (*RequestInfo) ProtoMessage()               {}
-func (*RequestInfo) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{3} }
+var xxx_messageInfo_RequestInfo proto.InternalMessageInfo
 
 func (m *RequestInfo) GetVersion() string {
 	if m != nil {
@@ -517,14 +605,45 @@ func (m *RequestInfo) GetVersion() string {
 
 // nondeterministic
 type RequestSetOption struct {
-	Key   string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
-	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+	Key                  string   `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
+	Value                string   `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{4}
+}
+func (m *RequestSetOption) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestSetOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestSetOption.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 *RequestSetOption) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestSetOption.Merge(dst, src)
+}
+func (m *RequestSetOption) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestSetOption) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestSetOption.DiscardUnknown(m)
 }
 
-func (m *RequestSetOption) Reset()                    { *m = RequestSetOption{} }
-func (m *RequestSetOption) String() string            { return proto.CompactTextString(m) }
-func (*RequestSetOption) ProtoMessage()               {}
-func (*RequestSetOption) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{4} }
+var xxx_messageInfo_RequestSetOption proto.InternalMessageInfo
 
 func (m *RequestSetOption) GetKey() string {
 	if m != nil {
@@ -541,23 +660,54 @@ func (m *RequestSetOption) GetValue() string {
 }
 
 type RequestInitChain struct {
-	Time            int64            `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"`
-	ChainId         string           `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
-	ConsensusParams *ConsensusParams `protobuf:"bytes,3,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"`
-	Validators      []Validator      `protobuf:"bytes,4,rep,name=validators" json:"validators"`
-	AppStateBytes   []byte           `protobuf:"bytes,5,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"`
+	Time                 time.Time        `protobuf:"bytes,1,opt,name=time,stdtime" json:"time"`
+	ChainId              string           `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+	ConsensusParams      *ConsensusParams `protobuf:"bytes,3,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"`
+	Validators           []Validator      `protobuf:"bytes,4,rep,name=validators" json:"validators"`
+	AppStateBytes        []byte           `protobuf:"bytes,5,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
+	XXX_unrecognized     []byte           `json:"-"`
+	XXX_sizecache        int32            `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{5}
+}
+func (m *RequestInitChain) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestInitChain) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestInitChain.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 *RequestInitChain) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestInitChain.Merge(dst, src)
+}
+func (m *RequestInitChain) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestInitChain) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestInitChain.DiscardUnknown(m)
 }
 
-func (m *RequestInitChain) Reset()                    { *m = RequestInitChain{} }
-func (m *RequestInitChain) String() string            { return proto.CompactTextString(m) }
-func (*RequestInitChain) ProtoMessage()               {}
-func (*RequestInitChain) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{5} }
+var xxx_messageInfo_RequestInitChain proto.InternalMessageInfo
 
-func (m *RequestInitChain) GetTime() int64 {
+func (m *RequestInitChain) GetTime() time.Time {
 	if m != nil {
 		return m.Time
 	}
-	return 0
+	return time.Time{}
 }
 
 func (m *RequestInitChain) GetChainId() string {
@@ -589,16 +739,47 @@ func (m *RequestInitChain) GetAppStateBytes() []byte {
 }
 
 type RequestQuery struct {
-	Data   []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
-	Path   string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
-	Height int64  `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
-	Prove  bool   `protobuf:"varint,4,opt,name=prove,proto3" json:"prove,omitempty"`
+	Data                 []byte   `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+	Path                 string   `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+	Height               int64    `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
+	Prove                bool     `protobuf:"varint,4,opt,name=prove,proto3" json:"prove,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{6}
+}
+func (m *RequestQuery) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestQuery.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 *RequestQuery) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestQuery.Merge(dst, src)
+}
+func (m *RequestQuery) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestQuery) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestQuery.DiscardUnknown(m)
 }
 
-func (m *RequestQuery) Reset()                    { *m = RequestQuery{} }
-func (m *RequestQuery) String() string            { return proto.CompactTextString(m) }
-func (*RequestQuery) ProtoMessage()               {}
-func (*RequestQuery) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{6} }
+var xxx_messageInfo_RequestQuery proto.InternalMessageInfo
 
 func (m *RequestQuery) GetData() []byte {
 	if m != nil {
@@ -628,17 +809,49 @@ func (m *RequestQuery) GetProve() bool {
 	return false
 }
 
+// NOTE: validators here have empty pubkeys.
 type RequestBeginBlock struct {
-	Hash                []byte             `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
-	Header              Header             `protobuf:"bytes,2,opt,name=header" json:"header"`
-	Validators          []SigningValidator `protobuf:"bytes,3,rep,name=validators" json:"validators"`
-	ByzantineValidators []Evidence         `protobuf:"bytes,4,rep,name=byzantine_validators,json=byzantineValidators" json:"byzantine_validators"`
+	Hash                 []byte         `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
+	Header               Header         `protobuf:"bytes,2,opt,name=header" json:"header"`
+	LastCommitInfo       LastCommitInfo `protobuf:"bytes,3,opt,name=last_commit_info,json=lastCommitInfo" json:"last_commit_info"`
+	ByzantineValidators  []Evidence     `protobuf:"bytes,4,rep,name=byzantine_validators,json=byzantineValidators" json:"byzantine_validators"`
+	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
+	XXX_unrecognized     []byte         `json:"-"`
+	XXX_sizecache        int32          `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{7}
+}
+func (m *RequestBeginBlock) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestBeginBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestBeginBlock.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 *RequestBeginBlock) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestBeginBlock.Merge(dst, src)
+}
+func (m *RequestBeginBlock) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestBeginBlock) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestBeginBlock.DiscardUnknown(m)
 }
 
-func (m *RequestBeginBlock) Reset()                    { *m = RequestBeginBlock{} }
-func (m *RequestBeginBlock) String() string            { return proto.CompactTextString(m) }
-func (*RequestBeginBlock) ProtoMessage()               {}
-func (*RequestBeginBlock) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{7} }
+var xxx_messageInfo_RequestBeginBlock proto.InternalMessageInfo
 
 func (m *RequestBeginBlock) GetHash() []byte {
 	if m != nil {
@@ -654,11 +867,11 @@ func (m *RequestBeginBlock) GetHeader() Header {
 	return Header{}
 }
 
-func (m *RequestBeginBlock) GetValidators() []SigningValidator {
+func (m *RequestBeginBlock) GetLastCommitInfo() LastCommitInfo {
 	if m != nil {
-		return m.Validators
+		return m.LastCommitInfo
 	}
-	return nil
+	return LastCommitInfo{}
 }
 
 func (m *RequestBeginBlock) GetByzantineValidators() []Evidence {
@@ -669,13 +882,44 @@ func (m *RequestBeginBlock) GetByzantineValidators() []Evidence {
 }
 
 type RequestCheckTx struct {
-	Tx []byte `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
+	Tx                   []byte   `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{8}
+}
+func (m *RequestCheckTx) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestCheckTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestCheckTx.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 *RequestCheckTx) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestCheckTx.Merge(dst, src)
+}
+func (m *RequestCheckTx) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestCheckTx) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestCheckTx.DiscardUnknown(m)
 }
 
-func (m *RequestCheckTx) Reset()                    { *m = RequestCheckTx{} }
-func (m *RequestCheckTx) String() string            { return proto.CompactTextString(m) }
-func (*RequestCheckTx) ProtoMessage()               {}
-func (*RequestCheckTx) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{8} }
+var xxx_messageInfo_RequestCheckTx proto.InternalMessageInfo
 
 func (m *RequestCheckTx) GetTx() []byte {
 	if m != nil {
@@ -685,13 +929,44 @@ func (m *RequestCheckTx) GetTx() []byte {
 }
 
 type RequestDeliverTx struct {
-	Tx []byte `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
+	Tx                   []byte   `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{9}
+}
+func (m *RequestDeliverTx) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestDeliverTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestDeliverTx.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 *RequestDeliverTx) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestDeliverTx.Merge(dst, src)
+}
+func (m *RequestDeliverTx) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestDeliverTx) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestDeliverTx.DiscardUnknown(m)
 }
 
-func (m *RequestDeliverTx) Reset()                    { *m = RequestDeliverTx{} }
-func (m *RequestDeliverTx) String() string            { return proto.CompactTextString(m) }
-func (*RequestDeliverTx) ProtoMessage()               {}
-func (*RequestDeliverTx) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{9} }
+var xxx_messageInfo_RequestDeliverTx proto.InternalMessageInfo
 
 func (m *RequestDeliverTx) GetTx() []byte {
 	if m != nil {
@@ -701,13 +976,44 @@ func (m *RequestDeliverTx) GetTx() []byte {
 }
 
 type RequestEndBlock struct {
-	Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
+	Height               int64    `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{10}
+}
+func (m *RequestEndBlock) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestEndBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestEndBlock.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 *RequestEndBlock) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestEndBlock.Merge(dst, src)
+}
+func (m *RequestEndBlock) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestEndBlock) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestEndBlock.DiscardUnknown(m)
 }
 
-func (m *RequestEndBlock) Reset()                    { *m = RequestEndBlock{} }
-func (m *RequestEndBlock) String() string            { return proto.CompactTextString(m) }
-func (*RequestEndBlock) ProtoMessage()               {}
-func (*RequestEndBlock) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{10} }
+var xxx_messageInfo_RequestEndBlock proto.InternalMessageInfo
 
 func (m *RequestEndBlock) GetHeight() int64 {
 	if m != nil {
@@ -717,12 +1023,43 @@ func (m *RequestEndBlock) GetHeight() int64 {
 }
 
 type RequestCommit struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{11}
+}
+func (m *RequestCommit) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *RequestCommit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_RequestCommit.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 *RequestCommit) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_RequestCommit.Merge(dst, src)
+}
+func (m *RequestCommit) XXX_Size() int {
+	return m.Size()
+}
+func (m *RequestCommit) XXX_DiscardUnknown() {
+	xxx_messageInfo_RequestCommit.DiscardUnknown(m)
 }
 
-func (m *RequestCommit) Reset()                    { *m = RequestCommit{} }
-func (m *RequestCommit) String() string            { return proto.CompactTextString(m) }
-func (*RequestCommit) ProtoMessage()               {}
-func (*RequestCommit) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{11} }
+var xxx_messageInfo_RequestCommit proto.InternalMessageInfo
 
 type Response struct {
 	// Types that are valid to be assigned to Value:
@@ -738,13 +1075,44 @@ type Response struct {
 	//	*Response_DeliverTx
 	//	*Response_EndBlock
 	//	*Response_Commit
-	Value isResponse_Value `protobuf_oneof:"value"`
+	Value                isResponse_Value `protobuf_oneof:"value"`
+	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
+	XXX_unrecognized     []byte           `json:"-"`
+	XXX_sizecache        int32            `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{12}
+}
+func (m *Response) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Response.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 *Response) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Response.Merge(dst, src)
+}
+func (m *Response) XXX_Size() int {
+	return m.Size()
+}
+func (m *Response) XXX_DiscardUnknown() {
+	xxx_messageInfo_Response.DiscardUnknown(m)
 }
 
-func (m *Response) Reset()                    { *m = Response{} }
-func (m *Response) String() string            { return proto.CompactTextString(m) }
-func (*Response) ProtoMessage()               {}
-func (*Response) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{12} }
+var xxx_messageInfo_Response proto.InternalMessageInfo
 
 type isResponse_Value interface {
 	isResponse_Value()
@@ -1093,62 +1461,62 @@ func _Response_OneofSizer(msg proto.Message) (n int) {
 	switch x := m.Value.(type) {
 	case *Response_Exception:
 		s := proto.Size(x.Exception)
-		n += proto.SizeVarint(1<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_Echo:
 		s := proto.Size(x.Echo)
-		n += proto.SizeVarint(2<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_Flush:
 		s := proto.Size(x.Flush)
-		n += proto.SizeVarint(3<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_Info:
 		s := proto.Size(x.Info)
-		n += proto.SizeVarint(4<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_SetOption:
 		s := proto.Size(x.SetOption)
-		n += proto.SizeVarint(5<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_InitChain:
 		s := proto.Size(x.InitChain)
-		n += proto.SizeVarint(6<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_Query:
 		s := proto.Size(x.Query)
-		n += proto.SizeVarint(7<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_BeginBlock:
 		s := proto.Size(x.BeginBlock)
-		n += proto.SizeVarint(8<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_CheckTx:
 		s := proto.Size(x.CheckTx)
-		n += proto.SizeVarint(9<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_DeliverTx:
 		s := proto.Size(x.DeliverTx)
-		n += proto.SizeVarint(10<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_EndBlock:
 		s := proto.Size(x.EndBlock)
-		n += proto.SizeVarint(11<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case *Response_Commit:
 		s := proto.Size(x.Commit)
-		n += proto.SizeVarint(12<<3 | proto.WireBytes)
+		n += 1 // tag and wire
 		n += proto.SizeVarint(uint64(s))
 		n += s
 	case nil:
@@ -1160,13 +1528,44 @@ func _Response_OneofSizer(msg proto.Message) (n int) {
 
 // nondeterministic
 type ResponseException struct {
-	Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
+	Error                string   `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{13}
+}
+func (m *ResponseException) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseException) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseException.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 *ResponseException) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseException.Merge(dst, src)
+}
+func (m *ResponseException) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseException) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseException.DiscardUnknown(m)
 }
 
-func (m *ResponseException) Reset()                    { *m = ResponseException{} }
-func (m *ResponseException) String() string            { return proto.CompactTextString(m) }
-func (*ResponseException) ProtoMessage()               {}
-func (*ResponseException) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{13} }
+var xxx_messageInfo_ResponseException proto.InternalMessageInfo
 
 func (m *ResponseException) GetError() string {
 	if m != nil {
@@ -1176,13 +1575,44 @@ func (m *ResponseException) GetError() string {
 }
 
 type ResponseEcho struct {
-	Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	Message              string   `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{14}
+}
+func (m *ResponseEcho) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseEcho) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseEcho.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 *ResponseEcho) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseEcho.Merge(dst, src)
+}
+func (m *ResponseEcho) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseEcho) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseEcho.DiscardUnknown(m)
 }
 
-func (m *ResponseEcho) Reset()                    { *m = ResponseEcho{} }
-func (m *ResponseEcho) String() string            { return proto.CompactTextString(m) }
-func (*ResponseEcho) ProtoMessage()               {}
-func (*ResponseEcho) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{14} }
+var xxx_messageInfo_ResponseEcho proto.InternalMessageInfo
 
 func (m *ResponseEcho) GetMessage() string {
 	if m != nil {
@@ -1192,24 +1622,86 @@ func (m *ResponseEcho) GetMessage() string {
 }
 
 type ResponseFlush struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{15}
+}
+func (m *ResponseFlush) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseFlush) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseFlush.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 *ResponseFlush) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseFlush.Merge(dst, src)
+}
+func (m *ResponseFlush) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseFlush) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseFlush.DiscardUnknown(m)
 }
 
-func (m *ResponseFlush) Reset()                    { *m = ResponseFlush{} }
-func (m *ResponseFlush) String() string            { return proto.CompactTextString(m) }
-func (*ResponseFlush) ProtoMessage()               {}
-func (*ResponseFlush) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{15} }
+var xxx_messageInfo_ResponseFlush proto.InternalMessageInfo
 
 type ResponseInfo struct {
-	Data             string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
-	Version          string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
-	LastBlockHeight  int64  `protobuf:"varint,3,opt,name=last_block_height,json=lastBlockHeight,proto3" json:"last_block_height,omitempty"`
-	LastBlockAppHash []byte `protobuf:"bytes,4,opt,name=last_block_app_hash,json=lastBlockAppHash,proto3" json:"last_block_app_hash,omitempty"`
+	Data                 string   `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+	Version              string   `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+	LastBlockHeight      int64    `protobuf:"varint,3,opt,name=last_block_height,json=lastBlockHeight,proto3" json:"last_block_height,omitempty"`
+	LastBlockAppHash     []byte   `protobuf:"bytes,4,opt,name=last_block_app_hash,json=lastBlockAppHash,proto3" json:"last_block_app_hash,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{16}
+}
+func (m *ResponseInfo) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseInfo.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 *ResponseInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseInfo.Merge(dst, src)
+}
+func (m *ResponseInfo) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseInfo) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseInfo.DiscardUnknown(m)
 }
 
-func (m *ResponseInfo) Reset()                    { *m = ResponseInfo{} }
-func (m *ResponseInfo) String() string            { return proto.CompactTextString(m) }
-func (*ResponseInfo) ProtoMessage()               {}
-func (*ResponseInfo) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{16} }
+var xxx_messageInfo_ResponseInfo proto.InternalMessageInfo
 
 func (m *ResponseInfo) GetData() string {
 	if m != nil {
@@ -1243,14 +1735,45 @@ func (m *ResponseInfo) GetLastBlockAppHash() []byte {
 type ResponseSetOption struct {
 	Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
 	// bytes data = 2;
-	Log  string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
-	Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
+	Log                  string   `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
+	Info                 string   `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{17}
+}
+func (m *ResponseSetOption) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseSetOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseSetOption.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 *ResponseSetOption) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseSetOption.Merge(dst, src)
+}
+func (m *ResponseSetOption) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseSetOption) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseSetOption.DiscardUnknown(m)
 }
 
-func (m *ResponseSetOption) Reset()                    { *m = ResponseSetOption{} }
-func (m *ResponseSetOption) String() string            { return proto.CompactTextString(m) }
-func (*ResponseSetOption) ProtoMessage()               {}
-func (*ResponseSetOption) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{17} }
+var xxx_messageInfo_ResponseSetOption proto.InternalMessageInfo
 
 func (m *ResponseSetOption) GetCode() uint32 {
 	if m != nil {
@@ -1274,14 +1797,45 @@ func (m *ResponseSetOption) GetInfo() string {
 }
 
 type ResponseInitChain struct {
-	ConsensusParams *ConsensusParams `protobuf:"bytes,1,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"`
-	Validators      []Validator      `protobuf:"bytes,2,rep,name=validators" json:"validators"`
+	ConsensusParams      *ConsensusParams `protobuf:"bytes,1,opt,name=consensus_params,json=consensusParams" json:"consensus_params,omitempty"`
+	Validators           []Validator      `protobuf:"bytes,2,rep,name=validators" json:"validators"`
+	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
+	XXX_unrecognized     []byte           `json:"-"`
+	XXX_sizecache        int32            `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{18}
+}
+func (m *ResponseInitChain) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseInitChain) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseInitChain.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 *ResponseInitChain) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseInitChain.Merge(dst, src)
+}
+func (m *ResponseInitChain) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseInitChain) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseInitChain.DiscardUnknown(m)
 }
 
-func (m *ResponseInitChain) Reset()                    { *m = ResponseInitChain{} }
-func (m *ResponseInitChain) String() string            { return proto.CompactTextString(m) }
-func (*ResponseInitChain) ProtoMessage()               {}
-func (*ResponseInitChain) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} }
+var xxx_messageInfo_ResponseInitChain proto.InternalMessageInfo
 
 func (m *ResponseInitChain) GetConsensusParams() *ConsensusParams {
 	if m != nil {
@@ -1300,19 +1854,50 @@ func (m *ResponseInitChain) GetValidators() []Validator {
 type ResponseQuery struct {
 	Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
 	// bytes data = 2; // use "value" instead.
-	Log    string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
-	Info   string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
-	Index  int64  `protobuf:"varint,5,opt,name=index,proto3" json:"index,omitempty"`
-	Key    []byte `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
-	Value  []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"`
-	Proof  []byte `protobuf:"bytes,8,opt,name=proof,proto3" json:"proof,omitempty"`
-	Height int64  `protobuf:"varint,9,opt,name=height,proto3" json:"height,omitempty"`
+	Log                  string   `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
+	Info                 string   `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
+	Index                int64    `protobuf:"varint,5,opt,name=index,proto3" json:"index,omitempty"`
+	Key                  []byte   `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
+	Value                []byte   `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"`
+	Proof                []byte   `protobuf:"bytes,8,opt,name=proof,proto3" json:"proof,omitempty"`
+	Height               int64    `protobuf:"varint,9,opt,name=height,proto3" json:"height,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{19}
+}
+func (m *ResponseQuery) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseQuery.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 *ResponseQuery) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseQuery.Merge(dst, src)
+}
+func (m *ResponseQuery) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseQuery) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseQuery.DiscardUnknown(m)
 }
 
-func (m *ResponseQuery) Reset()                    { *m = ResponseQuery{} }
-func (m *ResponseQuery) String() string            { return proto.CompactTextString(m) }
-func (*ResponseQuery) ProtoMessage()               {}
-func (*ResponseQuery) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19} }
+var xxx_messageInfo_ResponseQuery proto.InternalMessageInfo
 
 func (m *ResponseQuery) GetCode() uint32 {
 	if m != nil {
@@ -1371,13 +1956,44 @@ func (m *ResponseQuery) GetHeight() int64 {
 }
 
 type ResponseBeginBlock struct {
-	Tags []common.KVPair `protobuf:"bytes,1,rep,name=tags" json:"tags,omitempty"`
+	Tags                 []common.KVPair `protobuf:"bytes,1,rep,name=tags" json:"tags,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}        `json:"-"`
+	XXX_unrecognized     []byte          `json:"-"`
+	XXX_sizecache        int32           `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{20}
+}
+func (m *ResponseBeginBlock) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseBeginBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseBeginBlock.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 *ResponseBeginBlock) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseBeginBlock.Merge(dst, src)
+}
+func (m *ResponseBeginBlock) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseBeginBlock) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseBeginBlock.DiscardUnknown(m)
 }
 
-func (m *ResponseBeginBlock) Reset()                    { *m = ResponseBeginBlock{} }
-func (m *ResponseBeginBlock) String() string            { return proto.CompactTextString(m) }
-func (*ResponseBeginBlock) ProtoMessage()               {}
-func (*ResponseBeginBlock) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} }
+var xxx_messageInfo_ResponseBeginBlock proto.InternalMessageInfo
 
 func (m *ResponseBeginBlock) GetTags() []common.KVPair {
 	if m != nil {
@@ -1387,20 +2003,50 @@ func (m *ResponseBeginBlock) GetTags() []common.KVPair {
 }
 
 type ResponseCheckTx struct {
-	Code      uint32          `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
-	Data      []byte          `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
-	Log       string          `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
-	Info      string          `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
-	GasWanted int64           `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"`
-	GasUsed   int64           `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
-	Tags      []common.KVPair `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
-	Fee       common.KI64Pair `protobuf:"bytes,8,opt,name=fee" json:"fee"`
+	Code                 uint32          `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
+	Data                 []byte          `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	Log                  string          `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
+	Info                 string          `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
+	GasWanted            int64           `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"`
+	GasUsed              int64           `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
+	Tags                 []common.KVPair `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}        `json:"-"`
+	XXX_unrecognized     []byte          `json:"-"`
+	XXX_sizecache        int32           `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{21}
+}
+func (m *ResponseCheckTx) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseCheckTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseCheckTx.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 *ResponseCheckTx) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseCheckTx.Merge(dst, src)
+}
+func (m *ResponseCheckTx) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseCheckTx) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseCheckTx.DiscardUnknown(m)
 }
 
-func (m *ResponseCheckTx) Reset()                    { *m = ResponseCheckTx{} }
-func (m *ResponseCheckTx) String() string            { return proto.CompactTextString(m) }
-func (*ResponseCheckTx) ProtoMessage()               {}
-func (*ResponseCheckTx) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{21} }
+var xxx_messageInfo_ResponseCheckTx proto.InternalMessageInfo
 
 func (m *ResponseCheckTx) GetCode() uint32 {
 	if m != nil {
@@ -1451,28 +2097,51 @@ func (m *ResponseCheckTx) GetTags() []common.KVPair {
 	return nil
 }
 
-func (m *ResponseCheckTx) GetFee() common.KI64Pair {
-	if m != nil {
-		return m.Fee
+type ResponseDeliverTx struct {
+	Code                 uint32          `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
+	Data                 []byte          `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	Log                  string          `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
+	Info                 string          `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
+	GasWanted            int64           `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"`
+	GasUsed              int64           `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
+	Tags                 []common.KVPair `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}        `json:"-"`
+	XXX_unrecognized     []byte          `json:"-"`
+	XXX_sizecache        int32           `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{22}
+}
+func (m *ResponseDeliverTx) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseDeliverTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseDeliverTx.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalTo(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
 	}
-	return common.KI64Pair{}
 }
-
-type ResponseDeliverTx struct {
-	Code      uint32          `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
-	Data      []byte          `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
-	Log       string          `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"`
-	Info      string          `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"`
-	GasWanted int64           `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"`
-	GasUsed   int64           `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
-	Tags      []common.KVPair `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
-	Fee       common.KI64Pair `protobuf:"bytes,8,opt,name=fee" json:"fee"`
+func (dst *ResponseDeliverTx) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseDeliverTx.Merge(dst, src)
+}
+func (m *ResponseDeliverTx) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseDeliverTx) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseDeliverTx.DiscardUnknown(m)
 }
 
-func (m *ResponseDeliverTx) Reset()                    { *m = ResponseDeliverTx{} }
-func (m *ResponseDeliverTx) String() string            { return proto.CompactTextString(m) }
-func (*ResponseDeliverTx) ProtoMessage()               {}
-func (*ResponseDeliverTx) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22} }
+var xxx_messageInfo_ResponseDeliverTx proto.InternalMessageInfo
 
 func (m *ResponseDeliverTx) GetCode() uint32 {
 	if m != nil {
@@ -1523,23 +2192,47 @@ func (m *ResponseDeliverTx) GetTags() []common.KVPair {
 	return nil
 }
 
-func (m *ResponseDeliverTx) GetFee() common.KI64Pair {
-	if m != nil {
-		return m.Fee
-	}
-	return common.KI64Pair{}
-}
-
 type ResponseEndBlock struct {
 	ValidatorUpdates      []Validator      `protobuf:"bytes,1,rep,name=validator_updates,json=validatorUpdates" json:"validator_updates"`
 	ConsensusParamUpdates *ConsensusParams `protobuf:"bytes,2,opt,name=consensus_param_updates,json=consensusParamUpdates" json:"consensus_param_updates,omitempty"`
 	Tags                  []common.KVPair  `protobuf:"bytes,3,rep,name=tags" json:"tags,omitempty"`
+	XXX_NoUnkeyedLiteral  struct{}         `json:"-"`
+	XXX_unrecognized      []byte           `json:"-"`
+	XXX_sizecache         int32            `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{23}
+}
+func (m *ResponseEndBlock) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseEndBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseEndBlock.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 *ResponseEndBlock) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseEndBlock.Merge(dst, src)
+}
+func (m *ResponseEndBlock) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseEndBlock) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseEndBlock.DiscardUnknown(m)
 }
 
-func (m *ResponseEndBlock) Reset()                    { *m = ResponseEndBlock{} }
-func (m *ResponseEndBlock) String() string            { return proto.CompactTextString(m) }
-func (*ResponseEndBlock) ProtoMessage()               {}
-func (*ResponseEndBlock) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23} }
+var xxx_messageInfo_ResponseEndBlock proto.InternalMessageInfo
 
 func (m *ResponseEndBlock) GetValidatorUpdates() []Validator {
 	if m != nil {
@@ -1564,13 +2257,44 @@ func (m *ResponseEndBlock) GetTags() []common.KVPair {
 
 type ResponseCommit struct {
 	// reserve 1
-	Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	Data                 []byte   `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{24}
+}
+func (m *ResponseCommit) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ResponseCommit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ResponseCommit.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 *ResponseCommit) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ResponseCommit.Merge(dst, src)
+}
+func (m *ResponseCommit) XXX_Size() int {
+	return m.Size()
+}
+func (m *ResponseCommit) XXX_DiscardUnknown() {
+	xxx_messageInfo_ResponseCommit.DiscardUnknown(m)
 }
 
-func (m *ResponseCommit) Reset()                    { *m = ResponseCommit{} }
-func (m *ResponseCommit) String() string            { return proto.CompactTextString(m) }
-func (*ResponseCommit) ProtoMessage()               {}
-func (*ResponseCommit) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} }
+var xxx_messageInfo_ResponseCommit proto.InternalMessageInfo
 
 func (m *ResponseCommit) GetData() []byte {
 	if m != nil {
@@ -1582,15 +2306,46 @@ 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"`
+	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:"-"`
+}
+
+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_d8da2202f45d32c0, []int{25}
+}
+func (m *ConsensusParams) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *ConsensusParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_ConsensusParams.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 *ConsensusParams) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ConsensusParams.Merge(dst, src)
+}
+func (m *ConsensusParams) XXX_Size() int {
+	return m.Size()
+}
+func (m *ConsensusParams) XXX_DiscardUnknown() {
+	xxx_messageInfo_ConsensusParams.DiscardUnknown(m)
 }
 
-func (m *ConsensusParams) Reset()                    { *m = ConsensusParams{} }
-func (m *ConsensusParams) String() string            { return proto.CompactTextString(m) }
-func (*ConsensusParams) ProtoMessage()               {}
-func (*ConsensusParams) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} }
+var xxx_messageInfo_ConsensusParams proto.InternalMessageInfo
 
 func (m *ConsensusParams) GetBlockSize() *BlockSize {
 	if m != nil {
@@ -1613,17 +2368,48 @@ func (m *ConsensusParams) GetBlockGossip() *BlockGossip {
 	return nil
 }
 
-// BlockSize contain limits on the block size.
+// 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"`
-	MaxTxs   int32 `protobuf:"varint,2,opt,name=max_txs,json=maxTxs,proto3" json:"max_txs,omitempty"`
-	MaxGas   int64 `protobuf:"varint,3,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"`
+	MaxBytes             int32    `protobuf:"varint,1,opt,name=max_bytes,json=maxBytes,proto3" json:"max_bytes,omitempty"`
+	MaxTxs               int32    `protobuf:"varint,2,opt,name=max_txs,json=maxTxs,proto3" json:"max_txs,omitempty"`
+	MaxGas               int64    `protobuf:"varint,3,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{26}
+}
+func (m *BlockSize) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *BlockSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_BlockSize.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 *BlockSize) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BlockSize.Merge(dst, src)
+}
+func (m *BlockSize) XXX_Size() int {
+	return m.Size()
+}
+func (m *BlockSize) XXX_DiscardUnknown() {
+	xxx_messageInfo_BlockSize.DiscardUnknown(m)
 }
 
-func (m *BlockSize) Reset()                    { *m = BlockSize{} }
-func (m *BlockSize) String() string            { return proto.CompactTextString(m) }
-func (*BlockSize) ProtoMessage()               {}
-func (*BlockSize) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} }
+var xxx_messageInfo_BlockSize proto.InternalMessageInfo
 
 func (m *BlockSize) GetMaxBytes() int32 {
 	if m != nil {
@@ -1646,16 +2432,47 @@ func (m *BlockSize) GetMaxGas() int64 {
 	return 0
 }
 
-// TxSize contain limits on the tx size.
+// 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"`
+	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"`
+	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_d8da2202f45d32c0, []int{27}
+}
+func (m *TxSize) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *TxSize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_TxSize.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 *TxSize) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_TxSize.Merge(dst, src)
+}
+func (m *TxSize) XXX_Size() int {
+	return m.Size()
+}
+func (m *TxSize) XXX_DiscardUnknown() {
+	xxx_messageInfo_TxSize.DiscardUnknown(m)
 }
 
-func (m *TxSize) Reset()                    { *m = TxSize{} }
-func (m *TxSize) String() string            { return proto.CompactTextString(m) }
-func (*TxSize) ProtoMessage()               {}
-func (*TxSize) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} }
+var xxx_messageInfo_TxSize proto.InternalMessageInfo
 
 func (m *TxSize) GetMaxBytes() int32 {
 	if m != nil {
@@ -1675,13 +2492,44 @@ func (m *TxSize) GetMaxGas() int64 {
 // 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"`
+	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_d8da2202f45d32c0, []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)
 }
 
-func (m *BlockGossip) Reset()                    { *m = BlockGossip{} }
-func (m *BlockGossip) String() string            { return proto.CompactTextString(m) }
-func (*BlockGossip) ProtoMessage()               {}
-func (*BlockGossip) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} }
+var xxx_messageInfo_BlockGossip proto.InternalMessageInfo
 
 func (m *BlockGossip) GetBlockPartSizeBytes() int32 {
 	if m != nil {
@@ -1690,12 +2538,67 @@ func (m *BlockGossip) GetBlockPartSizeBytes() int32 {
 	return 0
 }
 
+type LastCommitInfo struct {
+	CommitRound          int32              `protobuf:"varint,1,opt,name=commit_round,json=commitRound,proto3" json:"commit_round,omitempty"`
+	Validators           []SigningValidator `protobuf:"bytes,2,rep,name=validators" json:"validators"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{29}
+}
+func (m *LastCommitInfo) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *LastCommitInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_LastCommitInfo.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 *LastCommitInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_LastCommitInfo.Merge(dst, src)
+}
+func (m *LastCommitInfo) XXX_Size() int {
+	return m.Size()
+}
+func (m *LastCommitInfo) XXX_DiscardUnknown() {
+	xxx_messageInfo_LastCommitInfo.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_LastCommitInfo proto.InternalMessageInfo
+
+func (m *LastCommitInfo) GetCommitRound() int32 {
+	if m != nil {
+		return m.CommitRound
+	}
+	return 0
+}
+
+func (m *LastCommitInfo) GetValidators() []SigningValidator {
+	if m != nil {
+		return m.Validators
+	}
+	return nil
+}
+
 // just the minimum the app might need
 type Header struct {
 	// basics
-	ChainID string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
-	Height  int64  `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
-	Time    int64  `protobuf:"varint,3,opt,name=time,proto3" json:"time,omitempty"`
+	ChainID string    `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+	Height  int64     `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
+	Time    time.Time `protobuf:"bytes,3,opt,name=time,stdtime" json:"time"`
 	// txs
 	NumTxs   int32 `protobuf:"varint,4,opt,name=num_txs,json=numTxs,proto3" json:"num_txs,omitempty"`
 	TotalTxs int64 `protobuf:"varint,5,opt,name=total_txs,json=totalTxs,proto3" json:"total_txs,omitempty"`
@@ -1704,13 +2607,44 @@ type Header struct {
 	ValidatorsHash []byte `protobuf:"bytes,7,opt,name=validators_hash,json=validatorsHash,proto3" json:"validators_hash,omitempty"`
 	AppHash        []byte `protobuf:"bytes,8,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"`
 	// consensus
-	Proposer Validator `protobuf:"bytes,9,opt,name=proposer" json:"proposer"`
+	Proposer             Validator `protobuf:"bytes,9,opt,name=proposer" json:"proposer"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{30}
+}
+func (m *Header) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Header.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 *Header) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Header.Merge(dst, src)
+}
+func (m *Header) XXX_Size() int {
+	return m.Size()
+}
+func (m *Header) XXX_DiscardUnknown() {
+	xxx_messageInfo_Header.DiscardUnknown(m)
 }
 
-func (m *Header) Reset()                    { *m = Header{} }
-func (m *Header) String() string            { return proto.CompactTextString(m) }
-func (*Header) ProtoMessage()               {}
-func (*Header) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} }
+var xxx_messageInfo_Header proto.InternalMessageInfo
 
 func (m *Header) GetChainID() string {
 	if m != nil {
@@ -1726,11 +2660,11 @@ func (m *Header) GetHeight() int64 {
 	return 0
 }
 
-func (m *Header) GetTime() int64 {
+func (m *Header) GetTime() time.Time {
 	if m != nil {
 		return m.Time
 	}
-	return 0
+	return time.Time{}
 }
 
 func (m *Header) GetNumTxs() int32 {
@@ -1777,15 +2711,46 @@ func (m *Header) GetProposer() Validator {
 
 // Validator
 type Validator struct {
-	Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
-	PubKey  PubKey `protobuf:"bytes,2,opt,name=pub_key,json=pubKey" json:"pub_key"`
-	Power   int64  `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"`
+	Address              []byte   `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+	PubKey               PubKey   `protobuf:"bytes,2,opt,name=pub_key,json=pubKey" json:"pub_key"`
+	Power                int64    `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{31}
+}
+func (m *Validator) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Validator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Validator.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 *Validator) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Validator.Merge(dst, src)
+}
+func (m *Validator) XXX_Size() int {
+	return m.Size()
+}
+func (m *Validator) XXX_DiscardUnknown() {
+	xxx_messageInfo_Validator.DiscardUnknown(m)
 }
 
-func (m *Validator) Reset()                    { *m = Validator{} }
-func (m *Validator) String() string            { return proto.CompactTextString(m) }
-func (*Validator) ProtoMessage()               {}
-func (*Validator) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} }
+var xxx_messageInfo_Validator proto.InternalMessageInfo
 
 func (m *Validator) GetAddress() []byte {
 	if m != nil {
@@ -1810,14 +2775,45 @@ func (m *Validator) GetPower() int64 {
 
 // Validator with an extra bool
 type SigningValidator struct {
-	Validator       Validator `protobuf:"bytes,1,opt,name=validator" json:"validator"`
-	SignedLastBlock bool      `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"`
+	Validator            Validator `protobuf:"bytes,1,opt,name=validator" json:"validator"`
+	SignedLastBlock      bool      `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+func (m *SigningValidator) Reset()         { *m = SigningValidator{} }
+func (m *SigningValidator) String() string { return proto.CompactTextString(m) }
+func (*SigningValidator) ProtoMessage()    {}
+func (*SigningValidator) Descriptor() ([]byte, []int) {
+	return fileDescriptor_types_d8da2202f45d32c0, []int{32}
+}
+func (m *SigningValidator) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *SigningValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_SigningValidator.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 *SigningValidator) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_SigningValidator.Merge(dst, src)
+}
+func (m *SigningValidator) XXX_Size() int {
+	return m.Size()
+}
+func (m *SigningValidator) XXX_DiscardUnknown() {
+	xxx_messageInfo_SigningValidator.DiscardUnknown(m)
 }
 
-func (m *SigningValidator) Reset()                    { *m = SigningValidator{} }
-func (m *SigningValidator) String() string            { return proto.CompactTextString(m) }
-func (*SigningValidator) ProtoMessage()               {}
-func (*SigningValidator) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} }
+var xxx_messageInfo_SigningValidator proto.InternalMessageInfo
 
 func (m *SigningValidator) GetValidator() Validator {
 	if m != nil {
@@ -1834,14 +2830,45 @@ func (m *SigningValidator) GetSignedLastBlock() bool {
 }
 
 type PubKey struct {
-	Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
-	Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	Type                 string   `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+	Data                 []byte   `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{33}
+}
+func (m *PubKey) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *PubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_PubKey.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 *PubKey) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_PubKey.Merge(dst, src)
+}
+func (m *PubKey) XXX_Size() int {
+	return m.Size()
+}
+func (m *PubKey) XXX_DiscardUnknown() {
+	xxx_messageInfo_PubKey.DiscardUnknown(m)
 }
 
-func (m *PubKey) Reset()                    { *m = PubKey{} }
-func (m *PubKey) String() string            { return proto.CompactTextString(m) }
-func (*PubKey) ProtoMessage()               {}
-func (*PubKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} }
+var xxx_messageInfo_PubKey proto.InternalMessageInfo
 
 func (m *PubKey) GetType() string {
 	if m != nil {
@@ -1858,17 +2885,48 @@ func (m *PubKey) GetData() []byte {
 }
 
 type Evidence struct {
-	Type             string    `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
-	Validator        Validator `protobuf:"bytes,2,opt,name=validator" json:"validator"`
-	Height           int64     `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
-	Time             int64     `protobuf:"varint,4,opt,name=time,proto3" json:"time,omitempty"`
-	TotalVotingPower int64     `protobuf:"varint,5,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"`
+	Type                 string    `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
+	Validator            Validator `protobuf:"bytes,2,opt,name=validator" json:"validator"`
+	Height               int64     `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"`
+	Time                 time.Time `protobuf:"bytes,4,opt,name=time,stdtime" json:"time"`
+	TotalVotingPower     int64     `protobuf:"varint,5,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+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_d8da2202f45d32c0, []int{34}
+}
+func (m *Evidence) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Evidence.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 *Evidence) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Evidence.Merge(dst, src)
+}
+func (m *Evidence) XXX_Size() int {
+	return m.Size()
+}
+func (m *Evidence) XXX_DiscardUnknown() {
+	xxx_messageInfo_Evidence.DiscardUnknown(m)
 }
 
-func (m *Evidence) Reset()                    { *m = Evidence{} }
-func (m *Evidence) String() string            { return proto.CompactTextString(m) }
-func (*Evidence) ProtoMessage()               {}
-func (*Evidence) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} }
+var xxx_messageInfo_Evidence proto.InternalMessageInfo
 
 func (m *Evidence) GetType() string {
 	if m != nil {
@@ -1891,11 +2949,11 @@ func (m *Evidence) GetHeight() int64 {
 	return 0
 }
 
-func (m *Evidence) GetTime() int64 {
+func (m *Evidence) GetTime() time.Time {
 	if m != nil {
 		return m.Time
 	}
-	return 0
+	return time.Time{}
 }
 
 func (m *Evidence) GetTotalVotingPower() int64 {
@@ -1964,6 +3022,8 @@ func init() {
 	golang_proto.RegisterType((*TxSize)(nil), "types.TxSize")
 	proto.RegisterType((*BlockGossip)(nil), "types.BlockGossip")
 	golang_proto.RegisterType((*BlockGossip)(nil), "types.BlockGossip")
+	proto.RegisterType((*LastCommitInfo)(nil), "types.LastCommitInfo")
+	golang_proto.RegisterType((*LastCommitInfo)(nil), "types.LastCommitInfo")
 	proto.RegisterType((*Header)(nil), "types.Header")
 	golang_proto.RegisterType((*Header)(nil), "types.Header")
 	proto.RegisterType((*Validator)(nil), "types.Validator")
@@ -2003,6 +3063,9 @@ func (this *Request) Equal(that interface{}) bool {
 	} else if !this.Value.Equal(that1.Value) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Request_Echo) Equal(that interface{}) bool {
@@ -2291,6 +3354,9 @@ func (this *RequestEcho) Equal(that interface{}) bool {
 	if this.Message != that1.Message {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestFlush) Equal(that interface{}) bool {
@@ -2312,6 +3378,9 @@ func (this *RequestFlush) Equal(that interface{}) bool {
 	} else if this == nil {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestInfo) Equal(that interface{}) bool {
@@ -2336,6 +3405,9 @@ func (this *RequestInfo) Equal(that interface{}) bool {
 	if this.Version != that1.Version {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestSetOption) Equal(that interface{}) bool {
@@ -2363,6 +3435,9 @@ func (this *RequestSetOption) Equal(that interface{}) bool {
 	if this.Value != that1.Value {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestInitChain) Equal(that interface{}) bool {
@@ -2384,7 +3459,7 @@ func (this *RequestInitChain) Equal(that interface{}) bool {
 	} else if this == nil {
 		return false
 	}
-	if this.Time != that1.Time {
+	if !this.Time.Equal(that1.Time) {
 		return false
 	}
 	if this.ChainId != that1.ChainId {
@@ -2404,6 +3479,9 @@ func (this *RequestInitChain) Equal(that interface{}) bool {
 	if !bytes.Equal(this.AppStateBytes, that1.AppStateBytes) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestQuery) Equal(that interface{}) bool {
@@ -2437,6 +3515,9 @@ func (this *RequestQuery) Equal(that interface{}) bool {
 	if this.Prove != that1.Prove {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestBeginBlock) Equal(that interface{}) bool {
@@ -2464,14 +3545,9 @@ func (this *RequestBeginBlock) Equal(that interface{}) bool {
 	if !this.Header.Equal(&that1.Header) {
 		return false
 	}
-	if len(this.Validators) != len(that1.Validators) {
+	if !this.LastCommitInfo.Equal(&that1.LastCommitInfo) {
 		return false
 	}
-	for i := range this.Validators {
-		if !this.Validators[i].Equal(&that1.Validators[i]) {
-			return false
-		}
-	}
 	if len(this.ByzantineValidators) != len(that1.ByzantineValidators) {
 		return false
 	}
@@ -2480,6 +3556,9 @@ func (this *RequestBeginBlock) Equal(that interface{}) bool {
 			return false
 		}
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestCheckTx) Equal(that interface{}) bool {
@@ -2504,6 +3583,9 @@ func (this *RequestCheckTx) Equal(that interface{}) bool {
 	if !bytes.Equal(this.Tx, that1.Tx) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestDeliverTx) Equal(that interface{}) bool {
@@ -2528,6 +3610,9 @@ func (this *RequestDeliverTx) Equal(that interface{}) bool {
 	if !bytes.Equal(this.Tx, that1.Tx) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestEndBlock) Equal(that interface{}) bool {
@@ -2552,6 +3637,9 @@ func (this *RequestEndBlock) Equal(that interface{}) bool {
 	if this.Height != that1.Height {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *RequestCommit) Equal(that interface{}) bool {
@@ -2573,6 +3661,9 @@ func (this *RequestCommit) Equal(that interface{}) bool {
 	} else if this == nil {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Response) Equal(that interface{}) bool {
@@ -2603,6 +3694,9 @@ func (this *Response) Equal(that interface{}) bool {
 	} else if !this.Value.Equal(that1.Value) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Response_Exception) Equal(that interface{}) bool {
@@ -2915,6 +4009,9 @@ func (this *ResponseException) Equal(that interface{}) bool {
 	if this.Error != that1.Error {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseEcho) Equal(that interface{}) bool {
@@ -2939,6 +4036,9 @@ func (this *ResponseEcho) Equal(that interface{}) bool {
 	if this.Message != that1.Message {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseFlush) Equal(that interface{}) bool {
@@ -2960,6 +4060,9 @@ func (this *ResponseFlush) Equal(that interface{}) bool {
 	} else if this == nil {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseInfo) Equal(that interface{}) bool {
@@ -2993,6 +4096,9 @@ func (this *ResponseInfo) Equal(that interface{}) bool {
 	if !bytes.Equal(this.LastBlockAppHash, that1.LastBlockAppHash) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseSetOption) Equal(that interface{}) bool {
@@ -3023,6 +4129,9 @@ func (this *ResponseSetOption) Equal(that interface{}) bool {
 	if this.Info != that1.Info {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseInitChain) Equal(that interface{}) bool {
@@ -3055,6 +4164,9 @@ func (this *ResponseInitChain) Equal(that interface{}) bool {
 			return false
 		}
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseQuery) Equal(that interface{}) bool {
@@ -3100,6 +4212,9 @@ func (this *ResponseQuery) Equal(that interface{}) bool {
 	if this.Height != that1.Height {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseBeginBlock) Equal(that interface{}) bool {
@@ -3129,6 +4244,9 @@ func (this *ResponseBeginBlock) Equal(that interface{}) bool {
 			return false
 		}
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseCheckTx) Equal(that interface{}) bool {
@@ -3176,7 +4294,7 @@ func (this *ResponseCheckTx) Equal(that interface{}) bool {
 			return false
 		}
 	}
-	if !this.Fee.Equal(&that1.Fee) {
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
 		return false
 	}
 	return true
@@ -3226,7 +4344,7 @@ func (this *ResponseDeliverTx) Equal(that interface{}) bool {
 			return false
 		}
 	}
-	if !this.Fee.Equal(&that1.Fee) {
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
 		return false
 	}
 	return true
@@ -3269,6 +4387,9 @@ func (this *ResponseEndBlock) Equal(that interface{}) bool {
 			return false
 		}
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ResponseCommit) Equal(that interface{}) bool {
@@ -3293,6 +4414,9 @@ func (this *ResponseCommit) Equal(that interface{}) bool {
 	if !bytes.Equal(this.Data, that1.Data) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *ConsensusParams) Equal(that interface{}) bool {
@@ -3323,6 +4447,9 @@ func (this *ConsensusParams) Equal(that interface{}) bool {
 	if !this.BlockGossip.Equal(that1.BlockGossip) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *BlockSize) Equal(that interface{}) bool {
@@ -3353,6 +4480,9 @@ func (this *BlockSize) Equal(that interface{}) bool {
 	if this.MaxGas != that1.MaxGas {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *TxSize) Equal(that interface{}) bool {
@@ -3380,6 +4510,9 @@ func (this *TxSize) Equal(that interface{}) bool {
 	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 {
@@ -3404,6 +4537,44 @@ func (this *BlockGossip) Equal(that interface{}) bool {
 	if this.BlockPartSizeBytes != that1.BlockPartSizeBytes {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
+	return true
+}
+func (this *LastCommitInfo) Equal(that interface{}) bool {
+	if that == nil {
+		return this == nil
+	}
+
+	that1, ok := that.(*LastCommitInfo)
+	if !ok {
+		that2, ok := that.(LastCommitInfo)
+		if ok {
+			that1 = &that2
+		} else {
+			return false
+		}
+	}
+	if that1 == nil {
+		return this == nil
+	} else if this == nil {
+		return false
+	}
+	if this.CommitRound != that1.CommitRound {
+		return false
+	}
+	if len(this.Validators) != len(that1.Validators) {
+		return false
+	}
+	for i := range this.Validators {
+		if !this.Validators[i].Equal(&that1.Validators[i]) {
+			return false
+		}
+	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Header) Equal(that interface{}) bool {
@@ -3431,7 +4602,7 @@ func (this *Header) Equal(that interface{}) bool {
 	if this.Height != that1.Height {
 		return false
 	}
-	if this.Time != that1.Time {
+	if !this.Time.Equal(that1.Time) {
 		return false
 	}
 	if this.NumTxs != that1.NumTxs {
@@ -3452,6 +4623,9 @@ func (this *Header) Equal(that interface{}) bool {
 	if !this.Proposer.Equal(&that1.Proposer) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Validator) Equal(that interface{}) bool {
@@ -3482,6 +4656,9 @@ func (this *Validator) Equal(that interface{}) bool {
 	if this.Power != that1.Power {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *SigningValidator) Equal(that interface{}) bool {
@@ -3509,6 +4686,9 @@ func (this *SigningValidator) Equal(that interface{}) bool {
 	if this.SignedLastBlock != that1.SignedLastBlock {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *PubKey) Equal(that interface{}) bool {
@@ -3536,6 +4716,9 @@ func (this *PubKey) Equal(that interface{}) bool {
 	if !bytes.Equal(this.Data, that1.Data) {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 func (this *Evidence) Equal(that interface{}) bool {
@@ -3566,12 +4749,15 @@ func (this *Evidence) Equal(that interface{}) bool {
 	if this.Height != that1.Height {
 		return false
 	}
-	if this.Time != that1.Time {
+	if !this.Time.Equal(that1.Time) {
 		return false
 	}
 	if this.TotalVotingPower != that1.TotalVotingPower {
 		return false
 	}
+	if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) {
+		return false
+	}
 	return true
 }
 
@@ -3609,7 +4795,7 @@ func NewABCIApplicationClient(cc *grpc.ClientConn) ABCIApplicationClient {
 
 func (c *aBCIApplicationClient) Echo(ctx context.Context, in *RequestEcho, opts ...grpc.CallOption) (*ResponseEcho, error) {
 	out := new(ResponseEcho)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/Echo", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/Echo", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3618,7 +4804,7 @@ func (c *aBCIApplicationClient) Echo(ctx context.Context, in *RequestEcho, opts
 
 func (c *aBCIApplicationClient) Flush(ctx context.Context, in *RequestFlush, opts ...grpc.CallOption) (*ResponseFlush, error) {
 	out := new(ResponseFlush)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/Flush", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/Flush", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3627,7 +4813,7 @@ func (c *aBCIApplicationClient) Flush(ctx context.Context, in *RequestFlush, opt
 
 func (c *aBCIApplicationClient) Info(ctx context.Context, in *RequestInfo, opts ...grpc.CallOption) (*ResponseInfo, error) {
 	out := new(ResponseInfo)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/Info", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/Info", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3636,7 +4822,7 @@ func (c *aBCIApplicationClient) Info(ctx context.Context, in *RequestInfo, opts
 
 func (c *aBCIApplicationClient) SetOption(ctx context.Context, in *RequestSetOption, opts ...grpc.CallOption) (*ResponseSetOption, error) {
 	out := new(ResponseSetOption)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/SetOption", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/SetOption", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3645,7 +4831,7 @@ func (c *aBCIApplicationClient) SetOption(ctx context.Context, in *RequestSetOpt
 
 func (c *aBCIApplicationClient) DeliverTx(ctx context.Context, in *RequestDeliverTx, opts ...grpc.CallOption) (*ResponseDeliverTx, error) {
 	out := new(ResponseDeliverTx)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/DeliverTx", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/DeliverTx", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3654,7 +4840,7 @@ func (c *aBCIApplicationClient) DeliverTx(ctx context.Context, in *RequestDelive
 
 func (c *aBCIApplicationClient) CheckTx(ctx context.Context, in *RequestCheckTx, opts ...grpc.CallOption) (*ResponseCheckTx, error) {
 	out := new(ResponseCheckTx)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/CheckTx", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/CheckTx", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3663,7 +4849,7 @@ func (c *aBCIApplicationClient) CheckTx(ctx context.Context, in *RequestCheckTx,
 
 func (c *aBCIApplicationClient) Query(ctx context.Context, in *RequestQuery, opts ...grpc.CallOption) (*ResponseQuery, error) {
 	out := new(ResponseQuery)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/Query", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/Query", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3672,7 +4858,7 @@ func (c *aBCIApplicationClient) Query(ctx context.Context, in *RequestQuery, opt
 
 func (c *aBCIApplicationClient) Commit(ctx context.Context, in *RequestCommit, opts ...grpc.CallOption) (*ResponseCommit, error) {
 	out := new(ResponseCommit)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/Commit", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/Commit", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3681,7 +4867,7 @@ func (c *aBCIApplicationClient) Commit(ctx context.Context, in *RequestCommit, o
 
 func (c *aBCIApplicationClient) InitChain(ctx context.Context, in *RequestInitChain, opts ...grpc.CallOption) (*ResponseInitChain, error) {
 	out := new(ResponseInitChain)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/InitChain", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/InitChain", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3690,7 +4876,7 @@ func (c *aBCIApplicationClient) InitChain(ctx context.Context, in *RequestInitCh
 
 func (c *aBCIApplicationClient) BeginBlock(ctx context.Context, in *RequestBeginBlock, opts ...grpc.CallOption) (*ResponseBeginBlock, error) {
 	out := new(ResponseBeginBlock)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/BeginBlock", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/BeginBlock", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3699,7 +4885,7 @@ func (c *aBCIApplicationClient) BeginBlock(ctx context.Context, in *RequestBegin
 
 func (c *aBCIApplicationClient) EndBlock(ctx context.Context, in *RequestEndBlock, opts ...grpc.CallOption) (*ResponseEndBlock, error) {
 	out := new(ResponseEndBlock)
-	err := grpc.Invoke(ctx, "/types.ABCIApplication/EndBlock", in, out, c.cc, opts...)
+	err := c.cc.Invoke(ctx, "/types.ABCIApplication/EndBlock", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -3999,6 +5185,9 @@ func (m *Request) MarshalTo(dAtA []byte) (int, error) {
 		}
 		i += nn1
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4179,6 +5368,9 @@ func (m *RequestEcho) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Message)))
 		i += copy(dAtA[i:], m.Message)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4197,6 +5389,9 @@ func (m *RequestFlush) MarshalTo(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4221,6 +5416,9 @@ func (m *RequestInfo) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Version)))
 		i += copy(dAtA[i:], m.Version)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4251,6 +5449,9 @@ func (m *RequestSetOption) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Value)))
 		i += copy(dAtA[i:], m.Value)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4269,11 +5470,14 @@ func (m *RequestInitChain) MarshalTo(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
-	if m.Time != 0 {
-		dAtA[i] = 0x8
-		i++
-		i = encodeVarintTypes(dAtA, i, uint64(m.Time))
+	dAtA[i] = 0xa
+	i++
+	i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)))
+	n13, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:])
+	if err != nil {
+		return 0, err
 	}
+	i += n13
 	if len(m.ChainId) > 0 {
 		dAtA[i] = 0x12
 		i++
@@ -4284,11 +5488,11 @@ func (m *RequestInitChain) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.ConsensusParams.Size()))
-		n13, err := m.ConsensusParams.MarshalTo(dAtA[i:])
+		n14, err := m.ConsensusParams.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n13
+		i += n14
 	}
 	if len(m.Validators) > 0 {
 		for _, msg := range m.Validators {
@@ -4308,6 +5512,9 @@ func (m *RequestInitChain) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.AppStateBytes)))
 		i += copy(dAtA[i:], m.AppStateBytes)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4353,6 +5560,9 @@ func (m *RequestQuery) MarshalTo(dAtA []byte) (int, error) {
 		}
 		i++
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4380,23 +5590,19 @@ func (m *RequestBeginBlock) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x12
 	i++
 	i = encodeVarintTypes(dAtA, i, uint64(m.Header.Size()))
-	n14, err := m.Header.MarshalTo(dAtA[i:])
+	n15, err := m.Header.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n14
-	if len(m.Validators) > 0 {
-		for _, msg := range m.Validators {
-			dAtA[i] = 0x1a
-			i++
-			i = encodeVarintTypes(dAtA, i, uint64(msg.Size()))
-			n, err := msg.MarshalTo(dAtA[i:])
-			if err != nil {
-				return 0, err
-			}
-			i += n
-		}
+	i += n15
+	dAtA[i] = 0x1a
+	i++
+	i = encodeVarintTypes(dAtA, i, uint64(m.LastCommitInfo.Size()))
+	n16, err := m.LastCommitInfo.MarshalTo(dAtA[i:])
+	if err != nil {
+		return 0, err
 	}
+	i += n16
 	if len(m.ByzantineValidators) > 0 {
 		for _, msg := range m.ByzantineValidators {
 			dAtA[i] = 0x22
@@ -4409,6 +5615,9 @@ func (m *RequestBeginBlock) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4433,6 +5642,9 @@ func (m *RequestCheckTx) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Tx)))
 		i += copy(dAtA[i:], m.Tx)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4457,6 +5669,9 @@ func (m *RequestDeliverTx) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Tx)))
 		i += copy(dAtA[i:], m.Tx)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4480,6 +5695,9 @@ func (m *RequestEndBlock) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Height))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4498,6 +5716,9 @@ func (m *RequestCommit) MarshalTo(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4517,11 +5738,14 @@ func (m *Response) MarshalTo(dAtA []byte) (int, error) {
 	var l int
 	_ = l
 	if m.Value != nil {
-		nn15, err := m.Value.MarshalTo(dAtA[i:])
+		nn17, err := m.Value.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += nn15
+		i += nn17
+	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
 	}
 	return i, nil
 }
@@ -4532,11 +5756,11 @@ func (m *Response_Exception) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Exception.Size()))
-		n16, err := m.Exception.MarshalTo(dAtA[i:])
+		n18, err := m.Exception.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n16
+		i += n18
 	}
 	return i, nil
 }
@@ -4546,11 +5770,11 @@ func (m *Response_Echo) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Echo.Size()))
-		n17, err := m.Echo.MarshalTo(dAtA[i:])
+		n19, err := m.Echo.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n17
+		i += n19
 	}
 	return i, nil
 }
@@ -4560,11 +5784,11 @@ func (m *Response_Flush) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Flush.Size()))
-		n18, err := m.Flush.MarshalTo(dAtA[i:])
+		n20, err := m.Flush.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n18
+		i += n20
 	}
 	return i, nil
 }
@@ -4574,11 +5798,11 @@ func (m *Response_Info) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x22
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Info.Size()))
-		n19, err := m.Info.MarshalTo(dAtA[i:])
+		n21, err := m.Info.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n19
+		i += n21
 	}
 	return i, nil
 }
@@ -4588,11 +5812,11 @@ func (m *Response_SetOption) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.SetOption.Size()))
-		n20, err := m.SetOption.MarshalTo(dAtA[i:])
+		n22, err := m.SetOption.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n20
+		i += n22
 	}
 	return i, nil
 }
@@ -4602,11 +5826,11 @@ func (m *Response_InitChain) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x32
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.InitChain.Size()))
-		n21, err := m.InitChain.MarshalTo(dAtA[i:])
+		n23, err := m.InitChain.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n21
+		i += n23
 	}
 	return i, nil
 }
@@ -4616,11 +5840,11 @@ func (m *Response_Query) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x3a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Query.Size()))
-		n22, err := m.Query.MarshalTo(dAtA[i:])
+		n24, err := m.Query.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n22
+		i += n24
 	}
 	return i, nil
 }
@@ -4630,11 +5854,11 @@ func (m *Response_BeginBlock) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x42
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.BeginBlock.Size()))
-		n23, err := m.BeginBlock.MarshalTo(dAtA[i:])
+		n25, err := m.BeginBlock.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n23
+		i += n25
 	}
 	return i, nil
 }
@@ -4644,11 +5868,11 @@ func (m *Response_CheckTx) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x4a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.CheckTx.Size()))
-		n24, err := m.CheckTx.MarshalTo(dAtA[i:])
+		n26, err := m.CheckTx.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n24
+		i += n26
 	}
 	return i, nil
 }
@@ -4658,11 +5882,11 @@ func (m *Response_DeliverTx) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x52
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.DeliverTx.Size()))
-		n25, err := m.DeliverTx.MarshalTo(dAtA[i:])
+		n27, err := m.DeliverTx.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n25
+		i += n27
 	}
 	return i, nil
 }
@@ -4672,11 +5896,11 @@ func (m *Response_EndBlock) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x5a
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.EndBlock.Size()))
-		n26, err := m.EndBlock.MarshalTo(dAtA[i:])
+		n28, err := m.EndBlock.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n26
+		i += n28
 	}
 	return i, nil
 }
@@ -4686,11 +5910,11 @@ func (m *Response_Commit) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0x62
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Commit.Size()))
-		n27, err := m.Commit.MarshalTo(dAtA[i:])
+		n29, err := m.Commit.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n27
+		i += n29
 	}
 	return i, nil
 }
@@ -4715,6 +5939,9 @@ func (m *ResponseException) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Error)))
 		i += copy(dAtA[i:], m.Error)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4739,6 +5966,9 @@ func (m *ResponseEcho) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Message)))
 		i += copy(dAtA[i:], m.Message)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4757,6 +5987,9 @@ func (m *ResponseFlush) MarshalTo(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4798,6 +6031,9 @@ func (m *ResponseInfo) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.LastBlockAppHash)))
 		i += copy(dAtA[i:], m.LastBlockAppHash)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4833,6 +6069,9 @@ func (m *ResponseSetOption) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Info)))
 		i += copy(dAtA[i:], m.Info)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4855,11 +6094,11 @@ func (m *ResponseInitChain) MarshalTo(dAtA []byte) (int, error) {
 		dAtA[i] = 0xa
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.ConsensusParams.Size()))
-		n28, err := m.ConsensusParams.MarshalTo(dAtA[i:])
+		n30, err := m.ConsensusParams.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n28
+		i += n30
 	}
 	if len(m.Validators) > 0 {
 		for _, msg := range m.Validators {
@@ -4873,6 +6112,9 @@ func (m *ResponseInitChain) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4936,6 +6178,9 @@ func (m *ResponseQuery) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Height))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -4966,6 +6211,9 @@ func (m *ResponseBeginBlock) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5029,14 +6277,9 @@ func (m *ResponseCheckTx) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
-	dAtA[i] = 0x42
-	i++
-	i = encodeVarintTypes(dAtA, i, uint64(m.Fee.Size()))
-	n29, err := m.Fee.MarshalTo(dAtA[i:])
-	if err != nil {
-		return 0, err
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
 	}
-	i += n29
 	return i, nil
 }
 
@@ -5100,14 +6343,9 @@ func (m *ResponseDeliverTx) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
-	dAtA[i] = 0x42
-	i++
-	i = encodeVarintTypes(dAtA, i, uint64(m.Fee.Size()))
-	n30, err := m.Fee.MarshalTo(dAtA[i:])
-	if err != nil {
-		return 0, err
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
 	}
-	i += n30
 	return i, nil
 }
 
@@ -5160,6 +6398,9 @@ func (m *ResponseEndBlock) MarshalTo(dAtA []byte) (int, error) {
 			i += n
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5184,6 +6425,9 @@ func (m *ResponseCommit) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Data)))
 		i += copy(dAtA[i:], m.Data)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5232,6 +6476,9 @@ func (m *ConsensusParams) MarshalTo(dAtA []byte) (int, error) {
 		}
 		i += n34
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5265,6 +6512,9 @@ func (m *BlockSize) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.MaxGas))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5293,6 +6543,9 @@ func (m *TxSize) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.MaxGas))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5316,6 +6569,47 @@ func (m *BlockGossip) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.BlockPartSizeBytes))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	return i, nil
+}
+
+func (m *LastCommitInfo) 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 *LastCommitInfo) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.CommitRound != 0 {
+		dAtA[i] = 0x8
+		i++
+		i = encodeVarintTypes(dAtA, i, uint64(m.CommitRound))
+	}
+	if len(m.Validators) > 0 {
+		for _, msg := range m.Validators {
+			dAtA[i] = 0x12
+			i++
+			i = encodeVarintTypes(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5345,11 +6639,14 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) {
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Height))
 	}
-	if m.Time != 0 {
-		dAtA[i] = 0x18
-		i++
-		i = encodeVarintTypes(dAtA, i, uint64(m.Time))
+	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:])
+	if err != nil {
+		return 0, err
 	}
+	i += n35
 	if m.NumTxs != 0 {
 		dAtA[i] = 0x20
 		i++
@@ -5381,11 +6678,14 @@ func (m *Header) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x4a
 	i++
 	i = encodeVarintTypes(dAtA, i, uint64(m.Proposer.Size()))
-	n35, err := m.Proposer.MarshalTo(dAtA[i:])
+	n36, err := m.Proposer.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n35
+	i += n36
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5413,16 +6713,19 @@ func (m *Validator) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x12
 	i++
 	i = encodeVarintTypes(dAtA, i, uint64(m.PubKey.Size()))
-	n36, err := m.PubKey.MarshalTo(dAtA[i:])
+	n37, err := m.PubKey.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n36
+	i += n37
 	if m.Power != 0 {
 		dAtA[i] = 0x18
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Power))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5444,11 +6747,11 @@ func (m *SigningValidator) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0xa
 	i++
 	i = encodeVarintTypes(dAtA, i, uint64(m.Validator.Size()))
-	n37, err := m.Validator.MarshalTo(dAtA[i:])
+	n38, err := m.Validator.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n37
+	i += n38
 	if m.SignedLastBlock {
 		dAtA[i] = 0x10
 		i++
@@ -5459,6 +6762,9 @@ func (m *SigningValidator) MarshalTo(dAtA []byte) (int, error) {
 		}
 		i++
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5489,6 +6795,9 @@ func (m *PubKey) MarshalTo(dAtA []byte) (int, error) {
 		i = encodeVarintTypes(dAtA, i, uint64(len(m.Data)))
 		i += copy(dAtA[i:], m.Data)
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5516,26 +6825,32 @@ func (m *Evidence) MarshalTo(dAtA []byte) (int, error) {
 	dAtA[i] = 0x12
 	i++
 	i = encodeVarintTypes(dAtA, i, uint64(m.Validator.Size()))
-	n38, err := m.Validator.MarshalTo(dAtA[i:])
+	n39, err := m.Validator.MarshalTo(dAtA[i:])
 	if err != nil {
 		return 0, err
 	}
-	i += n38
+	i += n39
 	if m.Height != 0 {
 		dAtA[i] = 0x18
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.Height))
 	}
-	if m.Time != 0 {
-		dAtA[i] = 0x20
-		i++
-		i = encodeVarintTypes(dAtA, i, uint64(m.Time))
+	dAtA[i] = 0x22
+	i++
+	i = encodeVarintTypes(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)))
+	n40, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i:])
+	if err != nil {
+		return 0, err
 	}
+	i += n40
 	if m.TotalVotingPower != 0 {
 		dAtA[i] = 0x28
 		i++
 		i = encodeVarintTypes(dAtA, i, uint64(m.TotalVotingPower))
 	}
+	if m.XXX_unrecognized != nil {
+		i += copy(dAtA[i:], m.XXX_unrecognized)
+	}
 	return i, nil
 }
 
@@ -5576,6 +6891,7 @@ func NewPopulatedRequest(r randyTypes, easy bool) *Request {
 		this.Value = NewPopulatedRequest_DeliverTx(r, easy)
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 20)
 	}
 	return this
 }
@@ -5639,6 +6955,7 @@ func NewPopulatedRequestEcho(r randyTypes, easy bool) *RequestEcho {
 	this := &RequestEcho{}
 	this.Message = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5646,6 +6963,7 @@ func NewPopulatedRequestEcho(r randyTypes, easy bool) *RequestEcho {
 func NewPopulatedRequestFlush(r randyTypes, easy bool) *RequestFlush {
 	this := &RequestFlush{}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 1)
 	}
 	return this
 }
@@ -5654,6 +6972,7 @@ func NewPopulatedRequestInfo(r randyTypes, easy bool) *RequestInfo {
 	this := &RequestInfo{}
 	this.Version = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5663,43 +6982,43 @@ func NewPopulatedRequestSetOption(r randyTypes, easy bool) *RequestSetOption {
 	this.Key = string(randStringTypes(r))
 	this.Value = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
 
 func NewPopulatedRequestInitChain(r randyTypes, easy bool) *RequestInitChain {
 	this := &RequestInitChain{}
-	this.Time = int64(r.Int63())
-	if r.Intn(2) == 0 {
-		this.Time *= -1
-	}
+	v1 := github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+	this.Time = *v1
 	this.ChainId = string(randStringTypes(r))
 	if r.Intn(10) != 0 {
 		this.ConsensusParams = NewPopulatedConsensusParams(r, easy)
 	}
 	if r.Intn(10) != 0 {
-		v1 := r.Intn(5)
-		this.Validators = make([]Validator, v1)
-		for i := 0; i < v1; i++ {
-			v2 := NewPopulatedValidator(r, easy)
-			this.Validators[i] = *v2
+		v2 := r.Intn(5)
+		this.Validators = make([]Validator, v2)
+		for i := 0; i < v2; i++ {
+			v3 := NewPopulatedValidator(r, easy)
+			this.Validators[i] = *v3
 		}
 	}
-	v3 := r.Intn(100)
-	this.AppStateBytes = make([]byte, v3)
-	for i := 0; i < v3; i++ {
+	v4 := r.Intn(100)
+	this.AppStateBytes = make([]byte, v4)
+	for i := 0; i < v4; i++ {
 		this.AppStateBytes[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 6)
 	}
 	return this
 }
 
 func NewPopulatedRequestQuery(r randyTypes, easy bool) *RequestQuery {
 	this := &RequestQuery{}
-	v4 := r.Intn(100)
-	this.Data = make([]byte, v4)
-	for i := 0; i < v4; i++ {
+	v5 := r.Intn(100)
+	this.Data = make([]byte, v5)
+	for i := 0; i < v5; i++ {
 		this.Data[i] = byte(r.Intn(256))
 	}
 	this.Path = string(randStringTypes(r))
@@ -5709,27 +7028,22 @@ func NewPopulatedRequestQuery(r randyTypes, easy bool) *RequestQuery {
 	}
 	this.Prove = bool(bool(r.Intn(2) == 0))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 5)
 	}
 	return this
 }
 
 func NewPopulatedRequestBeginBlock(r randyTypes, easy bool) *RequestBeginBlock {
 	this := &RequestBeginBlock{}
-	v5 := r.Intn(100)
-	this.Hash = make([]byte, v5)
-	for i := 0; i < v5; i++ {
+	v6 := r.Intn(100)
+	this.Hash = make([]byte, v6)
+	for i := 0; i < v6; i++ {
 		this.Hash[i] = byte(r.Intn(256))
 	}
-	v6 := NewPopulatedHeader(r, easy)
-	this.Header = *v6
-	if r.Intn(10) != 0 {
-		v7 := r.Intn(5)
-		this.Validators = make([]SigningValidator, v7)
-		for i := 0; i < v7; i++ {
-			v8 := NewPopulatedSigningValidator(r, easy)
-			this.Validators[i] = *v8
-		}
-	}
+	v7 := NewPopulatedHeader(r, easy)
+	this.Header = *v7
+	v8 := NewPopulatedLastCommitInfo(r, easy)
+	this.LastCommitInfo = *v8
 	if r.Intn(10) != 0 {
 		v9 := r.Intn(5)
 		this.ByzantineValidators = make([]Evidence, v9)
@@ -5739,6 +7053,7 @@ func NewPopulatedRequestBeginBlock(r randyTypes, easy bool) *RequestBeginBlock {
 		}
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 5)
 	}
 	return this
 }
@@ -5751,6 +7066,7 @@ func NewPopulatedRequestCheckTx(r randyTypes, easy bool) *RequestCheckTx {
 		this.Tx[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5763,6 +7079,7 @@ func NewPopulatedRequestDeliverTx(r randyTypes, easy bool) *RequestDeliverTx {
 		this.Tx[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5774,6 +7091,7 @@ func NewPopulatedRequestEndBlock(r randyTypes, easy bool) *RequestEndBlock {
 		this.Height *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5781,6 +7099,7 @@ func NewPopulatedRequestEndBlock(r randyTypes, easy bool) *RequestEndBlock {
 func NewPopulatedRequestCommit(r randyTypes, easy bool) *RequestCommit {
 	this := &RequestCommit{}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 1)
 	}
 	return this
 }
@@ -5815,6 +7134,7 @@ func NewPopulatedResponse(r randyTypes, easy bool) *Response {
 		this.Value = NewPopulatedResponse_Commit(r, easy)
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 13)
 	}
 	return this
 }
@@ -5883,6 +7203,7 @@ func NewPopulatedResponseException(r randyTypes, easy bool) *ResponseException {
 	this := &ResponseException{}
 	this.Error = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5891,6 +7212,7 @@ func NewPopulatedResponseEcho(r randyTypes, easy bool) *ResponseEcho {
 	this := &ResponseEcho{}
 	this.Message = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -5898,6 +7220,7 @@ func NewPopulatedResponseEcho(r randyTypes, easy bool) *ResponseEcho {
 func NewPopulatedResponseFlush(r randyTypes, easy bool) *ResponseFlush {
 	this := &ResponseFlush{}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 1)
 	}
 	return this
 }
@@ -5916,6 +7239,7 @@ func NewPopulatedResponseInfo(r randyTypes, easy bool) *ResponseInfo {
 		this.LastBlockAppHash[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 5)
 	}
 	return this
 }
@@ -5926,6 +7250,7 @@ func NewPopulatedResponseSetOption(r randyTypes, easy bool) *ResponseSetOption {
 	this.Log = string(randStringTypes(r))
 	this.Info = string(randStringTypes(r))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 5)
 	}
 	return this
 }
@@ -5944,6 +7269,7 @@ func NewPopulatedResponseInitChain(r randyTypes, easy bool) *ResponseInitChain {
 		}
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -5977,6 +7303,7 @@ func NewPopulatedResponseQuery(r randyTypes, easy bool) *ResponseQuery {
 		this.Height *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 10)
 	}
 	return this
 }
@@ -5992,6 +7319,7 @@ func NewPopulatedResponseBeginBlock(r randyTypes, easy bool) *ResponseBeginBlock
 		}
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
 	}
 	return this
 }
@@ -6022,9 +7350,8 @@ func NewPopulatedResponseCheckTx(r randyTypes, easy bool) *ResponseCheckTx {
 			this.Tags[i] = *v23
 		}
 	}
-	v24 := common.NewPopulatedKI64Pair(r, easy)
-	this.Fee = *v24
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 8)
 	}
 	return this
 }
@@ -6032,9 +7359,9 @@ func NewPopulatedResponseCheckTx(r randyTypes, easy bool) *ResponseCheckTx {
 func NewPopulatedResponseDeliverTx(r randyTypes, easy bool) *ResponseDeliverTx {
 	this := &ResponseDeliverTx{}
 	this.Code = uint32(r.Uint32())
-	v25 := r.Intn(100)
-	this.Data = make([]byte, v25)
-	for i := 0; i < v25; i++ {
+	v24 := r.Intn(100)
+	this.Data = make([]byte, v24)
+	for i := 0; i < v24; i++ {
 		this.Data[i] = byte(r.Intn(256))
 	}
 	this.Log = string(randStringTypes(r))
@@ -6048,16 +7375,15 @@ func NewPopulatedResponseDeliverTx(r randyTypes, easy bool) *ResponseDeliverTx {
 		this.GasUsed *= -1
 	}
 	if r.Intn(10) != 0 {
-		v26 := r.Intn(5)
-		this.Tags = make([]common.KVPair, v26)
-		for i := 0; i < v26; i++ {
-			v27 := common.NewPopulatedKVPair(r, easy)
-			this.Tags[i] = *v27
+		v25 := r.Intn(5)
+		this.Tags = make([]common.KVPair, v25)
+		for i := 0; i < v25; i++ {
+			v26 := common.NewPopulatedKVPair(r, easy)
+			this.Tags[i] = *v26
 		}
 	}
-	v28 := common.NewPopulatedKI64Pair(r, easy)
-	this.Fee = *v28
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 8)
 	}
 	return this
 }
@@ -6065,37 +7391,39 @@ func NewPopulatedResponseDeliverTx(r randyTypes, easy bool) *ResponseDeliverTx {
 func NewPopulatedResponseEndBlock(r randyTypes, easy bool) *ResponseEndBlock {
 	this := &ResponseEndBlock{}
 	if r.Intn(10) != 0 {
-		v29 := r.Intn(5)
-		this.ValidatorUpdates = make([]Validator, v29)
-		for i := 0; i < v29; i++ {
-			v30 := NewPopulatedValidator(r, easy)
-			this.ValidatorUpdates[i] = *v30
+		v27 := r.Intn(5)
+		this.ValidatorUpdates = make([]Validator, v27)
+		for i := 0; i < v27; i++ {
+			v28 := NewPopulatedValidator(r, easy)
+			this.ValidatorUpdates[i] = *v28
 		}
 	}
 	if r.Intn(10) != 0 {
 		this.ConsensusParamUpdates = NewPopulatedConsensusParams(r, easy)
 	}
 	if r.Intn(10) != 0 {
-		v31 := r.Intn(5)
-		this.Tags = make([]common.KVPair, v31)
-		for i := 0; i < v31; i++ {
-			v32 := common.NewPopulatedKVPair(r, easy)
-			this.Tags[i] = *v32
+		v29 := r.Intn(5)
+		this.Tags = make([]common.KVPair, v29)
+		for i := 0; i < v29; i++ {
+			v30 := common.NewPopulatedKVPair(r, easy)
+			this.Tags[i] = *v30
 		}
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 4)
 	}
 	return this
 }
 
 func NewPopulatedResponseCommit(r randyTypes, easy bool) *ResponseCommit {
 	this := &ResponseCommit{}
-	v33 := r.Intn(100)
-	this.Data = make([]byte, v33)
-	for i := 0; i < v33; i++ {
+	v31 := r.Intn(100)
+	this.Data = make([]byte, v31)
+	for i := 0; i < v31; i++ {
 		this.Data[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -6112,6 +7440,7 @@ func NewPopulatedConsensusParams(r randyTypes, easy bool) *ConsensusParams {
 		this.BlockGossip = NewPopulatedBlockGossip(r, easy)
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 4)
 	}
 	return this
 }
@@ -6131,6 +7460,7 @@ func NewPopulatedBlockSize(r randyTypes, easy bool) *BlockSize {
 		this.MaxGas *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 4)
 	}
 	return this
 }
@@ -6146,6 +7476,7 @@ func NewPopulatedTxSize(r randyTypes, easy bool) *TxSize {
 		this.MaxGas *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -6157,6 +7488,27 @@ func NewPopulatedBlockGossip(r randyTypes, easy bool) *BlockGossip {
 		this.BlockPartSizeBytes *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 2)
+	}
+	return this
+}
+
+func NewPopulatedLastCommitInfo(r randyTypes, easy bool) *LastCommitInfo {
+	this := &LastCommitInfo{}
+	this.CommitRound = int32(r.Int31())
+	if r.Intn(2) == 0 {
+		this.CommitRound *= -1
+	}
+	if r.Intn(10) != 0 {
+		v32 := r.Intn(5)
+		this.Validators = make([]SigningValidator, v32)
+		for i := 0; i < v32; i++ {
+			v33 := NewPopulatedSigningValidator(r, easy)
+			this.Validators[i] = *v33
+		}
+	}
+	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -6168,10 +7520,8 @@ func NewPopulatedHeader(r randyTypes, easy bool) *Header {
 	if r.Intn(2) == 0 {
 		this.Height *= -1
 	}
-	this.Time = int64(r.Int63())
-	if r.Intn(2) == 0 {
-		this.Time *= -1
-	}
+	v34 := github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+	this.Time = *v34
 	this.NumTxs = int32(r.Int31())
 	if r.Intn(2) == 0 {
 		this.NumTxs *= -1
@@ -6180,52 +7530,55 @@ func NewPopulatedHeader(r randyTypes, easy bool) *Header {
 	if r.Intn(2) == 0 {
 		this.TotalTxs *= -1
 	}
-	v34 := r.Intn(100)
-	this.LastBlockHash = make([]byte, v34)
-	for i := 0; i < v34; i++ {
-		this.LastBlockHash[i] = byte(r.Intn(256))
-	}
 	v35 := r.Intn(100)
-	this.ValidatorsHash = make([]byte, v35)
+	this.LastBlockHash = make([]byte, v35)
 	for i := 0; i < v35; i++ {
-		this.ValidatorsHash[i] = byte(r.Intn(256))
+		this.LastBlockHash[i] = byte(r.Intn(256))
 	}
 	v36 := r.Intn(100)
-	this.AppHash = make([]byte, v36)
+	this.ValidatorsHash = make([]byte, v36)
 	for i := 0; i < v36; i++ {
+		this.ValidatorsHash[i] = byte(r.Intn(256))
+	}
+	v37 := r.Intn(100)
+	this.AppHash = make([]byte, v37)
+	for i := 0; i < v37; i++ {
 		this.AppHash[i] = byte(r.Intn(256))
 	}
-	v37 := NewPopulatedValidator(r, easy)
-	this.Proposer = *v37
+	v38 := NewPopulatedValidator(r, easy)
+	this.Proposer = *v38
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 10)
 	}
 	return this
 }
 
 func NewPopulatedValidator(r randyTypes, easy bool) *Validator {
 	this := &Validator{}
-	v38 := r.Intn(100)
-	this.Address = make([]byte, v38)
-	for i := 0; i < v38; i++ {
+	v39 := r.Intn(100)
+	this.Address = make([]byte, v39)
+	for i := 0; i < v39; i++ {
 		this.Address[i] = byte(r.Intn(256))
 	}
-	v39 := NewPopulatedPubKey(r, easy)
-	this.PubKey = *v39
+	v40 := NewPopulatedPubKey(r, easy)
+	this.PubKey = *v40
 	this.Power = int64(r.Int63())
 	if r.Intn(2) == 0 {
 		this.Power *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 4)
 	}
 	return this
 }
 
 func NewPopulatedSigningValidator(r randyTypes, easy bool) *SigningValidator {
 	this := &SigningValidator{}
-	v40 := NewPopulatedValidator(r, easy)
-	this.Validator = *v40
+	v41 := NewPopulatedValidator(r, easy)
+	this.Validator = *v41
 	this.SignedLastBlock = bool(bool(r.Intn(2) == 0))
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -6233,12 +7586,13 @@ func NewPopulatedSigningValidator(r randyTypes, easy bool) *SigningValidator {
 func NewPopulatedPubKey(r randyTypes, easy bool) *PubKey {
 	this := &PubKey{}
 	this.Type = string(randStringTypes(r))
-	v41 := r.Intn(100)
-	this.Data = make([]byte, v41)
-	for i := 0; i < v41; i++ {
+	v42 := r.Intn(100)
+	this.Data = make([]byte, v42)
+	for i := 0; i < v42; i++ {
 		this.Data[i] = byte(r.Intn(256))
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 3)
 	}
 	return this
 }
@@ -6246,21 +7600,20 @@ func NewPopulatedPubKey(r randyTypes, easy bool) *PubKey {
 func NewPopulatedEvidence(r randyTypes, easy bool) *Evidence {
 	this := &Evidence{}
 	this.Type = string(randStringTypes(r))
-	v42 := NewPopulatedValidator(r, easy)
-	this.Validator = *v42
+	v43 := NewPopulatedValidator(r, easy)
+	this.Validator = *v43
 	this.Height = int64(r.Int63())
 	if r.Intn(2) == 0 {
 		this.Height *= -1
 	}
-	this.Time = int64(r.Int63())
-	if r.Intn(2) == 0 {
-		this.Time *= -1
-	}
+	v44 := github_com_gogo_protobuf_types.NewPopulatedStdTime(r, easy)
+	this.Time = *v44
 	this.TotalVotingPower = int64(r.Int63())
 	if r.Intn(2) == 0 {
 		this.TotalVotingPower *= -1
 	}
 	if !easy && r.Intn(10) != 0 {
+		this.XXX_unrecognized = randUnrecognizedTypes(r, 6)
 	}
 	return this
 }
@@ -6284,9 +7637,9 @@ func randUTF8RuneTypes(r randyTypes) rune {
 	return rune(ru + 61)
 }
 func randStringTypes(r randyTypes) string {
-	v43 := r.Intn(100)
-	tmps := make([]rune, v43)
-	for i := 0; i < v43; i++ {
+	v45 := r.Intn(100)
+	tmps := make([]rune, v45)
+	for i := 0; i < v45; i++ {
 		tmps[i] = randUTF8RuneTypes(r)
 	}
 	return string(tmps)
@@ -6308,11 +7661,11 @@ func randFieldTypes(dAtA []byte, r randyTypes, fieldNumber int, wire int) []byte
 	switch wire {
 	case 0:
 		dAtA = encodeVarintPopulateTypes(dAtA, uint64(key))
-		v44 := r.Int63()
+		v46 := r.Int63()
 		if r.Intn(2) == 0 {
-			v44 *= -1
+			v46 *= -1
 		}
-		dAtA = encodeVarintPopulateTypes(dAtA, uint64(v44))
+		dAtA = encodeVarintPopulateTypes(dAtA, uint64(v46))
 	case 1:
 		dAtA = encodeVarintPopulateTypes(dAtA, uint64(key))
 		dAtA = append(dAtA, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))
@@ -6343,6 +7696,9 @@ func (m *Request) Size() (n int) {
 	if m.Value != nil {
 		n += m.Value.Size()
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6452,12 +7808,18 @@ func (m *RequestEcho) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
 func (m *RequestFlush) Size() (n int) {
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6468,6 +7830,9 @@ func (m *RequestInfo) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6482,15 +7847,17 @@ func (m *RequestSetOption) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
 func (m *RequestInitChain) Size() (n int) {
 	var l int
 	_ = l
-	if m.Time != 0 {
-		n += 1 + sovTypes(uint64(m.Time))
-	}
+	l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
+	n += 1 + l + sovTypes(uint64(l))
 	l = len(m.ChainId)
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
@@ -6509,6 +7876,9 @@ func (m *RequestInitChain) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6529,6 +7899,9 @@ func (m *RequestQuery) Size() (n int) {
 	if m.Prove {
 		n += 2
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6541,18 +7914,17 @@ func (m *RequestBeginBlock) Size() (n int) {
 	}
 	l = m.Header.Size()
 	n += 1 + l + sovTypes(uint64(l))
-	if len(m.Validators) > 0 {
-		for _, e := range m.Validators {
-			l = e.Size()
-			n += 1 + l + sovTypes(uint64(l))
-		}
-	}
+	l = m.LastCommitInfo.Size()
+	n += 1 + l + sovTypes(uint64(l))
 	if len(m.ByzantineValidators) > 0 {
 		for _, e := range m.ByzantineValidators {
 			l = e.Size()
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6563,6 +7935,9 @@ func (m *RequestCheckTx) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6573,6 +7948,9 @@ func (m *RequestDeliverTx) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6582,12 +7960,18 @@ func (m *RequestEndBlock) Size() (n int) {
 	if m.Height != 0 {
 		n += 1 + sovTypes(uint64(m.Height))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
 func (m *RequestCommit) Size() (n int) {
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6597,6 +7981,9 @@ func (m *Response) Size() (n int) {
 	if m.Value != nil {
 		n += m.Value.Size()
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6715,6 +8102,9 @@ func (m *ResponseException) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6725,12 +8115,18 @@ func (m *ResponseEcho) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
 func (m *ResponseFlush) Size() (n int) {
 	var l int
 	_ = l
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6752,6 +8148,9 @@ func (m *ResponseInfo) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6769,6 +8168,9 @@ func (m *ResponseSetOption) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6785,6 +8187,9 @@ func (m *ResponseInitChain) Size() (n int) {
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6820,6 +8225,9 @@ func (m *ResponseQuery) Size() (n int) {
 	if m.Height != 0 {
 		n += 1 + sovTypes(uint64(m.Height))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6832,6 +8240,9 @@ func (m *ResponseBeginBlock) Size() (n int) {
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6865,8 +8276,9 @@ func (m *ResponseCheckTx) Size() (n int) {
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
-	l = m.Fee.Size()
-	n += 1 + l + sovTypes(uint64(l))
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6900,8 +8312,9 @@ func (m *ResponseDeliverTx) Size() (n int) {
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
-	l = m.Fee.Size()
-	n += 1 + l + sovTypes(uint64(l))
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6924,6 +8337,9 @@ func (m *ResponseEndBlock) Size() (n int) {
 			n += 1 + l + sovTypes(uint64(l))
 		}
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6934,6 +8350,9 @@ func (m *ResponseCommit) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6952,6 +8371,9 @@ func (m *ConsensusParams) Size() (n int) {
 		l = m.BlockGossip.Size()
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6967,6 +8389,9 @@ func (m *BlockSize) Size() (n int) {
 	if m.MaxGas != 0 {
 		n += 1 + sovTypes(uint64(m.MaxGas))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6979,6 +8404,9 @@ func (m *TxSize) Size() (n int) {
 	if m.MaxGas != 0 {
 		n += 1 + sovTypes(uint64(m.MaxGas))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -6988,6 +8416,27 @@ func (m *BlockGossip) Size() (n int) {
 	if m.BlockPartSizeBytes != 0 {
 		n += 1 + sovTypes(uint64(m.BlockPartSizeBytes))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
+func (m *LastCommitInfo) Size() (n int) {
+	var l int
+	_ = l
+	if m.CommitRound != 0 {
+		n += 1 + sovTypes(uint64(m.CommitRound))
+	}
+	if len(m.Validators) > 0 {
+		for _, e := range m.Validators {
+			l = e.Size()
+			n += 1 + l + sovTypes(uint64(l))
+		}
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7001,9 +8450,8 @@ func (m *Header) Size() (n int) {
 	if m.Height != 0 {
 		n += 1 + sovTypes(uint64(m.Height))
 	}
-	if m.Time != 0 {
-		n += 1 + sovTypes(uint64(m.Time))
-	}
+	l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
+	n += 1 + l + sovTypes(uint64(l))
 	if m.NumTxs != 0 {
 		n += 1 + sovTypes(uint64(m.NumTxs))
 	}
@@ -7024,6 +8472,9 @@ func (m *Header) Size() (n int) {
 	}
 	l = m.Proposer.Size()
 	n += 1 + l + sovTypes(uint64(l))
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7039,6 +8490,9 @@ func (m *Validator) Size() (n int) {
 	if m.Power != 0 {
 		n += 1 + sovTypes(uint64(m.Power))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7050,6 +8504,9 @@ func (m *SigningValidator) Size() (n int) {
 	if m.SignedLastBlock {
 		n += 2
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7064,6 +8521,9 @@ func (m *PubKey) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovTypes(uint64(l))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7079,12 +8539,14 @@ func (m *Evidence) Size() (n int) {
 	if m.Height != 0 {
 		n += 1 + sovTypes(uint64(m.Height))
 	}
-	if m.Time != 0 {
-		n += 1 + sovTypes(uint64(m.Time))
-	}
+	l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Time)
+	n += 1 + l + sovTypes(uint64(l))
 	if m.TotalVotingPower != 0 {
 		n += 1 + sovTypes(uint64(m.TotalVotingPower))
 	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
 	return n
 }
 
@@ -7494,6 +8956,7 @@ func (m *Request) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -7573,6 +9036,7 @@ func (m *RequestEcho) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -7623,6 +9087,7 @@ func (m *RequestFlush) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -7702,6 +9167,7 @@ func (m *RequestInfo) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -7810,6 +9276,7 @@ func (m *RequestSetOption) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -7849,10 +9316,10 @@ func (m *RequestInitChain) Unmarshal(dAtA []byte) error {
 		}
 		switch fieldNum {
 		case 1:
-			if wireType != 0 {
+			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType)
 			}
-			m.Time = 0
+			var msglen int
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowTypes
@@ -7862,11 +9329,22 @@ func (m *RequestInitChain) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				m.Time |= (int64(b) & 0x7F) << shift
+				msglen |= (int(b) & 0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
+			if msglen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		case 2:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType)
@@ -8003,6 +9481,7 @@ func (m *RequestInitChain) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8152,6 +9631,7 @@ func (m *RequestQuery) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8253,7 +9733,7 @@ func (m *RequestBeginBlock) Unmarshal(dAtA []byte) error {
 			iNdEx = postIndex
 		case 3:
 			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Validators", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field LastCommitInfo", wireType)
 			}
 			var msglen int
 			for shift := uint(0); ; shift += 7 {
@@ -8277,8 +9757,7 @@ func (m *RequestBeginBlock) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Validators = append(m.Validators, SigningValidator{})
-			if err := m.Validators[len(m.Validators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+			if err := m.LastCommitInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 				return err
 			}
 			iNdEx = postIndex
@@ -8325,6 +9804,7 @@ func (m *RequestBeginBlock) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8406,6 +9886,7 @@ func (m *RequestCheckTx) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8487,6 +9968,7 @@ func (m *RequestDeliverTx) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8556,6 +10038,7 @@ func (m *RequestEndBlock) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -8606,6 +10089,7 @@ func (m *RequestCommit) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9040,6 +10524,7 @@ func (m *Response) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9119,6 +10604,7 @@ func (m *ResponseException) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9198,6 +10684,7 @@ func (m *ResponseEcho) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9248,6 +10735,7 @@ func (m *ResponseFlush) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9406,6 +10894,7 @@ func (m *ResponseInfo) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9533,6 +11022,7 @@ func (m *ResponseSetOption) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9647,6 +11137,7 @@ func (m *ResponseInitChain) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9905,6 +11396,7 @@ func (m *ResponseQuery) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -9986,6 +11478,7 @@ func (m *ResponseBeginBlock) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10201,36 +11694,6 @@ func (m *ResponseCheckTx) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
-		case 8:
-			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Fee", 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 err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
-				return err
-			}
-			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipTypes(dAtA[iNdEx:])
@@ -10243,6 +11706,7 @@ func (m *ResponseCheckTx) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10458,36 +11922,6 @@ func (m *ResponseDeliverTx) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
-		case 8:
-			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Fee", 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 err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
-				return err
-			}
-			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipTypes(dAtA[iNdEx:])
@@ -10500,6 +11934,7 @@ func (m *ResponseDeliverTx) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10645,6 +12080,7 @@ func (m *ResponseEndBlock) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10726,6 +12162,7 @@ func (m *ResponseCommit) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10875,6 +12312,7 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -10982,6 +12420,7 @@ func (m *BlockSize) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11070,6 +12509,7 @@ func (m *TxSize) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11139,6 +12579,108 @@ func (m *BlockGossip) Unmarshal(dAtA []byte) error {
 			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 *LastCommitInfo) 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: LastCommitInfo: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: LastCommitInfo: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CommitRound", wireType)
+			}
+			m.CommitRound = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTypes
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.CommitRound |= (int32(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Validators", 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
+			}
+			m.Validators = append(m.Validators, SigningValidator{})
+			if err := m.Validators[len(m.Validators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		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
 		}
 	}
@@ -11226,10 +12768,10 @@ func (m *Header) Unmarshal(dAtA []byte) error {
 				}
 			}
 		case 3:
-			if wireType != 0 {
+			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType)
 			}
-			m.Time = 0
+			var msglen int
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowTypes
@@ -11239,11 +12781,22 @@ func (m *Header) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				m.Time |= (int64(b) & 0x7F) << shift
+				msglen |= (int(b) & 0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
+			if msglen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		case 4:
 			if wireType != 0 {
 				return fmt.Errorf("proto: wrong wireType = %d for field NumTxs", wireType)
@@ -11417,6 +12970,7 @@ func (m *Header) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11547,6 +13101,7 @@ func (m *Validator) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11647,6 +13202,7 @@ func (m *SigningValidator) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11757,6 +13313,7 @@ func (m *PubKey) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -11874,10 +13431,10 @@ func (m *Evidence) Unmarshal(dAtA []byte) error {
 				}
 			}
 		case 4:
-			if wireType != 0 {
+			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType)
 			}
-			m.Time = 0
+			var msglen int
 			for shift := uint(0); ; shift += 7 {
 				if shift >= 64 {
 					return ErrIntOverflowTypes
@@ -11887,11 +13444,22 @@ func (m *Evidence) Unmarshal(dAtA []byte) error {
 				}
 				b := dAtA[iNdEx]
 				iNdEx++
-				m.Time |= (int64(b) & 0x7F) << shift
+				msglen |= (int(b) & 0x7F) << shift
 				if b < 0x80 {
 					break
 				}
 			}
+			if msglen < 0 {
+				return ErrInvalidLengthTypes
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		case 5:
 			if wireType != 0 {
 				return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType)
@@ -11923,6 +13491,7 @@ func (m *Evidence) Unmarshal(dAtA []byte) error {
 			if (iNdEx + skippy) > l {
 				return io.ErrUnexpectedEOF
 			}
+			m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
 			iNdEx += skippy
 		}
 	}
@@ -12037,128 +13606,134 @@ var (
 	ErrIntOverflowTypes   = fmt.Errorf("proto: integer overflow")
 )
 
-func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptorTypes) }
-func init() { golang_proto.RegisterFile("abci/types/types.proto", fileDescriptorTypes) }
-
-var fileDescriptorTypes = []byte{
-	// 1892 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0x4b, 0x73, 0x1c, 0x49,
-	0x11, 0x56, 0xcf, 0xbb, 0x53, 0x8f, 0x19, 0x97, 0x6c, 0x69, 0x3c, 0x0b, 0xb2, 0xa3, 0x83, 0xf0,
-	0xca, 0xac, 0x56, 0x02, 0xed, 0xda, 0x61, 0xef, 0xc2, 0x06, 0x1a, 0xad, 0xd9, 0x51, 0x2c, 0x0f,
-	0xd1, 0xf6, 0x9a, 0x08, 0x2e, 0x13, 0x35, 0xd3, 0xa5, 0x9e, 0x0e, 0xcf, 0x74, 0xf7, 0x76, 0xd5,
-	0x68, 0x47, 0xbe, 0x71, 0xdf, 0xe0, 0xca, 0x99, 0x1b, 0x27, 0x0e, 0x44, 0x10, 0xc1, 0x91, 0x13,
-	0xb1, 0x47, 0xfe, 0x00, 0x0e, 0xd0, 0x72, 0xe2, 0x17, 0x70, 0x83, 0xa8, 0xac, 0xea, 0xa7, 0x7a,
-	0x1c, 0xc2, 0x1c, 0xb9, 0x48, 0x95, 0x9d, 0x99, 0x55, 0x95, 0x39, 0x99, 0x5f, 0x66, 0x16, 0x6c,
-	0xd1, 0xd1, 0xd8, 0x3b, 0x10, 0x17, 0x21, 0xe3, 0xea, 0xef, 0x7e, 0x18, 0x05, 0x22, 0x20, 0x75,
-	0x24, 0x7a, 0xef, 0xba, 0x9e, 0x98, 0xcc, 0x47, 0xfb, 0xe3, 0x60, 0x76, 0xe0, 0x06, 0x6e, 0x70,
-	0x80, 0xdc, 0xd1, 0xfc, 0x0c, 0x29, 0x24, 0x70, 0xa5, 0xb4, 0x7a, 0x8f, 0x32, 0xe2, 0x82, 0xf9,
-	0x0e, 0x8b, 0x66, 0x9e, 0x2f, 0xb2, 0xcb, 0xa9, 0x37, 0xe2, 0x07, 0xe3, 0x60, 0x36, 0x0b, 0xfc,
-	0xec, 0x79, 0xd6, 0x9f, 0x6b, 0xd0, 0xb4, 0xd9, 0xe7, 0x73, 0xc6, 0x05, 0xd9, 0x85, 0x1a, 0x1b,
-	0x4f, 0x82, 0x6e, 0xe5, 0xae, 0xb1, 0xbb, 0x7a, 0x48, 0xf6, 0x95, 0x9c, 0xe6, 0x3e, 0x19, 0x4f,
-	0x82, 0xc1, 0x8a, 0x8d, 0x12, 0xe4, 0x1d, 0xa8, 0x9f, 0x4d, 0xe7, 0x7c, 0xd2, 0xad, 0xa2, 0xe8,
-	0x66, 0x5e, 0xf4, 0x87, 0x92, 0x35, 0x58, 0xb1, 0x95, 0x8c, 0xdc, 0xd6, 0xf3, 0xcf, 0x82, 0x6e,
-	0xad, 0x6c, 0xdb, 0x13, 0xff, 0x0c, 0xb7, 0x95, 0x12, 0xe4, 0x11, 0x00, 0x67, 0x62, 0x18, 0x84,
-	0xc2, 0x0b, 0xfc, 0x6e, 0x1d, 0xe5, 0xb7, 0xf3, 0xf2, 0x4f, 0x99, 0xf8, 0x29, 0xb2, 0x07, 0x2b,
-	0xb6, 0xc9, 0x63, 0x42, 0x6a, 0x7a, 0xbe, 0x27, 0x86, 0xe3, 0x09, 0xf5, 0xfc, 0x6e, 0xa3, 0x4c,
-	0xf3, 0xc4, 0xf7, 0xc4, 0xb1, 0x64, 0x4b, 0x4d, 0x2f, 0x26, 0xa4, 0x29, 0x9f, 0xcf, 0x59, 0x74,
-	0xd1, 0x6d, 0x96, 0x99, 0xf2, 0x33, 0xc9, 0x92, 0xa6, 0xa0, 0x0c, 0xf9, 0x10, 0x56, 0x47, 0xcc,
-	0xf5, 0xfc, 0xe1, 0x68, 0x1a, 0x8c, 0x5f, 0x74, 0x5b, 0xa8, 0xd2, 0xcd, 0xab, 0xf4, 0xa5, 0x40,
-	0x5f, 0xf2, 0x07, 0x2b, 0x36, 0x8c, 0x12, 0x8a, 0x1c, 0x42, 0x6b, 0x3c, 0x61, 0xe3, 0x17, 0x43,
-	0xb1, 0xe8, 0x9a, 0xa8, 0x79, 0x2b, 0xaf, 0x79, 0x2c, 0xb9, 0xcf, 0x16, 0x83, 0x15, 0xbb, 0x39,
-	0x56, 0x4b, 0xf2, 0x00, 0x4c, 0xe6, 0x3b, 0xfa, 0xb8, 0x55, 0x54, 0xda, 0x2a, 0xfc, 0x2e, 0xbe,
-	0x13, 0x1f, 0xd6, 0x62, 0x7a, 0x4d, 0xf6, 0xa1, 0x21, 0x7f, 0x6b, 0x4f, 0x74, 0xd7, 0x50, 0xe7,
-	0x66, 0xe1, 0x20, 0xe4, 0x0d, 0x56, 0x6c, 0x2d, 0x25, 0xdd, 0xe7, 0xb0, 0xa9, 0x77, 0xce, 0x22,
-	0x79, 0xb9, 0xcd, 0x32, 0xf7, 0x7d, 0xac, 0xf8, 0x78, 0x3d, 0xd3, 0x89, 0x89, 0x7e, 0x13, 0xea,
-	0xe7, 0x74, 0x3a, 0x67, 0xd6, 0xdb, 0xb0, 0x9a, 0x89, 0x14, 0xd2, 0x85, 0xe6, 0x8c, 0x71, 0x4e,
-	0x5d, 0xd6, 0x35, 0xee, 0x1a, 0xbb, 0xa6, 0x1d, 0x93, 0xd6, 0x06, 0xac, 0x65, 0xe3, 0x24, 0xa3,
-	0x28, 0x63, 0x41, 0x2a, 0x9e, 0xb3, 0x88, 0xcb, 0x00, 0xd0, 0x8a, 0x9a, 0xb4, 0x3e, 0x80, 0x4e,
-	0x31, 0x08, 0x48, 0x07, 0xaa, 0x2f, 0xd8, 0x85, 0x96, 0x94, 0x4b, 0x72, 0x53, 0x5f, 0x08, 0xa3,
-	0xd8, 0xb4, 0xf5, 0xed, 0xfe, 0x61, 0x24, 0xca, 0x49, 0x1c, 0x10, 0x02, 0x35, 0xe1, 0xcd, 0xd4,
-	0x05, 0xab, 0x36, 0xae, 0xc9, 0x6d, 0xf9, 0x23, 0x51, 0xcf, 0x1f, 0x7a, 0x8e, 0xde, 0xa1, 0x89,
-	0xf4, 0x89, 0x43, 0x8e, 0xa0, 0x33, 0x0e, 0x7c, 0xce, 0x7c, 0x3e, 0xe7, 0xc3, 0x90, 0x46, 0x74,
-	0xc6, 0x75, 0xfc, 0xc7, 0x3f, 0xc9, 0x71, 0xcc, 0x3e, 0x45, 0xae, 0xdd, 0x1e, 0xe7, 0x3f, 0x90,
-	0x87, 0x00, 0xe7, 0x74, 0xea, 0x39, 0x54, 0x04, 0x11, 0xef, 0xd6, 0xee, 0x56, 0x77, 0x57, 0x0f,
-	0x3b, 0x5a, 0xf9, 0x79, 0xcc, 0xe8, 0xd7, 0xbe, 0x7a, 0x75, 0x67, 0xc5, 0xce, 0x48, 0x92, 0x7b,
-	0xd0, 0xa6, 0x61, 0x38, 0xe4, 0x82, 0x0a, 0x36, 0x1c, 0x5d, 0x08, 0xc6, 0x31, 0x3b, 0xd6, 0xec,
-	0x75, 0x1a, 0x86, 0x4f, 0xe5, 0xd7, 0xbe, 0xfc, 0x68, 0x39, 0x89, 0x6f, 0x31, 0x70, 0xa5, 0x85,
-	0x0e, 0x15, 0x14, 0x2d, 0x5c, 0xb3, 0x71, 0x2d, 0xbf, 0x85, 0x54, 0x4c, 0xb4, 0x75, 0xb8, 0x26,
-	0x5b, 0xd0, 0x98, 0x30, 0xcf, 0x9d, 0x08, 0x34, 0xa8, 0x6a, 0x6b, 0x4a, 0x3a, 0x33, 0x8c, 0x82,
-	0x73, 0x86, 0xb9, 0xdb, 0xb2, 0x15, 0x61, 0xfd, 0xd5, 0x80, 0x1b, 0x57, 0x82, 0x5d, 0xee, 0x3b,
-	0xa1, 0x7c, 0x12, 0x9f, 0x25, 0xd7, 0xe4, 0x1d, 0xb9, 0x2f, 0x75, 0x58, 0xa4, 0x31, 0x65, 0x5d,
-	0xdb, 0x3a, 0xc0, 0x8f, 0xda, 0x50, 0x2d, 0x42, 0xbe, 0x9f, 0x73, 0x4e, 0x15, 0x9d, 0x13, 0x07,
-	0xe1, 0x53, 0xcf, 0xf5, 0x3d, 0xdf, 0x7d, 0x9d, 0x8f, 0x06, 0x70, 0x73, 0x74, 0xf1, 0x92, 0xfa,
-	0xc2, 0xf3, 0xd9, 0xf0, 0x8a, 0x97, 0xdb, 0x7a, 0xa3, 0x27, 0xe7, 0x9e, 0xc3, 0xfc, 0x31, 0xd3,
-	0x1b, 0x6c, 0x26, 0x2a, 0xc9, 0xd6, 0xdc, 0xba, 0x0b, 0x1b, 0xf9, 0x8c, 0x24, 0x1b, 0x50, 0x11,
-	0x0b, 0x6d, 0x59, 0x45, 0x2c, 0x2c, 0x2b, 0x89, 0xa6, 0x24, 0x2d, 0xae, 0xc8, 0xdc, 0x87, 0x76,
-	0x21, 0x45, 0x33, 0x6e, 0x36, 0xb2, 0x6e, 0xb6, 0xda, 0xb0, 0x9e, 0xcb, 0x4c, 0xeb, 0xcb, 0x3a,
-	0xb4, 0x6c, 0xc6, 0x43, 0x19, 0x3e, 0xe4, 0x11, 0x98, 0x6c, 0x31, 0x66, 0x0a, 0x14, 0x8d, 0x02,
-	0xe4, 0x28, 0x99, 0x27, 0x31, 0x5f, 0x26, 0x67, 0x22, 0x4c, 0xee, 0xe7, 0x00, 0x7d, 0xb3, 0xa8,
-	0x94, 0x45, 0xf4, 0xbd, 0x3c, 0xa2, 0xdf, 0x2c, 0xc8, 0x16, 0x20, 0xfd, 0x7e, 0x0e, 0xd2, 0x8b,
-	0x1b, 0xe7, 0x30, 0xfd, 0x71, 0x09, 0xa6, 0x17, 0xaf, 0xbf, 0x04, 0xd4, 0x1f, 0x97, 0x80, 0x7a,
-	0xf7, 0xca, 0x59, 0xa5, 0xa8, 0xbe, 0x97, 0x47, 0xf5, 0xa2, 0x39, 0x05, 0x58, 0xff, 0x5e, 0x19,
-	0xac, 0xdf, 0x2e, 0xe8, 0x2c, 0xc5, 0xf5, 0xf7, 0xae, 0xe0, 0xfa, 0x56, 0x41, 0xb5, 0x04, 0xd8,
-	0x1f, 0xe7, 0x10, 0x17, 0x4a, 0x6d, 0x2b, 0x87, 0x5c, 0xf2, 0xf0, 0x6a, 0x4d, 0xd8, 0x2e, 0xfe,
-	0xb4, 0x65, 0x45, 0xe1, 0xa0, 0x50, 0x14, 0x6e, 0x15, 0x6f, 0x59, 0xa8, 0x0a, 0x29, 0xb6, 0xdf,
-	0x97, 0xf9, 0x5e, 0x88, 0x34, 0x89, 0x0d, 0x2c, 0x8a, 0x82, 0x48, 0x83, 0xaf, 0x22, 0xac, 0x5d,
-	0x89, 0x40, 0x69, 0x7c, 0xbd, 0xa6, 0x0e, 0x60, 0xd0, 0x67, 0xa2, 0xcb, 0xfa, 0xb5, 0x91, 0xea,
-	0x62, 0x29, 0xc8, 0xa2, 0x97, 0xa9, 0xd1, 0x2b, 0x53, 0x1e, 0x2a, 0xb9, 0xf2, 0x40, 0xbe, 0x0d,
-	0x37, 0xa6, 0x94, 0x0b, 0xe5, 0x97, 0x61, 0x0e, 0xce, 0xda, 0x92, 0xa1, 0x1c, 0xa2, 0x70, 0xed,
-	0x5d, 0xd8, 0xcc, 0xc8, 0x4a, 0x68, 0x45, 0xe8, 0xaa, 0x61, 0xf2, 0x76, 0x12, 0xe9, 0xa3, 0x30,
-	0x1c, 0x50, 0x3e, 0xb1, 0x7e, 0x9c, 0xda, 0x9f, 0x96, 0x1e, 0x02, 0xb5, 0x71, 0xe0, 0x28, 0xb3,
-	0xd6, 0x6d, 0x5c, 0xcb, 0x72, 0x34, 0x0d, 0x5c, 0x3c, 0xd5, 0xb4, 0xe5, 0x52, 0x4a, 0x25, 0x99,
-	0x62, 0xaa, 0x94, 0xb0, 0x7e, 0x65, 0xa4, 0xfb, 0xa5, 0xd5, 0xa8, 0xac, 0xbc, 0x18, 0xff, 0x4b,
-	0x79, 0xa9, 0x5c, 0xb7, 0xbc, 0x58, 0x7f, 0x30, 0xd2, 0xdf, 0x22, 0x29, 0x1c, 0x6f, 0x66, 0x9c,
-	0x0c, 0x0b, 0xcf, 0x77, 0xd8, 0x02, 0x53, 0xbd, 0x6a, 0x2b, 0x22, 0xae, 0xd3, 0x0d, 0x74, 0x70,
-	0xbe, 0x4e, 0x37, 0xf1, 0x9b, 0x22, 0x74, 0xc1, 0x09, 0xce, 0x30, 0x07, 0xd7, 0x6c, 0x45, 0x64,
-	0x70, 0xd3, 0xcc, 0xe1, 0xe6, 0x29, 0x90, 0xab, 0xd9, 0x49, 0x3e, 0x80, 0x9a, 0xa0, 0xae, 0x74,
-	0x9e, 0xb4, 0x7f, 0x63, 0x5f, 0x75, 0xbd, 0xfb, 0x9f, 0x3e, 0x3f, 0xa5, 0x5e, 0xd4, 0xdf, 0x92,
-	0xd6, 0xff, 0xf3, 0xd5, 0x9d, 0x0d, 0x29, 0xb3, 0x17, 0xcc, 0x3c, 0xc1, 0x66, 0xa1, 0xb8, 0xb0,
-	0x51, 0xc7, 0xfa, 0xb7, 0x21, 0x51, 0x3b, 0x97, 0xb5, 0xa5, 0xbe, 0x88, 0x43, 0xb3, 0x92, 0x29,
-	0xac, 0xd7, 0xf3, 0xcf, 0x37, 0x01, 0x5c, 0xca, 0x87, 0x5f, 0x50, 0x5f, 0x30, 0x47, 0x3b, 0xc9,
-	0x74, 0x29, 0xff, 0x39, 0x7e, 0x90, 0xfd, 0x87, 0x64, 0xcf, 0x39, 0x73, 0xd0, 0x5b, 0x55, 0xbb,
-	0xe9, 0x52, 0xfe, 0x19, 0x67, 0x4e, 0x62, 0x57, 0xf3, 0xbf, 0xb7, 0x8b, 0xec, 0x42, 0xf5, 0x8c,
-	0x31, 0x8d, 0x6c, 0x9d, 0x44, 0xf5, 0xe4, 0xe1, 0xfb, 0xa8, 0xac, 0x42, 0x42, 0x8a, 0x58, 0xbf,
-	0xac, 0xa4, 0xc1, 0x99, 0x16, 0xb7, 0xff, 0x2f, 0x1f, 0x7c, 0x8d, 0xdd, 0x62, 0x1e, 0x4a, 0xc9,
-	0x31, 0xdc, 0x48, 0x52, 0x66, 0x38, 0x0f, 0x1d, 0x2a, 0xbb, 0x30, 0xe3, 0xb5, 0x39, 0xd6, 0x49,
-	0x14, 0x3e, 0x53, 0xf2, 0xe4, 0x27, 0xb0, 0x5d, 0x48, 0xf2, 0x64, 0xab, 0xca, 0x6b, 0x73, 0xfd,
-	0x56, 0x3e, 0xd7, 0xe3, 0xfd, 0x62, 0x7f, 0x54, 0xdf, 0x20, 0xd6, 0xbf, 0x25, 0xdb, 0x9c, 0x2c,
-	0xf4, 0x97, 0xfd, 0xa2, 0xd6, 0x6f, 0x0c, 0x68, 0x17, 0x2e, 0x43, 0x0e, 0x00, 0x14, 0x72, 0x72,
-	0xef, 0x25, 0xd3, 0x20, 0x15, 0xfb, 0x00, 0x9d, 0xf5, 0xd4, 0x7b, 0xc9, 0x6c, 0x73, 0x14, 0x2f,
-	0xc9, 0x3d, 0x68, 0x8a, 0x85, 0x92, 0xce, 0x37, 0x82, 0xcf, 0x16, 0x28, 0xda, 0x10, 0xf8, 0x9f,
-	0x3c, 0x80, 0x35, 0xb5, 0xb1, 0x1b, 0x70, 0xee, 0x85, 0xba, 0x19, 0x21, 0xd9, 0xad, 0x3f, 0x41,
-	0x8e, 0xbd, 0x3a, 0x4a, 0x09, 0xeb, 0x17, 0x60, 0x26, 0xc7, 0x92, 0xb7, 0xc0, 0x9c, 0xd1, 0x85,
-	0xee, 0x92, 0xe5, 0xdd, 0xea, 0x76, 0x6b, 0x46, 0x17, 0xd8, 0x20, 0x93, 0x6d, 0x68, 0x4a, 0xa6,
-	0x58, 0x28, 0x7f, 0xd7, 0xed, 0xc6, 0x8c, 0x2e, 0x9e, 0x2d, 0x12, 0x86, 0x4b, 0x79, 0xdc, 0x02,
-	0xcf, 0xe8, 0xe2, 0x13, 0xca, 0xad, 0x8f, 0xa0, 0xa1, 0x2e, 0x79, 0xad, 0x8d, 0xa5, 0x7e, 0x25,
-	0xa7, 0xff, 0x03, 0x58, 0xcd, 0xdc, 0x9b, 0x7c, 0x17, 0x6e, 0x29, 0x0b, 0x43, 0x1a, 0x09, 0xf4,
-	0x48, 0x6e, 0x43, 0x82, 0xcc, 0x53, 0x1a, 0x09, 0x79, 0xa4, 0x6a, 0xea, 0x7f, 0x5f, 0x81, 0x86,
-	0x6a, 0x98, 0xc9, 0xbd, 0xcc, 0x74, 0x82, 0x55, 0xb1, 0xbf, 0x7a, 0xf9, 0xea, 0x4e, 0x13, 0x0b,
-	0xc8, 0xc9, 0xc7, 0xe9, 0xa8, 0x92, 0x02, 0x66, 0x25, 0xd7, 0xcf, 0xc7, 0x13, 0x4f, 0x35, 0x33,
-	0xf1, 0x6c, 0x43, 0xd3, 0x9f, 0xcf, 0xd0, 0x25, 0x35, 0xe5, 0x12, 0x7f, 0x3e, 0x93, 0x2e, 0x79,
-	0x0b, 0x4c, 0x11, 0x08, 0x3a, 0x45, 0x96, 0x4a, 0xd2, 0x16, 0x7e, 0x90, 0xcc, 0x7b, 0xd0, 0xce,
-	0x56, 0x5b, 0x59, 0x3d, 0x15, 0xb8, 0xaf, 0xa7, 0xb5, 0x56, 0x4e, 0x00, 0x6f, 0x43, 0x3b, 0x2d,
-	0x34, 0x4a, 0x4e, 0x01, 0xfe, 0x46, 0xfa, 0x19, 0x05, 0x6f, 0x43, 0x2b, 0xa9, 0xc3, 0x0a, 0xfc,
-	0x9b, 0x54, 0x95, 0x5f, 0x39, 0x38, 0x87, 0x51, 0x10, 0x06, 0x9c, 0x45, 0xba, 0xc1, 0x5a, 0x96,
-	0x70, 0x89, 0x9c, 0xe5, 0x81, 0x99, 0x30, 0x65, 0xd3, 0x40, 0x1d, 0x27, 0x62, 0x9c, 0xeb, 0xfe,
-	0x3c, 0x26, 0xc9, 0x1e, 0x34, 0xc3, 0xf9, 0x68, 0x28, 0x6b, 0x53, 0x3e, 0x30, 0x4f, 0xe7, 0xa3,
-	0x4f, 0xd9, 0x45, 0x3c, 0xa1, 0x84, 0x48, 0x61, 0x75, 0x0a, 0xbe, 0x60, 0x91, 0xf6, 0x9f, 0x22,
-	0x2c, 0x01, 0x9d, 0xe2, 0x78, 0x42, 0xde, 0x07, 0x33, 0xb1, 0xaf, 0x90, 0x20, 0xc5, 0x3b, 0xa7,
-	0x82, 0xb2, 0x85, 0xe1, 0x9e, 0xeb, 0x33, 0x67, 0x98, 0xfa, 0x16, 0xef, 0xd5, 0xb2, 0xdb, 0x8a,
-	0xf1, 0xa3, 0xd8, 0xb9, 0xd6, 0x77, 0xa0, 0xa1, 0xee, 0x88, 0x3f, 0xea, 0x45, 0x18, 0xf7, 0x57,
-	0xb8, 0x2e, 0xcd, 0xe4, 0xdf, 0x19, 0xd0, 0x8a, 0xc7, 0x9f, 0x52, 0xa5, 0xdc, 0xa5, 0x2b, 0xd7,
-	0xbd, 0xf4, 0xb2, 0xd9, 0x31, 0x8e, 0xb5, 0x5a, 0x26, 0xd6, 0xf6, 0x80, 0xa8, 0x90, 0x3a, 0x0f,
-	0x84, 0xe7, 0xbb, 0x43, 0xe5, 0x4d, 0x15, 0x5b, 0x1d, 0xe4, 0x3c, 0x47, 0xc6, 0xa9, 0xfc, 0x7e,
-	0xf8, 0x65, 0x1d, 0xda, 0x47, 0xfd, 0xe3, 0x93, 0xa3, 0x30, 0x9c, 0x7a, 0x63, 0x8a, 0x5d, 0xd7,
-	0x01, 0xd4, 0xb0, 0xaf, 0x2c, 0x79, 0x9d, 0xea, 0x95, 0x0d, 0x38, 0xe4, 0x10, 0xea, 0xd8, 0x5e,
-	0x92, 0xb2, 0x47, 0xaa, 0x5e, 0xe9, 0x9c, 0x23, 0x0f, 0x51, 0x0d, 0xe8, 0xd5, 0xb7, 0xaa, 0x5e,
-	0xd9, 0xb0, 0x43, 0x3e, 0x02, 0x33, 0x6d, 0x0c, 0x97, 0xbd, 0x58, 0xf5, 0x96, 0x8e, 0x3d, 0x52,
-	0x3f, 0xad, 0xb5, 0xcb, 0x1e, 0x5e, 0x7a, 0x4b, 0xe7, 0x03, 0xf2, 0x08, 0x9a, 0x71, 0xb7, 0x52,
-	0xfe, 0xa6, 0xd4, 0x5b, 0x32, 0x92, 0x48, 0xf7, 0xa8, 0x8e, 0xaf, 0xec, 0xe1, 0xab, 0x57, 0x3a,
-	0x37, 0x91, 0x07, 0xd0, 0xd0, 0x05, 0xa3, 0xf4, 0x5d, 0xa9, 0x57, 0x3e, 0x58, 0x48, 0x23, 0xd3,
-	0x6e, 0x77, 0xd9, 0xe3, 0x5c, 0x6f, 0xe9, 0x80, 0x47, 0x8e, 0x00, 0x32, 0x5d, 0xde, 0xd2, 0x57,
-	0xb7, 0xde, 0xf2, 0xc1, 0x8d, 0x7c, 0x08, 0xad, 0x74, 0x18, 0x2f, 0x7f, 0x47, 0xeb, 0x2d, 0x9b,
-	0xa5, 0xfa, 0xdf, 0xf8, 0xd7, 0xdf, 0x77, 0x8c, 0xdf, 0x5e, 0xee, 0x18, 0x7f, 0xbc, 0xdc, 0x31,
-	0xbe, 0xba, 0xdc, 0x31, 0xfe, 0x72, 0xb9, 0x63, 0xfc, 0xed, 0x72, 0xc7, 0xf8, 0xd3, 0xd7, 0x3b,
-	0xc6, 0xa8, 0x81, 0xef, 0xa9, 0xef, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x59, 0x8b, 0xa6,
-	0xd9, 0x15, 0x00, 0x00,
+func init() { proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_d8da2202f45d32c0) }
+func init() {
+	golang_proto.RegisterFile("abci/types/types.proto", fileDescriptor_types_d8da2202f45d32c0)
+}
+
+var fileDescriptor_types_d8da2202f45d32c0 = []byte{
+	// 1959 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0x4f, 0x73, 0x1b, 0x49,
+	0x15, 0xf7, 0xc8, 0xb2, 0xa4, 0x79, 0xb2, 0x2d, 0xa7, 0x9d, 0xd8, 0x8a, 0x16, 0xec, 0x30, 0x45,
+	0x65, 0x1d, 0xd6, 0x2b, 0x83, 0x97, 0x6c, 0x39, 0xbb, 0xb0, 0x85, 0xe5, 0x0d, 0x2b, 0xd7, 0x2e,
+	0x60, 0x26, 0xd9, 0x50, 0xc5, 0x45, 0xd5, 0xd2, 0xb4, 0x47, 0x53, 0x91, 0x66, 0x66, 0xa7, 0x5b,
+	0x5e, 0x39, 0x1f, 0x81, 0xda, 0xa2, 0xb8, 0x71, 0xe6, 0xc6, 0x17, 0xa0, 0x8a, 0x23, 0x27, 0x6a,
+	0x8f, 0x1c, 0xa0, 0xe0, 0x14, 0xc0, 0x5b, 0x5c, 0xf8, 0x04, 0x1c, 0xa9, 0xd7, 0xdd, 0xf3, 0xd7,
+	0xa3, 0x54, 0x12, 0x6e, 0x5c, 0xa4, 0xee, 0x7e, 0xef, 0xf5, 0xf4, 0x7b, 0xfd, 0xde, 0xfb, 0xbd,
+	0xd7, 0xb0, 0x45, 0x87, 0x23, 0xef, 0x40, 0x5c, 0x86, 0x8c, 0xab, 0xdf, 0x6e, 0x18, 0x05, 0x22,
+	0x20, 0x2b, 0x72, 0xd2, 0x79, 0xdb, 0xf5, 0xc4, 0x78, 0x36, 0xec, 0x8e, 0x82, 0xe9, 0x81, 0x1b,
+	0xb8, 0xc1, 0x81, 0xa4, 0x0e, 0x67, 0xe7, 0x72, 0x26, 0x27, 0x72, 0xa4, 0xa4, 0x3a, 0xbb, 0x6e,
+	0x10, 0xb8, 0x13, 0x96, 0x72, 0x09, 0x6f, 0xca, 0xb8, 0xa0, 0xd3, 0x50, 0x33, 0x1c, 0x65, 0xf6,
+	0x13, 0xcc, 0x77, 0x58, 0x34, 0xf5, 0x7c, 0x91, 0x1d, 0x4e, 0xbc, 0x21, 0x3f, 0x18, 0x05, 0xd3,
+	0x69, 0xe0, 0x67, 0x0f, 0x64, 0xfd, 0xb1, 0x0a, 0x75, 0x9b, 0x7d, 0x36, 0x63, 0x5c, 0x90, 0x3d,
+	0xa8, 0xb2, 0xd1, 0x38, 0x68, 0x57, 0xee, 0x18, 0x7b, 0xcd, 0x43, 0xd2, 0x55, 0x7c, 0x9a, 0xfa,
+	0x70, 0x34, 0x0e, 0xfa, 0x4b, 0xb6, 0xe4, 0x20, 0x6f, 0xc1, 0xca, 0xf9, 0x64, 0xc6, 0xc7, 0xed,
+	0x65, 0xc9, 0xba, 0x99, 0x67, 0xfd, 0x21, 0x92, 0xfa, 0x4b, 0xb6, 0xe2, 0xc1, 0x6d, 0x3d, 0xff,
+	0x3c, 0x68, 0x57, 0xcb, 0xb6, 0x3d, 0xf5, 0xcf, 0xe5, 0xb6, 0xc8, 0x41, 0x8e, 0x00, 0x38, 0x13,
+	0x83, 0x20, 0x14, 0x5e, 0xe0, 0xb7, 0x57, 0x24, 0xff, 0x76, 0x9e, 0xff, 0x11, 0x13, 0x3f, 0x91,
+	0xe4, 0xfe, 0x92, 0x6d, 0xf2, 0x78, 0x82, 0x92, 0x9e, 0xef, 0x89, 0xc1, 0x68, 0x4c, 0x3d, 0xbf,
+	0x5d, 0x2b, 0x93, 0x3c, 0xf5, 0x3d, 0x71, 0x82, 0x64, 0x94, 0xf4, 0xe2, 0x09, 0xaa, 0xf2, 0xd9,
+	0x8c, 0x45, 0x97, 0xed, 0x7a, 0x99, 0x2a, 0x3f, 0x45, 0x12, 0xaa, 0x22, 0x79, 0xc8, 0xfb, 0xd0,
+	0x1c, 0x32, 0xd7, 0xf3, 0x07, 0xc3, 0x49, 0x30, 0x7a, 0xda, 0x6e, 0x48, 0x91, 0x76, 0x5e, 0xa4,
+	0x87, 0x0c, 0x3d, 0xa4, 0xf7, 0x97, 0x6c, 0x18, 0x26, 0x33, 0x72, 0x08, 0x8d, 0xd1, 0x98, 0x8d,
+	0x9e, 0x0e, 0xc4, 0xbc, 0x6d, 0x4a, 0xc9, 0x5b, 0x79, 0xc9, 0x13, 0xa4, 0x3e, 0x9e, 0xf7, 0x97,
+	0xec, 0xfa, 0x48, 0x0d, 0xc9, 0x7d, 0x30, 0x99, 0xef, 0xe8, 0xcf, 0x35, 0xa5, 0xd0, 0x56, 0xe1,
+	0x5e, 0x7c, 0x27, 0xfe, 0x58, 0x83, 0xe9, 0x31, 0xe9, 0x42, 0x0d, 0xef, 0xda, 0x13, 0xed, 0x55,
+	0x29, 0x73, 0xb3, 0xf0, 0x21, 0x49, 0xeb, 0x2f, 0xd9, 0x9a, 0x0b, 0xcd, 0xe7, 0xb0, 0x89, 0x77,
+	0xc1, 0x22, 0x3c, 0xdc, 0x66, 0x99, 0xf9, 0x3e, 0x54, 0x74, 0x79, 0x3c, 0xd3, 0x89, 0x27, 0xbd,
+	0x3a, 0xac, 0x5c, 0xd0, 0xc9, 0x8c, 0x59, 0x6f, 0x42, 0x33, 0xe3, 0x29, 0xa4, 0x0d, 0xf5, 0x29,
+	0xe3, 0x9c, 0xba, 0xac, 0x6d, 0xdc, 0x31, 0xf6, 0x4c, 0x3b, 0x9e, 0x5a, 0xeb, 0xb0, 0x9a, 0xf5,
+	0x93, 0x8c, 0x20, 0xfa, 0x02, 0x0a, 0x5e, 0xb0, 0x88, 0xa3, 0x03, 0x68, 0x41, 0x3d, 0xb5, 0xde,
+	0x83, 0x8d, 0xa2, 0x13, 0x90, 0x0d, 0x58, 0x7e, 0xca, 0x2e, 0x35, 0x27, 0x0e, 0xc9, 0x4d, 0x7d,
+	0x20, 0xe9, 0xc5, 0xa6, 0xad, 0x4f, 0xf7, 0x8b, 0x4a, 0x22, 0x9c, 0xf8, 0x01, 0x39, 0x82, 0x2a,
+	0x06, 0x92, 0x94, 0x6e, 0x1e, 0x76, 0xba, 0x2a, 0xca, 0xba, 0x71, 0x94, 0x75, 0x1f, 0xc7, 0x51,
+	0xd6, 0x6b, 0x7c, 0xf9, 0x7c, 0x77, 0xe9, 0x57, 0x7f, 0xdf, 0x35, 0x6c, 0x29, 0x41, 0x6e, 0xe3,
+	0x55, 0x52, 0xcf, 0x1f, 0x78, 0x8e, 0xfe, 0x4e, 0x5d, 0xce, 0x4f, 0x1d, 0x72, 0x0c, 0x1b, 0xa3,
+	0xc0, 0xe7, 0xcc, 0xe7, 0x33, 0x3e, 0x08, 0x69, 0x44, 0xa7, 0x5c, 0x47, 0x49, 0x7c, 0x71, 0x27,
+	0x31, 0xf9, 0x4c, 0x52, 0xed, 0xd6, 0x28, 0xbf, 0x40, 0xde, 0x05, 0xb8, 0xa0, 0x13, 0xcf, 0xa1,
+	0x22, 0x88, 0x78, 0xbb, 0x7a, 0x67, 0x79, 0xaf, 0x79, 0xb8, 0xa1, 0x85, 0x9f, 0xc4, 0x84, 0x5e,
+	0x15, 0xcf, 0x64, 0x67, 0x38, 0xc9, 0x5d, 0x68, 0xd1, 0x30, 0x1c, 0x70, 0x41, 0x05, 0x1b, 0x0c,
+	0x2f, 0x05, 0xe3, 0x32, 0x86, 0x56, 0xed, 0x35, 0x1a, 0x86, 0x8f, 0x70, 0xb5, 0x87, 0x8b, 0x96,
+	0x93, 0xdc, 0x80, 0x74, 0x6f, 0x42, 0xa0, 0xea, 0x50, 0x41, 0xa5, 0x1d, 0x56, 0x6d, 0x39, 0xc6,
+	0xb5, 0x90, 0x8a, 0xb1, 0xd6, 0x4e, 0x8e, 0xc9, 0x16, 0xd4, 0xc6, 0xcc, 0x73, 0xc7, 0x42, 0x2a,
+	0xb4, 0x6c, 0xeb, 0x19, 0x9a, 0x3c, 0x8c, 0x82, 0x0b, 0x26, 0x23, 0xbc, 0x61, 0xab, 0x89, 0xf5,
+	0x2f, 0x03, 0x6e, 0x5c, 0x0b, 0x09, 0xdc, 0x77, 0x4c, 0xf9, 0x38, 0xfe, 0x16, 0x8e, 0xc9, 0x5b,
+	0xb8, 0x2f, 0x75, 0x58, 0xa4, 0x33, 0xcf, 0x9a, 0xd6, 0xb5, 0x2f, 0x17, 0xb5, 0xa2, 0x9a, 0x85,
+	0x3c, 0x84, 0x8d, 0x09, 0xe5, 0x62, 0xa0, 0x3c, 0x77, 0x20, 0x33, 0xcb, 0x72, 0x2e, 0x9a, 0x3e,
+	0xa1, 0xb1, 0x87, 0xa3, 0x43, 0x69, 0xf1, 0xf5, 0x49, 0x6e, 0x95, 0xf4, 0xe1, 0xe6, 0xf0, 0xf2,
+	0x19, 0xf5, 0x85, 0xe7, 0xb3, 0xc1, 0x35, 0x6b, 0xb7, 0xf4, 0x56, 0x0f, 0x2f, 0x3c, 0x87, 0xf9,
+	0x23, 0xa6, 0x37, 0xd9, 0x4c, 0x44, 0x92, 0x6b, 0xe0, 0xd6, 0x1d, 0x58, 0xcf, 0xc7, 0x2f, 0x59,
+	0x87, 0x8a, 0x98, 0x6b, 0x0d, 0x2b, 0x62, 0x6e, 0x59, 0x89, 0xef, 0x25, 0x41, 0x74, 0x8d, 0xe7,
+	0x1e, 0xb4, 0x0a, 0x01, 0x9d, 0x31, 0xb7, 0x91, 0x35, 0xb7, 0xd5, 0x82, 0xb5, 0x5c, 0x1c, 0x5b,
+	0x5f, 0xac, 0x40, 0xc3, 0x66, 0x3c, 0x44, 0x37, 0x22, 0x47, 0x60, 0xb2, 0xf9, 0x88, 0xa9, 0x14,
+	0x6a, 0x14, 0x12, 0x94, 0xe2, 0x79, 0x18, 0xd3, 0x31, 0x94, 0x13, 0x66, 0x72, 0x2f, 0x97, 0xfe,
+	0x37, 0x8b, 0x42, 0xd9, 0xfc, 0xbf, 0x9f, 0xcf, 0xff, 0x37, 0x0b, 0xbc, 0x05, 0x00, 0xb8, 0x97,
+	0x03, 0x80, 0xe2, 0xc6, 0x39, 0x04, 0x78, 0x50, 0x82, 0x00, 0xc5, 0xe3, 0x2f, 0x80, 0x80, 0x07,
+	0x25, 0x10, 0xd0, 0xbe, 0xf6, 0xad, 0x52, 0x0c, 0xd8, 0xcf, 0x63, 0x40, 0x51, 0x9d, 0x02, 0x08,
+	0x7c, 0xaf, 0x0c, 0x04, 0x6e, 0x17, 0x64, 0x16, 0xa2, 0xc0, 0x3b, 0xd7, 0x50, 0x60, 0xab, 0x20,
+	0x5a, 0x02, 0x03, 0x0f, 0x72, 0xf9, 0x19, 0x4a, 0x75, 0x2b, 0x4f, 0xd0, 0xe4, 0xdd, 0xeb, 0x08,
+	0xb2, 0x5d, 0xbc, 0xda, 0x32, 0x08, 0x39, 0x28, 0x40, 0xc8, 0xad, 0xe2, 0x29, 0x0b, 0x18, 0x92,
+	0x22, 0xc1, 0x3d, 0x8c, 0xfb, 0x82, 0xa7, 0x61, 0x8e, 0x60, 0x51, 0x14, 0x44, 0x3a, 0x55, 0xab,
+	0x89, 0xb5, 0x87, 0x99, 0x28, 0xf5, 0xaf, 0x17, 0xa0, 0x86, 0x74, 0xfa, 0x8c, 0x77, 0x59, 0xbf,
+	0x36, 0x52, 0x59, 0x19, 0xd1, 0xd9, 0x2c, 0x66, 0xea, 0x2c, 0x96, 0x01, 0x93, 0x4a, 0x0e, 0x4c,
+	0xc8, 0xb7, 0xe0, 0x86, 0x4c, 0x23, 0xd2, 0x2e, 0x83, 0x5c, 0x5a, 0x6b, 0x21, 0x41, 0x19, 0x44,
+	0xe5, 0xb7, 0xb7, 0x61, 0x33, 0xc3, 0x8b, 0x29, 0x56, 0xa6, 0xb0, 0xaa, 0x0c, 0xde, 0x8d, 0x84,
+	0xfb, 0x38, 0x0c, 0xfb, 0x94, 0x8f, 0xad, 0x1f, 0xa5, 0xfa, 0xa7, 0x40, 0x45, 0xa0, 0x3a, 0x0a,
+	0x1c, 0xa5, 0xd6, 0x9a, 0x2d, 0xc7, 0x08, 0x5e, 0x93, 0xc0, 0x95, 0x5f, 0x35, 0x6d, 0x1c, 0x22,
+	0x57, 0x12, 0x29, 0xa6, 0x0a, 0x09, 0xeb, 0x97, 0x46, 0xba, 0x5f, 0x8a, 0x5d, 0x65, 0x30, 0x63,
+	0xfc, 0x2f, 0x30, 0x53, 0x79, 0x59, 0x98, 0xb1, 0x7e, 0x67, 0xa4, 0x77, 0x91, 0x00, 0xc8, 0xeb,
+	0x29, 0x87, 0x6e, 0xe1, 0xf9, 0x0e, 0x9b, 0xcb, 0x50, 0x5f, 0xb6, 0xd5, 0x24, 0x46, 0xf5, 0x9a,
+	0x34, 0x70, 0x1e, 0xd5, 0xeb, 0x72, 0x4d, 0x4d, 0x34, 0xf0, 0x04, 0xe7, 0x32, 0x06, 0x57, 0x6d,
+	0x35, 0xc9, 0xe4, 0x4d, 0x33, 0x97, 0x37, 0xcf, 0x80, 0x5c, 0x8f, 0x4e, 0xf2, 0x1e, 0x54, 0x05,
+	0x75, 0xd1, 0x78, 0xa8, 0xff, 0x7a, 0x57, 0xd5, 0xc8, 0xdd, 0x8f, 0x9f, 0x9c, 0x51, 0x2f, 0xea,
+	0x6d, 0xa1, 0xf6, 0xff, 0x7e, 0xbe, 0xbb, 0x8e, 0x3c, 0xfb, 0xc1, 0xd4, 0x13, 0x6c, 0x1a, 0x8a,
+	0x4b, 0x5b, 0xca, 0x58, 0x7f, 0x31, 0x30, 0x6b, 0xe7, 0xa2, 0xb6, 0xd4, 0x16, 0xb1, 0x6b, 0x56,
+	0x32, 0x00, 0xfb, 0x72, 0xf6, 0xf9, 0x3a, 0x80, 0x4b, 0xf9, 0xe0, 0x73, 0xea, 0x0b, 0xe6, 0x68,
+	0x23, 0x99, 0x2e, 0xe5, 0x3f, 0x93, 0x0b, 0x58, 0x87, 0x20, 0x79, 0xc6, 0x99, 0x23, 0xad, 0xb5,
+	0x6c, 0xd7, 0x5d, 0xca, 0x3f, 0xe5, 0xcc, 0x49, 0xf4, 0xaa, 0xbf, 0x86, 0x5e, 0x7f, 0xcd, 0xb8,
+	0x5c, 0x0a, 0x59, 0xff, 0x0f, 0x9a, 0x7d, 0x65, 0x20, 0x16, 0xe7, 0xd3, 0x1e, 0x39, 0x81, 0x1b,
+	0x89, 0x7b, 0x0f, 0x66, 0xa1, 0x43, 0xb1, 0x72, 0x32, 0x5e, 0x18, 0x0f, 0x1b, 0x89, 0xc0, 0xa7,
+	0x8a, 0x9f, 0xfc, 0x18, 0xb6, 0x0b, 0x01, 0x99, 0x6c, 0x55, 0x79, 0x61, 0x5c, 0xde, 0xca, 0xc7,
+	0x65, 0xbc, 0x5f, 0xac, 0xe5, 0xf2, 0x6b, 0x68, 0xf9, 0x4d, 0x2c, 0x49, 0xb2, 0x69, 0xba, 0xec,
+	0x9e, 0xac, 0xdf, 0x18, 0xd0, 0x2a, 0x1c, 0x86, 0x1c, 0x00, 0xa8, 0x2c, 0xc7, 0xbd, 0x67, 0x71,
+	0x61, 0x1c, 0xdb, 0x40, 0x1a, 0xeb, 0x91, 0xf7, 0x8c, 0xd9, 0xe6, 0x30, 0x1e, 0x92, 0xbb, 0x50,
+	0x17, 0x73, 0xc5, 0x9d, 0x2f, 0xde, 0x1e, 0xcf, 0x25, 0x6b, 0x4d, 0xc8, 0x7f, 0x72, 0x1f, 0x56,
+	0xd5, 0xc6, 0x6e, 0xc0, 0xb9, 0x17, 0xea, 0xc2, 0x81, 0x64, 0xb7, 0xfe, 0x48, 0x52, 0xec, 0xe6,
+	0x30, 0x9d, 0x58, 0x3f, 0x07, 0x33, 0xf9, 0x2c, 0x79, 0x03, 0xcc, 0x29, 0x9d, 0xeb, 0xca, 0x16,
+	0xcf, 0xb6, 0x62, 0x37, 0xa6, 0x74, 0x2e, 0x8b, 0x5a, 0xb2, 0x0d, 0x75, 0x24, 0x8a, 0xb9, 0xb2,
+	0xf7, 0x8a, 0x5d, 0x9b, 0xd2, 0xf9, 0xe3, 0x79, 0x42, 0x70, 0x29, 0x8f, 0xcb, 0xd6, 0x29, 0x9d,
+	0x7f, 0x44, 0xb9, 0xf5, 0x01, 0xd4, 0xd4, 0x21, 0x5f, 0x6a, 0x63, 0x94, 0xaf, 0xe4, 0xe4, 0x7f,
+	0x00, 0xcd, 0xcc, 0xb9, 0xc9, 0x77, 0xe0, 0x96, 0xd2, 0x30, 0xa4, 0x91, 0x90, 0x16, 0xc9, 0x6d,
+	0x48, 0x24, 0xf1, 0x8c, 0x46, 0x02, 0x3f, 0xa9, 0x0a, 0xf1, 0x08, 0xd6, 0xf3, 0xc5, 0x2a, 0xf9,
+	0x06, 0xac, 0xea, 0xc2, 0x36, 0x0a, 0x66, 0xbe, 0xa3, 0x65, 0x9b, 0x6a, 0xcd, 0xc6, 0x25, 0xf2,
+	0xfd, 0x92, 0xb4, 0x1d, 0x23, 0xfa, 0x23, 0xcf, 0xf5, 0x3d, 0xdf, 0x7d, 0x51, 0xf6, 0xfe, 0x5b,
+	0x05, 0x6a, 0xaa, 0xb0, 0x26, 0x77, 0x33, 0x5d, 0x8c, 0x44, 0xcd, 0x5e, 0xf3, 0xea, 0xf9, 0x6e,
+	0x5d, 0x02, 0xcc, 0xe9, 0x87, 0x69, 0x4b, 0x93, 0x26, 0xd4, 0x4a, 0xae, 0xee, 0x8f, 0xfb, 0xa7,
+	0xe5, 0x57, 0xee, 0x9f, 0xb6, 0xa1, 0xee, 0xcf, 0xa6, 0xf2, 0xb2, 0xaa, 0xea, 0xb2, 0xfc, 0xd9,
+	0x14, 0x2f, 0xeb, 0x0d, 0x30, 0x45, 0x20, 0xe8, 0x44, 0x92, 0x54, 0x52, 0x68, 0xc8, 0x05, 0x24,
+	0xde, 0x85, 0x56, 0x16, 0xb3, 0x11, 0x83, 0x15, 0x44, 0xac, 0xa5, 0x88, 0x8d, 0xfd, 0xc4, 0x9b,
+	0xd0, 0x4a, 0x15, 0x56, 0x7c, 0x0a, 0x36, 0xd6, 0xd3, 0x65, 0xc9, 0x78, 0x1b, 0x1a, 0x09, 0x9a,
+	0x2b, 0x08, 0xa9, 0x53, 0x05, 0xe2, 0xd8, 0xac, 0x87, 0x51, 0x10, 0x06, 0x9c, 0x45, 0xba, 0x4c,
+	0x5b, 0x94, 0x0a, 0x12, 0x3e, 0xcb, 0x03, 0x33, 0x21, 0x62, 0xe9, 0x41, 0x1d, 0x27, 0x62, 0x9c,
+	0xeb, 0x2a, 0x3f, 0x9e, 0x92, 0x7d, 0xa8, 0x87, 0xb3, 0xe1, 0x00, 0x11, 0x2e, 0x1f, 0x32, 0x67,
+	0xb3, 0xe1, 0xc7, 0xec, 0x32, 0xee, 0x77, 0x42, 0x39, 0x93, 0x18, 0x17, 0x7c, 0xce, 0x22, 0xed,
+	0xbc, 0x6a, 0x62, 0x09, 0xd8, 0x28, 0xde, 0x35, 0xf9, 0x2e, 0x98, 0x89, 0x7e, 0x85, 0xd0, 0x2d,
+	0x9e, 0x39, 0x65, 0xc4, 0x42, 0x88, 0x7b, 0xae, 0xcf, 0x9c, 0x41, 0x6a, 0x5b, 0x79, 0xae, 0x86,
+	0xdd, 0x52, 0x84, 0x4f, 0x62, 0xe3, 0x5a, 0xdf, 0x86, 0x9a, 0x3a, 0x23, 0xe6, 0x13, 0xdc, 0x39,
+	0x2e, 0xb6, 0x70, 0x5c, 0x9a, 0x63, 0xfe, 0x6c, 0x40, 0x23, 0x6e, 0xa2, 0x4a, 0x85, 0x72, 0x87,
+	0xae, 0xbc, 0xec, 0xa1, 0x17, 0x75, 0xa2, 0xb1, 0x47, 0x56, 0x5f, 0xd9, 0x23, 0xf7, 0x81, 0x28,
+	0xc7, 0xbb, 0x08, 0x84, 0xe7, 0xbb, 0x03, 0x65, 0x73, 0xe5, 0x81, 0x1b, 0x92, 0xf2, 0x44, 0x12,
+	0xce, 0x70, 0xfd, 0xf0, 0x8b, 0x15, 0x68, 0x1d, 0xf7, 0x4e, 0x4e, 0x8f, 0xc3, 0x70, 0xe2, 0x8d,
+	0xa8, 0xac, 0xf0, 0x0e, 0xa0, 0x2a, 0x6b, 0xd8, 0x92, 0x77, 0xb3, 0x4e, 0x59, 0x33, 0x45, 0x0e,
+	0x61, 0x45, 0x96, 0xb2, 0xa4, 0xec, 0xf9, 0xac, 0x53, 0xda, 0x53, 0xe1, 0x47, 0x54, 0xb1, 0x7b,
+	0xfd, 0x15, 0xad, 0x53, 0xd6, 0x58, 0x91, 0x0f, 0xc0, 0x4c, 0x8b, 0xd0, 0x45, 0x6f, 0x69, 0x9d,
+	0x85, 0x2d, 0x16, 0xca, 0xa7, 0x15, 0xc0, 0xa2, 0x27, 0xa1, 0xce, 0xc2, 0x5e, 0x84, 0x1c, 0x41,
+	0x3d, 0xae, 0x8c, 0xca, 0x5f, 0xbb, 0x3a, 0x0b, 0xda, 0x1f, 0x34, 0x8f, 0xaa, 0x2e, 0xcb, 0x9e,
+	0xe4, 0x3a, 0xa5, 0x3d, 0x1a, 0xb9, 0x0f, 0x35, 0x0d, 0x78, 0xa5, 0x2f, 0x5e, 0x9d, 0xf2, 0x26,
+	0x06, 0x95, 0x4c, 0x2b, 0xeb, 0x45, 0xcf, 0x86, 0x9d, 0x85, 0xcd, 0x24, 0x39, 0x06, 0xc8, 0x54,
+	0x94, 0x0b, 0xdf, 0x03, 0x3b, 0x8b, 0x9b, 0x44, 0xf2, 0x3e, 0x34, 0xd2, 0xc6, 0xbf, 0xfc, 0x85,
+	0xaf, 0xb3, 0xa8, 0x6f, 0xeb, 0x7d, 0xed, 0x3f, 0xff, 0xdc, 0x31, 0x7e, 0x7b, 0xb5, 0x63, 0xfc,
+	0xfe, 0x6a, 0xc7, 0xf8, 0xf2, 0x6a, 0xc7, 0xf8, 0xd3, 0xd5, 0x8e, 0xf1, 0x8f, 0xab, 0x1d, 0xe3,
+	0x0f, 0x5f, 0xed, 0x18, 0xc3, 0x9a, 0x74, 0xff, 0x77, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xc1,
+	0xc2, 0x93, 0xfb, 0x94, 0x16, 0x00, 0x00,
 }
diff --git a/vendor/github.com/tendermint/tendermint/abci/types/types.proto b/vendor/github.com/tendermint/tendermint/abci/types/types.proto
index 0e1c18430fde7c6e2e399c1025189e8bbe277201..6e6b1cd3671a542833b635755ba6cab361cd52ac 100644
--- a/vendor/github.com/tendermint/tendermint/abci/types/types.proto
+++ b/vendor/github.com/tendermint/tendermint/abci/types/types.proto
@@ -4,6 +4,7 @@ package types;
 // For more information on gogo.proto, see:
 // https://github.com/gogo/protobuf/blob/master/extensions.md
 import "github.com/gogo/protobuf/gogoproto/gogo.proto";
+import "google/protobuf/timestamp.proto";
 import "github.com/tendermint/tendermint/libs/common/types.proto";
 
 // This file is copied from http://github.com/tendermint/abci
@@ -56,7 +57,7 @@ message RequestSetOption {
 }
 
 message RequestInitChain {
-  int64 time = 1;
+  google.protobuf.Timestamp time = 1  [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
   string chain_id = 2;
   ConsensusParams consensus_params = 3;
   repeated Validator validators = 4  [(gogoproto.nullable)=false];
@@ -70,10 +71,11 @@ message RequestQuery {
   bool prove = 4;
 }
 
+// NOTE: validators here have empty pubkeys.
 message RequestBeginBlock {
   bytes hash = 1;
   Header header = 2 [(gogoproto.nullable)=false];
-  repeated SigningValidator validators = 3  [(gogoproto.nullable)=false];
+  LastCommitInfo last_commit_info = 3 [(gogoproto.nullable)=false];
   repeated Evidence byzantine_validators = 4 [(gogoproto.nullable)=false];
 }
 
@@ -168,7 +170,6 @@ message ResponseCheckTx {
   int64 gas_wanted  = 5;
   int64 gas_used = 6;
   repeated common.KVPair tags = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="tags,omitempty"];
-  common.KI64Pair fee = 8 [(gogoproto.nullable)=false];
 }
 
 message ResponseDeliverTx {
@@ -179,7 +180,6 @@ message ResponseDeliverTx {
   int64 gas_wanted = 5;
   int64 gas_used = 6;
   repeated common.KVPair tags = 7 [(gogoproto.nullable)=false, (gogoproto.jsontag)="tags,omitempty"];
-  common.KI64Pair fee = 8 [(gogoproto.nullable)=false];
 }
 
 message ResponseEndBlock {
@@ -204,14 +204,14 @@ message ConsensusParams {
   BlockGossip block_gossip = 3;
 }
 
-// BlockSize contain limits on the block size.
+// BlockSize contains limits on the block size.
 message BlockSize {
   int32 max_bytes = 1;
   int32 max_txs = 2;
   int64 max_gas = 3;
 }
 
-// TxSize contain limits on the tx size.
+// TxSize contains limits on the tx size.
 message TxSize {
   int32 max_bytes = 1;
   int64 max_gas = 2;
@@ -224,6 +224,11 @@ message BlockGossip {
   int32 block_part_size_bytes = 1;
 }
 
+message LastCommitInfo {
+  int32 commit_round = 1;
+  repeated SigningValidator validators = 2 [(gogoproto.nullable)=false];
+}
+
 //----------------------------------------
 // Blockchain Types
 
@@ -232,7 +237,7 @@ message Header {
   // basics
   string chain_id = 1 [(gogoproto.customname)="ChainID"];
   int64 height = 2;
-  int64 time = 3;
+  google.protobuf.Timestamp time = 3 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
 
   // txs
   int32 num_txs = 4;
@@ -269,7 +274,7 @@ message Evidence {
   string type = 1;
   Validator validator = 2 [(gogoproto.nullable)=false];
   int64 height = 3;
-  int64 time = 4;
+  google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
   int64 total_voting_power = 5;
 }
 
diff --git a/vendor/github.com/tendermint/tendermint/blockchain/pool.go b/vendor/github.com/tendermint/tendermint/blockchain/pool.go
index e379d846a79508680e6665a56d9fc22980f65385..a881c7cb736a470b80955bf1784056695072539f 100644
--- a/vendor/github.com/tendermint/tendermint/blockchain/pool.go
+++ b/vendor/github.com/tendermint/tendermint/blockchain/pool.go
@@ -29,10 +29,10 @@ eg, L = latency = 0.1s
 */
 
 const (
-	requestIntervalMS         = 100
-	maxTotalRequesters        = 1000
+	requestIntervalMS         = 2
+	maxTotalRequesters        = 600
 	maxPendingRequests        = maxTotalRequesters
-	maxPendingRequestsPerPeer = 50
+	maxPendingRequestsPerPeer = 20
 
 	// Minimum recv rate to ensure we're receiving blocks from a peer fast
 	// enough. If a peer is not sending us data at at least that rate, we
@@ -219,14 +219,12 @@ func (pool *BlockPool) RedoRequest(height int64) p2p.ID {
 	defer pool.mtx.Unlock()
 
 	request := pool.requesters[height]
-
-	if request.block == nil {
-		panic("Expected block to be non-nil")
+	peerID := request.getPeerID()
+	if peerID != p2p.ID("") {
+		// RemovePeer will redo all requesters associated with this peer.
+		pool.removePeer(peerID)
 	}
-
-	// RemovePeer will redo all requesters associated with this peer.
-	pool.removePeer(request.peerID)
-	return request.peerID
+	return peerID
 }
 
 // TODO: ensure that blocks come in order for each peer.
diff --git a/vendor/github.com/tendermint/tendermint/blockchain/reactor.go b/vendor/github.com/tendermint/tendermint/blockchain/reactor.go
index 449a42ff09e6e17ab0a191d59373be6ec6cf0aff..f00df50c32879213186eed250dde5e6263d2dd28 100644
--- a/vendor/github.com/tendermint/tendermint/blockchain/reactor.go
+++ b/vendor/github.com/tendermint/tendermint/blockchain/reactor.go
@@ -18,7 +18,8 @@ const (
 	// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
 	BlockchainChannel = byte(0x40)
 
-	trySyncIntervalMS = 50
+	trySyncIntervalMS = 10
+
 	// stop syncing when last block's time is
 	// within this much of the system time.
 	// stopSyncingDurationMinutes = 10
@@ -76,8 +77,9 @@ func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *Bl
 			store.Height()))
 	}
 
-	const capacity = 1000 // must be bigger than peers count
-	requestsCh := make(chan BlockRequest, capacity)
+	requestsCh := make(chan BlockRequest, maxTotalRequesters)
+
+	const capacity = 1000                      // must be bigger than peers count
 	errorsCh := make(chan peerError, capacity) // so we don't block in #Receive#pool.AddBlock
 
 	pool := NewBlockPool(
@@ -107,9 +109,6 @@ func (bcR *BlockchainReactor) SetLogger(l log.Logger) {
 
 // OnStart implements cmn.Service.
 func (bcR *BlockchainReactor) OnStart() error {
-	if err := bcR.BaseReactor.OnStart(); err != nil {
-		return err
-	}
 	if bcR.fastSync {
 		err := bcR.pool.Start()
 		if err != nil {
@@ -122,7 +121,6 @@ func (bcR *BlockchainReactor) OnStart() error {
 
 // OnStop implements cmn.Service.
 func (bcR *BlockchainReactor) OnStop() {
-	bcR.BaseReactor.OnStop()
 	bcR.pool.Stop()
 }
 
@@ -209,7 +207,6 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
 
 // Handle messages from the poolReactor telling the reactor what to do.
 // NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down!
-// (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.)
 func (bcR *BlockchainReactor) poolRoutine() {
 
 	trySyncTicker := time.NewTicker(trySyncIntervalMS * time.Millisecond)
@@ -224,6 +221,8 @@ func (bcR *BlockchainReactor) poolRoutine() {
 	lastHundred := time.Now()
 	lastRate := 0.0
 
+	didProcessCh := make(chan struct{}, 1)
+
 FOR_LOOP:
 	for {
 		select {
@@ -239,14 +238,17 @@ FOR_LOOP:
 				// The pool handles timeouts, just let it go.
 				continue FOR_LOOP
 			}
+
 		case err := <-bcR.errorsCh:
 			peer := bcR.Switch.Peers().Get(err.peerID)
 			if peer != nil {
 				bcR.Switch.StopPeerForError(peer, err)
 			}
+
 		case <-statusUpdateTicker.C:
 			// ask for status updates
 			go bcR.BroadcastStatusRequest() // nolint: errcheck
+
 		case <-switchToConsensusTicker.C:
 			height, numPending, lenRequesters := bcR.pool.GetStatus()
 			outbound, inbound, _ := bcR.Switch.NumPeers()
@@ -261,60 +263,78 @@ FOR_LOOP:
 
 				break FOR_LOOP
 			}
+
 		case <-trySyncTicker.C: // chan time
-			// This loop can be slow as long as it's doing syncing work.
-		SYNC_LOOP:
-			for i := 0; i < 10; i++ {
-				// See if there are any blocks to sync.
-				first, second := bcR.pool.PeekTwoBlocks()
-				//bcR.Logger.Info("TrySync peeked", "first", first, "second", second)
-				if first == nil || second == nil {
-					// We need both to sync the first block.
-					break SYNC_LOOP
+			select {
+			case didProcessCh <- struct{}{}:
+			default:
+			}
+
+		case <-didProcessCh:
+			// NOTE: It is a subtle mistake to process more than a single block
+			// at a time (e.g. 10) here, because we only TrySend 1 request per
+			// loop.  The ratio mismatch can result in starving of blocks, a
+			// sudden burst of requests and responses, and repeat.
+			// Consequently, it is better to split these routines rather than
+			// coupling them as it's written here.  TODO uncouple from request
+			// routine.
+
+			// See if there are any blocks to sync.
+			first, second := bcR.pool.PeekTwoBlocks()
+			//bcR.Logger.Info("TrySync peeked", "first", first, "second", second)
+			if first == nil || second == nil {
+				// We need both to sync the first block.
+				continue FOR_LOOP
+			} else {
+				// Try again quickly next loop.
+				didProcessCh <- struct{}{}
+			}
+
+			firstParts := first.MakePartSet(state.ConsensusParams.BlockPartSizeBytes)
+			firstPartsHeader := firstParts.Header()
+			firstID := types.BlockID{first.Hash(), firstPartsHeader}
+			// Finally, verify the first block using the second's commit
+			// NOTE: we can probably make this more efficient, but note that calling
+			// first.Hash() doesn't verify the tx contents, so MakePartSet() is
+			// currently necessary.
+			err := state.Validators.VerifyCommit(
+				chainID, firstID, first.Height, second.LastCommit)
+			if err != nil {
+				bcR.Logger.Error("Error in validation", "err", err)
+				peerID := bcR.pool.RedoRequest(first.Height)
+				peer := bcR.Switch.Peers().Get(peerID)
+				if peer != nil {
+					// NOTE: we've already removed the peer's request, but we
+					// still need to clean up the rest.
+					bcR.Switch.StopPeerForError(peer, fmt.Errorf("BlockchainReactor validation error: %v", err))
 				}
-				firstParts := first.MakePartSet(state.ConsensusParams.BlockPartSizeBytes)
-				firstPartsHeader := firstParts.Header()
-				firstID := types.BlockID{first.Hash(), firstPartsHeader}
-				// Finally, verify the first block using the second's commit
-				// NOTE: we can probably make this more efficient, but note that calling
-				// first.Hash() doesn't verify the tx contents, so MakePartSet() is
-				// currently necessary.
-				err := state.Validators.VerifyCommit(
-					chainID, firstID, first.Height, second.LastCommit)
+				continue FOR_LOOP
+			} else {
+				bcR.pool.PopRequest()
+
+				// TODO: batch saves so we dont persist to disk every block
+				bcR.store.SaveBlock(first, firstParts, second.LastCommit)
+
+				// TODO: same thing for app - but we would need a way to
+				// get the hash without persisting the state
+				var err error
+				state, err = bcR.blockExec.ApplyBlock(state, firstID, first)
 				if err != nil {
-					bcR.Logger.Error("Error in validation", "err", err)
-					peerID := bcR.pool.RedoRequest(first.Height)
-					peer := bcR.Switch.Peers().Get(peerID)
-					if peer != nil {
-						bcR.Switch.StopPeerForError(peer, fmt.Errorf("BlockchainReactor validation error: %v", err))
-					}
-					break SYNC_LOOP
-				} else {
-					bcR.pool.PopRequest()
-
-					// TODO: batch saves so we dont persist to disk every block
-					bcR.store.SaveBlock(first, firstParts, second.LastCommit)
-
-					// TODO: same thing for app - but we would need a way to
-					// get the hash without persisting the state
-					var err error
-					state, err = bcR.blockExec.ApplyBlock(state, firstID, first)
-					if err != nil {
-						// TODO This is bad, are we zombie?
-						cmn.PanicQ(cmn.Fmt("Failed to process committed block (%d:%X): %v",
-							first.Height, first.Hash(), err))
-					}
-					blocksSynced++
-
-					if blocksSynced%100 == 0 {
-						lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
-						bcR.Logger.Info("Fast Sync Rate", "height", bcR.pool.height,
-							"max_peer_height", bcR.pool.MaxPeerHeight(), "blocks/s", lastRate)
-						lastHundred = time.Now()
-					}
+					// TODO This is bad, are we zombie?
+					cmn.PanicQ(cmn.Fmt("Failed to process committed block (%d:%X): %v",
+						first.Height, first.Hash(), err))
+				}
+				blocksSynced++
+
+				if blocksSynced%100 == 0 {
+					lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
+					bcR.Logger.Info("Fast Sync Rate", "height", bcR.pool.height,
+						"max_peer_height", bcR.pool.MaxPeerHeight(), "blocks/s", lastRate)
+					lastHundred = time.Now()
 				}
 			}
 			continue FOR_LOOP
+
 		case <-bcR.Quit():
 			break FOR_LOOP
 		}
diff --git a/vendor/github.com/tendermint/tendermint/consensus/reactor.go b/vendor/github.com/tendermint/tendermint/consensus/reactor.go
index 3eb1d73aa639e4393e2fc1b730740a8669682c48..58ff42ae2b75928c1f580b0798d8d3229371e52a 100644
--- a/vendor/github.com/tendermint/tendermint/consensus/reactor.go
+++ b/vendor/github.com/tendermint/tendermint/consensus/reactor.go
@@ -58,9 +58,6 @@ func NewConsensusReactor(consensusState *ConsensusState, fastSync bool) *Consens
 // broadcasted to other peers and starting state if we're not in fast sync.
 func (conR *ConsensusReactor) OnStart() error {
 	conR.Logger.Info("ConsensusReactor ", "fastSync", conR.FastSync())
-	if err := conR.BaseReactor.OnStart(); err != nil {
-		return err
-	}
 
 	conR.subscribeToBroadcastEvents()
 
@@ -77,7 +74,6 @@ func (conR *ConsensusReactor) OnStart() error {
 // OnStop implements BaseService by unsubscribing from events and stopping
 // state.
 func (conR *ConsensusReactor) OnStop() {
-	conR.BaseReactor.OnStop()
 	conR.unsubscribeFromBroadcastEvents()
 	conR.conS.Stop()
 	if !conR.FastSync() {
diff --git a/vendor/github.com/tendermint/tendermint/consensus/replay.go b/vendor/github.com/tendermint/tendermint/consensus/replay.go
index dd940998fabdf4753c637650e52e5187f7ee5702..bb1f2e46db9f6c4d33103d4c1bbe1c13a76009e8 100644
--- a/vendor/github.com/tendermint/tendermint/consensus/replay.go
+++ b/vendor/github.com/tendermint/tendermint/consensus/replay.go
@@ -227,7 +227,7 @@ func (h *Handshaker) NBlocks() int {
 func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
 
 	// Handshake is done via ABCI Info on the query conn.
-	res, err := proxyApp.Query().InfoSync(abci.RequestInfo{version.Version})
+	res, err := proxyApp.Query().InfoSync(abci.RequestInfo{Version: version.Version})
 	if err != nil {
 		return fmt.Errorf("Error calling Info: %v", err)
 	}
@@ -269,7 +269,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
 		validators := types.TM2PB.Validators(state.Validators)
 		csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
 		req := abci.RequestInitChain{
-			Time:            h.genDoc.GenesisTime.Unix(), // TODO
+			Time:            h.genDoc.GenesisTime,
 			ChainId:         h.genDoc.ChainID,
 			ConsensusParams: csParams,
 			Validators:      validators,
diff --git a/vendor/github.com/tendermint/tendermint/consensus/state.go b/vendor/github.com/tendermint/tendermint/consensus/state.go
index f66a872eb641133a4a922dc0da56b07a184162a1..6ffe6ef643196e6bac6a49fa24eeb8acbf2f07b4 100644
--- a/vendor/github.com/tendermint/tendermint/consensus/state.go
+++ b/vendor/github.com/tendermint/tendermint/consensus/state.go
@@ -553,9 +553,30 @@ func (cs *ConsensusState) newStep() {
 // Updates (state transitions) happen on timeouts, complete proposals, and 2/3 majorities.
 // ConsensusState must be locked before any internal state is updated.
 func (cs *ConsensusState) receiveRoutine(maxSteps int) {
+	onExit := func(cs *ConsensusState) {
+		// NOTE: the internalMsgQueue may have signed messages from our
+		// priv_val that haven't hit the WAL, but its ok because
+		// priv_val tracks LastSig
+
+		// close wal now that we're done writing to it
+		cs.wal.Stop()
+		cs.wal.Wait()
+
+		close(cs.done)
+	}
+
 	defer func() {
 		if r := recover(); r != nil {
 			cs.Logger.Error("CONSENSUS FAILURE!!!", "err", r, "stack", string(debug.Stack()))
+			// stop gracefully
+			//
+			// NOTE: We most probably shouldn't be running any further when there is
+			// some unexpected panic. Some unknown error happened, and so we don't
+			// know if that will result in the validator signing an invalid thing. It
+			// might be worthwhile to explore a mechanism for manual resuming via
+			// some console or secure RPC system, but for now, halting the chain upon
+			// unexpected consensus bugs sounds like the better option.
+			onExit(cs)
 		}
 	}()
 
@@ -588,16 +609,7 @@ func (cs *ConsensusState) receiveRoutine(maxSteps int) {
 			// go to the next step
 			cs.handleTimeout(ti, rs)
 		case <-cs.Quit():
-
-			// NOTE: the internalMsgQueue may have signed messages from our
-			// priv_val that haven't hit the WAL, but its ok because
-			// priv_val tracks LastSig
-
-			// close wal now that we're done writing to it
-			cs.wal.Stop()
-			cs.wal.Wait()
-
-			close(cs.done)
+			onExit(cs)
 			return
 		}
 	}
diff --git a/vendor/github.com/tendermint/tendermint/crypto/README.md b/vendor/github.com/tendermint/tendermint/crypto/README.md
index 5fac67338cb4caca65d610256d8c6e9376ec5b9a..bb663122733c118fd515d614464acc3c6a97c769 100644
--- a/vendor/github.com/tendermint/tendermint/crypto/README.md
+++ b/vendor/github.com/tendermint/tendermint/crypto/README.md
@@ -24,9 +24,7 @@ crypto `.Bytes()` uses Amino:binary encoding, but Amino:JSON is also supported.
 Example Amino:JSON encodings:
 
 ed25519.PrivKeyEd25519     - {"type":"954568A3288910","value":"EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="}
-crypto.SignatureEd25519   - {"type":"6BF5903DA1DB28","value":"77sQNZOrf7ltExpf7AV1WaYPCHbyRLgjBsoWVzcduuLk+jIGmYk+s5R6Emm29p12HeiNAuhUJgdFGmwkpeGJCA=="}
 ed25519.PubKeyEd25519      - {"type":"AC26791624DE60","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="}
 crypto.PrivKeySecp256k1   - {"type":"019E82E1B0F798","value":"zx4Pnh67N+g2V+5vZbQzEyRerX9c4ccNZOVzM9RvJ0Y="}
-crypto.SignatureSecp256k1 - {"type":"6D1EA416E1FEE8","value":"MEUCIQCIg5TqS1l7I+MKTrSPIuUN2+4m5tA29dcauqn3NhEJ2wIgICaZ+lgRc5aOTVahU/XoLopXKn8BZcl0bnuYWLvohR8="}
 crypto.PubKeySecp256k1    - {"type":"F8CCEAEB5AE980","value":"A8lPKJXcNl5VHt1FK8a244K9EJuS4WX1hFBnwisi0IJx"}
 ```
diff --git a/vendor/github.com/tendermint/tendermint/crypto/crypto.go b/vendor/github.com/tendermint/tendermint/crypto/crypto.go
index 4c097b3517934c445d958c15fb19c071ef61b322..09c12ff7660b672af338cceac6222305b5a5bf9d 100644
--- a/vendor/github.com/tendermint/tendermint/crypto/crypto.go
+++ b/vendor/github.com/tendermint/tendermint/crypto/crypto.go
@@ -6,7 +6,7 @@ import (
 
 type PrivKey interface {
 	Bytes() []byte
-	Sign(msg []byte) (Signature, error)
+	Sign(msg []byte) ([]byte, error)
 	PubKey() PubKey
 	Equals(PrivKey) bool
 }
@@ -19,16 +19,10 @@ type Address = cmn.HexBytes
 type PubKey interface {
 	Address() Address
 	Bytes() []byte
-	VerifyBytes(msg []byte, sig Signature) bool
+	VerifyBytes(msg []byte, sig []byte) bool
 	Equals(PubKey) bool
 }
 
-type Signature interface {
-	Bytes() []byte
-	IsZero() bool
-	Equals(Signature) bool
-}
-
 type Symmetric interface {
 	Keygen() []byte
 	Encrypt(plaintext []byte, secret []byte) (ciphertext []byte)
diff --git a/vendor/github.com/tendermint/tendermint/crypto/ed25519/ed25519.go b/vendor/github.com/tendermint/tendermint/crypto/ed25519/ed25519.go
index 8b7bd42bd955c15118dc672705453981bd970878..fa7526f3fcf716d8ab185a1279e1ef6f9a2c74fe 100644
--- a/vendor/github.com/tendermint/tendermint/crypto/ed25519/ed25519.go
+++ b/vendor/github.com/tendermint/tendermint/crypto/ed25519/ed25519.go
@@ -4,13 +4,13 @@ import (
 	"bytes"
 	"crypto/subtle"
 	"fmt"
+	"io"
 
 	"github.com/tendermint/ed25519"
 	"github.com/tendermint/ed25519/extra25519"
 	amino "github.com/tendermint/go-amino"
 	"github.com/tendermint/tendermint/crypto"
 	"github.com/tendermint/tendermint/crypto/tmhash"
-	cmn "github.com/tendermint/tendermint/libs/common"
 )
 
 //-------------------------------------
@@ -18,9 +18,11 @@ import (
 var _ crypto.PrivKey = PrivKeyEd25519{}
 
 const (
-	Ed25519PrivKeyAminoRoute   = "tendermint/PrivKeyEd25519"
-	Ed25519PubKeyAminoRoute    = "tendermint/PubKeyEd25519"
-	Ed25519SignatureAminoRoute = "tendermint/SignatureEd25519"
+	Ed25519PrivKeyAminoRoute = "tendermint/PrivKeyEd25519"
+	Ed25519PubKeyAminoRoute  = "tendermint/PubKeyEd25519"
+	// Size of an Edwards25519 signature. Namely the size of a compressed
+	// Edwards25519 point, and a field element. Both of which are 32 bytes.
+	SignatureEd25519Size = 64
 )
 
 var cdc = amino.NewCodec()
@@ -33,10 +35,6 @@ func init() {
 	cdc.RegisterInterface((*crypto.PrivKey)(nil), nil)
 	cdc.RegisterConcrete(PrivKeyEd25519{},
 		Ed25519PrivKeyAminoRoute, nil)
-
-	cdc.RegisterInterface((*crypto.Signature)(nil), nil)
-	cdc.RegisterConcrete(SignatureEd25519{},
-		Ed25519SignatureAminoRoute, nil)
 }
 
 // PrivKeyEd25519 implements crypto.PrivKey.
@@ -48,10 +46,10 @@ func (privKey PrivKeyEd25519) Bytes() []byte {
 }
 
 // Sign produces a signature on the provided message.
-func (privKey PrivKeyEd25519) Sign(msg []byte) (crypto.Signature, error) {
+func (privKey PrivKeyEd25519) Sign(msg []byte) ([]byte, error) {
 	privKeyBytes := [64]byte(privKey)
 	signatureBytes := ed25519.Sign(&privKeyBytes, msg)
-	return SignatureEd25519(*signatureBytes), nil
+	return signatureBytes[:], nil
 }
 
 // PubKey gets the corresponding public key from the private key.
@@ -102,8 +100,16 @@ func (privKey PrivKeyEd25519) ToCurve25519() *[PubKeyEd25519Size]byte {
 // It uses OS randomness in conjunction with the current global random seed
 // in tendermint/libs/common to generate the private key.
 func GenPrivKey() PrivKeyEd25519 {
+	return genPrivKey(crypto.CReader())
+}
+
+// genPrivKey generates a new ed25519 private key using the provided reader.
+func genPrivKey(rand io.Reader) PrivKeyEd25519 {
 	privKey := new([64]byte)
-	copy(privKey[:32], crypto.CRandBytes(32))
+	_, err := io.ReadFull(rand, privKey[:32])
+	if err != nil {
+		panic(err)
+	}
 	// ed25519.MakePublicKey(privKey) alters the last 32 bytes of privKey.
 	// It places the pubkey in the last 32 bytes of privKey, and returns the
 	// public key.
@@ -150,15 +156,15 @@ func (pubKey PubKeyEd25519) Bytes() []byte {
 	return bz
 }
 
-func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ crypto.Signature) bool {
+func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ []byte) bool {
 	// make sure we use the same algorithm to sign
-	sig, ok := sig_.(SignatureEd25519)
-	if !ok {
+	if len(sig_) != SignatureEd25519Size {
 		return false
 	}
+	sig := new([SignatureEd25519Size]byte)
+	copy(sig[:], sig_)
 	pubKeyBytes := [PubKeyEd25519Size]byte(pubKey)
-	sigBytes := [SignatureEd25519Size]byte(sig)
-	return ed25519.Verify(&pubKeyBytes, msg, &sigBytes)
+	return ed25519.Verify(&pubKeyBytes, msg, sig)
 }
 
 // ToCurve25519 takes a public key and returns its representation on
@@ -188,40 +194,3 @@ func (pubKey PubKeyEd25519) Equals(other crypto.PubKey) bool {
 		return false
 	}
 }
-
-//-------------------------------------
-
-var _ crypto.Signature = SignatureEd25519{}
-
-// Size of an Edwards25519 signature. Namely the size of a compressed
-// Edwards25519 point, and a field element. Both of which are 32 bytes.
-const SignatureEd25519Size = 64
-
-// SignatureEd25519 implements crypto.Signature
-type SignatureEd25519 [SignatureEd25519Size]byte
-
-func (sig SignatureEd25519) Bytes() []byte {
-	bz, err := cdc.MarshalBinaryBare(sig)
-	if err != nil {
-		panic(err)
-	}
-	return bz
-}
-
-func (sig SignatureEd25519) IsZero() bool { return len(sig) == 0 }
-
-func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", cmn.Fingerprint(sig[:])) }
-
-func (sig SignatureEd25519) Equals(other crypto.Signature) bool {
-	if otherEd, ok := other.(SignatureEd25519); ok {
-		return subtle.ConstantTimeCompare(sig[:], otherEd[:]) == 1
-	} else {
-		return false
-	}
-}
-
-func SignatureEd25519FromBytes(data []byte) crypto.Signature {
-	var sig SignatureEd25519
-	copy(sig[:], data)
-	return sig
-}
diff --git a/vendor/github.com/tendermint/tendermint/crypto/encoding/amino/amino.go b/vendor/github.com/tendermint/tendermint/crypto/encoding/amino/amino.go
index 2b5e15b4fd171591bd77166f537d1ca6e695fe18..fd9a08442e839c2cd675550fdc14b5e0c9385f68 100644
--- a/vendor/github.com/tendermint/tendermint/crypto/encoding/amino/amino.go
+++ b/vendor/github.com/tendermint/tendermint/crypto/encoding/amino/amino.go
@@ -33,12 +33,6 @@ func RegisterAmino(cdc *amino.Codec) {
 		"tendermint/PrivKeyEd25519", nil)
 	cdc.RegisterConcrete(secp256k1.PrivKeySecp256k1{},
 		"tendermint/PrivKeySecp256k1", nil)
-
-	cdc.RegisterInterface((*crypto.Signature)(nil), nil)
-	cdc.RegisterConcrete(ed25519.SignatureEd25519{},
-		"tendermint/SignatureEd25519", nil)
-	cdc.RegisterConcrete(secp256k1.SignatureSecp256k1{},
-		"tendermint/SignatureSecp256k1", nil)
 }
 
 func PrivKeyFromBytes(privKeyBytes []byte) (privKey crypto.PrivKey, err error) {
@@ -50,8 +44,3 @@ func PubKeyFromBytes(pubKeyBytes []byte) (pubKey crypto.PubKey, err error) {
 	err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
 	return
 }
-
-func SignatureFromBytes(pubKeyBytes []byte) (pubKey crypto.Signature, err error) {
-	err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
-	return
-}
diff --git a/vendor/github.com/tendermint/tendermint/crypto/secp256k1/secp256k1.go b/vendor/github.com/tendermint/tendermint/crypto/secp256k1/secp256k1.go
index 4b210dc7fe9c3889419837bb88570915ed7c5bc5..aee5dafe7a2154258bd7149742ae81bc212995e3 100644
--- a/vendor/github.com/tendermint/tendermint/crypto/secp256k1/secp256k1.go
+++ b/vendor/github.com/tendermint/tendermint/crypto/secp256k1/secp256k1.go
@@ -5,19 +5,18 @@ import (
 	"crypto/sha256"
 	"crypto/subtle"
 	"fmt"
+	"io"
 
 	secp256k1 "github.com/btcsuite/btcd/btcec"
 	amino "github.com/tendermint/go-amino"
 	"github.com/tendermint/tendermint/crypto"
-	"github.com/tendermint/tendermint/libs/common"
 	"golang.org/x/crypto/ripemd160"
 )
 
 //-------------------------------------
 const (
-	Secp256k1PrivKeyAminoRoute   = "tendermint/PrivKeySecp256k1"
-	Secp256k1PubKeyAminoRoute    = "tendermint/PubKeySecp256k1"
-	Secp256k1SignatureAminoRoute = "tendermint/SignatureSecp256k1"
+	Secp256k1PrivKeyAminoRoute = "tendermint/PrivKeySecp256k1"
+	Secp256k1PubKeyAminoRoute  = "tendermint/PubKeySecp256k1"
 )
 
 var cdc = amino.NewCodec()
@@ -30,10 +29,6 @@ func init() {
 	cdc.RegisterInterface((*crypto.PrivKey)(nil), nil)
 	cdc.RegisterConcrete(PrivKeySecp256k1{},
 		Secp256k1PrivKeyAminoRoute, nil)
-
-	cdc.RegisterInterface((*crypto.Signature)(nil), nil)
-	cdc.RegisterConcrete(SignatureSecp256k1{},
-		Secp256k1SignatureAminoRoute, nil)
 }
 
 //-------------------------------------
@@ -49,13 +44,13 @@ func (privKey PrivKeySecp256k1) Bytes() []byte {
 }
 
 // Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
-func (privKey PrivKeySecp256k1) Sign(msg []byte) (crypto.Signature, error) {
+func (privKey PrivKeySecp256k1) Sign(msg []byte) ([]byte, error) {
 	priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
 	sig, err := priv.Sign(crypto.Sha256(msg))
 	if err != nil {
 		return nil, err
 	}
-	return SignatureSecp256k1(sig.Serialize()), nil
+	return sig.Serialize(), nil
 }
 
 // PubKey performs the point-scalar multiplication from the privKey on the
@@ -80,8 +75,16 @@ func (privKey PrivKeySecp256k1) Equals(other crypto.PrivKey) bool {
 // It uses OS randomness in conjunction with the current global random seed
 // in tendermint/libs/common to generate the private key.
 func GenPrivKey() PrivKeySecp256k1 {
+	return genPrivKey(crypto.CReader())
+}
+
+// genPrivKey generates a new secp256k1 private key using the provided reader.
+func genPrivKey(rand io.Reader) PrivKeySecp256k1 {
 	privKeyBytes := [32]byte{}
-	copy(privKeyBytes[:], crypto.CRandBytes(32))
+	_, err := io.ReadFull(rand, privKeyBytes[:])
+	if err != nil {
+		panic(err)
+	}
 	// crypto.CRandBytes is guaranteed to be 32 bytes long, so it can be
 	// casted to PrivKeySecp256k1.
 	return PrivKeySecp256k1(privKeyBytes)
@@ -133,13 +136,7 @@ func (pubKey PubKeySecp256k1) Bytes() []byte {
 	return bz
 }
 
-func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, interfaceSig crypto.Signature) bool {
-	// and assert same algorithm to sign and verify
-	sig, ok := interfaceSig.(SignatureSecp256k1)
-	if !ok {
-		return false
-	}
-
+func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig []byte) bool {
 	pub, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256())
 	if err != nil {
 		return false
@@ -161,38 +158,3 @@ func (pubKey PubKeySecp256k1) Equals(other crypto.PubKey) bool {
 	}
 	return false
 }
-
-//-------------------------------------
-
-var _ crypto.Signature = SignatureSecp256k1{}
-
-// SignatureSecp256k1 implements crypto.Signature
-type SignatureSecp256k1 []byte
-
-func (sig SignatureSecp256k1) Bytes() []byte {
-	bz, err := cdc.MarshalBinaryBare(sig)
-	if err != nil {
-		panic(err)
-	}
-	return bz
-}
-
-func (sig SignatureSecp256k1) IsZero() bool { return len(sig) == 0 }
-
-func (sig SignatureSecp256k1) String() string {
-	return fmt.Sprintf("/%X.../", common.Fingerprint(sig[:]))
-}
-
-func (sig SignatureSecp256k1) Equals(other crypto.Signature) bool {
-	if otherSecp, ok := other.(SignatureSecp256k1); ok {
-		return subtle.ConstantTimeCompare(sig[:], otherSecp[:]) == 1
-	} else {
-		return false
-	}
-}
-
-func SignatureSecp256k1FromBytes(data []byte) crypto.Signature {
-	sig := make(SignatureSecp256k1, len(data))
-	copy(sig[:], data)
-	return sig
-}
diff --git a/vendor/github.com/tendermint/tendermint/evidence/reactor.go b/vendor/github.com/tendermint/tendermint/evidence/reactor.go
index bf11ac105572f0174e7d1a9da4d51f455acfda93..cfe47364c03a0aed82ce918fbcbbd086715ad2bf 100644
--- a/vendor/github.com/tendermint/tendermint/evidence/reactor.go
+++ b/vendor/github.com/tendermint/tendermint/evidence/reactor.go
@@ -44,11 +44,6 @@ func (evR *EvidenceReactor) SetLogger(l log.Logger) {
 	evR.evpool.SetLogger(l)
 }
 
-// OnStart implements cmn.Service
-func (evR *EvidenceReactor) OnStart() error {
-	return evR.BaseReactor.OnStart()
-}
-
 // GetChannels implements Reactor.
 // It returns the list of channels for this reactor.
 func (evR *EvidenceReactor) GetChannels() []*p2p.ChannelDescriptor {
diff --git a/vendor/github.com/tendermint/tendermint/libs/autofile/autofile.go b/vendor/github.com/tendermint/tendermint/libs/autofile/autofile.go
index 313da67890d826b785ff30c6c94847818f2fc32d..2f1bb4fd527a7aba72b82f5b8c18ddb8364f3a7d 100644
--- a/vendor/github.com/tendermint/tendermint/libs/autofile/autofile.go
+++ b/vendor/github.com/tendermint/tendermint/libs/autofile/autofile.go
@@ -35,18 +35,20 @@ const autoFileOpenDuration = 1000 * time.Millisecond
 // Automatically closes and re-opens file for writing.
 // This is useful for using a log file with the logrotate tool.
 type AutoFile struct {
-	ID     string
-	Path   string
-	ticker *time.Ticker
-	mtx    sync.Mutex
-	file   *os.File
+	ID            string
+	Path          string
+	ticker        *time.Ticker
+	tickerStopped chan struct{} // closed when ticker is stopped
+	mtx           sync.Mutex
+	file          *os.File
 }
 
 func OpenAutoFile(path string) (af *AutoFile, err error) {
 	af = &AutoFile{
-		ID:     cmn.RandStr(12) + ":" + path,
-		Path:   path,
-		ticker: time.NewTicker(autoFileOpenDuration),
+		ID:            cmn.RandStr(12) + ":" + path,
+		Path:          path,
+		ticker:        time.NewTicker(autoFileOpenDuration),
+		tickerStopped: make(chan struct{}),
 	}
 	if err = af.openFile(); err != nil {
 		return
@@ -58,18 +60,18 @@ func OpenAutoFile(path string) (af *AutoFile, err error) {
 
 func (af *AutoFile) Close() error {
 	af.ticker.Stop()
+	close(af.tickerStopped)
 	err := af.closeFile()
 	sighupWatchers.removeAutoFile(af)
 	return err
 }
 
 func (af *AutoFile) processTicks() {
-	for {
-		_, ok := <-af.ticker.C
-		if !ok {
-			return // Done.
-		}
+	select {
+	case <-af.ticker.C:
 		af.closeFile()
+	case <-af.tickerStopped:
+		return
 	}
 }
 
diff --git a/vendor/github.com/tendermint/tendermint/libs/autofile/group.go b/vendor/github.com/tendermint/tendermint/libs/autofile/group.go
index b4368ed9e0acafb3612bdd618dbdc5c8d5defc05..e747f04dd9ead3aec643e2d87fa7ec1f528c9bab 100644
--- a/vendor/github.com/tendermint/tendermint/libs/autofile/group.go
+++ b/vendor/github.com/tendermint/tendermint/libs/autofile/group.go
@@ -85,7 +85,6 @@ func OpenGroup(headPath string) (g *Group, err error) {
 		Head:           head,
 		headBuf:        bufio.NewWriterSize(head, 4096*10),
 		Dir:            dir,
-		ticker:         time.NewTicker(groupCheckDuration),
 		headSizeLimit:  defaultHeadSizeLimit,
 		totalSizeLimit: defaultTotalSizeLimit,
 		minIndex:       0,
@@ -102,6 +101,7 @@ func OpenGroup(headPath string) (g *Group, err error) {
 // OnStart implements Service by starting the goroutine that checks file and
 // group limits.
 func (g *Group) OnStart() error {
+	g.ticker = time.NewTicker(groupCheckDuration)
 	go g.processTicks()
 	return nil
 }
@@ -199,21 +199,15 @@ func (g *Group) Flush() error {
 }
 
 func (g *Group) processTicks() {
-	for {
-		_, ok := <-g.ticker.C
-		if !ok {
-			return // Done.
-		}
+	select {
+	case <-g.ticker.C:
 		g.checkHeadSizeLimit()
 		g.checkTotalSizeLimit()
+	case <-g.Quit():
+		return
 	}
 }
 
-// NOTE: for testing
-func (g *Group) stopTicker() {
-	g.ticker.Stop()
-}
-
 // NOTE: this function is called manually in tests.
 func (g *Group) checkHeadSizeLimit() {
 	limit := g.HeadSizeLimit()
diff --git a/vendor/github.com/tendermint/tendermint/libs/autofile/sighup_watcher.go b/vendor/github.com/tendermint/tendermint/libs/autofile/sighup_watcher.go
index 56fbd4d8693aae702a355049c9c55032fe1af470..f72f12fcdd17768a0dfa1a2c937c3b2a93e2a82a 100644
--- a/vendor/github.com/tendermint/tendermint/libs/autofile/sighup_watcher.go
+++ b/vendor/github.com/tendermint/tendermint/libs/autofile/sighup_watcher.go
@@ -18,13 +18,19 @@ var sighupCounter int32 // For testing
 func initSighupWatcher() {
 	sighupWatchers = newSighupWatcher()
 
-	c := make(chan os.Signal, 1)
-	signal.Notify(c, syscall.SIGHUP)
+	hup := make(chan os.Signal, 1)
+	signal.Notify(hup, syscall.SIGHUP)
+
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
 
 	go func() {
-		for range c {
+		select {
+		case <-hup:
 			sighupWatchers.closeAll()
 			atomic.AddInt32(&sighupCounter, 1)
+		case <-quit:
+			return
 		}
 	}()
 }
diff --git a/vendor/github.com/tendermint/tendermint/libs/common/bit_array.go b/vendor/github.com/tendermint/tendermint/libs/common/bit_array.go
index 0290921a6c178b9d0d174b934b76b70ece394e35..abf6110d80d810dac6ba120a094265ea7ddc9e38 100644
--- a/vendor/github.com/tendermint/tendermint/libs/common/bit_array.go
+++ b/vendor/github.com/tendermint/tendermint/libs/common/bit_array.go
@@ -8,13 +8,15 @@ import (
 	"sync"
 )
 
+// BitArray is a thread-safe implementation of a bit array.
 type BitArray struct {
 	mtx   sync.Mutex
 	Bits  int      `json:"bits"`  // NOTE: persisted via reflect, must be exported
 	Elems []uint64 `json:"elems"` // NOTE: persisted via reflect, must be exported
 }
 
-// There is no BitArray whose Size is 0.  Use nil instead.
+// NewBitArray returns a new bit array.
+// It returns nil if the number of bits is zero.
 func NewBitArray(bits int) *BitArray {
 	if bits <= 0 {
 		return nil
@@ -25,6 +27,7 @@ func NewBitArray(bits int) *BitArray {
 	}
 }
 
+// Size returns the number of bits in the bitarray
 func (bA *BitArray) Size() int {
 	if bA == nil {
 		return 0
@@ -32,7 +35,8 @@ func (bA *BitArray) Size() int {
 	return bA.Bits
 }
 
-// NOTE: behavior is undefined if i >= bA.Bits
+// GetIndex returns the bit at index i within the bit array.
+// The behavior is undefined if i >= bA.Bits
 func (bA *BitArray) GetIndex(i int) bool {
 	if bA == nil {
 		return false
@@ -49,7 +53,8 @@ func (bA *BitArray) getIndex(i int) bool {
 	return bA.Elems[i/64]&(uint64(1)<<uint(i%64)) > 0
 }
 
-// NOTE: behavior is undefined if i >= bA.Bits
+// SetIndex sets the bit at index i within the bit array.
+// The behavior is undefined if i >= bA.Bits
 func (bA *BitArray) SetIndex(i int, v bool) bool {
 	if bA == nil {
 		return false
@@ -71,6 +76,7 @@ func (bA *BitArray) setIndex(i int, v bool) bool {
 	return true
 }
 
+// Copy returns a copy of the provided bit array.
 func (bA *BitArray) Copy() *BitArray {
 	if bA == nil {
 		return nil
@@ -98,7 +104,9 @@ func (bA *BitArray) copyBits(bits int) *BitArray {
 	}
 }
 
-// Returns a BitArray of larger bits size.
+// Or returns a bit array resulting from a bitwise OR of the two bit arrays.
+// If the two bit-arrys have different lengths, Or right-pads the smaller of the two bit-arrays with zeroes.
+// Thus the size of the return value is the maximum of the two provided bit arrays.
 func (bA *BitArray) Or(o *BitArray) *BitArray {
 	if bA == nil && o == nil {
 		return nil
@@ -110,7 +118,11 @@ func (bA *BitArray) Or(o *BitArray) *BitArray {
 		return bA.Copy()
 	}
 	bA.mtx.Lock()
-	defer bA.mtx.Unlock()
+	o.mtx.Lock()
+	defer func() {
+		bA.mtx.Unlock()
+		o.mtx.Unlock()
+	}()
 	c := bA.copyBits(MaxInt(bA.Bits, o.Bits))
 	for i := 0; i < len(c.Elems); i++ {
 		c.Elems[i] |= o.Elems[i]
@@ -118,13 +130,19 @@ func (bA *BitArray) Or(o *BitArray) *BitArray {
 	return c
 }
 
-// Returns a BitArray of smaller bit size.
+// And returns a bit array resulting from a bitwise AND of the two bit arrays.
+// If the two bit-arrys have different lengths, this truncates the larger of the two bit-arrays from the right.
+// Thus the size of the return value is the minimum of the two provided bit arrays.
 func (bA *BitArray) And(o *BitArray) *BitArray {
 	if bA == nil || o == nil {
 		return nil
 	}
 	bA.mtx.Lock()
-	defer bA.mtx.Unlock()
+	o.mtx.Lock()
+	defer func() {
+		bA.mtx.Unlock()
+		o.mtx.Unlock()
+	}()
 	return bA.and(o)
 }
 
@@ -136,12 +154,17 @@ func (bA *BitArray) and(o *BitArray) *BitArray {
 	return c
 }
 
+// Not returns a bit array resulting from a bitwise Not of the provided bit array.
 func (bA *BitArray) Not() *BitArray {
 	if bA == nil {
 		return nil // Degenerate
 	}
 	bA.mtx.Lock()
 	defer bA.mtx.Unlock()
+	return bA.not()
+}
+
+func (bA *BitArray) not() *BitArray {
 	c := bA.copy()
 	for i := 0; i < len(c.Elems); i++ {
 		c.Elems[i] = ^c.Elems[i]
@@ -149,13 +172,20 @@ func (bA *BitArray) Not() *BitArray {
 	return c
 }
 
+// Sub subtracts the two bit-arrays bitwise, without carrying the bits.
+// This is essentially bA.And(o.Not()).
+// If bA is longer than o, o is right padded with zeroes.
 func (bA *BitArray) Sub(o *BitArray) *BitArray {
 	if bA == nil || o == nil {
 		// TODO: Decide if we should do 1's complement here?
 		return nil
 	}
 	bA.mtx.Lock()
-	defer bA.mtx.Unlock()
+	o.mtx.Lock()
+	defer func() {
+		bA.mtx.Unlock()
+		o.mtx.Unlock()
+	}()
 	if bA.Bits > o.Bits {
 		c := bA.copy()
 		for i := 0; i < len(o.Elems)-1; i++ {
@@ -164,15 +194,15 @@ func (bA *BitArray) Sub(o *BitArray) *BitArray {
 		i := len(o.Elems) - 1
 		if i >= 0 {
 			for idx := i * 64; idx < o.Bits; idx++ {
-				// NOTE: each individual GetIndex() call to o is safe.
-				c.setIndex(idx, c.getIndex(idx) && !o.GetIndex(idx))
+				c.setIndex(idx, c.getIndex(idx) && !o.getIndex(idx))
 			}
 		}
 		return c
 	}
-	return bA.and(o.Not()) // Note degenerate case where o == nil
+	return bA.and(o.not()) // Note degenerate case where o == nil
 }
 
+// IsEmpty returns true iff all bits in the bit array are 0
 func (bA *BitArray) IsEmpty() bool {
 	if bA == nil {
 		return true // should this be opposite?
@@ -187,6 +217,7 @@ func (bA *BitArray) IsEmpty() bool {
 	return true
 }
 
+// IsFull returns true iff all bits in the bit array are 1.
 func (bA *BitArray) IsFull() bool {
 	if bA == nil {
 		return true
@@ -207,6 +238,8 @@ func (bA *BitArray) IsFull() bool {
 	return (lastElem+1)&((uint64(1)<<uint(lastElemBits))-1) == 0
 }
 
+// PickRandom returns a random index in the bit array, and its value.
+// It uses the global randomness in `random.go` to get this index.
 func (bA *BitArray) PickRandom() (int, bool) {
 	if bA == nil {
 		return 0, false
@@ -260,6 +293,8 @@ func (bA *BitArray) String() string {
 	return bA.StringIndented("")
 }
 
+// StringIndented returns the same thing as String(), but applies the indent
+// at every 10th bit, and twice at every 50th bit.
 func (bA *BitArray) StringIndented(indent string) string {
 	if bA == nil {
 		return "nil-BitArray"
@@ -295,6 +330,7 @@ func (bA *BitArray) stringIndented(indent string) string {
 	return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent))
 }
 
+// Bytes returns the byte representation of the bits within the bitarray.
 func (bA *BitArray) Bytes() []byte {
 	bA.mtx.Lock()
 	defer bA.mtx.Unlock()
@@ -309,15 +345,18 @@ func (bA *BitArray) Bytes() []byte {
 	return bytes
 }
 
-// NOTE: other bitarray o is not locked when reading,
-// so if necessary, caller must copy or lock o prior to calling Update.
-// If bA is nil, does nothing.
+// Update sets the bA's bits to be that of the other bit array.
+// The copying begins from the begin of both bit arrays.
 func (bA *BitArray) Update(o *BitArray) {
 	if bA == nil || o == nil {
 		return
 	}
 	bA.mtx.Lock()
-	defer bA.mtx.Unlock()
+	o.mtx.Lock()
+	defer func() {
+		bA.mtx.Unlock()
+		o.mtx.Unlock()
+	}()
 
 	copy(bA.Elems, o.Elems)
 }
diff --git a/vendor/github.com/tendermint/tendermint/libs/common/os.go b/vendor/github.com/tendermint/tendermint/libs/common/os.go
index 00f4da57b0dd81e759520af9179a4d7b7d89f552..b8419764e9f82eef958fc99d903afeea8ecd68a9 100644
--- a/vendor/github.com/tendermint/tendermint/libs/common/os.go
+++ b/vendor/github.com/tendermint/tendermint/libs/common/os.go
@@ -8,7 +8,6 @@ import (
 	"os"
 	"os/exec"
 	"os/signal"
-	"path/filepath"
 	"strings"
 	"syscall"
 )
@@ -124,60 +123,6 @@ func MustWriteFile(filePath string, contents []byte, mode os.FileMode) {
 	}
 }
 
-// WriteFileAtomic creates a temporary file with data and the perm given and
-// swaps it atomically with filename if successful.
-func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error {
-	var (
-		dir      = filepath.Dir(filename)
-		tempFile = filepath.Join(dir, "write-file-atomic-"+RandStr(32))
-		// Override in case it does exist, create in case it doesn't and force kernel
-		// flush, which still leaves the potential of lingering disk cache.
-		flag = os.O_WRONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC
-	)
-
-	f, err := os.OpenFile(tempFile, flag, perm)
-	if err != nil {
-		return err
-	}
-	// Clean up in any case. Defer stacking order is last-in-first-out.
-	defer os.Remove(f.Name())
-	defer f.Close()
-
-	if n, err := f.Write(data); err != nil {
-		return err
-	} else if n < len(data) {
-		return io.ErrShortWrite
-	}
-	// Close the file before renaming it, otherwise it will cause "The process 
-	// cannot access the file because it is being used by another process." on windows.
-	f.Close()
-
-	return os.Rename(f.Name(), filename)
-}
-
-//--------------------------------------------------------------------------------
-
-func Tempfile(prefix string) (*os.File, string) {
-	file, err := ioutil.TempFile("", prefix)
-	if err != nil {
-		PanicCrisis(err)
-	}
-	return file, file.Name()
-}
-
-func Tempdir(prefix string) (*os.File, string) {
-	tempDir := os.TempDir() + "/" + prefix + RandStr(12)
-	err := EnsureDir(tempDir, 0700)
-	if err != nil {
-		panic(Fmt("Error creating temp dir: %v", err))
-	}
-	dir, err := os.Open(tempDir)
-	if err != nil {
-		panic(Fmt("Error opening temp dir: %v", err))
-	}
-	return dir, tempDir
-}
-
 //--------------------------------------------------------------------------------
 
 func Prompt(prompt string, defaultValue string) (string, error) {
diff --git a/vendor/github.com/tendermint/tendermint/libs/common/random.go b/vendor/github.com/tendermint/tendermint/libs/common/random.go
index 51bfd15c48cda7b635c99c0fef77949daf1ace39..4b0594d0e58daf5a9d9edb4e859c4d5911596cd6 100644
--- a/vendor/github.com/tendermint/tendermint/libs/common/random.go
+++ b/vendor/github.com/tendermint/tendermint/libs/common/random.go
@@ -109,6 +109,10 @@ func RandInt63n(n int64) int64 {
 	return grand.Int63n(n)
 }
 
+func RandBool() bool {
+	return grand.Bool()
+}
+
 func RandFloat32() float32 {
 	return grand.Float32()
 }
@@ -274,6 +278,13 @@ func (r *Rand) Intn(n int) int {
 	return i
 }
 
+// Bool returns a uniformly random boolean
+func (r *Rand) Bool() bool {
+	// See https://github.com/golang/go/issues/23804#issuecomment-365370418
+	// for reasoning behind computing like this
+	return r.Int63()%2 == 0
+}
+
 // Perm returns a pseudo-random permutation of n integers in [0, n).
 func (r *Rand) Perm(n int) []int {
 	r.Lock()
diff --git a/vendor/github.com/tendermint/tendermint/libs/common/tempfile.go b/vendor/github.com/tendermint/tendermint/libs/common/tempfile.go
new file mode 100644
index 0000000000000000000000000000000000000000..a5bb7a5b56cae478bb45ccfafd212afcb3f8f7f0
--- /dev/null
+++ b/vendor/github.com/tendermint/tendermint/libs/common/tempfile.go
@@ -0,0 +1,128 @@
+package common
+
+import (
+	fmt "fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	atomicWriteFilePrefix = "write-file-atomic-"
+	// Maximum number of atomic write file conflicts before we start reseeding
+	// (reduced from golang's default 10 due to using an increased randomness space)
+	atomicWriteFileMaxNumConflicts = 5
+	// Maximum number of attempts to make at writing the write file before giving up
+	// (reduced from golang's default 10000 due to using an increased randomness space)
+	atomicWriteFileMaxNumWriteAttempts = 1000
+	// LCG constants from Donald Knuth MMIX
+	// This LCG's has a period equal to 2**64
+	lcgA = 6364136223846793005
+	lcgC = 1442695040888963407
+	// Create in case it doesn't exist and force kernel
+	// flush, which still leaves the potential of lingering disk cache.
+	// Never overwrites files
+	atomicWriteFileFlag = os.O_WRONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC | os.O_EXCL
+)
+
+var (
+	atomicWriteFileRand   uint64
+	atomicWriteFileRandMu sync.Mutex
+)
+
+func writeFileRandReseed() uint64 {
+	// Scale the PID, to minimize the chance that two processes seeded at similar times
+	// don't get the same seed. Note that PID typically ranges in [0, 2**15), but can be
+	// up to 2**22 under certain configurations. We left bit-shift the PID by 20, so that
+	// a PID difference of one corresponds to a time difference of 2048 seconds.
+	// The important thing here is that now for a seed conflict, they would both have to be on
+	// the correct nanosecond offset, and second-based offset, which is much less likely than
+	// just a conflict with the correct nanosecond offset.
+	return uint64(time.Now().UnixNano() + int64(os.Getpid()<<20))
+}
+
+// Use a fast thread safe LCG for atomic write file names.
+// Returns a string corresponding to a 64 bit int.
+// If it was a negative int, the leading number is a 0.
+func randWriteFileSuffix() string {
+	atomicWriteFileRandMu.Lock()
+	r := atomicWriteFileRand
+	if r == 0 {
+		r = writeFileRandReseed()
+	}
+
+	// Update randomness according to lcg
+	r = r*lcgA + lcgC
+
+	atomicWriteFileRand = r
+	atomicWriteFileRandMu.Unlock()
+	// Can have a negative name, replace this in the following
+	suffix := strconv.Itoa(int(r))
+	if string(suffix[0]) == "-" {
+		// Replace first "-" with "0". This is purely for UI clarity,
+		// as otherwhise there would be two `-` in a row.
+		suffix = strings.Replace(suffix, "-", "0", 1)
+	}
+	return suffix
+}
+
+// WriteFileAtomic creates a temporary file with data and provided perm and
+// swaps it atomically with filename if successful.
+func WriteFileAtomic(filename string, data []byte, perm os.FileMode) (err error) {
+	// This implementation is inspired by the golang stdlibs method of creating
+	// tempfiles. Notable differences are that we use different flags, a 64 bit LCG
+	// and handle negatives differently.
+	// The core reason we can't use golang's TempFile is that we must write
+	// to the file synchronously, as we need this to persist to disk.
+	// We also open it in write-only mode, to avoid concerns that arise with read.
+	var (
+		dir = filepath.Dir(filename)
+		f   *os.File
+	)
+
+	nconflict := 0
+	// Limit the number of attempts to create a file. Something is seriously
+	// wrong if it didn't get created after 1000 attempts, and we don't want
+	// an infinite loop
+	i := 0
+	for ; i < atomicWriteFileMaxNumWriteAttempts; i++ {
+		name := filepath.Join(dir, atomicWriteFilePrefix+randWriteFileSuffix())
+		f, err = os.OpenFile(name, atomicWriteFileFlag, perm)
+		// If the file already exists, try a new file
+		if os.IsExist(err) {
+			// If the files exists too many times, start reseeding as we've
+			// likely hit another instances seed.
+			if nconflict++; nconflict > atomicWriteFileMaxNumConflicts {
+				atomicWriteFileRandMu.Lock()
+				atomicWriteFileRand = writeFileRandReseed()
+				atomicWriteFileRandMu.Unlock()
+			}
+			continue
+		} else if err != nil {
+			return err
+		}
+		break
+	}
+	if i == atomicWriteFileMaxNumWriteAttempts {
+		return fmt.Errorf("Could not create atomic write file after %d attempts", i)
+	}
+
+	// Clean up in any case. Defer stacking order is last-in-first-out.
+	defer os.Remove(f.Name())
+	defer f.Close()
+
+	if n, err := f.Write(data); err != nil {
+		return err
+	} else if n < len(data) {
+		return io.ErrShortWrite
+	}
+	// Close the file before renaming it, otherwise it will cause "The process
+	// cannot access the file because it is being used by another process." on windows.
+	f.Close()
+
+	return os.Rename(f.Name(), filename)
+}
diff --git a/vendor/github.com/tendermint/tendermint/node/id.go b/vendor/github.com/tendermint/tendermint/node/id.go
index 5100597c6233ffe30aead79f6a37548992d60efe..d8e41eca7028039fcbf408aa4c6f82e97c5b6d2e 100644
--- a/vendor/github.com/tendermint/tendermint/node/id.go
+++ b/vendor/github.com/tendermint/tendermint/node/id.go
@@ -26,7 +26,7 @@ type NodeGreeting struct {
 
 type SignedNodeGreeting struct {
 	NodeGreeting
-	Signature crypto.Signature
+	Signature []byte
 }
 
 func (pnid *PrivNodeID) SignGreeting() *SignedNodeGreeting {
diff --git a/vendor/github.com/tendermint/tendermint/node/node.go b/vendor/github.com/tendermint/tendermint/node/node.go
index e333c667a8991c39da89680431c8d8f33417053c..0c3396dc6860e7d2f63da394d63f8c6b6bc94fad 100644
--- a/vendor/github.com/tendermint/tendermint/node/node.go
+++ b/vendor/github.com/tendermint/tendermint/node/node.go
@@ -85,7 +85,7 @@ func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
 		proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
 		DefaultGenesisDocProviderFunc(config),
 		DefaultDBProvider,
-		DefaultMetricsProvider,
+		DefaultMetricsProvider(config.Instrumentation),
 		logger,
 	)
 }
@@ -93,15 +93,15 @@ func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
 // MetricsProvider returns a consensus, p2p and mempool Metrics.
 type MetricsProvider func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics)
 
-// DefaultMetricsProvider returns consensus, p2p and mempool Metrics build
-// using Prometheus client library.
-func DefaultMetricsProvider() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics) {
-	return cs.PrometheusMetrics(), p2p.PrometheusMetrics(), mempl.PrometheusMetrics()
-}
-
-// NopMetricsProvider returns consensus, p2p and mempool Metrics as no-op.
-func NopMetricsProvider() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics) {
-	return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics()
+// DefaultMetricsProvider returns Metrics build using Prometheus client library
+// if Prometheus is enabled. Otherwise, it returns no-op Metrics.
+func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider {
+	return func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics) {
+		if config.Prometheus {
+			return cs.PrometheusMetrics(), p2p.PrometheusMetrics(), mempl.PrometheusMetrics()
+		}
+		return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics()
+	}
 }
 
 //------------------------------------------------------------------------------
@@ -229,17 +229,7 @@ func NewNode(config *cfg.Config,
 		consensusLogger.Info("This node is not a validator", "addr", privValidator.GetAddress(), "pubKey", privValidator.GetPubKey())
 	}
 
-	// metrics
-	var (
-		csMetrics    *cs.Metrics
-		p2pMetrics   *p2p.Metrics
-		memplMetrics *mempl.Metrics
-	)
-	if config.Instrumentation.Prometheus {
-		csMetrics, p2pMetrics, memplMetrics = metricsProvider()
-	} else {
-		csMetrics, p2pMetrics, memplMetrics = NopMetricsProvider()
-	}
+	csMetrics, p2pMetrics, memplMetrics := metricsProvider()
 
 	// Make MempoolReactor
 	mempoolLogger := logger.With("module", "mempool")
@@ -462,7 +452,8 @@ func (n *Node) OnStart() error {
 		n.rpcListeners = listeners
 	}
 
-	if n.config.Instrumentation.Prometheus {
+	if n.config.Instrumentation.Prometheus &&
+		n.config.Instrumentation.PrometheusListenAddr != "" {
 		n.prometheusSrv = n.startPrometheusServer(n.config.Instrumentation.PrometheusListenAddr)
 	}
 
diff --git a/vendor/github.com/tendermint/tendermint/p2p/conn/secret_connection.go b/vendor/github.com/tendermint/tendermint/p2p/conn/secret_connection.go
index a2cbe008d6bb1626cc1a43b588246750c055c436..75199ee6ba3273dd9add491338ea1996f09527f2 100644
--- a/vendor/github.com/tendermint/tendermint/p2p/conn/secret_connection.go
+++ b/vendor/github.com/tendermint/tendermint/p2p/conn/secret_connection.go
@@ -1,9 +1,3 @@
-// Uses nacl's secret_box to encrypt a net.Conn.
-// It is (meant to be) an implementation of the STS protocol.
-// Note we do not (yet) assume that a remote peer's pubkey
-// is known ahead of time, and thus we are technically
-// still vulnerable to MITM. (TODO!)
-// See docs/sts-final.pdf for more info
 package conn
 
 import (
@@ -16,36 +10,45 @@ import (
 	"net"
 	"time"
 
+	"golang.org/x/crypto/chacha20poly1305"
+	"golang.org/x/crypto/curve25519"
 	"golang.org/x/crypto/nacl/box"
-	"golang.org/x/crypto/nacl/secretbox"
-	"golang.org/x/crypto/ripemd160"
 
 	"github.com/tendermint/tendermint/crypto"
 	cmn "github.com/tendermint/tendermint/libs/common"
+	"golang.org/x/crypto/hkdf"
 )
 
 // 4 + 1024 == 1028 total frame size
 const dataLenSize = 4
 const dataMaxSize = 1024
 const totalFrameSize = dataMaxSize + dataLenSize
-const sealedFrameSize = totalFrameSize + secretbox.Overhead
+const aeadSizeOverhead = 16 // overhead of poly 1305 authentication tag
+const aeadKeySize = chacha20poly1305.KeySize
+const aeadNonceSize = chacha20poly1305.NonceSize
 
-// Implements net.Conn
+// SecretConnection implements net.conn.
+// It is an implementation of the STS protocol.
+// Note we do not (yet) assume that a remote peer's pubkey
+// is known ahead of time, and thus we are technically
+// still vulnerable to MITM. (TODO!)
+// See docs/sts-final.pdf for more info
 type SecretConnection struct {
 	conn       io.ReadWriteCloser
 	recvBuffer []byte
-	recvNonce  *[24]byte
-	sendNonce  *[24]byte
+	recvNonce  *[aeadNonceSize]byte
+	sendNonce  *[aeadNonceSize]byte
+	recvSecret *[aeadKeySize]byte
+	sendSecret *[aeadKeySize]byte
 	remPubKey  crypto.PubKey
-	shrSecret  *[32]byte // shared secret
 }
 
-// Performs handshake and returns a new authenticated SecretConnection.
-// Returns nil if error in handshake.
+// MakeSecretConnection performs handshake and returns a new authenticated
+// SecretConnection.
+// Returns nil if there is an error in handshake.
 // Caller should call conn.Close()
 // See docs/sts-final.pdf for more information.
 func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*SecretConnection, error) {
-
 	locPubKey := locPrivKey.PubKey()
 
 	// Generate ephemeral keys for perfect forward secrecy.
@@ -59,29 +62,27 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
 		return nil, err
 	}
 
-	// Compute common shared secret.
-	shrSecret := computeSharedSecret(remEphPub, locEphPriv)
-
 	// Sort by lexical order.
-	loEphPub, hiEphPub := sort32(locEphPub, remEphPub)
+	loEphPub, _ := sort32(locEphPub, remEphPub)
 
 	// Check if the local ephemeral public key
 	// was the least, lexicographically sorted.
 	locIsLeast := bytes.Equal(locEphPub[:], loEphPub[:])
 
-	// Generate nonces to use for secretbox.
-	recvNonce, sendNonce := genNonces(loEphPub, hiEphPub, locIsLeast)
+	// Compute common diffie hellman secret using X25519.
+	dhSecret := computeDHSecret(remEphPub, locEphPriv)
 
-	// Generate common challenge to sign.
-	challenge := genChallenge(loEphPub, hiEphPub)
+	// generate the secret used for receiving, sending, challenge via hkdf-sha2 on dhSecret
+	recvSecret, sendSecret, challenge := deriveSecretAndChallenge(dhSecret, locIsLeast)
 
 	// Construct SecretConnection.
 	sc := &SecretConnection{
 		conn:       conn,
 		recvBuffer: nil,
-		recvNonce:  recvNonce,
-		sendNonce:  sendNonce,
-		shrSecret:  shrSecret,
+		recvNonce:  new([aeadNonceSize]byte),
+		sendNonce:  new([aeadNonceSize]byte),
+		recvSecret: recvSecret,
+		sendSecret: sendSecret,
 	}
 
 	// Sign the challenge bytes for authentication.
@@ -92,6 +93,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
 	if err != nil {
 		return nil, err
 	}
+
 	remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig
 	if !remPubKey.VerifyBytes(challenge[:], remSignature) {
 		return nil, errors.New("Challenge verification failed")
@@ -102,7 +104,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
 	return sc, nil
 }
 
-// Returns authenticated remote pubkey
+// RemotePubKey returns authenticated remote pubkey
 func (sc *SecretConnection) RemotePubKey() crypto.PubKey {
 	return sc.remPubKey
 }
@@ -124,14 +126,17 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) {
 		binary.BigEndian.PutUint32(frame, uint32(chunkLength))
 		copy(frame[dataLenSize:], chunk)
 
+		aead, err := chacha20poly1305.New(sc.sendSecret[:])
+		if err != nil {
+			return n, errors.New("Invalid SecretConnection Key")
+		}
 		// encrypt the frame
-		var sealedFrame = make([]byte, sealedFrameSize)
-		secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
-		// fmt.Printf("secretbox.Seal(sealed:%X,sendNonce:%X,shrSecret:%X\n", sealedFrame, sc.sendNonce, sc.shrSecret)
-		incr2Nonce(sc.sendNonce)
+		var sealedFrame = make([]byte, aeadSizeOverhead+totalFrameSize)
+		aead.Seal(sealedFrame[:0], sc.sendNonce[:], frame, nil)
+		incrNonce(sc.sendNonce)
 		// end encryption
 
-		_, err := sc.conn.Write(sealedFrame)
+		_, err = sc.conn.Write(sealedFrame)
 		if err != nil {
 			return n, err
 		}
@@ -148,7 +153,11 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
 		return
 	}
 
-	sealedFrame := make([]byte, sealedFrameSize)
+	aead, err := chacha20poly1305.New(sc.recvSecret[:])
+	if err != nil {
+		return n, errors.New("Invalid SecretConnection Key")
+	}
+	sealedFrame := make([]byte, totalFrameSize+aeadSizeOverhead)
 	_, err = io.ReadFull(sc.conn, sealedFrame)
 	if err != nil {
 		return
@@ -156,12 +165,11 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
 
 	// decrypt the frame
 	var frame = make([]byte, totalFrameSize)
-	// fmt.Printf("secretbox.Open(sealed:%X,recvNonce:%X,shrSecret:%X\n", sealedFrame, sc.recvNonce, sc.shrSecret)
-	_, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret)
-	if !ok {
+	_, err = aead.Open(frame[:0], sc.recvNonce[:], sealedFrame, nil)
+	if err != nil {
 		return n, errors.New("Failed to decrypt SecretConnection")
 	}
-	incr2Nonce(sc.recvNonce)
+	incrNonce(sc.recvNonce)
 	// end decryption
 
 	var chunkLength = binary.BigEndian.Uint32(frame) // read the first two bytes
@@ -176,6 +184,7 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
 }
 
 // Implements net.Conn
+// nolint
 func (sc *SecretConnection) Close() error                  { return sc.conn.Close() }
 func (sc *SecretConnection) LocalAddr() net.Addr           { return sc.conn.(net.Conn).LocalAddr() }
 func (sc *SecretConnection) RemoteAddr() net.Addr          { return sc.conn.(net.Conn).RemoteAddr() }
@@ -204,18 +213,16 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
 			var _, err1 = cdc.MarshalBinaryWriter(conn, locEphPub)
 			if err1 != nil {
 				return nil, err1, true // abort
-			} else {
-				return nil, nil, false
 			}
+			return nil, nil, false
 		},
 		func(_ int) (val interface{}, err error, abort bool) {
 			var _remEphPub [32]byte
 			var _, err2 = cdc.UnmarshalBinaryReader(conn, &_remEphPub, 1024*1024) // TODO
 			if err2 != nil {
 				return nil, err2, true // abort
-			} else {
-				return _remEphPub, nil, false
 			}
+			return _remEphPub, nil, false
 		},
 	)
 
@@ -230,9 +237,40 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
 	return &_remEphPub, nil
 }
 
-func computeSharedSecret(remPubKey, locPrivKey *[32]byte) (shrSecret *[32]byte) {
-	shrSecret = new([32]byte)
-	box.Precompute(shrSecret, remPubKey, locPrivKey)
+func deriveSecretAndChallenge(dhSecret *[32]byte, locIsLeast bool) (recvSecret, sendSecret *[aeadKeySize]byte, challenge *[32]byte) {
+	hash := sha256.New
+	hkdf := hkdf.New(hash, dhSecret[:], nil, []byte("TENDERMINT_SECRET_CONNECTION_KEY_AND_CHALLENGE_GEN"))
+	// get enough data for 2 aead keys, and a 32 byte challenge
+	res := new([2*aeadKeySize + 32]byte)
+	_, err := io.ReadFull(hkdf, res[:])
+	if err != nil {
+		panic(err)
+	}
+
+	challenge = new([32]byte)
+	recvSecret = new([aeadKeySize]byte)
+	sendSecret = new([aeadKeySize]byte)
+	// Use the last 32 bytes as the challenge
+	copy(challenge[:], res[2*aeadKeySize:2*aeadKeySize+32])
+
+	// bytes 0 through aeadKeySize - 1 are one aead key.
+	// bytes aeadKeySize through 2*aeadKeySize -1 are another aead key.
+	// which key corresponds to sending and receiving key depends on whether
+	// the local key is less than the remote key.
+	if locIsLeast {
+		copy(recvSecret[:], res[0:aeadKeySize])
+		copy(sendSecret[:], res[aeadKeySize:aeadKeySize*2])
+	} else {
+		copy(sendSecret[:], res[0:aeadKeySize])
+		copy(recvSecret[:], res[aeadKeySize:aeadKeySize*2])
+	}
+
+	return
+}
+
+func computeDHSecret(remPubKey, locPrivKey *[32]byte) (shrKey *[32]byte) {
+	shrKey = new([32]byte)
+	curve25519.ScalarMult(shrKey, locPrivKey, remPubKey)
 	return
 }
 
@@ -247,26 +285,7 @@ func sort32(foo, bar *[32]byte) (lo, hi *[32]byte) {
 	return
 }
 
-func genNonces(loPubKey, hiPubKey *[32]byte, locIsLo bool) (recvNonce, sendNonce *[24]byte) {
-	nonce1 := hash24(append(loPubKey[:], hiPubKey[:]...))
-	nonce2 := new([24]byte)
-	copy(nonce2[:], nonce1[:])
-	nonce2[len(nonce2)-1] ^= 0x01
-	if locIsLo {
-		recvNonce = nonce1
-		sendNonce = nonce2
-	} else {
-		recvNonce = nonce2
-		sendNonce = nonce1
-	}
-	return
-}
-
-func genChallenge(loPubKey, hiPubKey *[32]byte) (challenge *[32]byte) {
-	return hash32(append(loPubKey[:], hiPubKey[:]...))
-}
-
-func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature crypto.Signature) {
+func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature []byte) {
 	signature, err := locPrivKey.Sign(challenge[:])
 	// TODO(ismail): let signChallenge return an error instead
 	if err != nil {
@@ -277,10 +296,10 @@ func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature cr
 
 type authSigMessage struct {
 	Key crypto.PubKey
-	Sig crypto.Signature
+	Sig []byte
 }
 
-func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature crypto.Signature) (recvMsg authSigMessage, err error) {
+func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature []byte) (recvMsg authSigMessage, err error) {
 
 	// Send our info and receive theirs in tandem.
 	var trs, _ = cmn.Parallel(
@@ -288,18 +307,16 @@ func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature cr
 			var _, err1 = cdc.MarshalBinaryWriter(sc, authSigMessage{pubKey, signature})
 			if err1 != nil {
 				return nil, err1, true // abort
-			} else {
-				return nil, nil, false
 			}
+			return nil, nil, false
 		},
 		func(_ int) (val interface{}, err error, abort bool) {
 			var _recvMsg authSigMessage
 			var _, err2 = cdc.UnmarshalBinaryReader(sc, &_recvMsg, 1024*1024) // TODO
 			if err2 != nil {
 				return nil, err2, true // abort
-			} else {
-				return _recvMsg, nil, false
 			}
+			return _recvMsg, nil, false
 		},
 	)
 
@@ -315,36 +332,11 @@ func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature cr
 
 //--------------------------------------------------------------------------------
 
-// sha256
-func hash32(input []byte) (res *[32]byte) {
-	hasher := sha256.New()
-	hasher.Write(input) // nolint: errcheck, gas
-	resSlice := hasher.Sum(nil)
-	res = new([32]byte)
-	copy(res[:], resSlice)
-	return
-}
-
-// We only fill in the first 20 bytes with ripemd160
-func hash24(input []byte) (res *[24]byte) {
-	hasher := ripemd160.New()
-	hasher.Write(input) // nolint: errcheck, gas
-	resSlice := hasher.Sum(nil)
-	res = new([24]byte)
-	copy(res[:], resSlice)
-	return
-}
-
-// increment nonce big-endian by 2 with wraparound.
-func incr2Nonce(nonce *[24]byte) {
-	incrNonce(nonce)
-	incrNonce(nonce)
-}
-
 // increment nonce big-endian by 1 with wraparound.
-func incrNonce(nonce *[24]byte) {
-	for i := 23; 0 <= i; i-- {
+func incrNonce(nonce *[aeadNonceSize]byte) {
+	for i := aeadNonceSize - 1; 0 <= i; i-- {
 		nonce[i]++
+		// if this byte wrapped around to zero, we need to increment the next byte
 		if nonce[i] != 0 {
 			return
 		}
diff --git a/vendor/github.com/tendermint/tendermint/p2p/pex/addrbook.go b/vendor/github.com/tendermint/tendermint/p2p/pex/addrbook.go
index c630d14c370c0d467240b99f159f9a12390e8902..ad6e0c00be2d2603ecd8bb20e2321a719968717e 100644
--- a/vendor/github.com/tendermint/tendermint/p2p/pex/addrbook.go
+++ b/vendor/github.com/tendermint/tendermint/p2p/pex/addrbook.go
@@ -45,6 +45,9 @@ type AddrBook interface {
 
 	// Do we need more peers?
 	NeedMoreAddrs() bool
+	// Is Address Book Empty? Answer should not depend on being in your own
+	// address book, or private peers
+	Empty() bool
 
 	// Pick an address to dial
 	PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress
@@ -223,6 +226,12 @@ func (a *addrBook) NeedMoreAddrs() bool {
 	return a.Size() < needAddressThreshold
 }
 
+// Empty implements AddrBook - returns true if there are no addresses in the address book.
+// Does not count the peer appearing in its own address book, or private peers.
+func (a *addrBook) Empty() bool {
+	return a.Size() == 0
+}
+
 // PickAddress implements AddrBook. It picks an address to connect to.
 // The address is picked randomly from an old or new bucket according
 // to the biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to that range)
@@ -496,7 +505,6 @@ out:
 	}
 	saveFileTicker.Stop()
 	a.saveToFile(a.filePath)
-	a.Logger.Info("Address handler done")
 }
 
 //----------------------------------------------------------
@@ -638,6 +646,7 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
 	if a.routabilityStrict && !addr.Routable() {
 		return ErrAddrBookNonRoutable{addr}
 	}
+
 	// TODO: we should track ourAddrs by ID and by IP:PORT and refuse both.
 	if _, ok := a.ourAddrs[addr.String()]; ok {
 		return ErrAddrBookSelf{addr}
@@ -647,6 +656,10 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
 		return ErrAddrBookPrivate{addr}
 	}
 
+	if _, ok := a.privateIDs[src.ID]; ok {
+		return ErrAddrBookPrivateSrc{src}
+	}
+
 	ka := a.addrLookup[addr.ID]
 	if ka != nil {
 		// If its already old and the addr is the same, ignore it.
diff --git a/vendor/github.com/tendermint/tendermint/p2p/pex/errors.go b/vendor/github.com/tendermint/tendermint/p2p/pex/errors.go
index 34bfb5ab165746bdb1137b76641d67ea9edfcc03..7f660bdc5a7d860b3be6a2e74d3716be81579166 100644
--- a/vendor/github.com/tendermint/tendermint/p2p/pex/errors.go
+++ b/vendor/github.com/tendermint/tendermint/p2p/pex/errors.go
@@ -30,6 +30,14 @@ func (err ErrAddrBookPrivate) Error() string {
 	return fmt.Sprintf("Cannot add private peer with address %v", err.Addr)
 }
 
+type ErrAddrBookPrivateSrc struct {
+	Src *p2p.NetAddress
+}
+
+func (err ErrAddrBookPrivateSrc) Error() string {
+	return fmt.Sprintf("Cannot add peer coming from private peer with address %v", err.Src)
+}
+
 type ErrAddrBookNilAddr struct {
 	Addr *p2p.NetAddress
 	Src  *p2p.NetAddress
diff --git a/vendor/github.com/tendermint/tendermint/p2p/pex/pex_reactor.go b/vendor/github.com/tendermint/tendermint/p2p/pex/pex_reactor.go
index 5c4894ce481f2aff852f532996bd1a5398ee6f27..288cb0d150e0fd5bde094130e4a7b27ddb1fb3c8 100644
--- a/vendor/github.com/tendermint/tendermint/p2p/pex/pex_reactor.go
+++ b/vendor/github.com/tendermint/tendermint/p2p/pex/pex_reactor.go
@@ -7,9 +7,10 @@ import (
 	"sync"
 	"time"
 
+	"github.com/pkg/errors"
+
 	amino "github.com/tendermint/go-amino"
 	cmn "github.com/tendermint/tendermint/libs/common"
-
 	"github.com/tendermint/tendermint/p2p"
 	"github.com/tendermint/tendermint/p2p/conn"
 )
@@ -74,6 +75,8 @@ type PEXReactor struct {
 	requestsSent         *cmn.CMap // ID->struct{}: unanswered send requests
 	lastReceivedRequests *cmn.CMap // ID->time.Time: last time peer requested from us
 
+	seedAddrs []*p2p.NetAddress
+
 	attemptsToDial sync.Map // address (string) -> {number of attempts (int), last time dialed (time.Time)}
 }
 
@@ -113,20 +116,20 @@ func NewPEXReactor(b AddrBook, config *PEXReactorConfig) *PEXReactor {
 
 // OnStart implements BaseService
 func (r *PEXReactor) OnStart() error {
-	if err := r.BaseReactor.OnStart(); err != nil {
-		return err
-	}
 	err := r.book.Start()
 	if err != nil && err != cmn.ErrAlreadyStarted {
 		return err
 	}
 
-	// return err if user provided a bad seed address
-	// or a host name that we cant resolve
-	if err := r.checkSeeds(); err != nil {
+	numOnline, seedAddrs, err := r.checkSeeds()
+	if err != nil {
 		return err
+	} else if numOnline == 0 && r.book.Empty() {
+		return errors.New("Address book is empty, and could not connect to any seed nodes")
 	}
 
+	r.seedAddrs = seedAddrs
+
 	// Check if this node should run
 	// in seed/crawler mode
 	if r.config.SeedMode {
@@ -139,7 +142,6 @@ func (r *PEXReactor) OnStart() error {
 
 // OnStop implements BaseService
 func (r *PEXReactor) OnStop() {
-	r.BaseReactor.OnStop()
 	r.book.Stop()
 }
 
@@ -285,7 +287,6 @@ func (r *PEXReactor) RequestAddrs(p Peer) {
 // request for this peer and deletes the open request.
 // If there's no open request for the src peer, it returns an error.
 func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
-
 	id := string(src.ID())
 	if !r.requestsSent.Has(id) {
 		return cmn.NewError("Received unsolicited pexAddrsMessage")
@@ -301,6 +302,13 @@ func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
 
 		err := r.book.AddAddress(netAddr, srcAddr)
 		r.logErrAddrBook(err)
+
+		// If this address came from a seed node, try to connect to it without waiting.
+		for _, seedAddr := range r.seedAddrs {
+			if seedAddr.Equals(srcAddr) {
+				r.ensurePeers()
+			}
+		}
 	}
 	return nil
 }
@@ -471,34 +479,36 @@ func (r *PEXReactor) dialPeer(addr *p2p.NetAddress) {
 	}
 }
 
-// check seed addresses are well formed
-func (r *PEXReactor) checkSeeds() error {
+// checkSeeds checks that addresses are well formed.
+// Returns number of seeds we can connect to, along with all seeds addrs.
+// return err if user provided any badly formatted seed addresses.
+// Doesn't error if the seed node can't be reached.
+// numOnline returns -1 if no seed nodes were in the initial configuration.
+func (r *PEXReactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, err error) {
 	lSeeds := len(r.config.Seeds)
 	if lSeeds == 0 {
-		return nil
+		return -1, nil, nil
 	}
-	_, errs := p2p.NewNetAddressStrings(r.config.Seeds)
+	netAddrs, errs := p2p.NewNetAddressStrings(r.config.Seeds)
+	numOnline = lSeeds - len(errs)
 	for _, err := range errs {
-		if err != nil {
-			return err
+		switch e := err.(type) {
+		case p2p.ErrNetAddressLookup:
+			r.Logger.Error("Connecting to seed failed", "err", e)
+		default:
+			return 0, nil, errors.Wrap(e, "seed node configuration has error")
 		}
 	}
-	return nil
+	return
 }
 
 // randomly dial seeds until we connect to one or exhaust them
 func (r *PEXReactor) dialSeeds() {
-	lSeeds := len(r.config.Seeds)
-	if lSeeds == 0 {
-		return
-	}
-	seedAddrs, _ := p2p.NewNetAddressStrings(r.config.Seeds)
-
-	perm := cmn.RandPerm(lSeeds)
+	perm := cmn.RandPerm(len(r.seedAddrs))
 	// perm := r.Switch.rng.Perm(lSeeds)
 	for _, i := range perm {
 		// dial a random seed
-		seedAddr := seedAddrs[i]
+		seedAddr := r.seedAddrs[i]
 		err := r.Switch.DialPeerWithAddress(seedAddr, false)
 		if err == nil {
 			return
diff --git a/vendor/github.com/tendermint/tendermint/privval/priv_validator.go b/vendor/github.com/tendermint/tendermint/privval/priv_validator.go
index 5b056d8a0b5b3d8b7dce82e7b2099c3465f5387c..a81751a9147f9d79faf0d2f50289e954c951e2cf 100644
--- a/vendor/github.com/tendermint/tendermint/privval/priv_validator.go
+++ b/vendor/github.com/tendermint/tendermint/privval/priv_validator.go
@@ -38,14 +38,14 @@ func voteToStep(vote *types.Vote) int8 {
 // to prevent double signing.
 // NOTE: the directory containing the pv.filePath must already exist.
 type FilePV struct {
-	Address       types.Address    `json:"address"`
-	PubKey        crypto.PubKey    `json:"pub_key"`
-	LastHeight    int64            `json:"last_height"`
-	LastRound     int              `json:"last_round"`
-	LastStep      int8             `json:"last_step"`
-	LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures XXX Why would we lose signatures?
-	LastSignBytes cmn.HexBytes     `json:"last_signbytes,omitempty"` // so we dont lose signatures XXX Why would we lose signatures?
-	PrivKey       crypto.PrivKey   `json:"priv_key"`
+	Address       types.Address  `json:"address"`
+	PubKey        crypto.PubKey  `json:"pub_key"`
+	LastHeight    int64          `json:"last_height"`
+	LastRound     int            `json:"last_round"`
+	LastStep      int8           `json:"last_step"`
+	LastSignature []byte         `json:"last_signature,omitempty"` // so we dont lose signatures XXX Why would we lose signatures?
+	LastSignBytes cmn.HexBytes   `json:"last_signbytes,omitempty"` // so we dont lose signatures XXX Why would we lose signatures?
+	PrivKey       crypto.PrivKey `json:"priv_key"`
 
 	// For persistence.
 	// Overloaded for testing.
@@ -138,7 +138,7 @@ func (pv *FilePV) save() {
 // Reset resets all fields in the FilePV.
 // NOTE: Unsafe!
 func (pv *FilePV) Reset() {
-	var sig crypto.Signature
+	var sig []byte
 	pv.LastHeight = 0
 	pv.LastRound = 0
 	pv.LastStep = 0
@@ -277,7 +277,7 @@ func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error {
 
 // Persist height/round/step and signature
 func (pv *FilePV) saveSigned(height int64, round int, step int8,
-	signBytes []byte, sig crypto.Signature) {
+	signBytes []byte, sig []byte) {
 
 	pv.LastHeight = height
 	pv.LastRound = round
diff --git a/vendor/github.com/tendermint/tendermint/privval/socket.go b/vendor/github.com/tendermint/tendermint/privval/socket.go
index c33443edad01f81a01b461c2764252a82e7d07eb..d5ede471c2eb83722992ae9f477e8f74063b4c5b 100644
--- a/vendor/github.com/tendermint/tendermint/privval/socket.go
+++ b/vendor/github.com/tendermint/tendermint/privval/socket.go
@@ -7,12 +7,12 @@ import (
 	"net"
 	"time"
 
-	"github.com/tendermint/go-amino"
+	amino "github.com/tendermint/go-amino"
+
 	"github.com/tendermint/tendermint/crypto"
 	"github.com/tendermint/tendermint/crypto/ed25519"
 	cmn "github.com/tendermint/tendermint/libs/common"
 	"github.com/tendermint/tendermint/libs/log"
-
 	p2pconn "github.com/tendermint/tendermint/p2p/conn"
 	"github.com/tendermint/tendermint/types"
 )
@@ -33,7 +33,7 @@ var (
 )
 
 var (
-	acceptDeadline = time.Second + defaultAcceptDeadlineSeconds
+	acceptDeadline = time.Second * defaultAcceptDeadlineSeconds
 	connDeadline   = time.Second * defaultConnDeadlineSeconds
 	connHeartbeat  = time.Second * defaultConnHeartBeatSeconds
 )
diff --git a/vendor/github.com/tendermint/tendermint/rpc/core/README.md b/vendor/github.com/tendermint/tendermint/rpc/core/README.md
index 9547079b2975e9b6c28c521380d9d914cfd756ee..32c3051e336c37b16115a5ee8f585ec23c5437af 100644
--- a/vendor/github.com/tendermint/tendermint/rpc/core/README.md
+++ b/vendor/github.com/tendermint/tendermint/rpc/core/README.md
@@ -1,18 +1,15 @@
 # Tendermint RPC
 
-## Generate markdown for [Slate](https://github.com/tendermint/slate)
-
-We are using [Slate](https://github.com/tendermint/slate) to power our RPC
+We are using [Slate](https://github.com/lord/slate) to power our RPC
 documentation. For generating markdown use:
 
 ```shell
 go get github.com/davecheney/godoc2md
 
-godoc2md -template rpc/core/doc_template.txt github.com/tendermint/tendermint/rpc/core | grep -v -e "pipe.go" -e "routes.go" -e "dev.go" | sed 's$/src/target$https://github.com/tendermint/tendermint/tree/master/rpc/core$'
+# from root of this repo
+make rpc-docs
 ```
 
-For more information see the [CI script for building the Slate docs](/scripts/slate.sh)
-
 ## Pagination
 
 Requests that return multiple items will be paginated to 30 items by default.
diff --git a/vendor/github.com/tendermint/tendermint/rpc/core/abci.go b/vendor/github.com/tendermint/tendermint/rpc/core/abci.go
index 100176195771a5e88d7740d34d7b544901c9a97c..3f399be80fdf0254327c8a5a776f656f6727f44a 100644
--- a/vendor/github.com/tendermint/tendermint/rpc/core/abci.go
+++ b/vendor/github.com/tendermint/tendermint/rpc/core/abci.go
@@ -93,7 +93,7 @@ func ABCIQuery(path string, data cmn.HexBytes, height int64, trusted bool) (*cty
 // }
 // ```
 func ABCIInfo() (*ctypes.ResultABCIInfo, error) {
-	resInfo, err := proxyAppQuery.InfoSync(abci.RequestInfo{version.Version})
+	resInfo, err := proxyAppQuery.InfoSync(abci.RequestInfo{Version: version.Version})
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/tendermint/tendermint/rpc/core/slate_header.txt b/vendor/github.com/tendermint/tendermint/rpc/core/slate_header.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bb4ca6e03c40aa77c03374599031664f68692b4e
--- /dev/null
+++ b/vendor/github.com/tendermint/tendermint/rpc/core/slate_header.txt
@@ -0,0 +1,13 @@
+---
+title: RPC Reference
+
+language_tabs: # must be one of https://git.io/vQNgJ
+  - shell
+  - go
+
+toc_footers:
+  - <a href='https://tendermint.com/'>Tendermint</a>
+  - <a href='https://github.com/lord/slate'>Documentation Powered by Slate</a>
+
+search: true
+---
diff --git a/vendor/github.com/tendermint/tendermint/rpc/core/status.go b/vendor/github.com/tendermint/tendermint/rpc/core/status.go
index 739e67b8607cba0b504d4b624786becf655453f6..4cb7667b7568bde550258a2885c61325f90a91e4 100644
--- a/vendor/github.com/tendermint/tendermint/rpc/core/status.go
+++ b/vendor/github.com/tendermint/tendermint/rpc/core/status.go
@@ -104,20 +104,11 @@ func Status() (*ctypes.ResultStatus, error) {
 	return result, nil
 }
 
-const consensusTimeout = time.Second
-
 func validatorAtHeight(h int64) *types.Validator {
-	lastBlockHeight, vals := getValidatorsWithTimeout(
-		consensusState,
-		consensusTimeout,
-	)
-
-	if lastBlockHeight == -1 {
-		return nil
-	}
-
 	privValAddress := pubKey.Address()
 
+	lastBlockHeight, vals := consensusState.GetValidators()
+
 	// if we're still at height h, search in the current validator set
 	if lastBlockHeight == h {
 		for _, val := range vals {
@@ -140,32 +131,3 @@ func validatorAtHeight(h int64) *types.Validator {
 
 	return nil
 }
-
-type validatorRetriever interface {
-	GetValidators() (int64, []*types.Validator)
-}
-
-// NOTE: Consensus might halt, but we still need to process RPC requests (at
-// least for endpoints whole output does not depend on consensus state).
-func getValidatorsWithTimeout(
-	vr validatorRetriever,
-	t time.Duration,
-) (int64, []*types.Validator) {
-	resultCh := make(chan struct {
-		lastBlockHeight int64
-		vals            []*types.Validator
-	})
-	go func() {
-		h, v := vr.GetValidators()
-		resultCh <- struct {
-			lastBlockHeight int64
-			vals            []*types.Validator
-		}{h, v}
-	}()
-	select {
-	case res := <-resultCh:
-		return res.lastBlockHeight, res.vals
-	case <-time.After(t):
-		return -1, []*types.Validator{}
-	}
-}
diff --git a/vendor/github.com/tendermint/tendermint/state/execution.go b/vendor/github.com/tendermint/tendermint/state/execution.go
index f38f5e0bb9ace4986238b41409855d725abb01fd..54e1ec73ae04de0cad695bb74625e33ab2e1acf9 100644
--- a/vendor/github.com/tendermint/tendermint/state/execution.go
+++ b/vendor/github.com/tendermint/tendermint/state/execution.go
@@ -188,9 +188,12 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
 
 	// Begin block
 	_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
-		Hash:                block.Hash(),
-		Header:              types.TM2PB.Header(&block.Header),
-		Validators:          signVals,
+		Hash:   block.Hash(),
+		Header: types.TM2PB.Header(&block.Header),
+		LastCommitInfo: abci.LastCommitInfo{
+			CommitRound: int32(block.LastCommit.Round()),
+			Validators:  signVals,
+		},
 		ByzantineValidators: byzVals,
 	})
 	if err != nil {
@@ -207,7 +210,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
 	}
 
 	// End block
-	abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{block.Height})
+	abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height})
 	if err != nil {
 		logger.Error("Error in proxyAppConn.EndBlock", "err", err)
 		return nil, err
@@ -245,7 +248,7 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS
 			vote = block.LastCommit.Precommits[i]
 		}
 		val := abci.SigningValidator{
-			Validator:       types.TM2PB.Validator(val),
+			Validator:       types.TM2PB.ValidatorWithoutPubKey(val),
 			SignedLastBlock: vote != nil,
 		}
 		signVals[i] = val
diff --git a/vendor/github.com/tendermint/tendermint/state/store.go b/vendor/github.com/tendermint/tendermint/state/store.go
index 9e94e36faab74a8e1ac2642749f3db82327f65a3..3a1a6231b73decd9e3f61c690cb114496133c724 100644
--- a/vendor/github.com/tendermint/tendermint/state/store.go
+++ b/vendor/github.com/tendermint/tendermint/state/store.go
@@ -80,6 +80,7 @@ func loadState(db dbm.DB, key []byte) (state State) {
 }
 
 // SaveState persists the State, the ValidatorsInfo, and the ConsensusParamsInfo to the database.
+// This flushes the writes (e.g. calls SetSync).
 func SaveState(db dbm.DB, state State) {
 	saveState(db, state, stateKey)
 }
@@ -218,7 +219,7 @@ func saveValidatorsInfo(db dbm.DB, nextHeight, changeHeight int64, valSet *types
 	if changeHeight == nextHeight {
 		valInfo.ValidatorSet = valSet
 	}
-	db.SetSync(calcValidatorsKey(nextHeight), valInfo.Bytes())
+	db.Set(calcValidatorsKey(nextHeight), valInfo.Bytes())
 }
 
 //-----------------------------------------------------------------------------
@@ -289,5 +290,5 @@ func saveConsensusParamsInfo(db dbm.DB, nextHeight, changeHeight int64, params t
 	if changeHeight == nextHeight {
 		paramsInfo.ConsensusParams = params
 	}
-	db.SetSync(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes())
+	db.Set(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes())
 }
diff --git a/vendor/github.com/tendermint/tendermint/tools/build/LICENSE b/vendor/github.com/tendermint/tendermint/tools/build/LICENSE
deleted file mode 100644
index bb66bb3507e96f784d5f0e8d3d824fede11dcb5e..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/tendermint/tools/build/LICENSE
+++ /dev/null
@@ -1,204 +0,0 @@
-Tendermint Core
-License: Apache2.0
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "{}"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2016 All in Bits, Inc
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/vendor/github.com/tendermint/tendermint/tools/mintnet-kubernetes/LICENSE b/vendor/github.com/tendermint/tendermint/tools/mintnet-kubernetes/LICENSE
deleted file mode 100644
index 64a33ddf1a4455dceb070463508e23b500bc8936..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/tendermint/tools/mintnet-kubernetes/LICENSE
+++ /dev/null
@@ -1,192 +0,0 @@
-Copyright (C) 2017 Tendermint
-
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        https://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       https://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/vendor/github.com/tendermint/tendermint/tools/tm-bench/LICENSE b/vendor/github.com/tendermint/tendermint/tools/tm-bench/LICENSE
deleted file mode 100644
index f489139675ee621b374d23e48f555adc5c0b64d4..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/tendermint/tools/tm-bench/LICENSE
+++ /dev/null
@@ -1,204 +0,0 @@
-Tendermint Bench
-Copyright 2017 Tendermint
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/vendor/github.com/tendermint/tendermint/tools/tm-monitor/LICENSE b/vendor/github.com/tendermint/tendermint/tools/tm-monitor/LICENSE
deleted file mode 100644
index 20728d3180c4374e819e969750015e7588a15a21..0000000000000000000000000000000000000000
--- a/vendor/github.com/tendermint/tendermint/tools/tm-monitor/LICENSE
+++ /dev/null
@@ -1,204 +0,0 @@
-Tendermint Monitor
-Copyright 2017 Tendermint
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/vendor/github.com/tendermint/tendermint/types/canonical_json.go b/vendor/github.com/tendermint/tendermint/types/canonical_json.go
index 189a8a7a2fec6f93455e5b8e23aa636659d94001..aca9e9b799cc10d9aeaadc304d35af841e53cd8c 100644
--- a/vendor/github.com/tendermint/tendermint/types/canonical_json.go
+++ b/vendor/github.com/tendermint/tendermint/types/canonical_json.go
@@ -9,7 +9,7 @@ import (
 // Canonical json is amino's json for structs with fields in alphabetical order
 
 // TimeFormat is used for generating the sigs
-const TimeFormat = "2006-01-02T15:04:05.000Z"
+const TimeFormat = time.RFC3339Nano
 
 type CanonicalJSONBlockID struct {
 	Hash        cmn.HexBytes               `json:"hash,omitempty"`
diff --git a/vendor/github.com/tendermint/tendermint/types/heartbeat.go b/vendor/github.com/tendermint/tendermint/types/heartbeat.go
index cebe2864cf430211f5cf86043485cc9a492bf5bd..151f1b0b21705c55b20385b7bb8cc817011cc03c 100644
--- a/vendor/github.com/tendermint/tendermint/types/heartbeat.go
+++ b/vendor/github.com/tendermint/tendermint/types/heartbeat.go
@@ -3,7 +3,6 @@ package types
 import (
 	"fmt"
 
-	"github.com/tendermint/tendermint/crypto"
 	cmn "github.com/tendermint/tendermint/libs/common"
 )
 
@@ -13,12 +12,12 @@ import (
 // json field tags because we always want the JSON
 // representation to be in its canonical form.
 type Heartbeat struct {
-	ValidatorAddress Address          `json:"validator_address"`
-	ValidatorIndex   int              `json:"validator_index"`
-	Height           int64            `json:"height"`
-	Round            int              `json:"round"`
-	Sequence         int              `json:"sequence"`
-	Signature        crypto.Signature `json:"signature"`
+	ValidatorAddress Address `json:"validator_address"`
+	ValidatorIndex   int     `json:"validator_index"`
+	Height           int64   `json:"height"`
+	Round            int     `json:"round"`
+	Sequence         int     `json:"sequence"`
+	Signature        []byte  `json:"signature"`
 }
 
 // SignBytes returns the Heartbeat bytes for signing.
@@ -48,5 +47,6 @@ func (heartbeat *Heartbeat) String() string {
 
 	return fmt.Sprintf("Heartbeat{%v:%X %v/%02d (%v) %v}",
 		heartbeat.ValidatorIndex, cmn.Fingerprint(heartbeat.ValidatorAddress),
-		heartbeat.Height, heartbeat.Round, heartbeat.Sequence, heartbeat.Signature)
+		heartbeat.Height, heartbeat.Round, heartbeat.Sequence,
+		fmt.Sprintf("/%X.../", cmn.Fingerprint(heartbeat.Signature[:])))
 }
diff --git a/vendor/github.com/tendermint/tendermint/types/proposal.go b/vendor/github.com/tendermint/tendermint/types/proposal.go
index 52ce8756e8f591fb474e5c46dc4c8727191df4f0..81a5e2c33f5143e90f9009f93d79f209f88713bc 100644
--- a/vendor/github.com/tendermint/tendermint/types/proposal.go
+++ b/vendor/github.com/tendermint/tendermint/types/proposal.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/tendermint/tendermint/crypto"
+	cmn "github.com/tendermint/tendermint/libs/common"
 )
 
 var (
@@ -19,13 +19,13 @@ var (
 // to be considered valid. It may depend on votes from a previous round,
 // a so-called Proof-of-Lock (POL) round, as noted in the POLRound and POLBlockID.
 type Proposal struct {
-	Height           int64            `json:"height"`
-	Round            int              `json:"round"`
-	Timestamp        time.Time        `json:"timestamp"`
-	BlockPartsHeader PartSetHeader    `json:"block_parts_header"`
-	POLRound         int              `json:"pol_round"`    // -1 if null.
-	POLBlockID       BlockID          `json:"pol_block_id"` // zero if null.
-	Signature        crypto.Signature `json:"signature"`
+	Height           int64         `json:"height"`
+	Round            int           `json:"round"`
+	Timestamp        time.Time     `json:"timestamp"`
+	BlockPartsHeader PartSetHeader `json:"block_parts_header"`
+	POLRound         int           `json:"pol_round"`    // -1 if null.
+	POLBlockID       BlockID       `json:"pol_block_id"` // zero if null.
+	Signature        []byte        `json:"signature"`
 }
 
 // NewProposal returns a new Proposal.
@@ -43,9 +43,10 @@ func NewProposal(height int64, round int, blockPartsHeader PartSetHeader, polRou
 
 // String returns a string representation of the Proposal.
 func (p *Proposal) String() string {
-	return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %v @ %s}",
+	return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %X @ %s}",
 		p.Height, p.Round, p.BlockPartsHeader, p.POLRound,
-		p.POLBlockID, p.Signature, CanonicalTime(p.Timestamp))
+		p.POLBlockID,
+		cmn.Fingerprint(p.Signature), CanonicalTime(p.Timestamp))
 }
 
 // SignBytes returns the Proposal bytes for signing
diff --git a/vendor/github.com/tendermint/tendermint/types/protobuf.go b/vendor/github.com/tendermint/tendermint/types/protobuf.go
index 0e1e446dba4af2eb6b19e6748f03056425ebb990..01d4ebf0cbb3012dbd088aacdcd638ab5af47bd3 100644
--- a/vendor/github.com/tendermint/tendermint/types/protobuf.go
+++ b/vendor/github.com/tendermint/tendermint/types/protobuf.go
@@ -38,7 +38,7 @@ func (tm2pb) Header(header *Header) abci.Header {
 		ChainID: header.ChainID,
 		Height:  header.Height,
 
-		Time:     header.Time.Unix(),
+		Time:     header.Time,
 		NumTxs:   int32(header.NumTxs), // XXX: overflow
 		TotalTxs: header.TotalTxs,
 
@@ -50,6 +50,13 @@ func (tm2pb) Header(header *Header) abci.Header {
 	}
 }
 
+func (tm2pb) ValidatorWithoutPubKey(val *Validator) abci.Validator {
+	return abci.Validator{
+		Address: val.PubKey.Address(),
+		Power:   val.VotingPower,
+	}
+}
+
 // XXX: panics on unknown pubkey type
 func (tm2pb) Validator(val *Validator) abci.Validator {
 	return abci.Validator{
@@ -129,9 +136,9 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.
 
 	return abci.Evidence{
 		Type:             evType,
-		Validator:        TM2PB.Validator(val),
+		Validator:        TM2PB.ValidatorWithoutPubKey(val),
 		Height:           ev.Height(),
-		Time:             evTime.Unix(),
+		Time:             evTime,
 		TotalVotingPower: valSet.TotalVotingPower(),
 	}
 }
diff --git a/vendor/github.com/tendermint/tendermint/types/vote.go b/vendor/github.com/tendermint/tendermint/types/vote.go
index ed4ebd73e51c85f3d1806c27ce2e3d7e871681fa..9a6180d75567975f92959b814a3024e8ff51659f 100644
--- a/vendor/github.com/tendermint/tendermint/types/vote.go
+++ b/vendor/github.com/tendermint/tendermint/types/vote.go
@@ -61,14 +61,14 @@ type Address = cmn.HexBytes
 
 // Represents a prevote, precommit, or commit vote from validators for consensus.
 type Vote struct {
-	ValidatorAddress Address          `json:"validator_address"`
-	ValidatorIndex   int              `json:"validator_index"`
-	Height           int64            `json:"height"`
-	Round            int              `json:"round"`
-	Timestamp        time.Time        `json:"timestamp"`
-	Type             byte             `json:"type"`
-	BlockID          BlockID          `json:"block_id"` // zero if vote is nil.
-	Signature        crypto.Signature `json:"signature"`
+	ValidatorAddress Address   `json:"validator_address"`
+	ValidatorIndex   int       `json:"validator_index"`
+	Height           int64     `json:"height"`
+	Round            int       `json:"round"`
+	Timestamp        time.Time `json:"timestamp"`
+	Type             byte      `json:"type"`
+	BlockID          BlockID   `json:"block_id"` // zero if vote is nil.
+	Signature        []byte    `json:"signature"`
 }
 
 func (vote *Vote) SignBytes(chainID string) []byte {
@@ -98,10 +98,11 @@ func (vote *Vote) String() string {
 		cmn.PanicSanity("Unknown vote type")
 	}
 
-	return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %v @ %s}",
+	return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
 		vote.ValidatorIndex, cmn.Fingerprint(vote.ValidatorAddress),
 		vote.Height, vote.Round, vote.Type, typeString,
-		cmn.Fingerprint(vote.BlockID.Hash), vote.Signature,
+		cmn.Fingerprint(vote.BlockID.Hash),
+		cmn.Fingerprint(vote.Signature),
 		CanonicalTime(vote.Timestamp))
 }
 
diff --git a/vendor/github.com/tendermint/tendermint/types/vote_set.go b/vendor/github.com/tendermint/tendermint/types/vote_set.go
index c516810534863522cc01d4a9751f4e28d65d9930..36bf5ef7e3293a4963ab5bbcebb83cf19dc3bfd8 100644
--- a/vendor/github.com/tendermint/tendermint/types/vote_set.go
+++ b/vendor/github.com/tendermint/tendermint/types/vote_set.go
@@ -179,7 +179,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
 
 	// If we already know of this vote, return false.
 	if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
-		if existing.Signature.Equals(vote.Signature) {
+		if bytes.Equal(existing.Signature, vote.Signature) {
 			return false, nil // duplicate
 		}
 		return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", existing, vote)
diff --git a/vendor/github.com/tendermint/tendermint/version/version.go b/vendor/github.com/tendermint/tendermint/version/version.go
index 85b1f19185a9eb66a1a0d700838ef7afd68ca82f..04880cfe0de35b5a548a9fb034cb14ae6ab9623e 100644
--- a/vendor/github.com/tendermint/tendermint/version/version.go
+++ b/vendor/github.com/tendermint/tendermint/version/version.go
@@ -3,14 +3,14 @@ package version
 // Version components
 const (
 	Maj = "0"
-	Min = "22"
-	Fix = "8"
+	Min = "23"
+	Fix = "0"
 )
 
 var (
 	// Version is the current version of Tendermint
 	// Must be a string because scripts like dist.sh read this file.
-	Version = "0.22.8"
+	Version = "0.23.0"
 
 	// GitCommit is the current HEAD set using ldflags.
 	GitCommit string
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
new file mode 100644
index 0000000000000000000000000000000000000000..bbb86efef55d97e1f21185a87c3140c0134ceef3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
@@ -0,0 +1,101 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539,
+// and its extended nonce variant XChaCha20-Poly1305.
+package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+	"errors"
+)
+
+const (
+	// KeySize is the size of the key used by this AEAD, in bytes.
+	KeySize = 32
+
+	// NonceSize is the size of the nonce used with the standard variant of this
+	// AEAD, in bytes.
+	//
+	// Note that this is too short to be safely generated at random if the same
+	// key is reused more than 2³² times.
+	NonceSize = 12
+
+	// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
+	// variant of this AEAD, in bytes.
+	NonceSizeX = 24
+)
+
+type chacha20poly1305 struct {
+	key [8]uint32
+}
+
+// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+func New(key []byte) (cipher.AEAD, error) {
+	if len(key) != KeySize {
+		return nil, errors.New("chacha20poly1305: bad key length")
+	}
+	ret := new(chacha20poly1305)
+	ret.key[0] = binary.LittleEndian.Uint32(key[0:4])
+	ret.key[1] = binary.LittleEndian.Uint32(key[4:8])
+	ret.key[2] = binary.LittleEndian.Uint32(key[8:12])
+	ret.key[3] = binary.LittleEndian.Uint32(key[12:16])
+	ret.key[4] = binary.LittleEndian.Uint32(key[16:20])
+	ret.key[5] = binary.LittleEndian.Uint32(key[20:24])
+	ret.key[6] = binary.LittleEndian.Uint32(key[24:28])
+	ret.key[7] = binary.LittleEndian.Uint32(key[28:32])
+	return ret, nil
+}
+
+func (c *chacha20poly1305) NonceSize() int {
+	return NonceSize
+}
+
+func (c *chacha20poly1305) Overhead() int {
+	return 16
+}
+
+func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if len(nonce) != NonceSize {
+		panic("chacha20poly1305: bad nonce length passed to Seal")
+	}
+
+	if uint64(len(plaintext)) > (1<<38)-64 {
+		panic("chacha20poly1305: plaintext too large")
+	}
+
+	return c.seal(dst, nonce, plaintext, additionalData)
+}
+
+var errOpen = errors.New("chacha20poly1305: message authentication failed")
+
+func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if len(nonce) != NonceSize {
+		panic("chacha20poly1305: bad nonce length passed to Open")
+	}
+	if len(ciphertext) < 16 {
+		return nil, errOpen
+	}
+	if uint64(len(ciphertext)) > (1<<38)-48 {
+		panic("chacha20poly1305: ciphertext too large")
+	}
+
+	return c.open(dst, nonce, ciphertext, additionalData)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+	if total := len(in) + n; cap(in) >= total {
+		head = in[:total]
+	} else {
+		head = make([]byte, total)
+		copy(head, in)
+	}
+	tail = head[len(in):]
+	return
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
new file mode 100644
index 0000000000000000000000000000000000000000..ec13d138806546eb2fdc74abbc8dc5c35f3977d5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
@@ -0,0 +1,87 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+package chacha20poly1305
+
+import (
+	"encoding/binary"
+
+	"golang.org/x/crypto/internal/subtle"
+	"golang.org/x/sys/cpu"
+)
+
+//go:noescape
+func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
+
+//go:noescape
+func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
+
+var (
+	useASM  = cpu.X86.HasSSSE3
+	useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
+)
+
+// setupState writes a ChaCha20 input matrix to state. See
+// https://tools.ietf.org/html/rfc7539#section-2.3.
+func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) {
+	state[0] = 0x61707865
+	state[1] = 0x3320646e
+	state[2] = 0x79622d32
+	state[3] = 0x6b206574
+
+	state[4] = key[0]
+	state[5] = key[1]
+	state[6] = key[2]
+	state[7] = key[3]
+	state[8] = key[4]
+	state[9] = key[5]
+	state[10] = key[6]
+	state[11] = key[7]
+
+	state[12] = 0
+	state[13] = binary.LittleEndian.Uint32(nonce[:4])
+	state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+	state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+}
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if !useASM {
+		return c.sealGeneric(dst, nonce, plaintext, additionalData)
+	}
+
+	var state [16]uint32
+	setupState(&state, &c.key, nonce)
+
+	ret, out := sliceForAppend(dst, len(plaintext)+16)
+	if subtle.InexactOverlap(out, plaintext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
+	return ret
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if !useASM {
+		return c.openGeneric(dst, nonce, ciphertext, additionalData)
+	}
+
+	var state [16]uint32
+	setupState(&state, &c.key, nonce)
+
+	ciphertext = ciphertext[:len(ciphertext)-16]
+	ret, out := sliceForAppend(dst, len(ciphertext))
+	if subtle.InexactOverlap(out, ciphertext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+		for i := range out {
+			out[i] = 0
+		}
+		return nil, errOpen
+	}
+
+	return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
new file mode 100644
index 0000000000000000000000000000000000000000..af76bbcc93f8c7608b3ce3e9c7fa3e76724b413a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
@@ -0,0 +1,2695 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
+
+// +build go1.7,amd64,!gccgo,!appengine
+
+#include "textflag.h"
+// General register allocation
+#define oup DI
+#define inp SI
+#define inl BX
+#define adp CX // free to reuse, after we hash the additional data
+#define keyp R8 // free to reuse, when we copy the key to stack
+#define itr2 R9 // general iterator
+#define itr1 CX // general iterator
+#define acc0 R10
+#define acc1 R11
+#define acc2 R12
+#define t0 R13
+#define t1 R14
+#define t2 R15
+#define t3 R8
+// Register and stack allocation for the SSE code
+#define rStore (0*16)(BP)
+#define sStore (1*16)(BP)
+#define state1Store (2*16)(BP)
+#define state2Store (3*16)(BP)
+#define tmpStore (4*16)(BP)
+#define ctr0Store (5*16)(BP)
+#define ctr1Store (6*16)(BP)
+#define ctr2Store (7*16)(BP)
+#define ctr3Store (8*16)(BP)
+#define A0 X0
+#define A1 X1
+#define A2 X2
+#define B0 X3
+#define B1 X4
+#define B2 X5
+#define C0 X6
+#define C1 X7
+#define C2 X8
+#define D0 X9
+#define D1 X10
+#define D2 X11
+#define T0 X12
+#define T1 X13
+#define T2 X14
+#define T3 X15
+#define A3 T0
+#define B3 T1
+#define C3 T2
+#define D3 T3
+// Register and stack allocation for the AVX2 code
+#define rsStoreAVX2 (0*32)(BP)
+#define state1StoreAVX2 (1*32)(BP)
+#define state2StoreAVX2 (2*32)(BP)
+#define ctr0StoreAVX2 (3*32)(BP)
+#define ctr1StoreAVX2 (4*32)(BP)
+#define ctr2StoreAVX2 (5*32)(BP)
+#define ctr3StoreAVX2 (6*32)(BP)
+#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack
+#define AA0 Y0
+#define AA1 Y5
+#define AA2 Y6
+#define AA3 Y7
+#define BB0 Y14
+#define BB1 Y9
+#define BB2 Y10
+#define BB3 Y11
+#define CC0 Y12
+#define CC1 Y13
+#define CC2 Y8
+#define CC3 Y15
+#define DD0 Y4
+#define DD1 Y1
+#define DD2 Y2
+#define DD3 Y3
+#define TT0 DD3
+#define TT1 AA3
+#define TT2 BB3
+#define TT3 CC3
+// ChaCha20 constants
+DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574
+DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574
+// <<< 16 with PSHUFB
+DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
+DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A
+// <<< 8 with PSHUFB
+DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B
+DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B
+
+DATA ·avx2InitMask<>+0x00(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x08(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x10(SB)/8, $0x1
+DATA ·avx2InitMask<>+0x18(SB)/8, $0x0
+
+DATA ·avx2IncMask<>+0x00(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x08(SB)/8, $0x0
+DATA ·avx2IncMask<>+0x10(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x18(SB)/8, $0x0
+// Poly1305 key clamp
+DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+
+DATA ·sseIncMask<>+0x00(SB)/8, $0x1
+DATA ·sseIncMask<>+0x08(SB)/8, $0x0
+// To load/store the last < 16 bytes in a buffer
+DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff
+DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff
+
+GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32
+GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16
+GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
+// No PALIGNR in Go ASM yet (but VPALIGNR is present).
+#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3
+#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4
+#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5
+#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13
+#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6
+#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7
+#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8
+#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14
+#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9
+#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10
+#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11
+#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15
+#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3
+#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4
+#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5
+#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13
+#define shiftC0Right shiftC0Left
+#define shiftC1Right shiftC1Left
+#define shiftC2Right shiftC2Left
+#define shiftC3Right shiftC3Left
+#define shiftD0Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x04 // PALIGNR $4, X9, X9
+#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
+#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
+#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
+// Some macros
+#define chachaQR(A, B, C, D, T) \
+	PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D                            \
+	PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
+	PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D                             \
+	PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
+
+#define chachaQR_AVX2(A, B, C, D, T) \
+	VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol16<>(SB), D, D                         \
+	VPADDD D, C, C; VPXOR C, B, B; VPSLLD $12, B, T; VPSRLD $20, B, B; VPXOR T, B, B \
+	VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol8<>(SB), D, D                          \
+	VPADDD D, C, C; VPXOR C, B, B; VPSLLD $7, B, T; VPSRLD $25, B, B; VPXOR T, B, B
+
+#define polyAdd(S) ADDQ S, acc0; ADCQ 8+S, acc1; ADCQ $1, acc2
+#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX
+#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3
+#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t2:t3; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2
+
+#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3
+#define polyMulStage3_AVX2 IMULQ acc2, DX; ADDQ AX, t2; ADCQ DX, t3
+
+#define polyMul polyMulStage1; polyMulStage2; polyMulStage3; polyMulReduceStage
+#define polyMulAVX2 polyMulStage1_AVX2; polyMulStage2_AVX2; polyMulStage3_AVX2; polyMulReduceStage
+// ----------------------------------------------------------------------------
+TEXT polyHashADInternal<>(SB), NOSPLIT, $0
+	// adp points to beginning of additional data
+	// itr2 holds ad length
+	XORQ acc0, acc0
+	XORQ acc1, acc1
+	XORQ acc2, acc2
+	CMPQ itr2, $13
+	JNE  hashADLoop
+
+openFastTLSAD:
+	// Special treatment for the TLS case of 13 bytes
+	MOVQ (adp), acc0
+	MOVQ 5(adp), acc1
+	SHRQ $24, acc1
+	MOVQ $1, acc2
+	polyMul
+	RET
+
+hashADLoop:
+	// Hash in 16 byte chunks
+	CMPQ itr2, $16
+	JB   hashADTail
+	polyAdd(0(adp))
+	LEAQ (1*16)(adp), adp
+	SUBQ $16, itr2
+	polyMul
+	JMP  hashADLoop
+
+hashADTail:
+	CMPQ itr2, $0
+	JE   hashADDone
+
+	// Hash last < 16 byte tail
+	XORQ t0, t0
+	XORQ t1, t1
+	XORQ t2, t2
+	ADDQ itr2, adp
+
+hashADTailLoop:
+	SHLQ $8, t1:t0
+	SHLQ $8, t0
+	MOVB -1(adp), t2
+	XORQ t2, t0
+	DECQ adp
+	DECQ itr2
+	JNE  hashADTailLoop
+
+hashADTailFinish:
+	ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	// Finished AD
+hashADDone:
+	RET
+
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Open(dst, key, src, ad []byte) bool
+TEXT ·chacha20Poly1305Open(SB), 0, $288-97
+	// For aligned stack access
+	MOVQ SP, BP
+	ADDQ $32, BP
+	ANDQ $-32, BP
+	MOVQ dst+0(FP), oup
+	MOVQ key+24(FP), keyp
+	MOVQ src+48(FP), inp
+	MOVQ src_len+56(FP), inl
+	MOVQ ad+72(FP), adp
+
+	// Check for AVX2 support
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Open_AVX2
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $128
+	JBE  openSSE128 // About 16% faster
+
+	// For long buffers, prepare the poly key first
+	MOVOU ·chacha20Constants<>(SB), A0
+	MOVOU (1*16)(keyp), B0
+	MOVOU (2*16)(keyp), C0
+	MOVOU (3*16)(keyp), D0
+	MOVO  D0, T1
+
+	// Store state on stack for future use
+	MOVO B0, state1Store
+	MOVO C0, state2Store
+	MOVO D0, ctr3Store
+	MOVQ $10, itr2
+
+openSSEPreparePolyKey:
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	DECQ          itr2
+	JNE           openSSEPreparePolyKey
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0
+
+	// Clamp and store the key
+	PAND ·polyClampMask<>(SB), A0
+	MOVO A0, rStore; MOVO B0, sStore
+
+	// Hash AAD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openSSEMainLoop:
+	CMPQ inl, $256
+	JB   openSSEMainLoopDone
+
+	// Load state, increment counter blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+	// There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash 2 blocks, and for the remaining 4 only 1 block - for a total of 16
+	MOVQ $4, itr1
+	MOVQ inp, itr2
+
+openSSEInternalLoop:
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyAdd(0(itr2))
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	LEAQ          (2*8)(itr2), itr2
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	polyMulStage3
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr1
+	JGE           openSSEInternalLoop
+
+	polyAdd(0(itr2))
+	polyMul
+	LEAQ (2*8)(itr2), itr2
+
+	CMPQ itr1, $-6
+	JG   openSSEInternalLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+	// Load - xor - store
+	MOVO  D3, tmpStore
+	MOVOU (0*16)(inp), D3; PXOR D3, A0; MOVOU A0, (0*16)(oup)
+	MOVOU (1*16)(inp), D3; PXOR D3, B0; MOVOU B0, (1*16)(oup)
+	MOVOU (2*16)(inp), D3; PXOR D3, C0; MOVOU C0, (2*16)(oup)
+	MOVOU (3*16)(inp), D3; PXOR D3, D0; MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), D0; PXOR D0, A1; MOVOU A1, (4*16)(oup)
+	MOVOU (5*16)(inp), D0; PXOR D0, B1; MOVOU B1, (5*16)(oup)
+	MOVOU (6*16)(inp), D0; PXOR D0, C1; MOVOU C1, (6*16)(oup)
+	MOVOU (7*16)(inp), D0; PXOR D0, D1; MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), D0; PXOR D0, A2; MOVOU A2, (8*16)(oup)
+	MOVOU (9*16)(inp), D0; PXOR D0, B2; MOVOU B2, (9*16)(oup)
+	MOVOU (10*16)(inp), D0; PXOR D0, C2; MOVOU C2, (10*16)(oup)
+	MOVOU (11*16)(inp), D0; PXOR D0, D2; MOVOU D2, (11*16)(oup)
+	MOVOU (12*16)(inp), D0; PXOR D0, A3; MOVOU A3, (12*16)(oup)
+	MOVOU (13*16)(inp), D0; PXOR D0, B3; MOVOU B3, (13*16)(oup)
+	MOVOU (14*16)(inp), D0; PXOR D0, C3; MOVOU C3, (14*16)(oup)
+	MOVOU (15*16)(inp), D0; PXOR tmpStore, D0; MOVOU D0, (15*16)(oup)
+	LEAQ  256(inp), inp
+	LEAQ  256(oup), oup
+	SUBQ  $256, inl
+	JMP   openSSEMainLoop
+
+openSSEMainLoopDone:
+	// Handle the various tail sizes efficiently
+	TESTQ inl, inl
+	JE    openSSEFinalize
+	CMPQ  inl, $64
+	JBE   openSSETail64
+	CMPQ  inl, $128
+	JBE   openSSETail128
+	CMPQ  inl, $192
+	JBE   openSSETail192
+	JMP   openSSETail256
+
+openSSEFinalize:
+	// Hash in the PT, AAD lengths
+	ADDQ ad_len+80(FP), acc0; ADCQ src_len+56(FP), acc1; ADCQ $1, acc2
+	polyMul
+
+	// Final reduce
+	MOVQ    acc0, t0
+	MOVQ    acc1, t1
+	MOVQ    acc2, t2
+	SUBQ    $-5, acc0
+	SBBQ    $-1, acc1
+	SBBQ    $3, acc2
+	CMOVQCS t0, acc0
+	CMOVQCS t1, acc1
+	CMOVQCS t2, acc2
+
+	// Add in the "s" part of the key
+	ADDQ 0+sStore, acc0
+	ADCQ 8+sStore, acc1
+
+	// Finally, constant time compare to the tag at the end of the message
+	XORQ    AX, AX
+	MOVQ    $1, DX
+	XORQ    (0*8)(inp), acc0
+	XORQ    (1*8)(inp), acc1
+	ORQ     acc1, acc0
+	CMOVQEQ DX, AX
+
+	// Return true iff tags are equal
+	MOVB AX, ret+96(FP)
+	RET
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 129 bytes
+openSSE128:
+	// For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+	MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+	MOVO  A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO  A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO  B0, T1; MOVO C0, T2; MOVO D1, T3
+	MOVQ  $10, itr2
+
+openSSE128InnerCipherLoop:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left;  shiftB1Left; shiftB2Left
+	shiftC0Left;  shiftC1Left; shiftC2Left
+	shiftD0Left;  shiftD1Left; shiftD2Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftB1Right; shiftB2Right
+	shiftC0Right; shiftC1Right; shiftC2Right
+	shiftD0Right; shiftD1Right; shiftD2Right
+	DECQ          itr2
+	JNE           openSSE128InnerCipherLoop
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+	PADDL T2, C1; PADDL T2, C2
+	PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+
+	// Clamp and store the key
+	PAND  ·polyClampMask<>(SB), A0
+	MOVOU A0, rStore; MOVOU B0, sStore
+
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openSSE128Open:
+	CMPQ inl, $16
+	JB   openSSETail16
+	SUBQ $16, inl
+
+	// Load for hashing
+	polyAdd(0(inp))
+
+	// Load for decryption
+	MOVOU (inp), T0; PXOR T0, A1; MOVOU A1, (oup)
+	LEAQ  (1*16)(inp), inp
+	LEAQ  (1*16)(oup), oup
+	polyMul
+
+	// Shift the stream "left"
+	MOVO B1, A1
+	MOVO C1, B1
+	MOVO D1, C1
+	MOVO A2, D1
+	MOVO B2, A2
+	MOVO C2, B2
+	MOVO D2, C2
+	JMP  openSSE128Open
+
+openSSETail16:
+	TESTQ inl, inl
+	JE    openSSEFinalize
+
+	// We can safely load the CT from the end, because it is padded with the MAC
+	MOVQ   inl, itr2
+	SHLQ   $4, itr2
+	LEAQ   ·andMask<>(SB), t0
+	MOVOU  (inp), T0
+	ADDQ   inl, inp
+	PAND   -16(t0)(itr2*1), T0
+	MOVO   T0, 0+tmpStore
+	MOVQ   T0, t0
+	MOVQ   8+tmpStore, t1
+	PXOR   A1, T0
+
+	// We can only store one byte at a time, since plaintext can be shorter than 16 bytes
+openSSETail16Store:
+	MOVQ T0, t3
+	MOVB t3, (oup)
+	PSRLDQ $1, T0
+	INCQ   oup
+	DECQ   inl
+	JNE    openSSETail16Store
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+	JMP    openSSEFinalize
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of ciphertext
+openSSETail64:
+	// Need to decrypt up to 64 bytes - prepare single block
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	XORQ itr2, itr2
+	MOVQ inl, itr1
+	CMPQ itr1, $16
+	JB   openSSETail64LoopB
+
+openSSETail64LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+	SUBQ $16, itr1
+
+openSSETail64LoopB:
+	ADDQ          $16, itr2
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	chachaQR(A0, B0, C0, D0, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+
+	CMPQ itr1, $16
+	JAE  openSSETail64LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSETail64LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0; PADDL state2Store, C0; PADDL ctr0Store, D0
+
+openSSETail64DecLoop:
+	CMPQ  inl, $16
+	JB    openSSETail64DecLoopDone
+	SUBQ  $16, inl
+	MOVOU (inp), T0
+	PXOR  T0, A0
+	MOVOU A0, (oup)
+	LEAQ  16(inp), inp
+	LEAQ  16(oup), oup
+	MOVO  B0, A0
+	MOVO  C0, B0
+	MOVO  D0, C0
+	JMP   openSSETail64DecLoop
+
+openSSETail64DecLoopDone:
+	MOVO A0, A1
+	JMP  openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openSSETail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	MOVO ·chacha20Constants<>(SB), A1; MOVO state1Store, B1; MOVO state2Store, C1; MOVO ctr3Store, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr0Store
+	MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr1Store
+	XORQ itr2, itr2
+	MOVQ inl, itr1
+	ANDQ $-16, itr1
+
+openSSETail128LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+
+openSSETail128LoopB:
+	ADDQ          $16, itr2
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+
+	CMPQ itr2, itr1
+	JB   openSSETail128LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSETail128LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B0; PADDL state1Store, B1
+	PADDL state2Store, C0; PADDL state2Store, C1
+	PADDL ctr1Store, D0; PADDL ctr0Store, D1
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+
+	SUBQ $64, inl
+	LEAQ 64(inp), inp
+	LEAQ 64(oup), oup
+	JMP  openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of ciphertext
+openSSETail192:
+	// Need to decrypt up to 192 bytes - prepare three blocks
+	MOVO ·chacha20Constants<>(SB), A2; MOVO state1Store, B2; MOVO state2Store, C2; MOVO ctr3Store, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr0Store
+	MOVO A2, A1; MOVO B2, B1; MOVO C2, C1; MOVO D2, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+	MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr2Store
+
+	MOVQ    inl, itr1
+	MOVQ    $160, itr2
+	CMPQ    itr1, $160
+	CMOVQGT itr2, itr1
+	ANDQ    $-16, itr1
+	XORQ    itr2, itr2
+
+openSSLTail192LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+
+openSSLTail192LoopB:
+	ADDQ         $16, itr2
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left; shiftC0Left; shiftD0Left
+	shiftB1Left; shiftC1Left; shiftD1Left
+	shiftB2Left; shiftC2Left; shiftD2Left
+
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+	shiftB2Right; shiftC2Right; shiftD2Right
+
+	CMPQ itr2, itr1
+	JB   openSSLTail192LoopA
+
+	CMPQ itr2, $160
+	JNE  openSSLTail192LoopB
+
+	CMPQ inl, $176
+	JB   openSSLTail192Store
+
+	polyAdd(160(inp))
+	polyMul
+
+	CMPQ inl, $192
+	JB   openSSLTail192Store
+
+	polyAdd(176(inp))
+	polyMul
+
+openSSLTail192Store:
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+	PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+	PADDL ctr2Store, D0; PADDL ctr1Store, D1; PADDL ctr0Store, D2
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A2; PXOR T1, B2; PXOR T2, C2; PXOR T3, D2
+	MOVOU A2, (0*16)(oup); MOVOU B2, (1*16)(oup); MOVOU C2, (2*16)(oup); MOVOU D2, (3*16)(oup)
+
+	MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+	SUBQ $128, inl
+	LEAQ 128(inp), inp
+	LEAQ 128(oup), oup
+	JMP  openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openSSETail256:
+	// Need to decrypt up to 256 bytes - prepare four blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+	XORQ itr2, itr2
+
+openSSETail256Loop:
+	// This loop inteleaves 8 ChaCha quarter rounds with 1 poly multiplication
+	polyAdd(0(inp)(itr2*1))
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulStage3
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	ADDQ          $2*8, itr2
+	CMPQ          itr2, $160
+	JB            openSSETail256Loop
+	MOVQ          inl, itr1
+	ANDQ          $-16, itr1
+
+openSSETail256HashLoop:
+	polyAdd(0(inp)(itr2*1))
+	polyMul
+	ADDQ $2*8, itr2
+	CMPQ itr2, itr1
+	JB   openSSETail256HashLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+	MOVO  D3, tmpStore
+
+	// Load - xor - store
+	MOVOU (0*16)(inp), D3; PXOR D3, A0
+	MOVOU (1*16)(inp), D3; PXOR D3, B0
+	MOVOU (2*16)(inp), D3; PXOR D3, C0
+	MOVOU (3*16)(inp), D3; PXOR D3, D0
+	MOVOU A0, (0*16)(oup)
+	MOVOU B0, (1*16)(oup)
+	MOVOU C0, (2*16)(oup)
+	MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+	LEAQ  192(inp), inp
+	LEAQ  192(oup), oup
+	SUBQ  $192, inl
+	MOVO  A3, A0
+	MOVO  B3, B0
+	MOVO  C3, C0
+	MOVO  tmpStore, D0
+
+	JMP openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Open_AVX2:
+	VZEROUPPER
+	VMOVDQU ·chacha20Constants<>(SB), AA0
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+	BYTE    $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+	VPADDD  ·avx2InitMask<>(SB), DD0, DD0
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $192
+	JBE  openAVX2192
+	CMPQ inl, $320
+	JBE  openAVX2320
+
+	// For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+	VMOVDQA BB0, state1StoreAVX2
+	VMOVDQA CC0, state2StoreAVX2
+	VMOVDQA DD0, ctr3StoreAVX2
+	MOVQ    $10, itr2
+
+openAVX2PreparePolyKey:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	DECQ     itr2
+	JNE      openAVX2PreparePolyKey
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA0
+	VPADDD state1StoreAVX2, BB0, BB0
+	VPADDD state2StoreAVX2, CC0, CC0
+	VPADDD ctr3StoreAVX2, DD0, DD0
+
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for the first 64 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+
+	// Hash AD + first 64 bytes
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+openAVX2InitialHash64:
+	polyAdd(0(inp)(itr1*1))
+	polyMulAVX2
+	ADDQ $16, itr1
+	CMPQ itr1, $64
+	JNE  openAVX2InitialHash64
+
+	// Decrypt the first 64 bytes
+	VPXOR   (0*32)(inp), AA0, AA0
+	VPXOR   (1*32)(inp), BB0, BB0
+	VMOVDQU AA0, (0*32)(oup)
+	VMOVDQU BB0, (1*32)(oup)
+	LEAQ    (2*32)(inp), inp
+	LEAQ    (2*32)(oup), oup
+	SUBQ    $64, inl
+
+openAVX2MainLoop:
+	CMPQ inl, $512
+	JB   openAVX2MainLoopDone
+
+	// Load state, increment counter blocks, store the incremented counters
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	XORQ    itr1, itr1
+
+openAVX2InternalLoop:
+	// Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications
+	// Effectively per 512 bytes of stream we hash 480 bytes of ciphertext
+	polyAdd(0*8(inp)(itr1*1))
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage1_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulStage2_AVX2
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyMulStage3_AVX2
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	polyAdd(2*8(inp)(itr1*1))
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage1_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage2_AVX2
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage3_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulReduceStage
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(4*8(inp)(itr1*1))
+	LEAQ     (6*8)(itr1), itr1
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage1_AVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	polyMulStage2_AVX2
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage3_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	CMPQ     itr1, $480
+	JNE      openAVX2InternalLoop
+
+	VPADDD  ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD  state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD  state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD  ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA CC3, tmpStoreAVX2
+
+	// We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+	polyAdd(480(inp))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	// and here
+	polyAdd(496(inp))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+	VPXOR      (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+	LEAQ       (32*16)(inp), inp
+	LEAQ       (32*16)(oup), oup
+	SUBQ       $(32*16), inl
+	JMP        openAVX2MainLoop
+
+openAVX2MainLoopDone:
+	// Handle the various tail sizes efficiently
+	TESTQ inl, inl
+	JE    openSSEFinalize
+	CMPQ  inl, $128
+	JBE   openAVX2Tail128
+	CMPQ  inl, $256
+	JBE   openAVX2Tail256
+	CMPQ  inl, $384
+	JBE   openAVX2Tail384
+	JMP   openAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+openAVX2192:
+	// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+	VMOVDQA AA0, AA1
+	VMOVDQA BB0, BB1
+	VMOVDQA CC0, CC1
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2
+	VMOVDQA BB0, BB2
+	VMOVDQA CC0, CC2
+	VMOVDQA DD0, DD2
+	VMOVDQA DD1, TT3
+	MOVQ    $10, itr2
+
+openAVX2192InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ       itr2
+	JNE        openAVX2192InnerCipherLoop
+	VPADDD     AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+	VPADDD     BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+	VPADDD     CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+	VPADDD     DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for up to 192 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+
+openAVX2ShortOpen:
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+openAVX2ShortOpenLoop:
+	CMPQ inl, $32
+	JB   openAVX2ShortTail32
+	SUBQ $32, inl
+
+	// Load for hashing
+	polyAdd(0*8(inp))
+	polyMulAVX2
+	polyAdd(2*8(inp))
+	polyMulAVX2
+
+	// Load for decryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+	LEAQ    (1*32)(oup), oup
+
+	// Shift stream left
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	VMOVDQA AA1, DD0
+	VMOVDQA BB1, AA1
+	VMOVDQA CC1, BB1
+	VMOVDQA DD1, CC1
+	VMOVDQA AA2, DD1
+	VMOVDQA BB2, AA2
+	JMP     openAVX2ShortOpenLoop
+
+openAVX2ShortTail32:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      openAVX2ShortDone
+
+	SUBQ $16, inl
+
+	// Load for hashing
+	polyAdd(0*8(inp))
+	polyMulAVX2
+
+	// Load for decryption
+	VPXOR      (inp), A0, T0
+	VMOVDQU    T0, (oup)
+	LEAQ       (1*16)(inp), inp
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+openAVX2ShortDone:
+	VZEROUPPER
+	JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+openAVX2320:
+	// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+	VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+	MOVQ    $10, itr2
+
+openAVX2320InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr2
+	JNE      openAVX2320InnerCipherLoop
+
+	VMOVDQA ·chacha20Constants<>(SB), TT0
+	VPADDD  TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+	VPADDD  TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+	VPADDD  TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+	VMOVDQA ·avx2IncMask<>(SB), TT0
+	VPADDD  TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD2, DD2
+
+	// Clamp and store poly key
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPAND      ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA    TT0, rsStoreAVX2
+
+	// Stream for up to 320 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+	VPERM2I128 $0x02, AA2, BB2, CC1
+	VPERM2I128 $0x02, CC2, DD2, DD1
+	VPERM2I128 $0x13, AA2, BB2, AA2
+	VPERM2I128 $0x13, CC2, DD2, BB2
+	JMP        openAVX2ShortOpen
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openAVX2Tail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA1
+	VMOVDQA state1StoreAVX2, BB1
+	VMOVDQA state2StoreAVX2, CC1
+	VMOVDQA ctr3StoreAVX2, DD1
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD1
+	VMOVDQA DD1, DD0
+
+	XORQ  itr2, itr2
+	MOVQ  inl, itr1
+	ANDQ  $-16, itr1
+	TESTQ itr1, itr1
+	JE    openAVX2Tail128LoopB
+
+openAVX2Tail128LoopA:
+	// Perform ChaCha rounds, while hashing the remaining input
+	polyAdd(0(inp)(itr2*1))
+	polyMulAVX2
+
+openAVX2Tail128LoopB:
+	ADDQ     $16, itr2
+	chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD1, DD1, DD1
+	CMPQ     itr2, itr1
+	JB       openAVX2Tail128LoopA
+	CMPQ     itr2, $160
+	JNE      openAVX2Tail128LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC1, CC1
+	VPADDD     DD0, DD1, DD1
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+openAVX2TailLoop:
+	CMPQ inl, $32
+	JB   openAVX2Tail
+	SUBQ $32, inl
+
+	// Load for decryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+	LEAQ    (1*32)(oup), oup
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	JMP     openAVX2TailLoop
+
+openAVX2Tail:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      openAVX2TailDone
+	SUBQ    $16, inl
+
+	// Load for decryption
+	VPXOR      (inp), A0, T0
+	VMOVDQU    T0, (oup)
+	LEAQ       (1*16)(inp), inp
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+openAVX2TailDone:
+	VZEROUPPER
+	JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openAVX2Tail256:
+	// Need to decrypt up to 256 bytes - prepare four blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA DD0, TT1
+	VMOVDQA DD1, TT2
+
+	// Compute the number of iterations that will hash data
+	MOVQ    inl, tmpStoreAVX2
+	MOVQ    inl, itr1
+	SUBQ    $128, itr1
+	SHRQ    $4, itr1
+	MOVQ    $10, itr2
+	CMPQ    itr1, $10
+	CMOVQGT itr2, itr1
+	MOVQ    inp, inl
+	XORQ    itr2, itr2
+
+openAVX2Tail256LoopA:
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ 16(inl), inl
+
+	// Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail256LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	INCQ     itr2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	CMPQ     itr2, itr1
+	JB       openAVX2Tail256LoopA
+
+	CMPQ itr2, $10
+	JNE  openAVX2Tail256LoopB
+
+	MOVQ inl, itr2
+	SUBQ inp, inl
+	MOVQ inl, itr1
+	MOVQ tmpStoreAVX2, inl
+
+	// Hash the remainder of data (if any)
+openAVX2Tail256Hash:
+	ADDQ $16, itr1
+	CMPQ itr1, inl
+	JGT  openAVX2Tail256HashEnd
+	polyAdd (0(itr2))
+	polyMulAVX2
+	LEAQ 16(itr2), itr2
+	JMP  openAVX2Tail256Hash
+
+// Store 128 bytes safely, then go to store loop
+openAVX2Tail256HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, AA2; VPERM2I128 $0x02, CC0, DD0, BB2; VPERM2I128 $0x13, AA0, BB0, CC2; VPERM2I128 $0x13, CC0, DD0, DD2
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+	VPXOR   (0*32)(inp), AA2, AA2; VPXOR (1*32)(inp), BB2, BB2; VPXOR (2*32)(inp), CC2, CC2; VPXOR (3*32)(inp), DD2, DD2
+	VMOVDQU AA2, (0*32)(oup); VMOVDQU BB2, (1*32)(oup); VMOVDQU CC2, (2*32)(oup); VMOVDQU DD2, (3*32)(oup)
+	LEAQ    (4*32)(inp), inp
+	LEAQ    (4*32)(oup), oup
+	SUBQ    $4*32, inl
+
+	JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+openAVX2Tail384:
+	// Need to decrypt up to 384 bytes - prepare six blocks
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA DD0, ctr0StoreAVX2
+	VMOVDQA DD1, ctr1StoreAVX2
+	VMOVDQA DD2, ctr2StoreAVX2
+
+	// Compute the number of iterations that will hash two blocks of data
+	MOVQ    inl, tmpStoreAVX2
+	MOVQ    inl, itr1
+	SUBQ    $256, itr1
+	SHRQ    $4, itr1
+	ADDQ    $6, itr1
+	MOVQ    $10, itr2
+	CMPQ    itr1, $10
+	CMOVQGT itr2, itr1
+	MOVQ    inp, inl
+	XORQ    itr2, itr2
+
+	// Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail384LoopB:
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ 16(inl), inl
+
+openAVX2Tail384LoopA:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	polyAdd(0(inl))
+	polyMulAVX2
+	LEAQ     16(inl), inl
+	INCQ     itr2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+
+	CMPQ itr2, itr1
+	JB   openAVX2Tail384LoopB
+
+	CMPQ itr2, $10
+	JNE  openAVX2Tail384LoopA
+
+	MOVQ inl, itr2
+	SUBQ inp, inl
+	MOVQ inl, itr1
+	MOVQ tmpStoreAVX2, inl
+
+openAVX2Tail384Hash:
+	ADDQ $16, itr1
+	CMPQ itr1, inl
+	JGT  openAVX2Tail384HashEnd
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ 16(itr2), itr2
+	JMP  openAVX2Tail384Hash
+
+// Store 256 bytes safely, then go to store loop
+openAVX2Tail384HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2
+	VPERM2I128 $0x02, AA0, BB0, TT0; VPERM2I128 $0x02, CC0, DD0, TT1; VPERM2I128 $0x13, AA0, BB0, TT2; VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, TT0; VPERM2I128 $0x02, CC1, DD1, TT1; VPERM2I128 $0x13, AA1, BB1, TT2; VPERM2I128 $0x13, CC1, DD1, TT3
+	VPXOR      (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	LEAQ       (8*32)(inp), inp
+	LEAQ       (8*32)(oup), oup
+	SUBQ       $8*32, inl
+	JMP        openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+openAVX2Tail512:
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	XORQ    itr1, itr1
+	MOVQ    inp, itr2
+
+openAVX2Tail512LoopB:
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ (2*8)(itr2), itr2
+
+openAVX2Tail512LoopA:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyAdd(0*8(itr2))
+	polyMulAVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(2*8(itr2))
+	polyMulAVX2
+	LEAQ     (4*8)(itr2), itr2
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	INCQ     itr1
+	CMPQ     itr1, $4
+	JLT      openAVX2Tail512LoopB
+
+	CMPQ itr1, $10
+	JNE  openAVX2Tail512LoopA
+
+	MOVQ inl, itr1
+	SUBQ $384, itr1
+	ANDQ $-16, itr1
+
+openAVX2Tail512HashLoop:
+	TESTQ itr1, itr1
+	JE    openAVX2Tail512HashEnd
+	polyAdd(0(itr2))
+	polyMulAVX2
+	LEAQ  16(itr2), itr2
+	SUBQ  $16, itr1
+	JMP   openAVX2Tail512HashLoop
+
+openAVX2Tail512HashEnd:
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA    CC3, tmpStoreAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+	LEAQ (12*32)(inp), inp
+	LEAQ (12*32)(oup), oup
+	SUBQ $12*32, inl
+
+	JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Seal(dst, key, src, ad []byte)
+TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
+	// For aligned stack access
+	MOVQ SP, BP
+	ADDQ $32, BP
+	ANDQ $-32, BP
+	MOVQ dst+0(FP), oup
+	MOVQ key+24(FP), keyp
+	MOVQ src+48(FP), inp
+	MOVQ src_len+56(FP), inl
+	MOVQ ad+72(FP), adp
+
+	CMPB ·useAVX2(SB), $1
+	JE   chacha20Poly1305Seal_AVX2
+
+	// Special optimization, for very short buffers
+	CMPQ inl, $128
+	JBE  sealSSE128 // About 15% faster
+
+	// In the seal case - prepare the poly key + 3 blocks of stream in the first iteration
+	MOVOU ·chacha20Constants<>(SB), A0
+	MOVOU (1*16)(keyp), B0
+	MOVOU (2*16)(keyp), C0
+	MOVOU (3*16)(keyp), D0
+
+	// Store state on stack for future use
+	MOVO B0, state1Store
+	MOVO C0, state2Store
+
+	// Load state, increment counter blocks
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+	MOVQ $10, itr2
+
+sealSSEIntroLoop:
+	MOVO         C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO         tmpStore, C3
+	MOVO         C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO         tmpStore, C1
+	shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr2
+	JNE           sealSSEIntroLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+	// Clamp and store the key
+	PAND ·polyClampMask<>(SB), A0
+	MOVO A0, rStore
+	MOVO B0, sStore
+
+	// Hash AAD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (4*16)(oup); MOVOU B2, (5*16)(oup); MOVOU C2, (6*16)(oup); MOVOU D2, (7*16)(oup)
+
+	MOVQ $128, itr1
+	SUBQ $128, inl
+	LEAQ 128(inp), inp
+
+	MOVO A3, A1; MOVO B3, B1; MOVO C3, C1; MOVO D3, D1
+
+	CMPQ inl, $64
+	JBE  sealSSE128SealHash
+
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+	MOVOU A3, (8*16)(oup); MOVOU B3, (9*16)(oup); MOVOU C3, (10*16)(oup); MOVOU D3, (11*16)(oup)
+
+	ADDQ $64, itr1
+	SUBQ $64, inl
+	LEAQ 64(inp), inp
+
+	MOVQ $2, itr1
+	MOVQ $8, itr2
+
+	CMPQ inl, $64
+	JBE  sealSSETail64
+	CMPQ inl, $128
+	JBE  sealSSETail128
+	CMPQ inl, $192
+	JBE  sealSSETail192
+
+sealSSEMainLoop:
+	// Load state, increment counter blocks
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+	// Store counters
+	MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+sealSSEInnerLoop:
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyAdd(0(oup))
+	shiftB0Left;  shiftB1Left; shiftB2Left; shiftB3Left
+	shiftC0Left;  shiftC1Left; shiftC2Left; shiftC3Left
+	shiftD0Left;  shiftD1Left; shiftD2Left; shiftD3Left
+	polyMulStage1
+	polyMulStage2
+	LEAQ          (2*8)(oup), oup
+	MOVO          C3, tmpStore
+	chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+	MOVO          tmpStore, C3
+	MOVO          C1, tmpStore
+	polyMulStage3
+	chachaQR(A3, B3, C3, D3, C1)
+	MOVO          tmpStore, C1
+	polyMulReduceStage
+	shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+	shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+	shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+	DECQ          itr2
+	JGE           sealSSEInnerLoop
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          (2*8)(oup), oup
+	DECQ          itr1
+	JG            sealSSEInnerLoop
+
+	// Add in the state
+	PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+	PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+	PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+	PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+	MOVO  D3, tmpStore
+
+	// Load - xor - store
+	MOVOU (0*16)(inp), D3; PXOR D3, A0
+	MOVOU (1*16)(inp), D3; PXOR D3, B0
+	MOVOU (2*16)(inp), D3; PXOR D3, C0
+	MOVOU (3*16)(inp), D3; PXOR D3, D0
+	MOVOU A0, (0*16)(oup)
+	MOVOU B0, (1*16)(oup)
+	MOVOU C0, (2*16)(oup)
+	MOVOU D0, (3*16)(oup)
+	MOVO  tmpStore, D3
+
+	MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+	PXOR  A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+	MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+	PXOR  A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+	MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+	ADDQ  $192, inp
+	MOVQ  $192, itr1
+	SUBQ  $192, inl
+	MOVO  A3, A1
+	MOVO  B3, B1
+	MOVO  C3, C1
+	MOVO  D3, D1
+	CMPQ  inl, $64
+	JBE   sealSSE128SealHash
+	MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+	PXOR  A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+	MOVOU A3, (12*16)(oup); MOVOU B3, (13*16)(oup); MOVOU C3, (14*16)(oup); MOVOU D3, (15*16)(oup)
+	LEAQ  64(inp), inp
+	SUBQ  $64, inl
+	MOVQ  $6, itr1
+	MOVQ  $4, itr2
+	CMPQ  inl, $192
+	JG    sealSSEMainLoop
+
+	MOVQ  inl, itr1
+	TESTQ inl, inl
+	JE    sealSSE128SealHash
+	MOVQ  $6, itr1
+	CMPQ  inl, $64
+	JBE   sealSSETail64
+	CMPQ  inl, $128
+	JBE   sealSSETail128
+	JMP   sealSSETail192
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of plaintext
+sealSSETail64:
+	// Need to encrypt up to 64 bytes - prepare single block, hash 192 or 256 bytes
+	MOVO  ·chacha20Constants<>(SB), A1
+	MOVO  state1Store, B1
+	MOVO  state2Store, C1
+	MOVO  ctr3Store, D1
+	PADDL ·sseIncMask<>(SB), D1
+	MOVO  D1, ctr0Store
+
+sealSSETail64LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail64LoopB:
+	chachaQR(A1, B1, C1, D1, T1)
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	chachaQR(A1, B1, C1, D1, T1)
+	shiftB1Right; shiftC1Right; shiftD1Right
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          16(oup), oup
+
+	DECQ itr1
+	JG   sealSSETail64LoopA
+
+	DECQ  itr2
+	JGE   sealSSETail64LoopB
+	PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B1
+	PADDL state2Store, C1
+	PADDL ctr0Store, D1
+
+	JMP sealSSE128Seal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of plaintext
+sealSSETail128:
+	// Need to encrypt up to 128 bytes - prepare two blocks, hash 192 or 256 bytes
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+
+sealSSETail128LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail128LoopB:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Left;  shiftC0Left; shiftD0Left
+	shiftB1Left;  shiftC1Left; shiftD1Left
+	polyAdd(0(oup))
+	polyMul
+	LEAQ          16(oup), oup
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+
+	DECQ itr1
+	JG   sealSSETail128LoopA
+
+	DECQ itr2
+	JGE  sealSSETail128LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+	PADDL state1Store, B0; PADDL state1Store, B1
+	PADDL state2Store, C0; PADDL state2Store, C1
+	PADDL ctr0Store, D0; PADDL ctr1Store, D1
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+	MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+
+	MOVQ $64, itr1
+	LEAQ 64(inp), inp
+	SUBQ $64, inl
+
+	JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of plaintext
+sealSSETail192:
+	// Need to encrypt up to 192 bytes - prepare three blocks, hash 192 or 256 bytes
+	MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+	MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+	MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store
+
+sealSSETail192LoopA:
+	// Perform ChaCha rounds, while hashing the previously encrypted ciphertext
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealSSETail192LoopB:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left; shiftC0Left; shiftD0Left
+	shiftB1Left; shiftC1Left; shiftD1Left
+	shiftB2Left; shiftC2Left; shiftD2Left
+
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftC0Right; shiftD0Right
+	shiftB1Right; shiftC1Right; shiftD1Right
+	shiftB2Right; shiftC2Right; shiftD2Right
+
+	DECQ itr1
+	JG   sealSSETail192LoopA
+
+	DECQ itr2
+	JGE  sealSSETail192LoopB
+
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+	PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+	PADDL ctr0Store, D0; PADDL ctr1Store, D1; PADDL ctr2Store, D2
+
+	MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+	PXOR  T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+	MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+	MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+	PXOR  T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+	MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+	MOVO A2, A1
+	MOVO B2, B1
+	MOVO C2, C1
+	MOVO D2, D1
+	MOVQ $128, itr1
+	LEAQ 128(inp), inp
+	SUBQ $128, inl
+
+	JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special seal optimization for buffers smaller than 129 bytes
+sealSSE128:
+	// For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+	MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+	MOVO  A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+	MOVO  A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+	MOVO  B0, T1; MOVO C0, T2; MOVO D1, T3
+	MOVQ  $10, itr2
+
+sealSSE128InnerCipherLoop:
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Left;  shiftB1Left; shiftB2Left
+	shiftC0Left;  shiftC1Left; shiftC2Left
+	shiftD0Left;  shiftD1Left; shiftD2Left
+	chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+	shiftB0Right; shiftB1Right; shiftB2Right
+	shiftC0Right; shiftC1Right; shiftC2Right
+	shiftD0Right; shiftD1Right; shiftD2Right
+	DECQ          itr2
+	JNE           sealSSE128InnerCipherLoop
+
+	// A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+	PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+	PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+	PADDL T2, C1; PADDL T2, C2
+	PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+	PAND  ·polyClampMask<>(SB), A0
+	MOVOU A0, rStore
+	MOVOU B0, sStore
+
+	// Hash
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+sealSSE128SealHash:
+	// itr1 holds the number of bytes encrypted but not yet hashed
+	CMPQ itr1, $16
+	JB   sealSSE128Seal
+	polyAdd(0(oup))
+	polyMul
+
+	SUBQ $16, itr1
+	ADDQ $16, oup
+
+	JMP sealSSE128SealHash
+
+sealSSE128Seal:
+	CMPQ inl, $16
+	JB   sealSSETail
+	SUBQ $16, inl
+
+	// Load for decryption
+	MOVOU (inp), T0
+	PXOR  T0, A1
+	MOVOU A1, (oup)
+	LEAQ  (1*16)(inp), inp
+	LEAQ  (1*16)(oup), oup
+
+	// Extract for hashing
+	MOVQ   A1, t0
+	PSRLDQ $8, A1
+	MOVQ A1, t1
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	// Shift the stream "left"
+	MOVO B1, A1
+	MOVO C1, B1
+	MOVO D1, C1
+	MOVO A2, D1
+	MOVO B2, A2
+	MOVO C2, B2
+	MOVO D2, C2
+	JMP  sealSSE128Seal
+
+sealSSETail:
+	TESTQ inl, inl
+	JE    sealSSEFinalize
+
+	// We can only load the PT one byte at a time to avoid read after end of buffer
+	MOVQ inl, itr2
+	SHLQ $4, itr2
+	LEAQ ·andMask<>(SB), t0
+	MOVQ inl, itr1
+	LEAQ -1(inp)(inl*1), inp
+	XORQ t2, t2
+	XORQ t3, t3
+	XORQ AX, AX
+
+sealSSETailLoadLoop:
+	SHLQ $8, t2, t3
+	SHLQ $8, t2
+	MOVB (inp), AX
+	XORQ AX, t2
+	LEAQ   -1(inp), inp
+	DECQ   itr1
+	JNE    sealSSETailLoadLoop
+	MOVQ t2, 0+tmpStore
+	MOVQ t3, 8+tmpStore
+	PXOR 0+tmpStore, A1
+	MOVOU  A1, (oup)
+	MOVOU  -16(t0)(itr2*1), T0
+	PAND   T0, A1
+	MOVQ   A1, t0
+	PSRLDQ $8, A1
+	MOVQ   A1, t1
+	ADDQ   t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+	polyMul
+
+	ADDQ inl, oup
+
+sealSSEFinalize:
+	// Hash in the buffer lengths
+	ADDQ ad_len+80(FP), acc0
+	ADCQ src_len+56(FP), acc1
+	ADCQ $1, acc2
+	polyMul
+
+	// Final reduce
+	MOVQ    acc0, t0
+	MOVQ    acc1, t1
+	MOVQ    acc2, t2
+	SUBQ    $-5, acc0
+	SBBQ    $-1, acc1
+	SBBQ    $3, acc2
+	CMOVQCS t0, acc0
+	CMOVQCS t1, acc1
+	CMOVQCS t2, acc2
+
+	// Add in the "s" part of the key
+	ADDQ 0+sStore, acc0
+	ADCQ 8+sStore, acc1
+
+	// Finally store the tag at the end of the message
+	MOVQ acc0, (0*8)(oup)
+	MOVQ acc1, (1*8)(oup)
+	RET
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Seal_AVX2:
+	VZEROUPPER
+	VMOVDQU ·chacha20Constants<>(SB), AA0
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+	BYTE    $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+	BYTE    $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+	VPADDD  ·avx2InitMask<>(SB), DD0, DD0
+
+	// Special optimizations, for very short buffers
+	CMPQ inl, $192
+	JBE  seal192AVX2 // 33% faster
+	CMPQ inl, $320
+	JBE  seal320AVX2 // 17% faster
+
+	// For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+	VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3; VMOVDQA BB0, state1StoreAVX2
+	VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3; VMOVDQA CC0, state2StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1; VMOVDQA DD0, ctr0StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD1, DD2; VMOVDQA DD1, ctr1StoreAVX2
+	VPADDD  ·avx2IncMask<>(SB), DD2, DD3; VMOVDQA DD2, ctr2StoreAVX2
+	VMOVDQA DD3, ctr3StoreAVX2
+	MOVQ    $10, itr2
+
+sealAVX2IntroLoop:
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+	VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+	VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+	VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+	VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+	DECQ     itr2
+	JNE      sealAVX2IntroLoop
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+
+	VPERM2I128 $0x13, CC0, DD0, CC0 // Stream bytes 96 - 127
+	VPERM2I128 $0x02, AA0, BB0, DD0 // The Poly1305 key
+	VPERM2I128 $0x13, AA0, BB0, AA0 // Stream bytes 64 - 95
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), DD0, DD0
+	VMOVDQA DD0, rsStoreAVX2
+
+	// Hash AD
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+
+	// Can store at least 320 bytes
+	VPXOR   (0*32)(inp), AA0, AA0
+	VPXOR   (1*32)(inp), CC0, CC0
+	VMOVDQU AA0, (0*32)(oup)
+	VMOVDQU CC0, (1*32)(oup)
+
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (2*32)(inp), AA0, AA0; VPXOR (3*32)(inp), BB0, BB0; VPXOR (4*32)(inp), CC0, CC0; VPXOR (5*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (2*32)(oup); VMOVDQU BB0, (3*32)(oup); VMOVDQU CC0, (4*32)(oup); VMOVDQU DD0, (5*32)(oup)
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (6*32)(inp), AA0, AA0; VPXOR (7*32)(inp), BB0, BB0; VPXOR (8*32)(inp), CC0, CC0; VPXOR (9*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (6*32)(oup); VMOVDQU BB0, (7*32)(oup); VMOVDQU CC0, (8*32)(oup); VMOVDQU DD0, (9*32)(oup)
+
+	MOVQ $320, itr1
+	SUBQ $320, inl
+	LEAQ 320(inp), inp
+
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, CC3, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, CC3, DD3, DD0
+	CMPQ       inl, $128
+	JBE        sealAVX2SealHash
+
+	VPXOR   (0*32)(inp), AA0, AA0; VPXOR (1*32)(inp), BB0, BB0; VPXOR (2*32)(inp), CC0, CC0; VPXOR (3*32)(inp), DD0, DD0
+	VMOVDQU AA0, (10*32)(oup); VMOVDQU BB0, (11*32)(oup); VMOVDQU CC0, (12*32)(oup); VMOVDQU DD0, (13*32)(oup)
+	SUBQ    $128, inl
+	LEAQ    128(inp), inp
+
+	MOVQ $8, itr1
+	MOVQ $2, itr2
+
+	CMPQ inl, $128
+	JBE  sealAVX2Tail128
+	CMPQ inl, $256
+	JBE  sealAVX2Tail256
+	CMPQ inl, $384
+	JBE  sealAVX2Tail384
+	CMPQ inl, $512
+	JBE  sealAVX2Tail512
+
+	// We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+	VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+	VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+	VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+	VMOVDQA CC3, tmpStoreAVX2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+	VMOVDQA tmpStoreAVX2, CC3
+	VMOVDQA CC1, tmpStoreAVX2
+	chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+	VMOVDQA tmpStoreAVX2, CC1
+
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+	VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+	VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+	VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+
+	SUBQ $16, oup                  // Adjust the pointer
+	MOVQ $9, itr1
+	JMP  sealAVX2InternalLoopStart
+
+sealAVX2MainLoop:
+	// Load state, increment counter blocks, store the incremented counters
+	VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+	MOVQ    $10, itr1
+
+sealAVX2InternalLoop:
+	polyAdd(0*8(oup))
+	VPADDD  BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage1_AVX2
+	VPXOR   AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulStage2_AVX2
+	VPADDD  DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR   CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyMulStage3_AVX2
+	VMOVDQA CC3, tmpStoreAVX2
+	VPSLLD  $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD  $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD  $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD  $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA tmpStoreAVX2, CC3
+	polyMulReduceStage
+
+sealAVX2InternalLoopStart:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	polyAdd(2*8(oup))
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage1_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage2_AVX2
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	polyMulStage3_AVX2
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	polyMulReduceStage
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(4*8(oup))
+	LEAQ     (6*8)(oup), oup
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulStage1_AVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	polyMulStage2_AVX2
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	polyMulStage3_AVX2
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyMulReduceStage
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+	DECQ     itr1
+	JNE      sealAVX2InternalLoop
+
+	VPADDD  ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD  state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD  state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD  ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA CC3, tmpStoreAVX2
+
+	// We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	LEAQ       (4*8)(oup), oup
+	VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+	VPXOR      (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+	VMOVDQU    CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	// and here
+	polyAdd(-2*8(oup))
+	polyMulAVX2
+	VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+	VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+	VPXOR      (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+	LEAQ       (32*16)(inp), inp
+	SUBQ       $(32*16), inl
+	CMPQ       inl, $512
+	JG         sealAVX2MainLoop
+
+	// Tail can only hash 480 bytes
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ 32(oup), oup
+
+	MOVQ $10, itr1
+	MOVQ $0, itr2
+	CMPQ inl, $128
+	JBE  sealAVX2Tail128
+	CMPQ inl, $256
+	JBE  sealAVX2Tail256
+	CMPQ inl, $384
+	JBE  sealAVX2Tail384
+	JMP  sealAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+seal192AVX2:
+	// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+	VMOVDQA AA0, AA1
+	VMOVDQA BB0, BB1
+	VMOVDQA CC0, CC1
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2
+	VMOVDQA BB0, BB2
+	VMOVDQA CC0, CC2
+	VMOVDQA DD0, DD2
+	VMOVDQA DD1, TT3
+	MOVQ    $10, itr2
+
+sealAVX2192InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	VPALIGNR   $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR   $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR   $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ       itr2
+	JNE        sealAVX2192InnerCipherLoop
+	VPADDD     AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+	VPADDD     BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+	VPADDD     CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+	VPADDD     DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+
+	// Clamp and store poly key
+	VPAND   ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA TT0, rsStoreAVX2
+
+	// Stream for up to 192 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+
+sealAVX2ShortSeal:
+	// Hash aad
+	MOVQ ad_len+80(FP), itr2
+	CALL polyHashADInternal<>(SB)
+	XORQ itr1, itr1
+
+sealAVX2SealHash:
+	// itr1 holds the number of bytes encrypted but not yet hashed
+	CMPQ itr1, $16
+	JB   sealAVX2ShortSealLoop
+	polyAdd(0(oup))
+	polyMul
+	SUBQ $16, itr1
+	ADDQ $16, oup
+	JMP  sealAVX2SealHash
+
+sealAVX2ShortSealLoop:
+	CMPQ inl, $32
+	JB   sealAVX2ShortTail32
+	SUBQ $32, inl
+
+	// Load for encryption
+	VPXOR   (inp), AA0, AA0
+	VMOVDQU AA0, (oup)
+	LEAQ    (1*32)(inp), inp
+
+	// Now can hash
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ (1*32)(oup), oup
+
+	// Shift stream left
+	VMOVDQA BB0, AA0
+	VMOVDQA CC0, BB0
+	VMOVDQA DD0, CC0
+	VMOVDQA AA1, DD0
+	VMOVDQA BB1, AA1
+	VMOVDQA CC1, BB1
+	VMOVDQA DD1, CC1
+	VMOVDQA AA2, DD1
+	VMOVDQA BB2, AA2
+	JMP     sealAVX2ShortSealLoop
+
+sealAVX2ShortTail32:
+	CMPQ    inl, $16
+	VMOVDQA A0, A1
+	JB      sealAVX2ShortDone
+
+	SUBQ $16, inl
+
+	// Load for encryption
+	VPXOR   (inp), A0, T0
+	VMOVDQU T0, (oup)
+	LEAQ    (1*16)(inp), inp
+
+	// Hash
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	LEAQ       (1*16)(oup), oup
+	VPERM2I128 $0x11, AA0, AA0, AA0
+	VMOVDQA    A0, A1
+
+sealAVX2ShortDone:
+	VZEROUPPER
+	JMP sealSSETail
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+seal320AVX2:
+	// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+	VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+	MOVQ    $10, itr2
+
+sealAVX2320InnerCipherLoop:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr2
+	JNE      sealAVX2320InnerCipherLoop
+
+	VMOVDQA ·chacha20Constants<>(SB), TT0
+	VPADDD  TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+	VPADDD  TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+	VPADDD  TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+	VMOVDQA ·avx2IncMask<>(SB), TT0
+	VPADDD  TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+	VPADDD  TT3, DD2, DD2
+
+	// Clamp and store poly key
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPAND      ·polyClampMask<>(SB), TT0, TT0
+	VMOVDQA    TT0, rsStoreAVX2
+
+	// Stream for up to 320 bytes
+	VPERM2I128 $0x13, AA0, BB0, AA0
+	VPERM2I128 $0x13, CC0, DD0, BB0
+	VPERM2I128 $0x02, AA1, BB1, CC0
+	VPERM2I128 $0x02, CC1, DD1, DD0
+	VPERM2I128 $0x13, AA1, BB1, AA1
+	VPERM2I128 $0x13, CC1, DD1, BB1
+	VPERM2I128 $0x02, AA2, BB2, CC1
+	VPERM2I128 $0x02, CC2, DD2, DD1
+	VPERM2I128 $0x13, AA2, BB2, AA2
+	VPERM2I128 $0x13, CC2, DD2, BB2
+	JMP        sealAVX2ShortSeal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+sealAVX2Tail128:
+	// Need to decrypt up to 128 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0
+	VMOVDQA state1StoreAVX2, BB0
+	VMOVDQA state2StoreAVX2, CC0
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VMOVDQA DD0, DD1
+
+sealAVX2Tail128LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail128LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0
+	VPALIGNR $8, CC0, CC0, CC0
+	VPALIGNR $12, DD0, DD0, DD0
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0
+	VPALIGNR $8, CC0, CC0, CC0
+	VPALIGNR $4, DD0, DD0, DD0
+	DECQ     itr1
+	JG       sealAVX2Tail128LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail128LoopB
+
+	VPADDD ·chacha20Constants<>(SB), AA0, AA1
+	VPADDD state1StoreAVX2, BB0, BB1
+	VPADDD state2StoreAVX2, CC0, CC1
+	VPADDD DD1, DD0, DD1
+
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+	JMP        sealAVX2ShortSealLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+sealAVX2Tail256:
+	// Need to decrypt up to 256 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA ·chacha20Constants<>(SB), AA1
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA state1StoreAVX2, BB1
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA state2StoreAVX2, CC1
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD1
+	VMOVDQA DD0, TT1
+	VMOVDQA DD1, TT2
+
+sealAVX2Tail256LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail256LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+	DECQ     itr1
+	JG       sealAVX2Tail256LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail256LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPERM2I128 $0x02, CC0, DD0, TT1
+	VPERM2I128 $0x13, AA0, BB0, TT2
+	VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	MOVQ       $128, itr1
+	LEAQ       128(inp), inp
+	SUBQ       $128, inl
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+
+	JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+sealAVX2Tail384:
+	// Need to decrypt up to 384 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+	VMOVDQA DD0, TT1; VMOVDQA DD1, TT2; VMOVDQA DD2, TT3
+
+sealAVX2Tail384LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail384LoopB:
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	polyAdd(0(oup))
+	polyMul
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+	chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+	polyAdd(16(oup))
+	polyMul
+	LEAQ     32(oup), oup
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+	DECQ     itr1
+	JG       sealAVX2Tail384LoopA
+	DECQ     itr2
+	JGE      sealAVX2Tail384LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+	VPADDD     TT1, DD0, DD0; VPADDD TT2, DD1, DD1; VPADDD TT3, DD2, DD2
+	VPERM2I128 $0x02, AA0, BB0, TT0
+	VPERM2I128 $0x02, CC0, DD0, TT1
+	VPERM2I128 $0x13, AA0, BB0, TT2
+	VPERM2I128 $0x13, CC0, DD0, TT3
+	VPXOR      (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+	VPERM2I128 $0x02, AA1, BB1, TT0
+	VPERM2I128 $0x02, CC1, DD1, TT1
+	VPERM2I128 $0x13, AA1, BB1, TT2
+	VPERM2I128 $0x13, CC1, DD1, TT3
+	VPXOR      (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+	VMOVDQU    TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+	MOVQ       $256, itr1
+	LEAQ       256(inp), inp
+	SUBQ       $256, inl
+	VPERM2I128 $0x02, AA2, BB2, AA0
+	VPERM2I128 $0x02, CC2, DD2, BB0
+	VPERM2I128 $0x13, AA2, BB2, CC0
+	VPERM2I128 $0x13, CC2, DD2, DD0
+
+	JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+sealAVX2Tail512:
+	// Need to decrypt up to 512 bytes - prepare two blocks
+	// If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+	// If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+	VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+	VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+	VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+	VMOVDQA ctr3StoreAVX2, DD0
+	VPADDD  ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+	VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+sealAVX2Tail512LoopA:
+	polyAdd(0(oup))
+	polyMul
+	LEAQ 16(oup), oup
+
+sealAVX2Tail512LoopB:
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	polyAdd(0*8(oup))
+	polyMulAVX2
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	polyAdd(2*8(oup))
+	polyMulAVX2
+	LEAQ     (4*8)(oup), oup
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPADDD   BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+	VPXOR    AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+	VPSHUFB  ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+	VPADDD   DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+	VPXOR    CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+	VMOVDQA  CC3, tmpStoreAVX2
+	VPSLLD   $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+	VPSLLD   $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+	VPSLLD   $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+	VPSLLD   $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+	VMOVDQA  tmpStoreAVX2, CC3
+	VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+	VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+	VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+
+	DECQ itr1
+	JG   sealAVX2Tail512LoopA
+	DECQ itr2
+	JGE  sealAVX2Tail512LoopB
+
+	VPADDD     ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+	VPADDD     state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+	VPADDD     state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+	VPADDD     ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+	VMOVDQA    CC3, tmpStoreAVX2
+	VPERM2I128 $0x02, AA0, BB0, CC3
+	VPXOR      (0*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (0*32)(oup)
+	VPERM2I128 $0x02, CC0, DD0, CC3
+	VPXOR      (1*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (1*32)(oup)
+	VPERM2I128 $0x13, AA0, BB0, CC3
+	VPXOR      (2*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (2*32)(oup)
+	VPERM2I128 $0x13, CC0, DD0, CC3
+	VPXOR      (3*32)(inp), CC3, CC3
+	VMOVDQU    CC3, (3*32)(oup)
+
+	VPERM2I128 $0x02, AA1, BB1, AA0
+	VPERM2I128 $0x02, CC1, DD1, BB0
+	VPERM2I128 $0x13, AA1, BB1, CC0
+	VPERM2I128 $0x13, CC1, DD1, DD0
+	VPXOR      (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+	VPERM2I128 $0x02, AA2, BB2, AA0
+	VPERM2I128 $0x02, CC2, DD2, BB0
+	VPERM2I128 $0x13, AA2, BB2, CC0
+	VPERM2I128 $0x13, CC2, DD2, DD0
+	VPXOR      (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+	VMOVDQU    AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+
+	MOVQ       $384, itr1
+	LEAQ       384(inp), inp
+	SUBQ       $384, inl
+	VPERM2I128 $0x02, AA3, BB3, AA0
+	VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0
+	VPERM2I128 $0x13, AA3, BB3, CC0
+	VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+	JMP sealAVX2SealHash
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
new file mode 100644
index 0000000000000000000000000000000000000000..c27971216c9bfe8642bfccb543865cb923daffc8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
@@ -0,0 +1,81 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+	"encoding/binary"
+
+	"golang.org/x/crypto/internal/chacha20"
+	"golang.org/x/crypto/internal/subtle"
+	"golang.org/x/crypto/poly1305"
+)
+
+func roundTo16(n int) int {
+	return 16 * ((n + 15) / 16)
+}
+
+func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
+	ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
+	if subtle.InexactOverlap(out, plaintext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+
+	var polyKey [32]byte
+	s := chacha20.New(c.key, [3]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+	})
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.Advance() // skip the next 32 bytes
+	s.XORKeyStream(out, plaintext)
+
+	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
+	copy(polyInput, additionalData)
+	copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
+
+	var tag [poly1305.TagSize]byte
+	poly1305.Sum(&tag, polyInput, &polyKey)
+	copy(out[len(plaintext):], tag[:])
+
+	return ret
+}
+
+func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	var tag [poly1305.TagSize]byte
+	copy(tag[:], ciphertext[len(ciphertext)-16:])
+	ciphertext = ciphertext[:len(ciphertext)-16]
+
+	var polyKey [32]byte
+	s := chacha20.New(c.key, [3]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+	})
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.Advance() // skip the next 32 bytes
+
+	polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
+	copy(polyInput, additionalData)
+	copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+	binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
+
+	ret, out := sliceForAppend(dst, len(ciphertext))
+	if subtle.InexactOverlap(out, ciphertext) {
+		panic("chacha20poly1305: invalid buffer overlap")
+	}
+	if !poly1305.Verify(&tag, polyInput, &polyKey) {
+		for i := range out {
+			out[i] = 0
+		}
+		return nil, errOpen
+	}
+
+	s.XORKeyStream(out, ciphertext)
+	return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
new file mode 100644
index 0000000000000000000000000000000000000000..4c2eb703c327cddc1a3caea33cfc85e9b8dd59c1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 !go1.7 gccgo appengine
+
+package chacha20poly1305
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	return c.sealGeneric(dst, nonce, plaintext, additionalData)
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	return c.openGeneric(dst, nonce, ciphertext, additionalData)
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
new file mode 100644
index 0000000000000000000000000000000000000000..a02fa5719247380db85914ecae472bcffea9da17
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
@@ -0,0 +1,104 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+	"errors"
+
+	"golang.org/x/crypto/internal/chacha20"
+)
+
+type xchacha20poly1305 struct {
+	key [8]uint32
+}
+
+// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+//
+// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
+// suitable to be generated randomly without risk of collisions. It should be
+// preferred when nonce uniqueness cannot be trivially ensured, or whenever
+// nonces are randomly generated.
+func NewX(key []byte) (cipher.AEAD, error) {
+	if len(key) != KeySize {
+		return nil, errors.New("chacha20poly1305: bad key length")
+	}
+	ret := new(xchacha20poly1305)
+	ret.key[0] = binary.LittleEndian.Uint32(key[0:4])
+	ret.key[1] = binary.LittleEndian.Uint32(key[4:8])
+	ret.key[2] = binary.LittleEndian.Uint32(key[8:12])
+	ret.key[3] = binary.LittleEndian.Uint32(key[12:16])
+	ret.key[4] = binary.LittleEndian.Uint32(key[16:20])
+	ret.key[5] = binary.LittleEndian.Uint32(key[20:24])
+	ret.key[6] = binary.LittleEndian.Uint32(key[24:28])
+	ret.key[7] = binary.LittleEndian.Uint32(key[28:32])
+	return ret, nil
+}
+
+func (*xchacha20poly1305) NonceSize() int {
+	return NonceSizeX
+}
+
+func (*xchacha20poly1305) Overhead() int {
+	return 16
+}
+
+func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+	if len(nonce) != NonceSizeX {
+		panic("chacha20poly1305: bad nonce length passed to Seal")
+	}
+
+	// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
+	// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
+	// the second half of the counter is not available. This is unlikely to be
+	// an issue because the cipher.AEAD API requires the entire message to be in
+	// memory, and the counter overflows at 256 GB.
+	if uint64(len(plaintext)) > (1<<38)-64 {
+		panic("chacha20poly1305: plaintext too large")
+	}
+
+	hNonce := [4]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+		binary.LittleEndian.Uint32(nonce[12:16]),
+	}
+	c := &chacha20poly1305{
+		key: chacha20.HChaCha20(&x.key, &hNonce),
+	}
+	// The first 4 bytes of the final nonce are unused counter space.
+	cNonce := make([]byte, NonceSize)
+	copy(cNonce[4:12], nonce[16:24])
+
+	return c.seal(dst, cNonce[:], plaintext, additionalData)
+}
+
+func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	if len(nonce) != NonceSizeX {
+		panic("chacha20poly1305: bad nonce length passed to Open")
+	}
+	if len(ciphertext) < 16 {
+		return nil, errOpen
+	}
+	if uint64(len(ciphertext)) > (1<<38)-48 {
+		panic("chacha20poly1305: ciphertext too large")
+	}
+
+	hNonce := [4]uint32{
+		binary.LittleEndian.Uint32(nonce[0:4]),
+		binary.LittleEndian.Uint32(nonce[4:8]),
+		binary.LittleEndian.Uint32(nonce[8:12]),
+		binary.LittleEndian.Uint32(nonce[12:16]),
+	}
+	c := &chacha20poly1305{
+		key: chacha20.HChaCha20(&x.key, &hNonce),
+	}
+	// The first 4 bytes of the final nonce are unused counter space.
+	cNonce := make([]byte, NonceSize)
+	copy(cNonce[4:12], nonce[16:24])
+
+	return c.open(dst, cNonce[:], ciphertext, additionalData)
+}
diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go
new file mode 100644
index 0000000000000000000000000000000000000000..5bc246355a265a3359b491152779b0c35fa180a4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go
@@ -0,0 +1,75 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation
+// Function (HKDF) as defined in RFC 5869.
+//
+// HKDF is a cryptographic key derivation function (KDF) with the goal of
+// expanding limited input keying material into one or more cryptographically
+// strong secret keys.
+//
+// RFC 5869: https://tools.ietf.org/html/rfc5869
+package hkdf // import "golang.org/x/crypto/hkdf"
+
+import (
+	"crypto/hmac"
+	"errors"
+	"hash"
+	"io"
+)
+
+type hkdf struct {
+	expander hash.Hash
+	size     int
+
+	info    []byte
+	counter byte
+
+	prev  []byte
+	cache []byte
+}
+
+func (f *hkdf) Read(p []byte) (int, error) {
+	// Check whether enough data can be generated
+	need := len(p)
+	remains := len(f.cache) + int(255-f.counter+1)*f.size
+	if remains < need {
+		return 0, errors.New("hkdf: entropy limit reached")
+	}
+	// Read from the cache, if enough data is present
+	n := copy(p, f.cache)
+	p = p[n:]
+
+	// Fill the buffer
+	for len(p) > 0 {
+		f.expander.Reset()
+		f.expander.Write(f.prev)
+		f.expander.Write(f.info)
+		f.expander.Write([]byte{f.counter})
+		f.prev = f.expander.Sum(f.prev[:0])
+		f.counter++
+
+		// Copy the new batch into p
+		f.cache = f.prev
+		n = copy(p, f.cache)
+		p = p[n:]
+	}
+	// Save leftovers for next run
+	f.cache = f.cache[n:]
+
+	return need, nil
+}
+
+// New returns a new HKDF using the given hash, the secret keying material to expand
+// and optional salt and info fields.
+func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
+	if salt == nil {
+		salt = make([]byte, hash().Size())
+	}
+	extractor := hmac.New(hash, salt)
+	extractor.Write(secret)
+	prk := extractor.Sum(nil)
+
+	return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil}
+}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
new file mode 100644
index 0000000000000000000000000000000000000000..6570847f5e07ae83da7cc84acb4c3048ce785ca9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
@@ -0,0 +1,264 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ChaCha20 implements the core ChaCha20 function as specified
+// in https://tools.ietf.org/html/rfc7539#section-2.3.
+package chacha20
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+
+	"golang.org/x/crypto/internal/subtle"
+)
+
+// assert that *Cipher implements cipher.Stream
+var _ cipher.Stream = (*Cipher)(nil)
+
+// Cipher is a stateful instance of ChaCha20 using a particular key
+// and nonce. A *Cipher implements the cipher.Stream interface.
+type Cipher struct {
+	key     [8]uint32
+	counter uint32 // incremented after each block
+	nonce   [3]uint32
+	buf     [bufSize]byte // buffer for unused keystream bytes
+	len     int           // number of unused keystream bytes at end of buf
+}
+
+// New creates a new ChaCha20 stream cipher with the given key and nonce.
+// The initial counter value is set to 0.
+func New(key [8]uint32, nonce [3]uint32) *Cipher {
+	return &Cipher{key: key, nonce: nonce}
+}
+
+// ChaCha20 constants spelling "expand 32-byte k"
+const (
+	j0 uint32 = 0x61707865
+	j1 uint32 = 0x3320646e
+	j2 uint32 = 0x79622d32
+	j3 uint32 = 0x6b206574
+)
+
+func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
+	a += b
+	d ^= a
+	d = (d << 16) | (d >> 16)
+	c += d
+	b ^= c
+	b = (b << 12) | (b >> 20)
+	a += b
+	d ^= a
+	d = (d << 8) | (d >> 24)
+	c += d
+	b ^= c
+	b = (b << 7) | (b >> 25)
+	return a, b, c, d
+}
+
+// XORKeyStream XORs each byte in the given slice with a byte from the
+// cipher's key stream. Dst and src must overlap entirely or not at all.
+//
+// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
+// to pass a dst bigger than src, and in that case, XORKeyStream will
+// only update dst[:len(src)] and will not touch the rest of dst.
+//
+// Multiple calls to XORKeyStream behave as if the concatenation of
+// the src buffers was passed in a single run. That is, Cipher
+// maintains state and does not reset at each XORKeyStream call.
+func (s *Cipher) XORKeyStream(dst, src []byte) {
+	if len(dst) < len(src) {
+		panic("chacha20: output smaller than input")
+	}
+	if subtle.InexactOverlap(dst[:len(src)], src) {
+		panic("chacha20: invalid buffer overlap")
+	}
+
+	// xor src with buffered keystream first
+	if s.len != 0 {
+		buf := s.buf[len(s.buf)-s.len:]
+		if len(src) < len(buf) {
+			buf = buf[:len(src)]
+		}
+		td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
+		for i, b := range buf {
+			td[i] = ts[i] ^ b
+		}
+		s.len -= len(buf)
+		if s.len != 0 {
+			return
+		}
+		s.buf = [len(s.buf)]byte{} // zero the empty buffer
+		src = src[len(buf):]
+		dst = dst[len(buf):]
+	}
+
+	if len(src) == 0 {
+		return
+	}
+	if haveAsm {
+		if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
+			panic("chacha20: counter overflow")
+		}
+		s.xorKeyStreamAsm(dst, src)
+		return
+	}
+
+	// set up a 64-byte buffer to pad out the final block if needed
+	// (hoisted out of the main loop to avoid spills)
+	rem := len(src) % 64  // length of final block
+	fin := len(src) - rem // index of final block
+	if rem > 0 {
+		copy(s.buf[len(s.buf)-64:], src[fin:])
+	}
+
+	// pre-calculate most of the first round
+	s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
+	s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
+	s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
+
+	n := len(src)
+	src, dst = src[:n:n], dst[:n:n] // BCE hint
+	for i := 0; i < n; i += 64 {
+		// calculate the remainder of the first round
+		s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
+
+		// execute the second round
+		x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
+		x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
+		x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
+		x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
+
+		// execute the remaining 18 rounds
+		for i := 0; i < 9; i++ {
+			x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+			x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+			x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+			x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+			x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+			x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+			x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+			x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
+		}
+
+		x0 += j0
+		x1 += j1
+		x2 += j2
+		x3 += j3
+
+		x4 += s.key[0]
+		x5 += s.key[1]
+		x6 += s.key[2]
+		x7 += s.key[3]
+		x8 += s.key[4]
+		x9 += s.key[5]
+		x10 += s.key[6]
+		x11 += s.key[7]
+
+		x12 += s.counter
+		x13 += s.nonce[0]
+		x14 += s.nonce[1]
+		x15 += s.nonce[2]
+
+		// increment the counter
+		s.counter += 1
+		if s.counter == 0 {
+			panic("chacha20: counter overflow")
+		}
+
+		// pad to 64 bytes if needed
+		in, out := src[i:], dst[i:]
+		if i == fin {
+			// src[fin:] has already been copied into s.buf before
+			// the main loop
+			in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
+		}
+		in, out = in[:64], out[:64] // BCE hint
+
+		// XOR the key stream with the source and write out the result
+		xor(out[0:], in[0:], x0)
+		xor(out[4:], in[4:], x1)
+		xor(out[8:], in[8:], x2)
+		xor(out[12:], in[12:], x3)
+		xor(out[16:], in[16:], x4)
+		xor(out[20:], in[20:], x5)
+		xor(out[24:], in[24:], x6)
+		xor(out[28:], in[28:], x7)
+		xor(out[32:], in[32:], x8)
+		xor(out[36:], in[36:], x9)
+		xor(out[40:], in[40:], x10)
+		xor(out[44:], in[44:], x11)
+		xor(out[48:], in[48:], x12)
+		xor(out[52:], in[52:], x13)
+		xor(out[56:], in[56:], x14)
+		xor(out[60:], in[60:], x15)
+	}
+	// copy any trailing bytes out of the buffer and into dst
+	if rem != 0 {
+		s.len = 64 - rem
+		copy(dst[fin:], s.buf[len(s.buf)-64:])
+	}
+}
+
+// Advance discards bytes in the key stream until the next 64 byte block
+// boundary is reached and updates the counter accordingly. If the key
+// stream is already at a block boundary no bytes will be discarded and
+// the counter will be unchanged.
+func (s *Cipher) Advance() {
+	s.len -= s.len % 64
+	if s.len == 0 {
+		s.buf = [len(s.buf)]byte{}
+	}
+}
+
+// XORKeyStream crypts bytes from in to out using the given key and counters.
+// In and out must overlap entirely or not at all. Counter contains the raw
+// ChaCha20 counter bytes (i.e. block counter followed by nonce).
+func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
+	s := Cipher{
+		key: [8]uint32{
+			binary.LittleEndian.Uint32(key[0:4]),
+			binary.LittleEndian.Uint32(key[4:8]),
+			binary.LittleEndian.Uint32(key[8:12]),
+			binary.LittleEndian.Uint32(key[12:16]),
+			binary.LittleEndian.Uint32(key[16:20]),
+			binary.LittleEndian.Uint32(key[20:24]),
+			binary.LittleEndian.Uint32(key[24:28]),
+			binary.LittleEndian.Uint32(key[28:32]),
+		},
+		nonce: [3]uint32{
+			binary.LittleEndian.Uint32(counter[4:8]),
+			binary.LittleEndian.Uint32(counter[8:12]),
+			binary.LittleEndian.Uint32(counter[12:16]),
+		},
+		counter: binary.LittleEndian.Uint32(counter[0:4]),
+	}
+	s.XORKeyStream(out, in)
+}
+
+// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
+// nonce. It should only be used as part of the XChaCha20 construction.
+func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
+	x0, x1, x2, x3 := j0, j1, j2, j3
+	x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
+	x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
+	x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
+
+	for i := 0; i < 10; i++ {
+		x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+		x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+		x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+		x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+		x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+		x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+		x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+		x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
+	}
+
+	var out [8]uint32
+	out[0], out[1], out[2], out[3] = x0, x1, x2, x3
+	out[4], out[5], out[6], out[7] = x12, x13, x14, x15
+	return out
+}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
new file mode 100644
index 0000000000000000000000000000000000000000..91520d1de079f2958f132a50dbdfba24c3bb4814
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go
@@ -0,0 +1,16 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !s390x gccgo appengine
+
+package chacha20
+
+const (
+	bufSize = 64
+	haveAsm = false
+)
+
+func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
+	panic("not implemented")
+}
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
new file mode 100644
index 0000000000000000000000000000000000000000..0c1c671c40b77f6bdce6ecf16c4fc69ce57efb55
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go
@@ -0,0 +1,30 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x,!gccgo,!appengine
+
+package chacha20
+
+var haveAsm = hasVectorFacility()
+
+const bufSize = 256
+
+// hasVectorFacility reports whether the machine supports the vector
+// facility (vx).
+// Implementation in asm_s390x.s.
+func hasVectorFacility() bool
+
+// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
+// be called when the vector facility is available.
+// Implementation in asm_s390x.s.
+//go:noescape
+func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
+
+func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
+	xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len)
+}
+
+// EXRL targets, DO NOT CALL!
+func mvcSrcToBuf()
+func mvcBufToDst()
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
new file mode 100644
index 0000000000000000000000000000000000000000..98427c5e222afb50882af5fc9a8846aa90aa3dde
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s
@@ -0,0 +1,283 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x,!gccgo,!appengine
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// This is an implementation of the ChaCha20 encryption algorithm as
+// specified in RFC 7539. It uses vector instructions to compute
+// 4 keystream blocks in parallel (256 bytes) which are then XORed
+// with the bytes in the input slice.
+
+GLOBL ·constants<>(SB), RODATA|NOPTR, $32
+// BSWAP: swap bytes in each 4-byte element
+DATA ·constants<>+0x00(SB)/4, $0x03020100
+DATA ·constants<>+0x04(SB)/4, $0x07060504
+DATA ·constants<>+0x08(SB)/4, $0x0b0a0908
+DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c
+// J0: [j0, j1, j2, j3]
+DATA ·constants<>+0x10(SB)/4, $0x61707865
+DATA ·constants<>+0x14(SB)/4, $0x3320646e
+DATA ·constants<>+0x18(SB)/4, $0x79622d32
+DATA ·constants<>+0x1c(SB)/4, $0x6b206574
+
+// EXRL targets:
+TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0
+	MVC $1, (R1), (R8)
+	RET
+
+TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0
+	MVC $1, (R8), (R9)
+	RET
+
+#define BSWAP V5
+#define J0    V6
+#define KEY0  V7
+#define KEY1  V8
+#define NONCE V9
+#define CTR   V10
+#define M0    V11
+#define M1    V12
+#define M2    V13
+#define M3    V14
+#define INC   V15
+#define X0    V16
+#define X1    V17
+#define X2    V18
+#define X3    V19
+#define X4    V20
+#define X5    V21
+#define X6    V22
+#define X7    V23
+#define X8    V24
+#define X9    V25
+#define X10   V26
+#define X11   V27
+#define X12   V28
+#define X13   V29
+#define X14   V30
+#define X15   V31
+
+#define NUM_ROUNDS 20
+
+#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \
+	VAF    a1, a0, a0  \
+	VAF    b1, b0, b0  \
+	VAF    c1, c0, c0  \
+	VAF    d1, d0, d0  \
+	VX     a0, a2, a2  \
+	VX     b0, b2, b2  \
+	VX     c0, c2, c2  \
+	VX     d0, d2, d2  \
+	VERLLF $16, a2, a2 \
+	VERLLF $16, b2, b2 \
+	VERLLF $16, c2, c2 \
+	VERLLF $16, d2, d2 \
+	VAF    a2, a3, a3  \
+	VAF    b2, b3, b3  \
+	VAF    c2, c3, c3  \
+	VAF    d2, d3, d3  \
+	VX     a3, a1, a1  \
+	VX     b3, b1, b1  \
+	VX     c3, c1, c1  \
+	VX     d3, d1, d1  \
+	VERLLF $12, a1, a1 \
+	VERLLF $12, b1, b1 \
+	VERLLF $12, c1, c1 \
+	VERLLF $12, d1, d1 \
+	VAF    a1, a0, a0  \
+	VAF    b1, b0, b0  \
+	VAF    c1, c0, c0  \
+	VAF    d1, d0, d0  \
+	VX     a0, a2, a2  \
+	VX     b0, b2, b2  \
+	VX     c0, c2, c2  \
+	VX     d0, d2, d2  \
+	VERLLF $8, a2, a2  \
+	VERLLF $8, b2, b2  \
+	VERLLF $8, c2, c2  \
+	VERLLF $8, d2, d2  \
+	VAF    a2, a3, a3  \
+	VAF    b2, b3, b3  \
+	VAF    c2, c3, c3  \
+	VAF    d2, d3, d3  \
+	VX     a3, a1, a1  \
+	VX     b3, b1, b1  \
+	VX     c3, c1, c1  \
+	VX     d3, d1, d1  \
+	VERLLF $7, a1, a1  \
+	VERLLF $7, b1, b1  \
+	VERLLF $7, c1, c1  \
+	VERLLF $7, d1, d1
+
+#define PERMUTE(mask, v0, v1, v2, v3) \
+	VPERM v0, v0, mask, v0 \
+	VPERM v1, v1, mask, v1 \
+	VPERM v2, v2, mask, v2 \
+	VPERM v3, v3, mask, v3
+
+#define ADDV(x, v0, v1, v2, v3) \
+	VAF x, v0, v0 \
+	VAF x, v1, v1 \
+	VAF x, v2, v2 \
+	VAF x, v3, v3
+
+#define XORV(off, dst, src, v0, v1, v2, v3) \
+	VLM  off(src), M0, M3          \
+	PERMUTE(BSWAP, v0, v1, v2, v3) \
+	VX   v0, M0, M0                \
+	VX   v1, M1, M1                \
+	VX   v2, M2, M2                \
+	VX   v3, M3, M3                \
+	VSTM M0, M3, off(dst)
+
+#define SHUFFLE(a, b, c, d, t, u, v, w) \
+	VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]}
+	VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]}
+	VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]}
+	VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]}
+	VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]}
+	VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]}
+	VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
+	VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}
+
+// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
+TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
+	MOVD $·constants<>(SB), R1
+	MOVD dst+0(FP), R2         // R2=&dst[0]
+	LMG  src+24(FP), R3, R4    // R3=&src[0] R4=len(src)
+	MOVD key+48(FP), R5        // R5=key
+	MOVD nonce+56(FP), R6      // R6=nonce
+	MOVD counter+64(FP), R7    // R7=counter
+	MOVD buf+72(FP), R8        // R8=buf
+	MOVD len+80(FP), R9        // R9=len
+
+	// load BSWAP and J0
+	VLM (R1), BSWAP, J0
+
+	// set up tail buffer
+	ADD     $-1, R4, R12
+	MOVBZ   R12, R12
+	CMPUBEQ R12, $255, aligned
+	MOVD    R4, R1
+	AND     $~255, R1
+	MOVD    $(R3)(R1*1), R1
+	EXRL    $·mvcSrcToBuf(SB), R12
+	MOVD    $255, R0
+	SUB     R12, R0
+	MOVD    R0, (R9)               // update len
+
+aligned:
+	// setup
+	MOVD  $95, R0
+	VLM   (R5), KEY0, KEY1
+	VLL   R0, (R6), NONCE
+	VZERO M0
+	VLEIB $7, $32, M0
+	VSRLB M0, NONCE, NONCE
+
+	// initialize counter values
+	VLREPF (R7), CTR
+	VZERO  INC
+	VLEIF  $1, $1, INC
+	VLEIF  $2, $2, INC
+	VLEIF  $3, $3, INC
+	VAF    INC, CTR, CTR
+	VREPIF $4, INC
+
+chacha:
+	VREPF $0, J0, X0
+	VREPF $1, J0, X1
+	VREPF $2, J0, X2
+	VREPF $3, J0, X3
+	VREPF $0, KEY0, X4
+	VREPF $1, KEY0, X5
+	VREPF $2, KEY0, X6
+	VREPF $3, KEY0, X7
+	VREPF $0, KEY1, X8
+	VREPF $1, KEY1, X9
+	VREPF $2, KEY1, X10
+	VREPF $3, KEY1, X11
+	VLR   CTR, X12
+	VREPF $1, NONCE, X13
+	VREPF $2, NONCE, X14
+	VREPF $3, NONCE, X15
+
+	MOVD $(NUM_ROUNDS/2), R1
+
+loop:
+	ROUND4(X0, X4, X12,  X8, X1, X5, X13,  X9, X2, X6, X14, X10, X3, X7, X15, X11)
+	ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8,  X3, X4, X14, X9)
+
+	ADD $-1, R1
+	BNE loop
+
+	// decrement length
+	ADD $-256, R4
+	BLT tail
+
+continue:
+	// rearrange vectors
+	SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
+	ADDV(J0, X0, X1, X2, X3)
+	SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3)
+	ADDV(KEY0, X4, X5, X6, X7)
+	SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3)
+	ADDV(KEY1, X8, X9, X10, X11)
+	VAF CTR, X12, X12
+	SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3)
+	ADDV(NONCE, X12, X13, X14, X15)
+
+	// increment counters
+	VAF INC, CTR, CTR
+
+	// xor keystream with plaintext
+	XORV(0*64, R2, R3, X0, X4,  X8, X12)
+	XORV(1*64, R2, R3, X1, X5,  X9, X13)
+	XORV(2*64, R2, R3, X2, X6, X10, X14)
+	XORV(3*64, R2, R3, X3, X7, X11, X15)
+
+	// increment pointers
+	MOVD $256(R2), R2
+	MOVD $256(R3), R3
+
+	CMPBNE  R4, $0, chacha
+	CMPUBEQ R12, $255, return
+	EXRL    $·mvcBufToDst(SB), R12 // len was updated during setup
+
+return:
+	VSTEF $0, CTR, (R7)
+	RET
+
+tail:
+	MOVD R2, R9
+	MOVD R8, R2
+	MOVD R8, R3
+	MOVD $0, R4
+	JMP  continue
+
+// func hasVectorFacility() bool
+TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
+	MOVD  $x-24(SP), R1
+	XC    $24, 0(R1), 0(R1) // clear the storage
+	MOVD  $2, R0            // R0 is the number of double words stored -1
+	WORD  $0xB2B01000       // STFLE 0(R1)
+	XOR   R0, R0            // reset the value of R0
+	MOVBZ z-8(SP), R1
+	AND   $0x40, R1
+	BEQ   novector
+
+vectorinstalled:
+	// check if the vector instruction has been enabled
+	VLEIB  $0, $0xF, V16
+	VLGVB  $0, V16, R1
+	CMPBNE R1, $0xF, novector
+	MOVB   $1, ret+0(FP)      // have vx
+	RET
+
+novector:
+	MOVB $0, ret+0(FP) // no vx
+	RET
diff --git a/vendor/golang.org/x/crypto/internal/chacha20/xor.go b/vendor/golang.org/x/crypto/internal/chacha20/xor.go
new file mode 100644
index 0000000000000000000000000000000000000000..9c5ba0b33ae3a873c3c8f1aa7d0c9f303d65b74d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/chacha20/xor.go
@@ -0,0 +1,43 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found src the LICENSE file.
+
+package chacha20
+
+import (
+	"runtime"
+)
+
+// Platforms that have fast unaligned 32-bit little endian accesses.
+const unaligned = runtime.GOARCH == "386" ||
+	runtime.GOARCH == "amd64" ||
+	runtime.GOARCH == "arm64" ||
+	runtime.GOARCH == "ppc64le" ||
+	runtime.GOARCH == "s390x"
+
+// xor reads a little endian uint32 from src, XORs it with u and
+// places the result in little endian byte order in dst.
+func xor(dst, src []byte, u uint32) {
+	_, _ = src[3], dst[3] // eliminate bounds checks
+	if unaligned {
+		// The compiler should optimize this code into
+		// 32-bit unaligned little endian loads and stores.
+		// TODO: delete once the compiler does a reliably
+		// good job with the generic code below.
+		// See issue #25111 for more details.
+		v := uint32(src[0])
+		v |= uint32(src[1]) << 8
+		v |= uint32(src[2]) << 16
+		v |= uint32(src[3]) << 24
+		v ^= u
+		dst[0] = byte(v)
+		dst[1] = byte(v >> 8)
+		dst[2] = byte(v >> 16)
+		dst[3] = byte(v >> 24)
+	} else {
+		dst[0] = src[0] ^ byte(u)
+		dst[1] = src[1] ^ byte(u>>8)
+		dst[2] = src[2] ^ byte(u>>16)
+		dst[3] = src[3] ^ byte(u>>24)
+	}
+}