diff --git a/.github/workflows/ci-image.yml b/.github/workflows/ci-image.yml
new file mode 100644
index 0000000..2a4a60f
--- /dev/null
+++ b/.github/workflows/ci-image.yml
@@ -0,0 +1,39 @@
+name: CI - Release
+
+on:
+ push:
+
+jobs:
+ release-image:
+ permissions:
+ id-token: write
+ contents: write
+ runs-on: docker
+ steps:
+ - name: 'Checkout scm ${{ inputs.commitOrTag }}'
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ ref: ${{ inputs.commitOrTag }}
+
+ - name: Image tag
+ id: set-tag
+ run: echo "tag=$(git rev-parse --short=7 HEAD)" >> $GITHUB_OUTPUT
+ shell: bash
+
+ - name: Build Docker images
+ run: docker build -t zilliqa/zilliqa-relayer:experimental-${{ steps.set-tag.outputs.tag }} -t zilliqa/zilliqa-relayer:latest .
+ shell: bash
+
+ - name: Login to the DockerHub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_PASSWORD }}
+
+ - name: Push Docker images to Dockerhub
+ if: github.actor != 'dependabot[bot]' && github.ref_name == 'main'
+ run: |
+ docker push zilliqa/zilliqa-relayer:experimental-${{ steps.set-tag.outputs.tag }}
+ docker push zilliqa/zilliqa-relayer:latest
+ shell: bash
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7f71c6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+*~
+\#*
+.\#*
+zilliqa-relayer
+.idea
+bolt.bin
+config.local.yaml
+constants.xml
+cross_chain_manager_admin.json
+xiaohuo.wallet
+zilliqa.wallet
+poly.wallet
+relayer.wallet
+secrets
+config.devnet.yaml
+config.testnet.yaml
+config.production.yaml
+target_contracts_local.json
+target_contracts_devnet.json
+target_contracts_production.json
+audit.log
+zil_relayer
+wallet.dat
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..038b8bd
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,14 @@
+FROM golang:1.15 AS build
+WORKDIR /app/zilliqa-relayer
+COPY . ./
+RUN go build
+#RUN git clone https://github.com/Zilliqa/zilliqa-relayer.git && \
+# cd zilliqa-relayer && \
+# go build
+
+FROM ubuntu:18.04
+RUN apt-get update && apt-get install -y ca-certificates
+WORKDIR /app
+COPY run.sh run.sh
+COPY --from=build /app/zilliqa-relayer/zilliqa-relayer zilliqa-relayer
+ENTRYPOINT ["/bin/bash", "run.sh"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4e61c8d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
index 5274f53..ee4e691 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,135 @@
-# zilliqa-relayer
\ No newline at end of file
+# zilliqa-relayer
+
+*This program is still under developing!*
+
+Zilliqa Relayer is an important character of Poly cross-chain interactive protocol which is responsible for relaying cross-chain transaction from and to Zilliqa.
+
+## Build From Source
+
+### Prerequisites
+
+- [Golang](https://golang.org/doc/install) version 1.14 or later
+
+### Build
+
+```shell
+git clone https://github.com/polynetwork/zil-relayer.git
+cd zil-relayer
+./build.sh
+```
+
+After building the source code successfully, you should see the executable program `zilliqa-relayer`.
+
+### Build Docker Image
+
+```
+docker build -t polynetwork/zilliqa-relayer .
+```
+
+This command will copy config.yaml to /app/config.yaml in the image. So you need to prepare config.yaml before running this command and you should start the zilliqa-relayer in container basing on the configuration in /app/config.yaml.
+
+
+## Run Relayer
+Before you can run the relayer you will need to create a wallet file of PolyNetwork by running(build Poly CLI first):
+
+```shell
+./poly account add -d
+```
+
+After creation, you need to register it as a Relayer to Poly net and get consensus nodes approving your registeration. And then you can send transaction to Poly net and start relaying.
+
+Before running, you need feed the configuration file `config.yaml`.
+
+`practice_only: true` will stop the relayer sending any actual transactions - it just prints what it would have done.
+`debug: true` will produce a bunch of debug info useful when debugging ZilBridge sync.
+
+```yaml
+practice_only: false
+debug: true
+zil_config:
+ zil_api: https://api.zilliqa.com
+ zil_chain_id: 111
+ zil_message_version: 1
+ zil_force_height: 0
+ zil_monitor_interval: 10
+ zil_headers_per_batch: 2
+ corss_chain_manager_address: zil1tjru7m5zdn3x6k0t72nzmmpz62e5qds62nte9t
+ cross_chain_manager_proxy_address: zil1n7wkwr0xxslwsrhnqtjrwlus80dp5ncnlpaw93
+ side_chain_id: 85
+ key_store_path: zilliqa.wallet
+ key_store_pwd_set:
+ 6c89b62d65dc632e259b96f7ae2f1d68a27e3383: ""
+poly_config:
+ poly_wallet_file: poly.wallet
+ poly_wallet_pwd:
+ poly_start_height: 0
+ poly_monitor_interval: 2
+ entrance_contract_address: "0300000000000000000000000000000000000000"
+ rest_url: http://poly.com
+target_contracts: target_contracts.json
+db_path: persistence
+```
+
+A sample keystore file could be:
+
+```text
+{"address":"7d48043742a1103042d327111746531ca26be9be","id":"6cd445ed-8f5f-4565-af2a-cc2306a82b73","version":3,"crypto":{"cipher":"aes-128-ctr","ciphertext":"d136660a4e5664709031ebc162616556e8c812ab37d0157ea3276aa08d0a6c2d","kdf":"pbkdf2","mac":"b30dd459f1fd9d99c0b2f3452ccd2bf11414ad92d32ac70d1d7b52f17281b4e5","cipherparams":{"iv":"6a14f95c8cbafe7d1f317bec88e9d1b8"},"kdfparams":{"n":8192,"c":262144,"r":8,"p":1,"dklen":32,"salt":"c4939e7cead32935d1972a2cd06d249dd501181e6ad2d1872fa0eb397d7fea20"}}}
+```
+# Relayer Container Administration
+## Running the Relayer Container
+### Prerequisites:
+If you are running via docker-compose, you'll need to install docker-compose first via the following guide:
+```
+https://docs.docker.com/compose/install/
+```
+
+You need the following files and folders created:
+If persistence is already created:
+```
+./persistence/bolt.bin
+```
+If persistence folder is not created:
+```
+create a folder named 'persistence'. The container will use that folder to store the bolt.bin file.
+```
+Configuration Files:
+```
+secrets/config.local.yaml
+secrets/target_contracts.json
+secrets/poly.wallet
+secrets/zilliqa.wallet
+```
+### Running Relayer via Docker Container
+```
+./docker-run
+```
+
+### Running Relayer via Docker Compose
+```
+docker-compose up -d
+```
+## Stopping the Relayer
+### Stopping Relayer via Docker Container
+```
+docker stop zilliqa-relayer && docker rm zilliqa-relayer
+```
+### Stopping Relayer via Docker Compose
+```
+docker-compose down
+```
+## Getting logs
+```
+docker logs -f zilliqa-relayer
+```
+
+
+## Other Resources
+
+- [zilliqa cross chain manager proxy](https://github.com/Zilliqa/zilliqa-contracts/blob/main/contracts/ZilCrossChainManagerProxy.scilla)
+- [zilliqa cross chain manager](https://github.com/Zilliqa/zilliqa-contracts/blob/main/contracts/ZilCrossChainManager.scilla)
+- [zilliqa lock proxy](https://github.com/Zilliqa/zilliqa-contracts/blob/main/contracts/LockProxy.scilla)
+- [polynetwork](https://github.com/polynetwork/poly)
+
+
+
+
diff --git a/build-docker.sh b/build-docker.sh
new file mode 100755
index 0000000..deab546
--- /dev/null
+++ b/build-docker.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+docker build -t polynetwork/zilliqa-relayer .
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..b972750
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+go build
\ No newline at end of file
diff --git a/cmd/root.go b/cmd/root.go
new file mode 100644
index 0000000..506ea8f
--- /dev/null
+++ b/cmd/root.go
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package cmd
+
+import (
+ log "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+
+ "os"
+)
+
+var RootCmd = &cobra.Command{
+ Use: "zilliqa-relayer",
+ Short: "To run zilliqa relayer for poly network",
+ Long: `To run zilliqa relayer for poly network`,
+ Run: func(cmd *cobra.Command, args []string) {
+ },
+}
+
+func Execute() {
+ if err := RootCmd.Execute(); err != nil {
+ log.Error(err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/run.go b/cmd/run.go
new file mode 100644
index 0000000..00eb5ca
--- /dev/null
+++ b/cmd/run.go
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package cmd
+
+import (
+ "encoding/json"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ poly_go_sdk "github.com/polynetwork/poly-go-sdk"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/db"
+ "github.com/polynetwork/zilliqa-relayer/service"
+ log "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+ "github.com/spf13/viper"
+ "io/ioutil"
+ "os"
+ "path"
+)
+
+var cfgFile string
+
+func init() {
+ cobra.OnInitialize(initConfig)
+ RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+
+ RootCmd.AddCommand(runCmd)
+ log.SetFormatter(&log.TextFormatter{
+ FullTimestamp: true,
+ })
+}
+
+func initConfig() {
+ if cfgFile != "" {
+ // Use config file from the flag.
+ viper.SetConfigFile(cfgFile)
+ } else {
+ viper.AddConfigPath("./")
+ viper.SetConfigName("config.local")
+ }
+
+ viper.AutomaticEnv()
+
+ err := viper.ReadInConfig()
+ if err == nil {
+ log.Info("Using config file:", viper.ConfigFileUsed())
+ } else {
+ log.Error(err.Error())
+ }
+}
+
+func setUpPoly(poly *poly_go_sdk.PolySdk, RpcAddr string) error {
+ poly.NewRpcClient().SetAddress(RpcAddr)
+ hdr, err := poly.GetHeaderByHeight(0)
+ if err != nil {
+ return err
+ }
+ poly.SetChainId(hdr.ChainID)
+ return nil
+}
+
+func checkIfExist(dir string) bool {
+ _, err := os.Stat(dir)
+ if err != nil && !os.IsExist(err) {
+ return false
+ }
+ return true
+}
+
+var runCmd = &cobra.Command{
+ Use: "run",
+ Short: "Run zilliqa relayer",
+ Long: `Run zilliqa relayer`,
+ Run: func(cmd *cobra.Command, args []string) {
+ viper.SetDefault("debug", false)
+ viper.SetDefault("practiceOnly", false)
+ debugInfo := viper.GetBool("debug")
+ practiceOnly := viper.GetBool("practice_only")
+ zilConfigMap := viper.GetStringMap("zil_config")
+ targetContractsPath := viper.GetString("target_contracts")
+ dbPath := viper.GetString("db_path")
+ removeDb := viper.GetBool("remove_db")
+ bytes, e := ioutil.ReadFile(targetContractsPath)
+ if e != nil {
+ log.Errorf("read target contracts error: %s, path: %s\n", e.Error(), targetContractsPath)
+ return
+ }
+ var targetContract []map[string]map[string][]uint64
+ e2 := json.Unmarshal(bytes, &targetContract)
+ if e2 != nil {
+ log.Errorf("unmarshal target contracts error: %s\n", e2.Error())
+ return
+ }
+ log.Info(targetContract)
+ zilConfig := &config.ZILConfig{
+ ZilApiEndpoint: zilConfigMap["zil_api"].(string),
+ ZilChainId: zilConfigMap["zil_chain_id"].(int),
+ ZilMessageVersion: zilConfigMap["zil_message_version"].(int),
+ ZilForceHeight: uint64(zilConfigMap["zil_force_height"].(int)),
+ ZilMonitorInterval: uint32(zilConfigMap["zil_monitor_interval"].(int)),
+ ZilHeadersPerBatch: uint32(zilConfigMap["zil_headers_per_batch"].(int)),
+ SideChainId: uint64(zilConfigMap["side_chain_id"].(int)),
+ CrossChainManagerContract: zilConfigMap["corss_chain_manager_address"].(string),
+ CrossChainManagerProxyContract: zilConfigMap["cross_chain_manager_proxy_address"].(string),
+ MaxExistTxEpoch: zilConfigMap["max_exist_tx_epoch"].(int),
+ KeyStorePath: zilConfigMap["key_store_path"].(string),
+ KeyStorePwdSet: zilConfigMap["key_store_pwd_set"].(map[string]interface{}),
+ }
+
+ polyConfigMap := viper.GetStringMap("poly_config")
+
+ polyConfig := &config.POLYConfig{
+ PolyWalletFile: polyConfigMap["poly_wallet_file"].(string),
+ PolyWalletPassword: polyConfigMap["poly_wallet_pwd"].(string),
+ PolyStartHeight: uint32(polyConfigMap["poly_start_height"].(int)),
+ PolyMonitorInterval: uint32(polyConfigMap["poly_monitor_interval"].(int)),
+ EntranceContractAddress: polyConfigMap["entrance_contract_address"].(string),
+ RestUrl: polyConfigMap["rest_url"].(string),
+ }
+
+ cfg := &config.Config{
+ ZilConfig: zilConfig,
+ PolyConfig: polyConfig,
+ TargetContracts: targetContract,
+ Path: dbPath,
+ RemoveDB: removeDb,
+ }
+
+ cfgStr, _ := json.Marshal(cfg)
+ log.Infof("config file: %s\n", cfgStr)
+
+ zilSdk := provider.NewProvider(cfg.ZilConfig.ZilApiEndpoint)
+ polySdk := poly_go_sdk.NewPolySdk()
+ err1 := setUpPoly(polySdk, cfg.PolyConfig.RestUrl)
+ if err1 != nil {
+ log.Errorf("init poly sdk error: %s\n", err1.Error())
+ return
+ }
+
+ if cfg.RemoveDB {
+ os.Remove(path.Join(cfg.Path, "bolt.bin"))
+ }
+
+ if !checkIfExist(cfg.Path) {
+ os.Mkdir(cfg.Path, os.ModePerm)
+ }
+ boltDB, err2 := db.NewBoltDB(cfg.Path)
+ if err2 != nil {
+ log.Errorf("cannot init bolt db: %s\n", err2.Error())
+ return
+ }
+
+ // zil to poly
+ zilliqaManager, err := service.NewZilliqaSyncManager(cfg, zilSdk, polySdk, boltDB, debugInfo, practiceOnly)
+ if err != nil {
+ log.Errorf("init zilliqamanger error: %s\n", err.Error())
+ return
+ }
+ // poly to zil
+ polyManager, err1 := service.NewPolySyncManager(cfg, zilSdk, polySdk, boltDB, cfg.ZilConfig.CrossChainManagerContract, cfg.ZilConfig.CrossChainManagerProxyContract)
+ if err1 != nil {
+ log.Errorf("init polymanager error: %s\n", err1.Error())
+ return
+ }
+
+ zilliqaManager.Run(true)
+ polyManager.Run(true)
+
+ service.WaitToExit()
+
+ },
+}
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000..b4660a1
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,23 @@
+zil_config:
+ zil_api: https://api.zilliqa.com
+ zil_chain_id: 111
+ zil_message_version: 1
+ zil_force_height: 0
+ zil_monitor_interval: 10
+ zil_headers_per_batch: 2
+ corss_chain_manager_address: zil1tjru7m5zdn3x6k0t72nzmmpz62e5qds62nte9t
+ cross_chain_manager_proxy_address: zil1n7wkwr0xxslwsrhnqtjrwlus80dp5ncnlpaw93
+ side_chain_id: 85
+ key_store_path: zilliqa.wallet
+ max_exist_tx_epoch: 5
+ key_store_pwd_set:
+ 6c89b62d65dc632e259b96f7ae2f1d68a27e3383: ""
+poly_config:
+ poly_wallet_file: poly.wallet
+ poly_wallet_pwd:
+ poly_start_height: 0
+ poly_monitor_interval: 2
+ entrance_contract_address: "0300000000000000000000000000000000000000"
+ rest_url: http://poly.com
+target_contracts: target_contracts.json
+remove_db: false
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..511c930
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package config
+
+const (
+ OntUsefulBlockNum = 1
+)
+
+type Config struct {
+ ZilConfig *ZILConfig
+ PolyConfig *POLYConfig
+ Path string
+ RemoveDB bool
+ TargetContracts []map[string]map[string][]uint64
+}
+
+type ZILConfig struct {
+ ZilApiEndpoint string
+ ZilChainId int
+ ZilMessageVersion int
+ ZilMonitorInterval uint32
+ ZilHeadersPerBatch uint32
+ ZilForceHeight uint64
+ SideChainId uint64
+ CrossChainManagerContract string
+ CrossChainManagerProxyContract string
+ MaxExistTxEpoch int
+ KeyStorePath string
+ KeyStorePwdSet map[string]interface{}
+}
+
+type POLYConfig struct {
+ PolyWalletFile string
+ PolyWalletPassword string
+ PolyStartHeight uint32
+ PolyMonitorInterval uint32
+ EntranceContractAddress string
+ RestUrl string
+}
diff --git a/db/db.go b/db/db.go
new file mode 100644
index 0000000..e21d1cf
--- /dev/null
+++ b/db/db.go
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package db
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "github.com/boltdb/bolt"
+ "path"
+ "strings"
+ "sync"
+)
+
+const MAX_NUM = 1000
+
+type BoltDB struct {
+ rwLock *sync.RWMutex
+ db *bolt.DB
+ filePath string
+}
+
+var (
+ BKTCheck = []byte("Check")
+ BKTRetry = []byte("Retry")
+ BKTHeight = []byte("Height")
+)
+
+func NewBoltDB(filePath string) (*BoltDB, error) {
+ if !strings.Contains(filePath, ".bin") {
+ filePath = path.Join(filePath, "bolt.bin")
+ }
+
+ w := new(BoltDB)
+ db, err := bolt.Open(filePath, 0644, &bolt.Options{InitialMmapSize: 500000})
+ if err != nil {
+ return nil, err
+ }
+
+ w.db = db
+ w.rwLock = new(sync.RWMutex)
+ w.filePath = filePath
+
+ // poly check
+ if err = db.Update(func(btx *bolt.Tx) error {
+ _, err := btx.CreateBucketIfNotExists(BKTCheck)
+ if err != nil {
+ return err
+ }
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+
+ // poly retry
+ if err = db.Update(func(btx *bolt.Tx) error {
+ _, err := btx.CreateBucketIfNotExists(BKTRetry)
+ if err != nil {
+ return err
+ }
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+
+ // poly check
+ if err = db.Update(func(btx *bolt.Tx) error {
+ _, err := btx.CreateBucketIfNotExists(BKTHeight)
+ if err != nil {
+ return err
+ }
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+
+ return w, nil
+}
+
+func (w *BoltDB) PutRetry(k []byte) error {
+ w.rwLock.Lock()
+ defer w.rwLock.Unlock()
+
+ return w.db.Update(func(btx *bolt.Tx) error {
+ bucket := btx.Bucket(BKTRetry)
+ err := bucket.Put(k, []byte{0x00})
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+}
+
+func (w *BoltDB) DeleteRetry(k []byte) error {
+ w.rwLock.Lock()
+ defer w.rwLock.Unlock()
+
+ return w.db.Update(func(tx *bolt.Tx) error {
+ bucket := tx.Bucket(BKTRetry)
+ err := bucket.Delete(k)
+ if err != nil {
+ return err
+ }
+ return nil
+ })
+}
+
+func (w *BoltDB) PutCheck(txHash string, v []byte) error {
+ w.rwLock.Lock()
+ defer w.rwLock.Unlock()
+
+ k, err := hex.DecodeString(txHash)
+ if err != nil {
+ return err
+ }
+ return w.db.Update(func(btx *bolt.Tx) error {
+ bucket := btx.Bucket(BKTCheck)
+ err := bucket.Put(k, v)
+ if err != nil {
+ return err
+ }
+
+ return nil
+ })
+}
+
+func (w *BoltDB) GetAllRetry() ([][]byte, error) {
+ w.rwLock.Lock()
+ defer w.rwLock.Unlock()
+
+ retryList := make([][]byte, 0)
+ err := w.db.Update(func(tx *bolt.Tx) error {
+ bw := tx.Bucket(BKTRetry)
+ bw.ForEach(func(k, _ []byte) error {
+ _k := make([]byte, len(k))
+ copy(_k, k)
+ retryList = append(retryList, _k)
+ if len(retryList) >= MAX_NUM {
+ return fmt.Errorf("max num")
+ }
+ return nil
+ })
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return retryList, nil
+}
+
+func (w *BoltDB) UpdatePolyHeight(h uint32) error {
+ w.rwLock.Lock()
+ defer w.rwLock.Unlock()
+
+ raw := make([]byte, 4)
+ binary.LittleEndian.PutUint32(raw, h)
+
+ return w.db.Update(func(tx *bolt.Tx) error {
+ bkt := tx.Bucket(BKTHeight)
+ return bkt.Put([]byte("poly_height"), raw)
+ })
+}
+
+func (w *BoltDB) GetPolyHeight() uint32 {
+ w.rwLock.RLock()
+ defer w.rwLock.RUnlock()
+
+ var h uint32
+ _ = w.db.View(func(tx *bolt.Tx) error {
+ bkt := tx.Bucket(BKTHeight)
+ raw := bkt.Get([]byte("poly_height"))
+ if len(raw) == 0 {
+ h = 0
+ return nil
+ }
+ h = binary.LittleEndian.Uint32(raw)
+ return nil
+ })
+ return h
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..157d6e4
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,11 @@
+version: "3.9"
+services:
+ zilliqa-relayer:
+ container_name: zilliqa-relayer
+ build: .
+ volumes:
+ - ./persistence:/app/persistence
+ - ./secrets/config.local.yaml:/app/config.local.yaml
+ - ./secrets/target_contracts.json:/app/target_contracts.json
+ - ./secrets/poly.wallet:/app/poly.wallet
+ - ./secrets/zilliqa.wallet:/app/zilliqa.wallet
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..ed342e2
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,21 @@
+module github.com/polynetwork/zilliqa-relayer
+
+go 1.15
+
+require (
+ github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20210927032600-4c733f2cb879
+ github.com/boltdb/bolt v1.3.1
+ github.com/btcsuite/btcd v0.20.1-beta
+ github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e // indirect
+ github.com/ethereum/go-ethereum v1.9.24 // indirect
+ github.com/magiconair/properties v1.8.1
+ github.com/ontio/ontology v1.11.0
+ github.com/ontio/ontology-crypto v1.0.9
+ github.com/polynetwork/poly v0.0.0-20200715030435-4f1d1a0adb44
+ github.com/polynetwork/poly-go-sdk v0.0.0-20200817120957-365691ad3493
+ github.com/sirupsen/logrus v1.7.0
+ github.com/spf13/cobra v1.1.1
+ github.com/spf13/viper v1.7.0
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
+ launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..08f2f03
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,900 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904=
+github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
+github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
+github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
+github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
+github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
+github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
+github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
+github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
+github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
+github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
+github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw=
+github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
+github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc=
+github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw=
+github.com/JohnCGriffin/overflow v0.0.0-20170615021017-4d914c927216 h1:2ZboyJ8vl75fGesnG9NpMTD2DyQI3FzMXy4x752rGF0=
+github.com/JohnCGriffin/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
+github.com/OpenBazaar/jsonpb v0.0.0-20171123000858-37d32ddf4eef/go.mod h1:55mCznBcN9WQgrtgaAkv+p2LxeW/tQRdidyyE9D0I5k=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
+github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
+github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
+github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
+github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI=
+github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
+github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20210927032600-4c733f2cb879 h1:/OXqInjRm8CEd81EEFCGJ5Q24TTlY1/qu6DQ0D91WPA=
+github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20210927032600-4c733f2cb879/go.mod h1:XLd05IRvH+nQt2lLvW6I2pfWBtRYE4i8Tpx45xBrlUE=
+github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
+github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
+github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
+github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
+github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
+github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
+github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
+github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
+github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
+github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
+github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
+github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4=
+github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
+github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE=
+github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
+github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
+github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw=
+github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cosmos/cosmos-sdk v0.38.4 h1:jPZOvhMQkm7wwwzcLxuluhVpKfuIgddNGt999pAiz/Y=
+github.com/cosmos/cosmos-sdk v0.38.4/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw=
+github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
+github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
+github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
+github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
+github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dchest/siphash v1.2.1 h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4=
+github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
+github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0=
+github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
+github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
+github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
+github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
+github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
+github.com/ethereum/go-ethereum v1.9.13/go.mod h1:qwN9d1GLyDh0N7Ab8bMGd0H9knaji2jOBm2RrMGjXls=
+github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0=
+github.com/ethereum/go-ethereum v1.9.24 h1:6AK+ORt3EMDO+FTjzXy/AQwHMbu52J2nYHIjyQX9azQ=
+github.com/ethereum/go-ethereum v1.9.24/go.mod h1:JIfVb6esrqALTExdz9hRYvrP0xBDf6wCncIu1hNwHpM=
+github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
+github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
+github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
+github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
+github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
+github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
+github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
+github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
+github.com/gcash/bchd v0.14.7/go.mod h1:Gk/O1ktRVW5Kao0RsnVXp3bWxeYQadqawZ1Im9HE78M=
+github.com/gcash/bchd v0.15.2/go.mod h1:k9wIjgwnhbrAw+ruIPZ2tHZMzfFNdyUnORZZX7lqXGY=
+github.com/gcash/bchd v0.16.4 h1:+aq3sk3MDTLLwfDldvJaQBbpALCiDMH1bT32qIeHYos=
+github.com/gcash/bchd v0.16.4/go.mod h1:gR67ljCexTNwbKYN3wjbRHi9lYLp4rMomy1UQ3E1USA=
+github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 h1:3pZvWJ8MSfWstGrb8Hfh4ZpLyZNcXypcGx2Ju4ZibVM=
+github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6/go.mod h1:PpfmXTLfjRp7Tf6v/DCGTRXHz+VFbiRcsoUxi7HvwlQ=
+github.com/gcash/bchutil v0.0.0-20190625002603-800e62fe9aff/go.mod h1:zXSP0Fg2L52wpSEDApQDQMiSygnQiK5HDquDl0a5BHg=
+github.com/gcash/bchutil v0.0.0-20191012211144-98e73ec336ba/go.mod h1:nUIrcbbtEQdCsRwcp+j/CndDKMQE9Fi8p2F8cIZmIqI=
+github.com/gcash/bchutil v0.0.0-20200229194731-128fc9884722/go.mod h1:wB++2ZcHUvGLN1OgO9swBmJK1vmyshJLW9SNS+apXwc=
+github.com/gcash/bchutil v0.0.0-20200506001747-c2894cd54b33 h1:HNO6rKAfeYm6hE+0KXMfRomDZ8cQNlBmWirH8PSk9MY=
+github.com/gcash/bchutil v0.0.0-20200506001747-c2894cd54b33/go.mod h1:wB++2ZcHUvGLN1OgO9swBmJK1vmyshJLW9SNS+apXwc=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
+github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5+85/pbdkiYcBqM1JWmhpAXLmy0fw=
+github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64=
+github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
+github.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI=
+github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
+github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
+github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM=
+github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
+github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
+github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw=
+github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
+github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
+github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
+github.com/improbable-eng/grpc-web v0.9.1/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
+github.com/improbable-eng/grpc-web v0.12.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/itchyny/base58-go v0.1.0 h1:zF5spLDo956exUAD17o+7GamZTRkXOZlqJjRciZwd1I=
+github.com/itchyny/base58-go v0.1.0/go.mod h1:SrMWPE3DFuJJp1M/RUhu4fccp/y9AlB8AL3o3duPToU=
+github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v0.0.0-20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
+github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
+github.com/joeqian10/neo-gogogo v0.0.0-20200611102831-c17de5e1f0f8 h1:C+PIS6p7oQ4DwT+1IJkIvS+BMLn9TodglcqcGzhE+fQ=
+github.com/joeqian10/neo-gogogo v0.0.0-20200611102831-c17de5e1f0f8/go.mod h1:1fVDp4U1ROZQBRIooecbGNHHJpfs3bG9528sqlZ096g=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
+github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
+github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
+github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
+github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
+github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3tNxjXGHeul8z2t6H2N2TlAqpKe5yryJztRx4Jk=
+github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/ontio/go-bip32 v0.0.0-20190520025953-d3cea6894a2b h1:UQDN12BzdWhXQL0t2QcRixHqAIG+JKNvQ20DhrIODtU=
+github.com/ontio/go-bip32 v0.0.0-20190520025953-d3cea6894a2b/go.mod h1:J0eVc7BEMmVVXbGv9PHoxjRSEwOwLr0qfzPk8Rdl5iw=
+github.com/ontio/ontology v1.11.0 h1:0T/hxFDHQqRcs1+yEdgaym5YIvGx5yebOsHYdKVWgHI=
+github.com/ontio/ontology v1.11.0/go.mod h1:Qw74bfTBlIQka+jQX4nXuWvyOYGGt368/V7XFxaf4tY=
+github.com/ontio/ontology-crypto v1.0.9 h1:6fxBsz3W4CcdJk4/9QO7j0Qq7NdlP2ixPrViu8XpzzM=
+github.com/ontio/ontology-crypto v1.0.9/go.mod h1:h/jeqqb9Ma/Leszxqh6zY3eTF2yks44hyRKikMni+YQ=
+github.com/ontio/ontology-eventbus v0.9.1 h1:nt3AXWx3gOyqtLiU4EwI92Yc4ik/pWHu9xRK15uHSOs=
+github.com/ontio/ontology-eventbus v0.9.1/go.mod h1:hCQIlbdPckcfykMeVUdWrqHZ8d30TBdmLfXCVWGkYhM=
+github.com/ontio/wagon v0.4.1/go.mod h1:oTPdgWT7WfPlEyzVaHSn1vQPMSbOpQPv+WphxibWlhg=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw=
+github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
+github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/polynetwork/poly v0.0.0-20200715030435-4f1d1a0adb44 h1:QXznsPhBBa1vY6Fhav8S9+qoHBi8iGy6g1VeIMdYglI=
+github.com/polynetwork/poly v0.0.0-20200715030435-4f1d1a0adb44/go.mod h1:UzlGEWk0eCGsuMJOZfBoZjRbmu4Yw/SudKAIFe1gPnY=
+github.com/polynetwork/poly-go-sdk v0.0.0-20200817120957-365691ad3493 h1:wob4aH5NxiDFIOWlpKbmoIb88QOccDNa1+rl93czjr8=
+github.com/polynetwork/poly-go-sdk v0.0.0-20200817120957-365691ad3493/go.mod h1:a1wMo/VFoUAKX2yVjipvFug6Yu5BPhf/2tP5xywqfIc=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A=
+github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/scylladb/go-set v1.0.2/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I=
+github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
+github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
+github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
+github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
+github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
+github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
+github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
+github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
+github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk=
+github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
+github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok=
+github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
+github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
+github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
+github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso=
+github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ=
+github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
+github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk=
+github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA=
+github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
+github.com/tendermint/tendermint v0.33.3 h1:6lMqjEoCGejCzAghbvfQgmw87snGSqEhDTo/jw+W8CI=
+github.com/tendermint/tendermint v0.33.3/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
+github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY=
+github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ=
+github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
+github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8=
+github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/ybbus/jsonrpc v2.1.2+incompatible h1:V4mkE9qhbDQ92/MLMIhlhMSbz8jNXdagC3xBR5NDwaQ=
+github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
+github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
+github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1 h1:1qKTeMTSIEvRIjvVYzgcRp0xVp0eoiRTTiHSncb5gD8=
+github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1/go.mod h1:bslhAiUxakrA6z6CHmVyvkfpnxx18RJBwVyx2TluJWw=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
+golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYUO2VM9mDLqo2V6CFBY84lFSZAfoi4=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
+launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/hooks/post_push b/hooks/post_push
new file mode 100644
index 0000000..4575c25
--- /dev/null
+++ b/hooks/post_push
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+if [ $SOURCE_BRANCH == "main" ]; then
+ docker tag $IMAGE_NAME $DOCKER_REPO:experimental-${SOURCE_COMMIT:0:7}
+ docker push $DOCKER_REPO:experimental-${SOURCE_COMMIT:0:7}
+fi
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..56deda4
--- /dev/null
+++ b/main.go
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package main
+
+import "github.com/polynetwork/zilliqa-relayer/cmd"
+
+func main() {
+ cmd.Execute()
+}
diff --git a/run-docker.sh b/run-docker.sh
new file mode 100755
index 0000000..9a53340
--- /dev/null
+++ b/run-docker.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+docker stop zilliqa-relayer
+docker rm zilliqa-relayer
+
+docker run -d \
+-v $(pwd)/persistence:/app/persistence \
+-v $(pwd)/secrets/config.local.yaml:/app/config.local.yaml \
+-v $(pwd)/secrets/target_contracts.json:/app/target_contracts.json \
+-v $(pwd)/secrets/poly.wallet:/app/poly.wallet \
+-v $(pwd)/secrets/zilliqa.wallet:/app/zilliqa.wallet \
+--name zilliqa-relayer polynetwork/zilliqa-relayer
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000..052a2ce
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+./zilliqa-relayer run
\ No newline at end of file
diff --git a/service/common.go b/service/common.go
new file mode 100644
index 0000000..47be13e
--- /dev/null
+++ b/service/common.go
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ log "github.com/sirupsen/logrus"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func WaitToExit() {
+ exit := make(chan bool, 0)
+ sc := make(chan os.Signal, 1)
+ signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
+ go func() {
+ for sig := range sc {
+ log.Infof("Zilliqa Relayer received exit signal: %v.", sig.String())
+ close(exit)
+ break
+ }
+ }()
+ <-exit
+}
diff --git a/service/nonce_manager.go b/service/nonce_manager.go
new file mode 100644
index 0000000..d714ac6
--- /dev/null
+++ b/service/nonce_manager.go
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "encoding/json"
+ "github.com/Zilliqa/gozilliqa-sdk/keytools"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ "github.com/Zilliqa/gozilliqa-sdk/transaction"
+ "github.com/Zilliqa/gozilliqa-sdk/util"
+ polytypes "github.com/polynetwork/poly/core/types"
+ common2 "github.com/polynetwork/poly/native/service/cross_chain_manager/common"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/tools"
+ log "github.com/sirupsen/logrus"
+ "math"
+ "strconv"
+ "sync"
+ "time"
+)
+
+const AuditLogFile = "audit.log"
+
+type NonceAndSender struct {
+ Sender *ZilSender
+ LocalNonce int64
+}
+
+type TransactionWithAge struct {
+ Txn *transaction.Transaction
+ StartTxBlock uint64
+ Age int
+}
+
+type NonceManager struct {
+ UpdateInterval int64
+ ZilClient *provider.Provider
+ // address => hash => transaction
+ SentTransactions map[string]map[string]TransactionWithAge
+ LockSentTransaction sync.Mutex
+ // address => list of transaction hash
+ ConfirmedTransactions map[string][]string
+ // private key => nonce and sender
+ ZilSenderMap map[string]*NonceAndSender
+ SenderPrivateKeys []string
+ CurrentIndex int
+ Cfg *config.Config
+}
+
+func (nm *NonceManager) Run() {
+ log.Infof("starting nonce manager...")
+ for {
+ time.Sleep(time.Second * time.Duration(nm.UpdateInterval))
+ nm.stat()
+ }
+}
+
+func (nm *NonceManager) commitHeader(hdr *polytypes.Header) bool {
+ nm.LockSentTransaction.Lock()
+ defer nm.LockSentTransaction.Unlock()
+ currentSenderPrivateKey := nm.SenderPrivateKeys[nm.CurrentIndex]
+ nm.CurrentIndex++
+ if nm.CurrentIndex > len(nm.SenderPrivateKeys)-1 {
+ nm.CurrentIndex = 0
+ }
+ currentSender := nm.ZilSenderMap[currentSenderPrivateKey].Sender
+ log.Infof("NonceManager - commitHeader use sender %s", currentSender.address)
+ nonce := strconv.FormatUint(uint64(nm.ZilSenderMap[currentSenderPrivateKey].LocalNonce+1), 10)
+ txn, err := currentSender.commitHeaderWithNonce(hdr, nonce)
+ if err != nil {
+ log.Warnf("NonceManager - commitHeader error %s", err.Error())
+ return false
+ }
+
+ hash, _ := txn.Hash()
+
+ // handle nonce
+ nm.ZilSenderMap[currentSenderPrivateKey] = &NonceAndSender{
+ Sender: nm.ZilSenderMap[currentSenderPrivateKey].Sender,
+ LocalNonce: nm.ZilSenderMap[currentSenderPrivateKey].LocalNonce + 1,
+ }
+
+ outerMap := nm.SentTransactions[currentSender.address]
+ if outerMap == nil {
+ outerMap = make(map[string]TransactionWithAge)
+ }
+ outerMap[util.EncodeHex(hash)] = TransactionWithAge{
+ Txn: txn,
+ Age: 0,
+ }
+ nm.SentTransactions[currentSender.address] = outerMap
+ return true
+}
+
+type TransactionAuditLog struct {
+ Time time.Time
+ PayLoad string
+ Error string
+}
+
+func (nm *NonceManager) commitDepositEventsWithHeader(header *polytypes.Header, param *common2.ToMerkleValue, headerProof string, anchorHeader *polytypes.Header, polyTxHash string, rawAuditPath []byte) bool {
+ nm.LockSentTransaction.Lock()
+ defer nm.LockSentTransaction.Unlock()
+ currentSenderPrivateKey := nm.SenderPrivateKeys[nm.CurrentIndex]
+ nm.CurrentIndex++
+ if nm.CurrentIndex > len(nm.SenderPrivateKeys)-1 {
+ nm.CurrentIndex = 0
+ }
+
+ currentSender := nm.ZilSenderMap[currentSenderPrivateKey].Sender
+ log.Infof("NonceManager - commitDepositEventsWithHeader use sender %s", currentSender.address)
+ nonce := strconv.FormatUint(uint64(nm.ZilSenderMap[currentSenderPrivateKey].LocalNonce+1), 10)
+ txn, err := currentSender.commitDepositEventsWithHeaderWithNonce(header, param, headerProof, anchorHeader, polyTxHash, rawAuditPath, nonce)
+ var auditLog TransactionAuditLog
+ if err != nil {
+ auditLog = TransactionAuditLog{
+ Time: time.Now(),
+ Error: err.Error(),
+ }
+ } else {
+ transactionRaw, _ := json.Marshal(txn)
+ auditLog = TransactionAuditLog{
+ Time: time.Now(),
+ PayLoad: string(transactionRaw),
+ }
+ }
+
+ auditLogRaw, _ := json.Marshal(auditLog)
+ tools.AppendToFile(AuditLogFile, string(auditLogRaw))
+
+ if err != nil {
+ log.Warnf("NonceManager - commitDepositEventsWithHeaderWithNonc e error %s", err.Error())
+ return false
+ }
+
+ hash, _ := txn.Hash()
+
+ // handle nonce
+ nm.ZilSenderMap[currentSenderPrivateKey] = &NonceAndSender{
+ Sender: nm.ZilSenderMap[currentSenderPrivateKey].Sender,
+ LocalNonce: nm.ZilSenderMap[currentSenderPrivateKey].LocalNonce + 1,
+ }
+
+ outerMap := nm.SentTransactions[currentSender.address]
+ if outerMap == nil {
+ outerMap = make(map[string]TransactionWithAge)
+ }
+ outerMap[util.EncodeHex(hash)] = TransactionWithAge{
+ Txn: txn,
+ Age: 0,
+ }
+ nm.SentTransactions[currentSender.address] = outerMap
+ return true
+}
+
+func (nm *NonceManager) stat() {
+ txBlock, err := nm.ZilClient.GetLatestTxBlock()
+ if err != nil {
+ log.Warnf("NonceManager - get current tx block number error: %s", err.Error())
+ return
+ }
+ currentTxEpoch, _ := strconv.ParseUint(txBlock.Header.BlockNum, 10, 64)
+ log.Infof("NonceManager - current tx block number is: %s", txBlock.Header.BlockNum)
+ nm.LockSentTransaction.Lock()
+ defer nm.LockSentTransaction.Unlock()
+ for _, key := range nm.SenderPrivateKeys {
+ addr := keytools.GetAddressFromPrivateKey(util.DecodeHex(key))
+ balAndNonce, err := nm.ZilClient.GetBalance(addr)
+ if err != nil {
+ log.Warnf("NonceManager - get nonce for address %s error %s", addr, err.Error())
+ continue
+ }
+
+ // print some stat info about this address
+ log.Infof("NonceManager - address %s, local nonce = %d, remote nonce = %d", addr, nm.ZilSenderMap[key].LocalNonce, balAndNonce.Nonce)
+ log.Infof("NonceManager - sent transactions: %+v", nm.SentTransactions[addr])
+ log.Infof("NonceManager - confimred transactions: %+v", len(nm.ConfirmedTransactions[addr]))
+
+ // check sent transactions
+ log.Infof("NonceManager - check sent transactions")
+ var confirmedTxn []string
+
+ sentTransactionMap := nm.SentTransactions[addr]
+ for hash, txn := range sentTransactionMap {
+ log.Infof("NonceManager - check transaction %s", hash)
+ _, err := nm.ZilClient.GetTransaction(hash)
+
+ if err == nil {
+ log.Infof("NonceManager - transaction %s confirmed", hash)
+ confirmedTxn = append(confirmedTxn, hash)
+ } else {
+ // if start block is 0, try to give it a number first
+ if sentTransactionMap[hash].StartTxBlock == 0 {
+ log.Infof("NonceManager - stat try to determine start tx block for hash: %s", hash)
+ sentTransactionMap[hash] = TransactionWithAge{
+ Txn: txn.Txn,
+ StartTxBlock: currentTxEpoch,
+ Age: 0,
+ }
+ } else {
+ log.Warnf("NonceManager - stat already has inserted epoch, update age, hash is %s", hash)
+ age := 0
+ if currentTxEpoch > sentTransactionMap[hash].StartTxBlock {
+ age = int(currentTxEpoch - sentTransactionMap[hash].StartTxBlock)
+ }
+ sentTransactionMap[hash] = TransactionWithAge{
+ Txn: txn.Txn,
+ StartTxBlock: txn.StartTxBlock,
+ Age: age,
+ }
+ }
+ }
+
+ }
+
+ for _, hash := range confirmedTxn {
+ delete(sentTransactionMap, hash)
+ nm.ConfirmedTransactions[addr] = append(nm.ConfirmedTransactions[addr], hash)
+ }
+ nm.SentTransactions[addr] = sentTransactionMap
+
+ // print some stat info about this address again
+ log.Infof("NonceManager - sent transactions: %+v", nm.SentTransactions[addr])
+ log.Infof("NonceManager - confimred transactions: %+v", len(nm.ConfirmedTransactions[addr]))
+
+ // detect dead transactions
+ log.Infof("NonceManager - stat start to detect dead transactions")
+ currentNonce := uint64(math.MaxUint64)
+ for hash, txn := range nm.SentTransactions[addr] {
+ if txn.Age > nm.Cfg.ZilConfig.MaxExistTxEpoch {
+ log.Warnf("NonceManager - stat found dead transaction, hash: %s, nonce is %s", hash, txn.Txn.Nonce)
+ log.Warnf("NonceManager - stat current nonce is: %d", currentNonce)
+ nonce, _ := strconv.ParseUint(txn.Txn.Nonce, 10, 64)
+ if currentNonce > nonce {
+ log.Warnf("NonceManager - stat replace current nonce with it")
+ currentNonce = nonce
+ }
+ }
+ }
+
+ if currentNonce == math.MaxUint64 {
+ log.Infof("NonceManager - stat no dead found")
+ } else {
+ log.Infof("NonceManager - stat dead transaction, bad nonce is: %d, start to resend transactions", currentNonce)
+ for hash, txn := range nm.SentTransactions[addr] {
+ nonce, _ := strconv.ParseUint(txn.Txn.Nonce, 10, 64)
+ if nonce >= currentNonce {
+ log.Infof("NonceManager - stat start to resend transaction %s, nonce %d", hash, nonce)
+ // todo handle error
+ nm.ZilClient.CreateTransaction(txn.Txn.ToTransactionPayload())
+ nm.SentTransactions[addr][hash] = TransactionWithAge{
+ Txn: txn.Txn,
+ StartTxBlock: currentTxEpoch,
+ Age: 0,
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/service/poly2zil.go b/service/poly2zil.go
new file mode 100644
index 0000000..4cbd4bc
--- /dev/null
+++ b/service/poly2zil.go
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "github.com/Zilliqa/gozilliqa-sdk/bech32"
+ "github.com/Zilliqa/gozilliqa-sdk/util"
+ "github.com/polynetwork/poly/common"
+ "github.com/polynetwork/poly/consensus/vbft/config"
+ polytypes "github.com/polynetwork/poly/core/types"
+ common2 "github.com/polynetwork/poly/native/service/cross_chain_manager/common"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/tools"
+ log "github.com/sirupsen/logrus"
+ "strconv"
+ "time"
+)
+
+func (p *PolySyncManager) MonitorChain() {
+ if !p.init() {
+ log.Errorf("PolySyncManager MonitorChain - init error\n")
+ return
+ }
+
+ log.Infof("PolySyncManager MonitorChain - start scan block at height: %d\n", p.currentHeight)
+ monitorTicker := time.NewTicker(time.Duration(p.cfg.PolyConfig.PolyMonitorInterval) * time.Second)
+ var blockHandleResult bool
+ for {
+ start:
+ log.Infof("PolySyncManager MonitorChain - current height: %d\n", p.currentHeight)
+ select {
+ case <-monitorTicker.C:
+ latestHeight, err := p.polySdk.GetCurrentBlockHeight()
+ if err != nil {
+ log.Errorf("PolySyncManager MonitorChain - cannot get node hight, err: %s\n", err.Error())
+ continue
+ }
+ latestHeight--
+ if latestHeight-p.currentHeight < config.OntUsefulBlockNum {
+ log.Infof("PolySyncManager MonitorChain - poly chain skip current height: %d", latestHeight)
+ continue
+ }
+ log.Infof("PolySyncManager MonitorChain - poly chain current height: %d", latestHeight)
+ blockHandleResult = true
+ for p.currentHeight <= latestHeight-config.OntUsefulBlockNum {
+ blockHandleResult = p.handleDepositEvents(p.currentHeight, latestHeight)
+ if blockHandleResult {
+ p.currentHeight++
+ if err = p.db.UpdatePolyHeight(p.currentHeight - 1); err != nil {
+ log.Errorf("PolySyncManager MonitorChain - failed to save height of poly: %v", err)
+ }
+ } else {
+ goto start
+ }
+ }
+
+ case <-p.exitChan:
+ return
+
+ }
+ }
+}
+
+func (p *PolySyncManager) handleDepositEvents(height, latest uint32) bool {
+ log.Infof("PolySyncManager handleDepositEvents at height %d, latest height %d\n", height, latest)
+ lastEpoch := p.findLatestHeight()
+ hdr, err := p.polySdk.GetHeaderByHeight(height + 1)
+ if err != nil {
+ log.Errorf("PolySyncManager handleBlockHeader - GetNodeHeader on height :%d failed", height)
+ return false
+ }
+ isCurr := lastEpoch < height+1
+ info := &vconfig.VbftBlockInfo{}
+ if err := json.Unmarshal(hdr.ConsensusPayload, info); err != nil {
+ log.Errorf("PolySyncManager failed to unmarshal ConsensusPayload for height %d: %v", height+1, err)
+ return false
+ }
+ isEpoch := hdr.NextBookkeeper != common.ADDRESS_EMPTY && info.NewChainConfig != nil
+ var (
+ anchor *polytypes.Header
+ hp string
+ )
+ if !isCurr {
+ anchor, _ = p.polySdk.GetHeaderByHeight(lastEpoch + 1)
+ proof, _ := p.polySdk.GetMerkleProof(height+1, lastEpoch+1)
+ hp = proof.AuditPath
+ } else if isEpoch {
+ anchor, _ = p.polySdk.GetHeaderByHeight(height + 2)
+ proof, _ := p.polySdk.GetMerkleProof(height+1, height+2)
+ hp = proof.AuditPath
+ }
+
+ cnt := 0
+ events, err := p.polySdk.GetSmartContractEventByBlock(height)
+ for err != nil {
+ log.Errorf("PolySyncManager handleDepositEvents - get block event at height:%d error: %s", height, err.Error())
+ return false
+ }
+ for _, event := range events {
+ for _, notify := range event.Notify {
+ log.Infof("PolySyncManager handleDepositEvents get notify address: %s\n", notify.ContractAddress)
+ if notify.ContractAddress == p.cfg.PolyConfig.EntranceContractAddress {
+ states := notify.States.([]interface{})
+ method, _ := states[0].(string)
+ if method != "makeProof" {
+ continue
+ }
+ if uint64(states[2].(float64)) != p.cfg.ZilConfig.SideChainId {
+ continue
+ }
+ proof, err := p.polySdk.GetCrossStatesProof(hdr.Height-1, states[5].(string))
+ if err != nil {
+ log.Errorf("handleDepositEvents - failed to get proof for key %s: %v", states[5].(string), err)
+ continue
+ }
+ auditpath, _ := hex.DecodeString(proof.AuditPath)
+ value, _, _, _ := tools.ParseAuditpath(auditpath)
+ param := &common2.ToMerkleValue{}
+ if err := param.Deserialization(common.NewZeroCopySource(value)); err != nil {
+ log.Errorf("handleDepositEvents - failed to deserialize MakeTxParam (value: %x, err: %v)", value, err)
+ continue
+ }
+ var isTarget bool
+ if len(p.cfg.TargetContracts) > 0 {
+ // target address configuration should include those contracts are allowed to be triggered by
+ // cross chain transactions. e.g LockProxy
+ toContractStr, _ := bech32.ToBech32Address(util.EncodeHex(param.MakeTxParam.ToContractAddress))
+ for _, v := range p.cfg.TargetContracts {
+ toChainIdArr, ok := v[toContractStr]
+ if ok {
+ if len(toChainIdArr["inbound"]) == 0 {
+ isTarget = true
+ break
+ }
+ for _, id := range toChainIdArr["inbound"] {
+ if id == param.FromChainID {
+ isTarget = true
+ break
+ }
+ }
+ if isTarget {
+ break
+ }
+ }
+ }
+ if !isTarget {
+ continue
+ }
+ }
+ cnt++
+ p.nonceManager.commitDepositEventsWithHeader(hdr, param, hp, anchor, event.TxHash, auditpath)
+ }
+ }
+ }
+
+ if cnt == 0 && isEpoch && isCurr {
+ return p.nonceManager.commitHeader(hdr)
+ }
+
+ return true
+}
+
+func (p *PolySyncManager) selectSender() *ZilSender {
+S:
+ log.Info("start select sender")
+ for _, sender := range p.senders {
+ sender.mu.Lock()
+ if !sender.inUse {
+ sender.inUse = true
+ sender.mu.Unlock()
+ log.Infof("sender %s selected", sender.address)
+ return sender
+ }
+ sender.mu.Unlock()
+ }
+ log.Warn("Current no zilliqa sender can use, sleep 10 seconds and reselect")
+ time.Sleep(time.Second * 10)
+ goto S
+}
+
+type EpochStartHeight struct {
+ CurEpochStartHeight string `json:"curEpochStartHeight"`
+}
+
+type EpochStartHeightRep struct {
+ Id string `json:"id"`
+ JsonRpc string `json:"jsonrpc"`
+ Result EpochStartHeight `json:"result"`
+}
+
+type FromChainTxExist struct {
+ FromChainTxExist map[string]interface{} `json:"fromChainTxExist"`
+}
+
+type FromChainTxExistRsp struct {
+ Id string `json:"id"`
+ JsonRpc string `json:"jsonrpc"`
+ Result *FromChainTxExist `json:"result"`
+}
+
+// ZilCrossChainManager.scilla
+// check fromChainTxExist map
+func (z *ZilSender) checkIfFromChainTxExist(fromChainId uint64, fromTx string) bool {
+ ccm, err := bech32.FromBech32Addr(z.cfg.ZilConfig.CrossChainManagerContract)
+ if err != nil {
+ log.Errorf("PolySyncManager checkIfFromChainTxExist - failed to convert cross chain manager contract address: %s\n", err.Error())
+ return false
+ }
+
+ state, err1 := z.zilSdk.GetSmartContractSubState(ccm, "fromChainTxExist", []interface{}{strconv.FormatUint(fromChainId, 10), fromTx})
+ if err1 != nil {
+ log.Errorf("PolySyncManager checkIfFromChainTxExist - failed to get state of fromChainTxExist: %s\n", err1.Error())
+ return false
+ }
+
+ var fromChainTxExistRsp FromChainTxExistRsp
+ err2 := json.Unmarshal([]byte(state), &fromChainTxExistRsp)
+ if err2 != nil {
+ log.Errorf("PolySyncManager checkIfFromChainTxExist - failed to parse fromChainTxExistRsp: %s\n", err2.Error())
+ return false
+ }
+
+ if fromChainTxExistRsp.Result == nil {
+ return false
+ } else {
+ return true
+ }
+}
+
+// ZilCrossChainManager.scilla
+// curEpochStartHeight
+func (p *PolySyncManager) findLatestHeight() uint32 {
+ ccm, err := bech32.FromBech32Addr(p.cfg.ZilConfig.CrossChainManagerContract)
+ if err != nil {
+ log.Errorf("PolySyncManager FindLatestHeight - failed to convert cross chain manager contract address: %s\n", err.Error())
+ return 0
+ }
+ curEpochStartHeight, err1 := p.zilSdk.GetSmartContractSubState(ccm, "curEpochStartHeight", []interface{}{})
+ if err1 != nil {
+ log.Errorf("PolySyncManager FindLatestHeight - faild to get current epoch start height: %s\n", err1.Error())
+ return 0
+ }
+
+ var epochStartHeightRep EpochStartHeightRep
+ err3 := json.Unmarshal([]byte(curEpochStartHeight), &epochStartHeightRep)
+ if err3 != nil {
+ log.Errorf("PolySyncManager FindLatestHeight - faild to unmarshal current epoch start height: %s\n", err3.Error())
+ return 0
+ }
+
+ height, err2 := strconv.ParseUint(epochStartHeightRep.Result.CurEpochStartHeight, 10, 32)
+ if err2 != nil {
+ log.Errorf("PolySyncManager FindLatestHeight - failed to parse epoch start height: %s\n", err2.Error())
+ return 0
+ }
+ return uint32(height)
+}
diff --git a/service/poly2zil_test.go b/service/poly2zil_test.go
new file mode 100644
index 0000000..25f8ff0
--- /dev/null
+++ b/service/poly2zil_test.go
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "fmt"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ "github.com/magiconair/properties/assert"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "testing"
+)
+
+var p *PolySyncManager
+var s *ZilSender
+
+func init() {
+ zilSdk := provider.NewProvider("https://polynetworkcc3dcb2-5-api.dev.z7a.xyz")
+ p = &PolySyncManager{
+ zilSdk: zilSdk,
+ cfg: &config.Config{ZilConfig: &config.ZILConfig{
+ CrossChainManagerContract: "zil1ur4vwcmcz3jqypksgq7qeju2sk5jrskzaadau5",
+ }},
+ }
+ s = &ZilSender{
+ cfg: &config.Config{ZilConfig: &config.ZILConfig{
+ CrossChainManagerContract: "zil1ur4vwcmcz3jqypksgq7qeju2sk5jrskzaadau5",
+ }},
+ zilSdk: zilSdk,
+ address: "zil1ur4vwcmcz3jqypksgq7qeju2sk5jrskzaadau5",
+ }
+}
+
+func TestPolySyncManager_FindLatestHeight(t *testing.T) {
+ fmt.Println(p.findLatestHeight())
+}
+
+func TestZilSender_CheckIfFromChainTxExist(t *testing.T) {
+ exist := s.checkIfFromChainTxExist(3, "0x00ca93f8738111a063d8ab7221f47c70a4cade0ca4a2829df494cd4b5e231bd6")
+ assert.Equal(t, exist, true)
+
+ exist = s.checkIfFromChainTxExist(3, "0x00ca93f8738111a063d8ab7221f47c70a4cade0ca4a2829df494cd4b5e231bd7")
+ assert.Equal(t, exist, false)
+
+}
diff --git a/service/polymanager.go b/service/polymanager.go
new file mode 100644
index 0000000..dd95463
--- /dev/null
+++ b/service/polymanager.go
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "encoding/json"
+ "errors"
+ "github.com/Zilliqa/gozilliqa-sdk/account"
+ "github.com/Zilliqa/gozilliqa-sdk/crosschain/polynetwork"
+ "github.com/Zilliqa/gozilliqa-sdk/crypto"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ "github.com/ontio/ontology/common/log"
+ "github.com/polynetwork/poly-go-sdk"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/db"
+ "github.com/polynetwork/zilliqa-relayer/tools"
+ "strings"
+)
+
+type PolySyncManager struct {
+ currentHeight uint32
+ polySdk *poly_go_sdk.PolySdk
+ exitChan chan int
+ cfg *config.Config
+ db *db.BoltDB
+
+ zilSdk *provider.Provider
+ crossChainManager string
+ crossChainManagerProxy string
+ senders []*ZilSender
+ nonceManager *NonceManager
+}
+
+func (p *PolySyncManager) init() bool {
+ if p.currentHeight > 0 {
+ log.Infof("PolySyncManager init - start height from flag: %d", p.currentHeight)
+ return true
+ }
+
+ p.currentHeight = p.db.GetPolyHeight()
+ log.Infof("PolySyncManager init - get poly height from local storage: %d", p.currentHeight)
+ latestHeight := p.findLatestHeight()
+ log.Infof("PolySyncManager init - get poly height from cross chain manager contract: %d", latestHeight)
+ if latestHeight > p.currentHeight {
+ p.currentHeight = latestHeight
+ return true
+ }
+ log.Infof("PolySyncManager init - start height from flag: %d", p.currentHeight)
+ return true
+}
+
+func (p *PolySyncManager) Run(enable bool) {
+ if enable {
+ go p.MonitorChain()
+ go p.nonceManager.Run()
+ }
+}
+
+func NewPolySyncManager(cfg *config.Config, zilSdk *provider.Provider, polySdk *poly_go_sdk.PolySdk, boltDB *db.BoltDB, crossChainManager, crossChainManagerProxy string) (*PolySyncManager, error) {
+ keystores, err := tools.ReadLine(cfg.ZilConfig.KeyStorePath)
+ keystorepwdset := cfg.ZilConfig.KeyStorePwdSet
+ if err != nil {
+ return nil, err
+ }
+ descryptor := crypto.NewDefaultKeystore()
+
+ var senders []*ZilSender
+ var privateKeys []string
+ zilSenderMap := make(map[string]*NonceAndSender, 0)
+
+ for _, keystore := range keystores {
+ var ks crypto.KeystoreV3
+ err1 := json.Unmarshal([]byte(keystore), &ks)
+ if err1 != nil {
+ return nil, err1
+ }
+ pwd := keystorepwdset[strings.ToLower(ks.Address)]
+ if pwd == nil {
+ return nil, errors.New("NewPolySyncManager - there is no password for zilliqa.wallet: " + ks.Address)
+ }
+ privateKey, err2 := descryptor.DecryptPrivateKey(keystore, pwd.(string))
+ if err2 != nil {
+ return nil, errors.New("NewPolySyncManager - descrypt zilliqa.wallet error: " + err2.Error())
+ }
+
+ // init cross chain smart contract proxy
+ wallet := account.NewWallet()
+ wallet.AddByPrivateKey(privateKey)
+ log.Infof("NewPolySyncManager get zilliqa wallet: %s", wallet.DefaultAccount.Address)
+ proxy := &polynetwork.Proxy{
+ ProxyAddr: crossChainManagerProxy,
+ ImplAddr: crossChainManager,
+ Wallet: wallet,
+ Client: zilSdk,
+ ChainId: cfg.ZilConfig.ZilChainId,
+ MsgVersion: cfg.ZilConfig.ZilMessageVersion,
+ }
+
+ addr := strings.Replace(ks.Address, "0x", "", 1)
+ sender := &ZilSender{
+ cfg: cfg,
+ zilSdk: zilSdk,
+ address: addr,
+ privateKey: privateKey,
+ polySdk: polySdk,
+ crossChainProxy: proxy,
+ inUse: false,
+ }
+
+ senders = append(senders, sender)
+
+ balAndNonce, err3 := zilSdk.GetBalance(addr)
+ if err3 != nil {
+ log.Infof("NewPolySyncManager get address %s nonce error %s", addr, err3.Error())
+ continue
+ }
+
+ privateKeyAndNonce := &NonceAndSender{
+ Sender: sender,
+ LocalNonce: balAndNonce.Nonce,
+ }
+
+ privateKeys = append(privateKeys, privateKey)
+ zilSenderMap[privateKey] = privateKeyAndNonce
+ }
+
+ nonceManager := &NonceManager{
+ UpdateInterval: 30,
+ ZilClient: zilSdk,
+ SentTransactions: make(map[string]map[string]TransactionWithAge),
+ ConfirmedTransactions: make(map[string][]string),
+ SenderPrivateKeys: privateKeys,
+ ZilSenderMap: zilSenderMap,
+ CurrentIndex: 0,
+ Cfg: cfg,
+ }
+
+ return &PolySyncManager{
+ currentHeight: cfg.PolyConfig.PolyStartHeight,
+ polySdk: polySdk,
+ exitChan: make(chan int),
+ cfg: cfg,
+ db: boltDB,
+ zilSdk: zilSdk,
+ crossChainManager: crossChainManager,
+ crossChainManagerProxy: crossChainManagerProxy,
+ senders: senders,
+ nonceManager: nonceManager,
+ }, nil
+}
diff --git a/service/zil2poly.go b/service/zil2poly.go
new file mode 100644
index 0000000..d617ecb
--- /dev/null
+++ b/service/zil2poly.go
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/Zilliqa/gozilliqa-sdk/bech32"
+ "github.com/Zilliqa/gozilliqa-sdk/core"
+ "github.com/Zilliqa/gozilliqa-sdk/util"
+ "github.com/polynetwork/poly/common"
+ scom "github.com/polynetwork/poly/native/service/header_sync/common"
+ autils "github.com/polynetwork/poly/native/service/utils"
+ "github.com/polynetwork/zilliqa-relayer/tools"
+ log "github.com/sirupsen/logrus"
+)
+
+/**
+ * handle new block:
+ * 1. commit tx block and ds block
+ * 2. filter deposit event, put into local database
+ * 3. from database, handle deposit event, get proof and commit to poly
+ */
+
+func (s *ZilliqaSyncManager) MonitorChain() {
+ log.Infof("ZilliqaSyncManager MonitorChain - start scan block at height: %d\n", s.currentHeight)
+ fetchBlockTicker := time.NewTicker(time.Duration(s.cfg.ZilConfig.ZilMonitorInterval) * time.Second)
+ var blockHandleResult bool
+ for {
+ select {
+ case <-fetchBlockTicker.C:
+ txBlock, err := s.zilSdk.GetLatestTxBlock()
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager MonitorChain - cannot get node hight, err: %s\n", err.Error())
+ continue
+ }
+ log.Infof("ZilliqaSyncManager MonitorChain - current tx block height: %s\n", txBlock.Header.BlockNum)
+ blockNumber, err2 := strconv.ParseUint(txBlock.Header.BlockNum, 10, 32)
+ if err2 != nil {
+ log.Errorf("ZilliqaSyncManager MonitorChain - cannot parse block height, err: %s\n", err2.Error())
+ }
+ if s.currentHeight >= blockNumber {
+ log.Infof("ZilliqaSyncManager MonitorChain - current height is not changed, skip")
+ continue
+ }
+
+ blockHandleResult = true
+ for s.currentHeight < blockNumber {
+ if s.debugInfo {
+ s.dumpPendingHeaders()
+ }
+ if !s.handleNewBlock(s.currentHeight + 1) {
+ break
+ }
+ s.currentHeight++
+
+ if uint32(len(s.header4sync)) > s.cfg.ZilConfig.ZilHeadersPerBatch {
+ log.Infof("ZilliqaSyncManager MonitorChain - commit header")
+ if s.debugInfo {
+ s.dumpPendingHeaders()
+ }
+ if res := s.commitHeader(); res != 0 {
+ log.Errorf("ZilliqaSyncManager MonitorChain -- commit header error, result %d", res)
+ blockHandleResult = false
+ break
+ }
+ }
+ }
+
+ if blockHandleResult && len(s.header4sync) > 0 {
+ s.commitHeader()
+ }
+
+ case <-s.exitChan:
+ return
+ }
+ }
+}
+
+func (s *ZilliqaSyncManager) handleNewBlock(height uint64) bool {
+ log.Infof("ZilliqaSyncManager handle new block: %d\n", height)
+ ret := s.handleBlockHeader(height)
+ if !ret {
+ log.Infof("ZilliqaSyncManager handleNewBlock - handleBlockHeader on height :%d failed\n", height)
+ return false
+ }
+ ret = s.fetchLockDepositEvents(height)
+ if !ret {
+ log.Infof("ZilliqaSyncManager handleNewBlock - fetchLockDepositEvents on height :%d failed\n", height)
+ return false
+ }
+ return true
+}
+
+func (s *ZilliqaSyncManager) handleBlockHeader(height uint64) bool {
+ log.Infof("ZilliqaSyncManager handle new block header height is: %d\n", height)
+T:
+ txBlockT, err := s.zilSdk.GetTxBlockVerbose(strconv.FormatUint(height, 10))
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager - handleBlockHeader error: %s", err)
+ return false
+ }
+ txBlock := core.NewTxBlockFromTxBlockT(txBlockT)
+ if txBlock.BlockHeader.DSBlockNum == 18446744073709551615 {
+ log.Infof("ZilliqaSyncManager - handleBlockHeader query ds block: ds block not ready")
+ time.Sleep(time.Second * 2)
+ goto T
+ }
+ if txBlock.BlockHeader.DSBlockNum > s.currentDsBlockNum {
+ // as we can't control the order how the header4sync on the poly
+ // nodes after we sent it across,
+ // this will ensure that all the TXBlock for a given DSBlock are synced before
+ // we proceed with the next dsblock.
+ log.Infof("ZilliqaSyncManager - new DsBlock %d", txBlock.BlockHeader.DSBlockNum)
+ log.Infof("ZilliqaSyncManager - sync all the txblock for %d", s.currentDsBlockNum)
+ if res := s.commitHeader(); res != 0 {
+ log.Errorf("ZilliqaSyncManager MonitorChain -- commit header error, result %d", res)
+ return false
+ }
+
+ log.Infof("ZilliqaSyncManager - handleBlockHeader query ds block: %d\n", txBlock.BlockHeader.DSBlockNum)
+ dsBlock, err := s.zilSdk.GetDsBlockVerbose(strconv.FormatUint(txBlock.BlockHeader.DSBlockNum, 10))
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager - handleBlockHeader get ds block error: %s", err)
+ return false
+ }
+ txBlockOrDsBlock := core.TxBlockOrDsBlock{
+ DsBlock: core.NewDsBlockFromDsBlockT(dsBlock),
+ }
+ rawBlock, _ := json.Marshal(txBlockOrDsBlock)
+ log.Infof("ZilliqaSyncManager handle new block header: %s\n", rawBlock)
+ s.header4sync = append(s.header4sync, rawBlock)
+ s.currentDsBlockNum++
+ }
+
+ txBlockOrDsBlock := core.TxBlockOrDsBlock{
+ TxBlock: txBlock,
+ }
+ rawBlock, err2 := json.Marshal(txBlockOrDsBlock)
+ if err2 != nil {
+ log.Errorf("ZilliqaSyncManager - handleBlockHeader marshal block error: %s", err2)
+ return false
+ }
+ log.Debugf("ZilliqaSyncManager handle new block header: %s\n", rawBlock)
+ blockHash := txBlock.BlockHash[:]
+ log.Infof("ZilliqaSyncManager handleBlockHeader - header hash: %s\n", util.EncodeHex(blockHash))
+ raw, _ := s.polySdk.GetStorage(autils.HeaderSyncContractAddress.ToHexString(),
+ append(append([]byte(scom.MAIN_CHAIN), autils.GetUint64Bytes(s.cfg.ZilConfig.SideChainId)...), autils.GetUint64Bytes(height)...))
+ if len(raw) == 0 || !bytes.Equal(raw, blockHash) {
+ s.header4sync = append(s.header4sync, rawBlock)
+ }
+ if s.debugInfo {
+ s.dumpPendingHeaders()
+ }
+ return true
+}
+
+// the workflow is: user -> LockProxy on zilliqa -> Cross Chain Manager -> emit event
+// so here we need to filter out those transactions related to cross chain manager
+// and parse the events, store them to local db, and commit them to the polynetwork
+func (s *ZilliqaSyncManager) fetchLockDepositEvents(height uint64) bool {
+ transactions, err := s.zilSdk.GetTxnBodiesForTxBlock(strconv.FormatUint(height, 10))
+ if err != nil {
+ if strings.Contains(err.Error(), "TxBlock has no transactions") {
+ log.Infof("ZilliqaSyncManager no transaction in block %d\n", height)
+ return true
+ } else {
+ log.Infof("ZilliqaSyncManager get transactions for tx block %d failed: %s\n", height, err.Error())
+ return false
+ }
+ }
+
+ for _, transaction := range transactions {
+ if !transaction.Receipt.Success {
+ continue
+ }
+ events := transaction.Receipt.EventLogs
+ for _, event := range events {
+ // 1. contract address should be cross chain manager
+ // 2. event name should be CrossChainEvent
+ toAddr, _ := bech32.ToBech32Address(event.Address)
+ if toAddr == s.crossChainManagerAddress {
+ if event.EventName != "CrossChainEvent" {
+ continue
+ }
+ log.Infof("ZilliqaSyncManager found event on cross chain manager: %+v\n", event)
+ // todo parse event to struct CrossTransfer
+ crossTx := &CrossTransfer{}
+ for _, param := range event.Params {
+ switch param.VName {
+ case "txId":
+ index := big.NewInt(0)
+ index.SetBytes(util.DecodeHex(param.Value.(string)))
+ crossTx.txIndex = tools.EncodeBigInt(index)
+ case "toChainId":
+ toChainId, _ := strconv.ParseUint(param.Value.(string), 10, 32)
+ crossTx.toChain = uint32(toChainId)
+ case "rawdata":
+ crossTx.value = util.DecodeHex(param.Value.(string))
+ }
+ }
+ crossTx.height = height
+ crossTx.txId = util.DecodeHex(transaction.ID)
+ log.Infof("ZilliqaSyncManager parsed cross tx is: %+v\n", crossTx)
+ sink := common.NewZeroCopySink(nil)
+ crossTx.Serialization(sink)
+ err1 := s.db.PutRetry(sink.Bytes())
+ if err1 != nil {
+ log.Errorf("ZilliqaSyncManager fetchLockDepositEvents - this.db.PutRetry error: %s", err)
+ }
+ log.Infof("ZilliqaSyncManager fetchLockDepositEvent - height: %d", height)
+ } else {
+ log.Infof("ZilliqaSyncManager found event but not on cross chain manager, ignore: %+v\n", event)
+ }
+ }
+ }
+
+ return true
+}
+
+func (s *ZilliqaSyncManager) handleLockDepositEvents(height uint64) error {
+ if s.practiceOnly {
+ return nil
+ }
+ log.Infof("ZilliqaSyncManager handleLockDepositEvents - height is %d", height)
+ retryList, err := s.db.GetAllRetry()
+ if err != nil {
+ return fmt.Errorf("ZilliqaSyncManager - handleLockDepositEvents - this.db.GetAllRetry error: %s", err)
+ }
+ for _, v := range retryList {
+ time.Sleep(time.Second * 1)
+ crosstx := new(CrossTransfer)
+ err := crosstx.Deserialization(common.NewZeroCopySource(v))
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager - handleLockDepositEvents - retry.Deserialization error: %s", err)
+ continue
+ }
+ heightString := new(string)
+ *heightString = strconv.FormatUint(height, 10)
+ ccmc, _ := bech32.FromBech32Addr(s.cfg.ZilConfig.CrossChainManagerContract)
+ ccmc = strings.ToLower(ccmc)
+ txIndexBigInt, _ := new(big.Int).SetString(crosstx.txIndex, 16)
+ txIndexDecimal := txIndexBigInt.String()
+ storageKey := core.GenerateStorageKey(ccmc, "zilToPolyTxHashMap", []string{txIndexDecimal})
+ hashedStorageKey := util.Sha256(storageKey)
+ log.Infof("ZilliqaSyncManager - handleLockDepositEvents start get proof on address %s, hashed key is: %s, height is %s", ccmc, util.EncodeHex(hashedStorageKey), *heightString)
+ proof, err := s.zilSdk.GetStateProof(ccmc, util.EncodeHex(hashedStorageKey), heightString)
+ if err != nil {
+ return fmt.Errorf("ZilliqaSyncManager - handleLockDepositEvents - get proof from api error: %s", err)
+ }
+
+ if proof == nil {
+ log.Warnf("ZilliqaSyncManager - handleLockDepositEvents - get proof from api error: %s", "proof is nil")
+ return fmt.Errorf("ZilliqaSyncManager - handleLockDepositEvents - get proof from api error: %s", "proof is nil")
+ }
+
+ log.Infof("ZilliqaSyncManager - handleLockDepositEvents get proof from zilliqa api endpoint: %+v, height is: %d\n", proof, height)
+
+ zilProof := &ZILProof{
+ AccountProof: proof.AccountProof,
+ }
+
+ hexskey := util.EncodeHex(storageKey)
+ storageProof := StorageProof{
+ Key: []byte(hexskey),
+ Value: crosstx.value,
+ Proof: proof.StateProof,
+ }
+
+ zilProof.StorageProofs = []StorageProof{storageProof}
+ proofRaw, _ := json.Marshal(zilProof)
+
+ // commit proof
+ proofString, _ := json.Marshal(proof)
+ log.Infof("ZilliqaSyncManager - handleLockDepositEvents commit proof, height: %d, proof: %s, value: %s, txhash: %s\n", height, proofString, util.EncodeHex(crosstx.value), util.EncodeHex(crosstx.txId))
+ tx, err := s.polySdk.Native.Ccm.ImportOuterTransfer(
+ s.cfg.ZilConfig.SideChainId,
+ crosstx.value,
+ uint32(height),
+ proofRaw,
+ util.DecodeHex(s.polySigner.Address.ToHexString()),
+ []byte{},
+ s.polySigner)
+
+ if err != nil {
+ if strings.Contains(err.Error(), "ZilliqaSyncManager - handleLockDepositEvents chooseUtxos, current utxo is not enough") {
+ log.Infof("ZilliqaSyncManager - handleLockDepositEvents handleLockDepositEvents - invokeNativeContract error: %s", err)
+ continue
+ } else {
+ if err := s.db.DeleteRetry(v); err != nil {
+ log.Errorf("ZilliqaSyncManager - handleLockDepositEvents handleLockDepositEvents handleLockDepositEvents - this.db.DeleteRetry error: %s", err)
+ }
+ if strings.Contains(err.Error(), "tx already done") {
+ log.Debugf("ZilliqaSyncManager - handleLockDepositEvents handleLockDepositEvents handleLockDepositEvents - eth_tx %s already on poly", util.EncodeHex(crosstx.txId))
+ } else {
+ log.Errorf("ZilliqaSyncManager handleLockDepositEvents invokeNativeContract error for zil_tx %s: %s", util.EncodeHex(crosstx.txId), err)
+ }
+ continue
+ }
+ } else {
+ log.Infof("ZilliqaSyncManager - handleLockDepositEvents commitProof - send transaction to poly chain: ( poly_txhash: %s, zil_txhash: %s, height: %d )",
+ tx.ToHexString(), util.EncodeHex(crosstx.txId), height)
+ txHash := tx.ToHexString()
+ err = s.db.PutCheck(txHash, v)
+ err = s.db.PutCheck(txHash, v)
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager handleLockDepositEvents - this.db.PutCheck error: %s", err)
+ }
+ err = s.db.DeleteRetry(v)
+ if err != nil {
+ log.Errorf("ZilliqaSyncManager handleLockDepositEvents - this.db.PutCheck error: %s", err)
+ }
+ log.Infof("ZilliqaSyncManager handleLockDepositEvents - syncProofToAlia txHash is %s", txHash)
+ }
+ }
+
+ return nil
+}
+
+// should be the same as relayer side
+type ZILProof struct {
+ AccountProof []string `json:"accountProof"`
+ StorageProofs []StorageProof `json:"storageProof"`
+}
+
+// key should be storage key (in zilliqa)
+type StorageProof struct {
+ Key []byte `json:"key"`
+ Value []byte `json:"value"`
+ Proof []string `json:"proof"`
+}
+
+type CrossTransfer struct {
+ txIndex string
+ txId []byte
+ value []byte
+ toChain uint32
+ height uint64
+}
+
+func (this *CrossTransfer) Serialization(sink *common.ZeroCopySink) {
+ sink.WriteString(this.txIndex)
+ sink.WriteVarBytes(this.txId)
+ sink.WriteVarBytes(this.value)
+ sink.WriteUint32(this.toChain)
+ sink.WriteUint64(this.height)
+}
+
+func (this *CrossTransfer) Deserialization(source *common.ZeroCopySource) error {
+ txIndex, eof := source.NextString()
+ if eof {
+ return fmt.Errorf("Waiting deserialize txIndex error")
+ }
+ txId, eof := source.NextVarBytes()
+ if eof {
+ return fmt.Errorf("Waiting deserialize txId error")
+ }
+ value, eof := source.NextVarBytes()
+ if eof {
+ return fmt.Errorf("Waiting deserialize value error")
+ }
+ toChain, eof := source.NextUint32()
+ if eof {
+ return fmt.Errorf("Waiting deserialize toChain error")
+ }
+ height, eof := source.NextUint64()
+ if eof {
+ return fmt.Errorf("Waiting deserialize height error")
+ }
+ this.txIndex = txIndex
+ this.txId = txId
+ this.value = value
+ this.toChain = toChain
+ this.height = height
+ return nil
+}
+
+func (s *ZilliqaSyncManager) dumpPendingHeaders() {
+ log.Infof("ZilliqaSyncManager pending headers ------**-*")
+ for _, raw := range s.header4sync {
+ var block core.TxBlockOrDsBlock
+ _ = json.Unmarshal(raw, &block)
+ if block.TxBlock != nil {
+ log.Infof("ZilliqaSyncManager txBlk %d", block.TxBlock.BlockHeader.BlockNum)
+ }
+ if block.DsBlock != nil {
+ log.Infof("ZilliqaSyncManager dsBlk %d", block.DsBlock.BlockHeader.BlockNum)
+ }
+ }
+ log.Infof("ZilliqaSyncManager pending headers ======**=*")
+}
+
+func (s *ZilliqaSyncManager) commitHeader() int {
+ // maybe delete this after it is stable
+ for _, raw := range s.header4sync {
+ var block core.TxBlockOrDsBlock
+ _ = json.Unmarshal(raw, &block)
+ if block.TxBlock != nil {
+ log.Infof("ZilliqaSyncManager commitHeader - about to commit tx block: %d from DS %d \n", block.TxBlock.BlockHeader.BlockNum,
+ block.TxBlock.BlockHeader.DSBlockNum)
+ if s.debugInfo {
+ log.Infof("000 Check if DS block is in storage")
+ s.checkDSBlockInStorage(block.TxBlock.BlockHeader.DSBlockNum)
+ log.Infof("Check header index")
+ s.getHeaderIndex(block.TxBlock.BlockHeader.BlockNum, block.TxBlock.BlockHash[:])
+ log.Infof("Check main chain")
+ s.getMainChain(block.TxBlock.BlockHeader.BlockNum)
+ }
+ }
+
+ if block.DsBlock != nil {
+ log.Infof("ZilliqaSyncManager commitHeader - about to commit ds block: %d\n", block.DsBlock.BlockHeader.BlockNum)
+ if s.debugInfo {
+ s.checkDSBlockInStorage(block.DsBlock.BlockHeader.BlockNum)
+ log.Infof("000 check ds block hash")
+ s.getDsBlockHeader(block.DsBlock.BlockHeader.BlockNum, block.DsBlock.BlockHash[:])
+ }
+ }
+ }
+
+ if s.practiceOnly {
+ log.Infof("ZilliqaSyncManager commitHeader - exit without sync")
+ return 1
+ }
+ tx, err := s.polySdk.Native.Hs.SyncBlockHeader(
+ s.cfg.ZilConfig.SideChainId,
+ s.polySigner.Address,
+ s.header4sync,
+ s.polySigner,
+ )
+
+ if err != nil {
+ errDesc := err.Error()
+ if strings.Contains(errDesc, "get the parent block failed") || strings.Contains(errDesc, "missing required field") {
+ log.Warnf("ZilliqaSyncManager commitHeader - send transaction to poly chain err: %s", errDesc)
+ s.rollBackToCommAncestor()
+ return 0
+ } else {
+ log.Errorf("ZilliqaSyncManager commitHeader - send transaction to poly chain err: %s", errDesc)
+ if s.debugInfo {
+ log.Info("ZilliqaSyncManager - Raw data ****** ")
+ for _, raw := range s.header4sync {
+ log.Infof(string(raw[:]))
+ }
+ log.Infof("ZilliqaSyncManager - Raw data ends ====== ")
+ }
+ return 1
+ }
+ }
+
+ tick := time.NewTicker(100 * time.Millisecond)
+ retries := 0
+ var h uint32
+ for range tick.C {
+ if retries > 5000 {
+ return 1
+ } else {
+ retries++
+ }
+ h, err = s.polySdk.GetBlockHeightByTxHash(tx.ToHexString())
+
+ if err != nil {
+ if strings.Contains(err.Error(), "JsonRpcResponse error code:42002 desc:INVALID PARAMS") {
+ log.Infof("ZilliqaSyncManager commitHeader - wait for confirmation")
+ } else {
+ log.Warnf("ZilliqaSyncManager commitHeader get block height by hash, hash: %s error: %s", tx.ToHexString(), err.Error())
+ }
+ }
+ curr, err2 := s.polySdk.GetCurrentBlockHeight()
+ if err2 != nil {
+ log.Warnf("ZilliqaSyncManager commitHeader get current block height error: %s", err2.Error())
+ }
+ if h > 0 && curr > h {
+ log.Infof("ZilliqaSyncManager commitHeader h > 0 or curr > h")
+ break
+ }
+ }
+
+ log.Infof("ZilliqaSyncManager commitHeader - send transaction %s to poly chain and confirmed on height %d", tx.ToHexString(), h)
+ s.header4sync = make([][]byte, 0)
+
+ s.handleLockDepositEvents(s.currentHeight)
+ return 0
+}
+
+func (s *ZilliqaSyncManager) rollBackToCommAncestor() {
+ for ; ; s.currentHeight-- {
+ raw, err := s.polySdk.GetStorage(autils.HeaderSyncContractAddress.ToHexString(),
+ append(append([]byte(scom.MAIN_CHAIN), autils.GetUint64Bytes(s.cfg.ZilConfig.SideChainId)...), autils.GetUint64Bytes(s.currentHeight)...))
+ if len(raw) == 0 || err != nil {
+ continue
+ }
+ txBlockT, err2 := s.zilSdk.GetTxBlockVerbose(strconv.FormatUint(s.currentHeight, 10))
+ if err2 != nil {
+ log.Errorf("rollBackToCommAncestor - failed to get header by number, so we wait for one second to retry: %v", err2)
+ time.Sleep(time.Second)
+ s.currentHeight++
+ continue
+ }
+ blockHeader := core.NewTxBlockFromTxBlockT(txBlockT).BlockHeader
+ if bytes.Equal(util.Sha256(blockHeader.Serialize()), raw) {
+ bs, _ := json.Marshal(blockHeader)
+ log.Infof("ZilliqaSyncManager rollBackToCommAncestor - find the common ancestor: %s(number: %d)", bs, s.currentHeight)
+ break
+ }
+ }
+
+ s.header4sync = make([][]byte, 0)
+ txBlock, err := s.zilSdk.GetTxBlock(strconv.FormatUint(s.currentHeight, 10))
+ if err != nil {
+ log.Warnf("rollBackToCommAncestor, fail to get tx block, err: %s\n", err)
+ }
+
+ dsNum, err2 := strconv.ParseUint(txBlock.Header.DSBlockNum, 10, 64)
+ if err2 != nil {
+ log.Warnf("rollBackToCommAncestor, fail to parse ds num, err: %s\n", err2)
+ }
+
+ a, _ := s.zilSdk.GetDsBlockVerbose(txBlock.Header.DSBlockNum)
+ b := core.NewDsBlockFromDsBlockT(a)
+ txBlockOrDsBlock := core.TxBlockOrDsBlock{
+ DsBlock: b,
+ }
+ rawBlock, _ := json.Marshal(txBlockOrDsBlock)
+ s.header4sync = append(s.header4sync, rawBlock)
+ s.currentDsBlockNum = dsNum
+
+}
diff --git a/service/zil_sender.go b/service/zil_sender.go
new file mode 100644
index 0000000..8caa5c6
--- /dev/null
+++ b/service/zil_sender.go
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "github.com/Zilliqa/gozilliqa-sdk/crosschain/polynetwork"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ "github.com/Zilliqa/gozilliqa-sdk/transaction"
+ "github.com/Zilliqa/gozilliqa-sdk/util"
+ "github.com/ontio/ontology-crypto/keypair"
+ "github.com/ontio/ontology-crypto/signature"
+ poly_go_sdk "github.com/polynetwork/poly-go-sdk"
+ vconfig "github.com/polynetwork/poly/consensus/vbft/config"
+ polytypes "github.com/polynetwork/poly/core/types"
+ common2 "github.com/polynetwork/poly/native/service/cross_chain_manager/common"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/tools"
+ log "github.com/sirupsen/logrus"
+ "sync"
+)
+
+type ZilSender struct {
+ cfg *config.Config
+ zilSdk *provider.Provider
+ //non-bech32 address
+ address string
+ privateKey string
+
+ polySdk *poly_go_sdk.PolySdk
+ crossChainProxy *polynetwork.Proxy
+ inUse bool
+ mu sync.Mutex
+}
+
+func (sender *ZilSender) commitDepositEventsWithHeaderWithNonce(header *polytypes.Header, param *common2.ToMerkleValue, headerProof string, anchorHeader *polytypes.Header, polyTxHash string, rawAuditPath []byte, nonce string) (*transaction.Transaction, error) {
+ // verifyHeaderAndExecuteTx
+ var (
+ sigs []byte
+ headerData []byte
+ )
+ if anchorHeader != nil && headerProof != "" {
+ for _, sig := range anchorHeader.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+ } else {
+ for _, sig := range header.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+ }
+
+ exist := sender.checkIfFromChainTxExist(param.FromChainID, util.EncodeHex(param.TxHash))
+ if exist {
+ log.Infof("ZilSender commitDepositEventsWithHeader - already relayed to zil: (from_chain_id: %d, from_txhash: %x, param.TxHash: %x\n)", param.FromChainID, param.TxHash, param.MakeTxParam.TxHash)
+ return nil, errors.New("ZilSender commitDepositEventsWithHeader - already relayed to zil")
+ }
+
+ var rawAnchor []byte
+ if anchorHeader != nil {
+ rawAnchor = anchorHeader.GetMessage()
+ }
+ headerData = header.GetMessage()
+
+ pe := polynetwork.DeserializeProof(util.EncodeHex(rawAuditPath), 0)
+ rawHeader := "0x" + util.EncodeHex(headerData)
+ hpe := polynetwork.DeserializeProof(headerProof, 0)
+ curRawHeader := "0x" + util.EncodeHex(rawAnchor)
+ signatures, _ := polynetwork.SplitSignature(util.EncodeHex(sigs))
+
+ return sender.crossChainProxy.VerifyHeaderAndExecuteTxWithNonce(pe, rawHeader, hpe, curRawHeader, signatures, nonce)
+}
+
+func (sender *ZilSender) commitDepositEventsWithHeader(header *polytypes.Header, param *common2.ToMerkleValue, headerProof string, anchorHeader *polytypes.Header, polyTxHash string, rawAuditPath []byte) bool {
+ // verifyHeaderAndExecuteTx
+ var (
+ sigs []byte
+ headerData []byte
+ )
+ if anchorHeader != nil && headerProof != "" {
+ for _, sig := range anchorHeader.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+ } else {
+ for _, sig := range header.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+ }
+
+ exist := sender.checkIfFromChainTxExist(param.FromChainID, util.EncodeHex(param.TxHash))
+ if exist {
+ log.Infof("ZilSender commitDepositEventsWithHeader - already relayed to zil: (from_chain_id: %d, from_txhash: %x, param.TxHash: %x\n)", param.FromChainID, param.TxHash, param.MakeTxParam.TxHash)
+ return true
+ }
+
+ var rawAnchor []byte
+ if anchorHeader != nil {
+ rawAnchor = anchorHeader.GetMessage()
+ }
+ headerData = header.GetMessage()
+
+ pe := polynetwork.DeserializeProof(util.EncodeHex(rawAuditPath), 0)
+ rawHeader := "0x" + util.EncodeHex(headerData)
+ hpe := polynetwork.DeserializeProof(headerProof, 0)
+ curRawHeader := "0x" + util.EncodeHex(rawAnchor)
+ signatures, _ := polynetwork.SplitSignature(util.EncodeHex(sigs))
+
+ transaction, err := sender.crossChainProxy.VerifyHeaderAndExecuteTx(pe, rawHeader, hpe, curRawHeader, signatures)
+ sender.inUse = false
+ if err != nil {
+ log.Errorf("ZilSender commitDepositEventsWithHeader - failed to call VerifyHeaderAndExecuteTx: %s\n", err.Error())
+ return false
+ }
+
+ log.Infof("ZilSender commitDepositEventsWithHeader - confirmed transaction: %s\n", transaction.ID)
+ return true
+
+}
+
+func (sender *ZilSender) commitHeader(hdr *polytypes.Header) bool {
+ log.Infof("ZilSender commitHeader - height: %d\n", hdr.Height)
+ headerdata := hdr.GetMessage()
+ var (
+ bookkeepers []keypair.PublicKey
+ sigs []byte
+ )
+
+ for _, sig := range hdr.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+
+ blkInfo := &vconfig.VbftBlockInfo{}
+ if err := json.Unmarshal(hdr.ConsensusPayload, blkInfo); err != nil {
+ log.Errorf("commitHeader - unmarshal blockInfo error: %s", err)
+ return false
+ }
+
+ for _, peer := range blkInfo.NewChainConfig.Peers {
+ keystr, _ := hex.DecodeString(peer.ID)
+ key, _ := keypair.DeserializePublicKey(keystr)
+ bookkeepers = append(bookkeepers, key)
+ }
+
+ bookkeepers = keypair.SortPublicKeys(bookkeepers)
+ publickeys := make([]byte, 0)
+ for _, key := range bookkeepers {
+ publickeys = append(publickeys, tools.GetNoCompresskey(key)...)
+ }
+
+ rawHeader := "0x" + util.EncodeHex(headerdata)
+ PubKeys, _ := polynetwork.SplitPubKeys(util.EncodeHex(publickeys))
+ signatures, _ := polynetwork.SplitSignature(util.EncodeHex(sigs))
+ transaction, err := sender.crossChainProxy.ChangeBookKeeper(rawHeader, PubKeys, signatures)
+ sender.inUse = false
+ if err != nil {
+ log.Errorf("ZilSender commitHeader - failed to call VerifyHeaderAndExecuteTx: %s\n", err.Error())
+ return false
+ }
+
+ log.Infof("ZilSender commitHeader - confirmed transaction: %s\n", transaction.ID)
+
+ return true
+
+}
+
+func (sender *ZilSender) commitHeaderWithNonce(hdr *polytypes.Header, nonce string) (*transaction.Transaction, error) {
+ log.Infof("ZilSender commitHeader - height: %d\n", hdr.Height)
+ headerdata := hdr.GetMessage()
+ var (
+ bookkeepers []keypair.PublicKey
+ sigs []byte
+ )
+
+ for _, sig := range hdr.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+
+ blkInfo := &vconfig.VbftBlockInfo{}
+ if err := json.Unmarshal(hdr.ConsensusPayload, blkInfo); err != nil {
+ return nil, err
+ }
+
+ for _, peer := range blkInfo.NewChainConfig.Peers {
+ keystr, _ := hex.DecodeString(peer.ID)
+ key, _ := keypair.DeserializePublicKey(keystr)
+ bookkeepers = append(bookkeepers, key)
+ }
+
+ bookkeepers = keypair.SortPublicKeys(bookkeepers)
+ publickeys := make([]byte, 0)
+ for _, key := range bookkeepers {
+ publickeys = append(publickeys, tools.GetNoCompresskey(key)...)
+ }
+
+ rawHeader := "0x" + util.EncodeHex(headerdata)
+ PubKeys, _ := polynetwork.SplitPubKeys(util.EncodeHex(publickeys))
+ signatures, _ := polynetwork.SplitSignature(util.EncodeHex(sigs))
+ return sender.crossChainProxy.ChangeBookKeeperWithNonce(rawHeader, PubKeys, signatures, nonce)
+}
diff --git a/service/zilliqamanager.go b/service/zilliqamanager.go
new file mode 100644
index 0000000..354f1b6
--- /dev/null
+++ b/service/zilliqamanager.go
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package service
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "github.com/Zilliqa/gozilliqa-sdk/account"
+ "github.com/Zilliqa/gozilliqa-sdk/core"
+ "github.com/Zilliqa/gozilliqa-sdk/provider"
+ poly "github.com/polynetwork/poly-go-sdk"
+ sdk "github.com/polynetwork/poly-go-sdk"
+ "github.com/polynetwork/poly/common"
+ scom "github.com/polynetwork/poly/native/service/header_sync/common"
+ autils "github.com/polynetwork/poly/native/service/utils"
+ "github.com/polynetwork/zilliqa-relayer/config"
+ "github.com/polynetwork/zilliqa-relayer/db"
+ log "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+/**
+ * currentHeight's source is either from poly remote storage or forceHeight
+ */
+type ZilliqaSyncManager struct {
+ polySigner *poly.Account
+ polySdk *poly.PolySdk
+ relaySyncHeight uint32
+ zilAccount *account.Account
+ currentHeight uint64
+ currentDsBlockNum uint64
+ forceHeight uint64
+ zilSdk *provider.Provider
+ crossChainManagerAddress string
+ cfg *config.Config
+ db *db.BoltDB
+ exitChan chan int
+ header4sync [][]byte
+ debugInfo bool
+ practiceOnly bool
+}
+
+func NewZilliqaSyncManager(cfg *config.Config, zilSdk *provider.Provider, polysdk *sdk.PolySdk, boltDB *db.BoltDB, debugInfo bool, practiceOnly bool) (*ZilliqaSyncManager, error) {
+ var wallet *sdk.Wallet
+ var err error
+ if !common.FileExisted(cfg.PolyConfig.PolyWalletFile) {
+ wallet, err = polysdk.OpenWallet(cfg.PolyConfig.PolyWalletFile)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ wallet, err = polysdk.OpenWallet(cfg.PolyConfig.PolyWalletFile)
+ if err != nil {
+ log.Errorf("NewZilliqaSyncManager - wallet open error: %s", err.Error())
+ return nil, err
+ }
+ }
+ signer, err := wallet.GetDefaultAccount([]byte(cfg.PolyConfig.PolyWalletPassword))
+ if err != nil || signer == nil {
+ signer, err = wallet.NewDefaultSettingAccount([]byte(cfg.PolyConfig.PolyWalletPassword))
+ if err != nil {
+ log.Errorf("NewETHManager - wallet password error")
+ return nil, err
+ }
+
+ err = wallet.Save()
+ if err != nil {
+ return nil, err
+ }
+ }
+ log.Infof("NewZilliqaSyncManager - poly address: %s", signer.Address.ToBase58())
+ zilliqaSyncManager := &ZilliqaSyncManager{
+ db: boltDB,
+ cfg: cfg,
+ exitChan: make(chan int),
+ zilSdk: zilSdk,
+ forceHeight: cfg.ZilConfig.ZilForceHeight,
+ crossChainManagerAddress: cfg.ZilConfig.CrossChainManagerContract,
+ polySigner: signer,
+ polySdk: polysdk,
+ debugInfo: debugInfo,
+ practiceOnly: practiceOnly,
+ }
+
+ err = zilliqaSyncManager.init()
+ if err != nil {
+ return nil, err
+ } else {
+ return zilliqaSyncManager, nil
+ }
+}
+
+func (s *ZilliqaSyncManager) Run(enable bool) {
+ if enable {
+ go s.MonitorChain()
+ }
+}
+
+func (s *ZilliqaSyncManager) init() error {
+ // get latest tx block from remote poly storage, thus we can know current tx block num and ds block num
+ latestHeight := s.findLatestTxBlockHeight()
+ log.Infof("ZilliqaSyncManager init - get latest tx block from poly, tx block height is: %d\n", latestHeight)
+
+ if latestHeight == 0 {
+ return fmt.Errorf("ZilliqaSyncManager init - the genesis block has not synced!")
+ }
+
+ if s.forceHeight > 0 && s.forceHeight < latestHeight {
+ s.currentHeight = s.forceHeight
+ } else {
+ s.currentHeight = latestHeight
+ }
+ log.Infof("ZilliqaSyncManager init - start height: %d", s.currentHeight)
+ if s.debugInfo {
+ s.getGenesisHeader()
+ s.getMainChain(latestHeight)
+ }
+ txBlockT, err := s.zilSdk.GetTxBlockVerbose(strconv.FormatUint(s.currentHeight, 10))
+ if err != nil {
+ return fmt.Errorf("ZilliqaSyncManager init - get tx block error: %s", err.Error())
+ }
+ dsBlockNum, _ := strconv.ParseUint(txBlockT.Header.DSBlockNum, 10, 64)
+ s.currentDsBlockNum = dsBlockNum
+ log.Infof("ZilliqaSyncManager init - current ds block height is: %d\n", s.currentDsBlockNum)
+ return nil
+}
+
+func (s *ZilliqaSyncManager) getGenesisHeader() {
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ key := append([]byte(scom.GENESIS_HEADER), sideChainIdBytes[:]...)
+ contractAddress := autils.HeaderSyncContractAddress
+ result, err := s.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ if err != nil {
+ log.Infof("cannot obtain latest genesis header\n")
+ }
+ if result == nil || len(result) == 0 {
+ log.Infof("0-length result from gensis header query\n")
+ }
+ // Turns out the genesis header is a string.
+ block := new(core.TxBlock)
+ genesisString := string(result[:])
+ log.Infof("----- GENESIS HEADER ----- \n")
+ log.Infof("%s", genesisString)
+ log.Infof("====== END GENESIS HEADER ===== \n")
+ err = json.Unmarshal(result, block)
+ if err != nil {
+ log.Infof("!!!!! Could not unmarshal genesis - %s", err)
+ } else {
+ log.Infof("Get main chain for %d", block.BlockHeader.BlockNum)
+ s.getMainChain(block.BlockHeader.BlockNum)
+ log.Infof("GetHeaderIndex for %d:%x", block.BlockHeader.BlockNum, block.BlockHash)
+ s.getHeaderIndex(block.BlockHeader.BlockNum, block.BlockHash[:])
+ dsBlockNum := block.BlockHeader.DSBlockNum
+ log.Infof("Get DsComm %d from polynet", dsBlockNum)
+ s.checkDSBlockInStorage(dsBlockNum)
+ log.Infof("Get DS Block %d from chain", dsBlockNum)
+ dsb, err := s.zilSdk.GetDsBlockVerbose(strconv.FormatUint(dsBlockNum, 10))
+ if err != nil {
+ log.Infof("Could not get DS Block - %s", err)
+ } else {
+ if dsb == nil {
+ log.Infof("nil DS Block %s", strconv.Itoa(int(dsBlockNum)))
+ } else {
+ dsbval := core.NewDsBlockFromDsBlockT(dsb)
+ log.Infof("getDsBlockHeader %x", dsbval.BlockHash)
+ s.getDsBlockHeader(dsBlockNum, dsbval.BlockHash[:])
+ }
+ }
+ log.Infof("XXX Done")
+ s.scanForDsCommittees(dsBlockNum)
+ }
+}
+
+func (s *ZilliqaSyncManager) scanForDsCommittees(seedBlk uint64) {
+ for i := -32; i < 32; i += 1 {
+ toSearch := int(seedBlk) + i
+ log.Infof("==== Is there a DSC for %d? ", toSearch)
+ s.checkDSBlockInStorage(uint64(toSearch))
+ log.Infof("---- NEXT DSC")
+ }
+}
+
+// Get the DS Block Header
+func (s *ZilliqaSyncManager) getDsBlockHeader(dsBlkNum uint64, hash []byte) {
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ key := append([]byte(scom.HEADER_INDEX), sideChainIdBytes[:]...)
+ key = append(key, hash...)
+ contractAddress := autils.HeaderSyncContractAddress
+ result, err := s.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ log.Infof("---- DS Header hash with blknum %d hash %x", dsBlkNum, hash)
+ if err != nil {
+ log.Infof("==== FAILED %s", err)
+ }
+ if result == nil || len(result) == 0 {
+ log.Infof("==== 0-length or empty result")
+ } else {
+ log.Infof("==== Retrieved: %x", result)
+ }
+
+}
+
+// Given a tx block number, try to obtain MAIN_CHAIN
+func (s *ZilliqaSyncManager) getMainChain(blknum uint64) {
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ key := append([]byte(scom.MAIN_CHAIN), sideChainIdBytes[:]...)
+ var blkNumBytes [8]byte
+ binary.LittleEndian.PutUint64(blkNumBytes[:], blknum)
+ key = append(key, blkNumBytes[:]...)
+ contractAddress := autils.HeaderSyncContractAddress
+ result, err := s.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ log.Infof("---- MAIN_CHAIN with blknum %d", blknum)
+ if err != nil {
+ log.Infof("==== FAILED %s", err)
+ }
+ if result == nil || len(result) == 0 {
+ log.Infof("==== 0-length or empty result")
+ } else {
+ log.Infof("==== Retrieved: %x", result)
+ }
+}
+
+// Given a tx block hash, see if the header index is in storage.
+func (s *ZilliqaSyncManager) getHeaderIndex(blknum uint64, hash []byte) {
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ key := append([]byte(scom.HEADER_INDEX), sideChainIdBytes[:]...)
+ key = append(key, hash...)
+ contractAddress := autils.HeaderSyncContractAddress
+ result, err := s.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ log.Infof("---- Header hash with blknum %d hash %x", blknum, hash)
+ if err != nil {
+ log.Infof("==== FAILED %s", err)
+ }
+ if result == nil || len(result) == 0 {
+ log.Infof("==== 0-length or empty result")
+ } else {
+ log.Infof("==== Retrieved: %x", result)
+ }
+}
+
+func (s *ZilliqaSyncManager) checkDSBlockInStorage(blk uint64) {
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ var blkc [8]byte
+ binary.LittleEndian.PutUint64(blkc[:], blk)
+ key := append(sideChainIdBytes[:], []byte("dsComm")...)
+ key = append(key, blkc[:]...)
+ result, err := s.polySdk.GetStorage(autils.HeaderSyncContractAddress.ToHexString(), key)
+ if err != nil {
+ log.Infof("XXXX Couldn't retrieve polynet storage for DS Block %d: %s", blk, err.Error())
+ }
+ if result == nil || len(result) == 0 {
+ log.Infof("XXXX no DSC stored for ds block %d", blk)
+ } else {
+ log.Infof("==== DSC for DS block %d is %x", blk, result)
+ }
+}
+
+func (s *ZilliqaSyncManager) findLatestTxBlockHeight() uint64 {
+ // try to get key
+ var sideChainIdBytes [8]byte
+ binary.LittleEndian.PutUint64(sideChainIdBytes[:], s.cfg.ZilConfig.SideChainId)
+ contractAddress := autils.HeaderSyncContractAddress
+ key := append([]byte(scom.CURRENT_HEADER_HEIGHT), sideChainIdBytes[:]...)
+ // try to get storage
+ result, err := s.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ if err != nil {
+ log.Infof("get latest tx block from poly failed,err: %s\n", err.Error())
+ return 0
+ }
+ if result == nil || len(result) == 0 {
+ return 0
+ } else {
+ return binary.LittleEndian.Uint64(result)
+ }
+}
diff --git a/target_contracts.json b/target_contracts.json
new file mode 100644
index 0000000..f755f41
--- /dev/null
+++ b/target_contracts.json
@@ -0,0 +1,8 @@
+[
+ {
+ "zil1v4v858qjqd5s88vvsj3qsn89nndeldkpwd9l2c": {
+ "inbound": [202],
+ "outbound": [202]
+ }
+ }
+]
\ No newline at end of file
diff --git a/tools/utils.go b/tools/utils.go
new file mode 100644
index 0000000..5313566
--- /dev/null
+++ b/tools/utils.go
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 Zilliqa
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package tools
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/elliptic"
+ "encoding/hex"
+ "github.com/btcsuite/btcd/btcec"
+ "github.com/ontio/ontology-crypto/ec"
+ "github.com/ontio/ontology-crypto/keypair"
+ "github.com/ontio/ontology-crypto/sm2"
+ "github.com/polynetwork/poly/common"
+ "golang.org/x/crypto/ed25519"
+ "math/big"
+ "os"
+ "strings"
+)
+
+func EncodeBigInt(b *big.Int) string {
+ if b.Uint64() == 0 {
+ return "00"
+ }
+ return hex.EncodeToString(b.Bytes())
+}
+
+func ParseAuditpath(path []byte) ([]byte, []byte, [][32]byte, error) {
+ source := common.NewZeroCopySource(path)
+ /*
+ l, eof := source.NextUint64()
+ if eof {
+ return nil, nil, nil, nil
+ }
+ */
+ value, eof := source.NextVarBytes()
+ if eof {
+ return nil, nil, nil, nil
+ }
+ size := int((source.Size() - source.Pos()) / common.UINT256_SIZE)
+ pos := make([]byte, 0)
+ hashs := make([][32]byte, 0)
+ for i := 0; i < size; i++ {
+ f, eof := source.NextByte()
+ if eof {
+ return nil, nil, nil, nil
+ }
+ pos = append(pos, f)
+
+ v, eof := source.NextHash()
+ if eof {
+ return nil, nil, nil, nil
+ }
+ var onehash [32]byte
+ copy(onehash[:], (v.ToArray())[0:32])
+ hashs = append(hashs, onehash)
+ }
+
+ return value, pos, hashs, nil
+}
+
+func ReadLine(path string) ([]string, error) {
+ var lines []string
+ file, err := os.Open(path)
+ if err != nil {
+ return lines, err
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ lines = append(lines, scanner.Text())
+ }
+
+ if err1 := scanner.Err(); err1 != nil {
+ return lines, err1
+ }
+
+ return lines, nil
+}
+
+func GetCurveLabel(name string) (byte, error) {
+ switch strings.ToUpper(name) {
+ case strings.ToUpper(elliptic.P224().Params().Name):
+ return 1, nil
+ case strings.ToUpper(elliptic.P256().Params().Name):
+ return 2, nil
+ case strings.ToUpper(elliptic.P384().Params().Name):
+ return 3, nil
+ case strings.ToUpper(elliptic.P521().Params().Name):
+ return 4, nil
+ case strings.ToUpper(sm2.SM2P256V1().Params().Name):
+ return 20, nil
+ case strings.ToUpper(btcec.S256().Name):
+ return 5, nil
+ default:
+ panic("err")
+ }
+}
+
+func GetNoCompresskey(key keypair.PublicKey) []byte {
+ var buf bytes.Buffer
+ switch t := key.(type) {
+ case *ec.PublicKey:
+ switch t.Algorithm {
+ case ec.ECDSA:
+ // Take P-256 as a special case
+ if t.Params().Name == elliptic.P256().Params().Name {
+ return ec.EncodePublicKey(t.PublicKey, false)
+ }
+ buf.WriteByte(byte(0x12))
+ case ec.SM2:
+ buf.WriteByte(byte(0x13))
+ }
+ label, err := GetCurveLabel(t.Curve.Params().Name)
+ if err != nil {
+ panic(err)
+ }
+ buf.WriteByte(label)
+ buf.Write(ec.EncodePublicKey(t.PublicKey, false))
+ case ed25519.PublicKey:
+ panic("err")
+ default:
+ panic("err")
+ }
+ return buf.Bytes()
+}
+
+func AppendToFile(fileName string, context string) {
+ f, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
+ if err != nil {
+ panic(err)
+ }
+
+ defer f.Close()
+
+ if _, err = f.WriteString(context); err != nil {
+ panic(err)
+ }
+}