diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..beb15a5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+.idea/
+.idea/workspace.xml
+capital*
+db/bolt.bin
+wallet.dat
+config-debug.json
+log/20*
+UTC--*
+Log
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f288702
--- /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 0bf26bc..4a48f01 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,70 @@
-# kai-relayer
\ No newline at end of file
+ Kai Relayer
+
+Kai(Kardiachain) Relayer is an important character of Poly cross-chain interactive protocol which is responsible for relaying cross-chain transaction from and to Kardiachain.
+
+## Build From Source
+
+### Prerequisites
+
+- [Golang](https://golang.org/doc/install) version 1.14 or later
+
+### Build
+
+```shell
+git clone https://github.com/polynetwork/kai-relayer.git
+cd kai_relayer
+go build -o kai_relayer main.go
+```
+
+After building the source code successfully, you should see the executable program `kai_relayer`.
+
+### Build Docker Image
+
+```
+docker build -t polynetwork/kai_relayer -f Dockerfile ./
+```
+
+This command will copy ./config.json to /app/config.json in the image. So you need to prepare config.json before running this command and you should start the kai-relayer in container basing on the configuration in /app/config.json.
+
+## Run Relayer
+
+Before you can run the relayer you will need to create a wallet file of PolyNetwork. 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.json`.
+
+```
+{
+ "MultiChainConfig":{
+ "RestURL":"http://poly_ip:20336", // address of Poly
+ "EntranceContractAddress":"0300000000000000000000000000000000000000", // CrossChainManagerContractAddress on Poly. No need to change
+ "WalletFile":"./wallet.dat", // your poly wallet
+ "WalletPwd":"pwd" //password
+ },
+ "KaiConfig":{
+ "SideChainId": 2, // kai side chainID registered on poly
+ "RestURL":"https://dev-1@kardiachain.io", // your kai node
+ "ECCMContractAddress":"kai_cross_chain_contract",
+ "ECCDContractAddress":"kai_cross_chain_data_contract",
+ "KeyStorePath": "./keystore", // path to store your kai(ethereum) wallet
+ "KeyStorePwdSet": { // password to protect your kai(ethereum) wallet
+ "0xd12e...54ccacf91ca364d": "pwd1", // password for address "0xd12e...54ccacf91ca364d"
+ "0xabb4...0aba7cf3ee3b953": "pwd2" // password for address "0xabb4...0aba7cf3ee3b953"
+ },
+ "BlockConfig": 20, // blocks to confirm a kai tx
+ "HeadersPerBatch": 500, // number of kai headers commited to poly in one transaction at most
+ "MonitorInterval": 3, // seconds of ticker to monitor kai chain
+ "EnableChangeBookKeeper": false // normally speaking, set this value as false
+ },
+ "BoltDbPath": "./db", // DB path
+ "RoutineNum": 64,
+ "TargetContracts": [
+ {
+ "0xD8aE73e06552E...bcAbf9277a1aac99": { // your lockproxy hash on kai chain
+ "inbound": [6], // from which chain allowed
+ "outbound": [6] // to which chain allowed
+ }
+ }
+ ]
+}
+```
+
diff --git a/cmd/flags.go b/cmd/flags.go
new file mode 100644
index 0000000..7c956e8
--- /dev/null
+++ b/cmd/flags.go
@@ -0,0 +1,95 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package cmd
+
+import (
+ "strings"
+
+ "github.com/polynetwork/kai-relayer/config"
+ "github.com/urfave/cli"
+)
+
+var (
+ LogLevelFlag = cli.UintFlag{
+ Name: "loglevel",
+ Usage: "Set the log level to `` (0~6). 0:Trace 1:Debug 2:Info 3:Warn 4:Error 5:Fatal 6:MaxLevel",
+ Value: config.DEFAULT_LOG_LEVEL,
+ }
+
+ //CliWalletDirFlag = cli.StringFlag{
+ // Name: "walletdir",
+ // Usage: "Wallet data ``",
+ // Value: config.DEFAULT_WALLET_PATH,
+ //}
+
+ //CliAddressFlag = cli.StringFlag{
+ // Name: "cliaddress",
+ // Usage: "Rpc bind ``",
+ // Value: config.DEFUALT_CLI_RPC_ADDRESS,
+ //}
+
+ //CliRpcPortFlag = cli.UintFlag{
+ // Name: "cliport",
+ // Usage: "Rpc bind port ``",
+ // Value: config.DEFAULT_CLI_RPC_PORT,
+ //}
+
+ ConfigPathFlag = cli.StringFlag{
+ Name: "cliconfig",
+ Usage: "Server config file ``",
+ Value: config.DEFAULT_CONFIG_FILE_NAME,
+ }
+
+ KaiStartFlag = cli.Uint64Flag{
+ Name: "kardiachain",
+ Usage: "kai start block height ",
+ Value: uint64(0),
+ }
+
+ KaiStartForceFlag = cli.Uint64Flag{
+ Name: "kardiachainforce",
+ Usage: "kai start block height ",
+ Value: uint64(0),
+ }
+
+ PolyStartFlag = cli.Uint64Flag{
+ Name: "poly",
+ Usage: "poly start block height ",
+ Value: uint64(0),
+ }
+
+ LogDir = cli.StringFlag{
+ Name: "logdir",
+ Usage: "log directory",
+ Value: "./Log/",
+ }
+
+ //EncryptFlag = cli.StringFlag{
+ // Name: "encrypt",
+ // Usage: "encrypt string `pwd`",
+ // Value: "",
+ //}
+)
+
+//GetFlagName deal with short flag, and return the flag name whether flag name have short name
+func GetFlagName(flag cli.Flag) string {
+ name := flag.GetName()
+ if name == "" {
+ return ""
+ }
+ return strings.TrimSpace(strings.Split(name, ",")[0])
+}
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..3de4aa6
--- /dev/null
+++ b/config.json
@@ -0,0 +1,26 @@
+{
+ "PolyConfig":{
+ "RestURL":"http://138.91.6.226:40336",
+ "EntranceContractAddress":"0300000000000000000000000000000000000000",
+ "WalletFile":"/home/thangn/go/pkg/github.com/polynetwork/poly/wallet.dat",
+ "WalletPwd":"123456"
+ },
+ "KaiConfig":{
+ "SideChainId": 141,
+ "RestURL":"https://dev-1.kardiachain.io",
+ "ECCMContractAddress":"0x14E8226B63C77c6fdCB3830e1bde2b6981F01AAe",
+ "ECCDContractAddress":"0xad8673ba653c75494EF43F3431b67aD597B21314",
+ "KeyStorePath": "/home/thangn/snap/geth/477/.ethereum/keystore",
+ "KeyStorePwdSet": {
+ "0x2290ddc3874523ffd48c948c8b9379425bDe8BeC": "123456"
+ },
+ "BlockConfig": 2,
+ "HeadersPerBatch": 500,
+ "MonitorInterval": 3,
+ "EnableChangeBookKeeper": false
+ },
+ "BoltDbPath": "./db",
+ "RoutineNum": 64,
+ "TargetContracts": [
+ ]
+}
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..5e47b50
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,113 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package config
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/polynetwork/kai-relayer/log"
+)
+
+const (
+ KAI_MONITOR_INTERVAL = 3 * time.Second
+ ONT_MONITOR_INTERVAL = 3 * time.Second
+ KEY_UNLOCK_TIME = 30 * time.Second
+
+ KAI_USEFUL_BLOCK_NUM = 3
+ KAI_PROOF_USERFUL_BLOCK = 12
+ ONT_USEFUL_BLOCK_NUM = 1
+ DEFAULT_CONFIG_FILE_NAME = "./config.json"
+ Version = "1.0"
+
+ DEFAULT_LOG_LEVEL = log.InfoLog
+)
+
+//type ETH struct {
+// Chain string // eth or etc
+// ChainId uint64
+// RpcAddress string
+// ConfirmedBlockNum uint
+// //Tokens []*Token
+//}
+
+type ServiceConfig struct {
+ PolyConfig *PolyConfig
+ KAIConfig *KAIConfig
+ BoltDbPath string
+ RoutineNum int64
+}
+
+type PolyConfig struct {
+ RestURL string
+ EntranceContractAddress string
+ WalletFile string
+ WalletPwd string
+}
+
+type KAIConfig struct {
+ RestURL string
+ ECCMContractAddress string
+ ECCDContractAddress string
+ KeyStorePath string
+ KeyStorePwdSet map[string]string
+ BlockConfig uint64
+ SideChainId uint64
+}
+
+func ReadFile(fileName string) ([]byte, error) {
+ file, err := os.OpenFile(fileName, os.O_RDONLY, 0666)
+ if err != nil {
+ return nil, fmt.Errorf("ReadFile: open file %s error %s", fileName, err)
+ }
+ defer func() {
+ err := file.Close()
+ if err != nil {
+ log.Errorf("ReadFile: File %s close error %s", fileName, err)
+ }
+ }()
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ return nil, fmt.Errorf("ReadFile: ioutil.ReadAll %s error %s", fileName, err)
+ }
+ return data, nil
+}
+
+func NewServiceConfig(configFilePath string) *ServiceConfig {
+ fileContent, err := ReadFile(configFilePath)
+ if err != nil {
+ log.Errorf("NewServiceConfig: failed, err: %s", err)
+ return nil
+ }
+ servConfig := &ServiceConfig{}
+ err = json.Unmarshal(fileContent, servConfig)
+ if err != nil {
+ log.Errorf("NewServiceConfig: failed, err: %s", err)
+ return nil
+ }
+
+ for k, v := range servConfig.KAIConfig.KeyStorePwdSet {
+ delete(servConfig.KAIConfig.KeyStorePwdSet, k)
+ servConfig.KAIConfig.KeyStorePwdSet[strings.ToLower(k)] = v
+ }
+
+ return servConfig
+}
diff --git a/db/db.go b/db/db.go
new file mode 100644
index 0000000..f6a1b42
--- /dev/null
+++ b/db/db.go
@@ -0,0 +1,244 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package db
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "path"
+ "strings"
+ "sync"
+
+ "github.com/boltdb/bolt"
+)
+
+const MAX_NUM = 1000
+
+var (
+ BKTCheck = []byte("Check")
+ BKTRetry = []byte("Retry")
+ BKTHeight = []byte("Height")
+)
+
+type BoltDB struct {
+ rwlock *sync.RWMutex
+ db *bolt.DB
+ filePath string
+}
+
+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
+
+ 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
+ }
+
+ 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
+ }
+
+ 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) 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) DeleteCheck(txHash string) error {
+ w.rwlock.Lock()
+ defer w.rwlock.Unlock()
+
+ k, err := hex.DecodeString(txHash)
+ if err != nil {
+ return err
+ }
+ return w.db.Update(func(tx *bolt.Tx) error {
+ bucket := tx.Bucket(BKTCheck)
+ err := bucket.Delete(k)
+ if err != nil {
+ return err
+ }
+ return 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) GetAllCheck() (map[string][]byte, error) {
+ w.rwlock.Lock()
+ defer w.rwlock.Unlock()
+
+ checkMap := make(map[string][]byte)
+ err := w.db.Update(func(tx *bolt.Tx) error {
+ bw := tx.Bucket(BKTCheck)
+ bw.ForEach(func(k, v []byte) error {
+ _k := make([]byte, len(k))
+ _v := make([]byte, len(v))
+ copy(_k, k)
+ copy(_v, v)
+ checkMap[hex.EncodeToString(_k)] = _v
+ if len(checkMap) >= MAX_NUM {
+ return fmt.Errorf("max num")
+ }
+ return nil
+ })
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return checkMap, 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
+}
+
+func (w *BoltDB) Close() {
+ w.rwlock.Lock()
+ w.db.Close()
+ w.rwlock.Unlock()
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..3a81ed8
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,18 @@
+module github.com/polynetwork/kai-relayer
+
+go 1.14
+
+require (
+ github.com/boltdb/bolt v1.3.1
+ github.com/btcsuite/btcd v0.21.0-beta
+ github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e // indirect
+ github.com/ethereum/go-ethereum v1.9.18
+ github.com/kardiachain/go-kardia v1.1.1-0.20210518091640-d13a5b7f7c4c
+ github.com/ontio/ontology-crypto v1.0.9
+ github.com/polynetwork/eth-contracts v0.0.0-20200814062128-70f58e22b014
+ github.com/polynetwork/poly v0.0.0-20200722075529-eea88acb37b2
+ github.com/polynetwork/poly-go-sdk v0.0.0-20200729103825-af447ef53ef0
+ github.com/stretchr/testify v1.7.0
+ github.com/urfave/cli v1.22.4
+ launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..1d09c83
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,904 @@
+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=
+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/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/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/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
+github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
+github.com/antlr/antlr4 v0.0.0-20190819145818-b43a4c3a8015/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
+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/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
+github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015 h1:7ABPr1+uJdqESAdlVevnc/2FJGiC/K3uMg1JiELeF+0=
+github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015/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/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.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=
+github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
+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-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/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
+github.com/cespare/cp v1.1.1/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/go-semver v0.2.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 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+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/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
+github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
+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/docker/docker v17.12.0-ce-rc1.0.20200531234253-77e06fda0c94+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/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/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/ebuchman/fail-test v0.0.0-20170303061230-95f809107225 h1:7TXT8REobzZUI9GzsRtAD29efTY/HgKRU2xYnV1zlaM=
+github.com/ebuchman/fail-test v0.0.0-20170303061230-95f809107225/go.mod h1:OFTBW14UVJS8P0shpX7OdPY0qpkTdA7AWGYFacMC2D8=
+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.18 h1:+vzvufVD7+OfQa07IJP20Z7AGZsJaw0M6JIA/WQcqy8=
+github.com/ethereum/go-ethereum v1.9.18/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg=
+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/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
+github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/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 h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
+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-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/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+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.3.1-0.20190508161146-9fa652df1129/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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
+github.com/golang/protobuf v1.4.3/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/cel-go v0.3.2/go.mod h1:DoRSdzaJzNiP1lVuWhp/RjSnHLDQr/aNPlyqSBasBqA=
+github.com/google/cel-spec v0.3.0/go.mod h1:MjQm800JAGhOZXI7vatnVpmIaFTR6L8FHcKk+piiKpI=
+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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/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 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+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/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
+github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
+github.com/gtank/merlin v0.1.1/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.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+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 h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=
+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 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
+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 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
+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/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+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/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw=
+github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
+github.com/kardiachain/go-kardia v1.1.1-0.20210518091640-d13a5b7f7c4c h1:xjhQZf1wiA+ebCz/oNZ7xaZZY/mi/FNoNnMP3iSV/GQ=
+github.com/kardiachain/go-kardia v1.1.1-0.20210518091640-d13a5b7f7c4c/go.mod h1:dIcZ5VO21q0HAjL9LiHqJ8bKMDkoE3T/4H0vy8urggs=
+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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+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/konsorten/go-windows-terminal-sequences v1.0.3/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/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-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+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/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
+github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+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 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pebbe/zmq4 v1.0.0/go.mod h1:7N4y5R18zBiu3l0vajMUWQgZyjv464prE8RCyBcmnZM=
+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 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM=
+github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
+github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
+github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
+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/eth-contracts v0.0.0-20200814062128-70f58e22b014 h1:fbVjTnsS7nZwsTtRdbv+2162e/odNN1rqfLf/gBmhAM=
+github.com/polynetwork/eth-contracts v0.0.0-20200814062128-70f58e22b014/go.mod h1:TeePrYZfWJAwuksPlie7RPequ51Ujp5l/JY6TcutsFc=
+github.com/polynetwork/poly v0.0.0-20200715030435-4f1d1a0adb44/go.mod h1:UzlGEWk0eCGsuMJOZfBoZjRbmu4Yw/SudKAIFe1gPnY=
+github.com/polynetwork/poly v0.0.0-20200722075529-eea88acb37b2 h1:t4zDeTSvzn8Mo2jxUwg8WImqih3ZZWoytTFcnbpGZuU=
+github.com/polynetwork/poly v0.0.0-20200722075529-eea88acb37b2/go.mod h1:UzlGEWk0eCGsuMJOZfBoZjRbmu4Yw/SudKAIFe1gPnY=
+github.com/polynetwork/poly-go-sdk v0.0.0-20200729103825-af447ef53ef0 h1:pWDLHm20+92Oa3kIDSKPJBtZeLe1/ZcKfcSDrw2fpZQ=
+github.com/polynetwork/poly-go-sdk v0.0.0-20200729103825-af447ef53ef0/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/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
+github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
+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/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
+github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+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/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
+github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
+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/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
+github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+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 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
+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 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+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/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
+github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
+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 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+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.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+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 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
+github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+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 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
+github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
+github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
+github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
+github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/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/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+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 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
+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 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
+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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+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.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-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-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 h1:phUcVbl53swtrUN8kQEXFhUxPlIlWyBfKmidCu7P95o=
+golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/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-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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+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-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+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/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/sync v0.0.0-20201020160332-67f06af15bc9/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-20180926160741-c2ed4eda69e7/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-20190130150945-aca44879d564/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+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-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-20200106162015-b016eb3dc98e/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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/text v0.3.0/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-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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+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-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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+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/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/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-20190425155659-357c62f0e4bb/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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6 h1:iRN4+t0lvZX/l9gH14ARF9i58tsVa5a97k6aH95rC3Y=
+google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+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.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/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
+gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/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 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
+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=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+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-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=
+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/kaiclient/client.go b/kaiclient/client.go
new file mode 100644
index 0000000..e7b95d7
--- /dev/null
+++ b/kaiclient/client.go
@@ -0,0 +1,133 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package kaiclient provides a client for the KardiaChain RPC API.
+package kaiclient
+
+import (
+ "context"
+ "math"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/rpc"
+
+ kai "github.com/kardiachain/go-kardia/mainchain"
+ ktypes "github.com/kardiachain/go-kardia/types"
+)
+
+// Client defines typed wrappers for the Ethereum RPC API.
+type Client struct {
+ c *rpc.Client
+}
+
+// Dial connects a client to the given URL.
+func Dial(rawurl string) (*Client, error) {
+ return DialContext(context.Background(), rawurl)
+}
+
+func DialContext(ctx context.Context, rawurl string) (*Client, error) {
+ c, err := rpc.DialContext(ctx, rawurl)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(c), nil
+}
+
+// NewClient creates a client that uses the given RPC client.
+func NewClient(c *rpc.Client) *Client {
+ return &Client{c}
+}
+
+func (ec *Client) Close() {
+ ec.c.Close()
+}
+
+// HeaderByNumber returns a block header from the current canonical chain. If number is
+// nil, the latest known header is returned.
+func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*ktypes.Header, error) {
+ var head *ktypes.Header
+ err := ec.c.CallContext(ctx, &head, "kai_getBlockHeaderByNumber", toBlockNumArg(number))
+ if err == nil && head == nil {
+ err = ethereum.NotFound
+ }
+ return head, err
+}
+
+type KaiHeader struct {
+ Header *ktypes.Header
+ Commit *ktypes.Commit
+ ValidatorSet *ktypes.ValidatorSet
+}
+
+func (ec *Client) FullHeaderByNumber(ctx context.Context, number *big.Int) (*KaiHeader, error) {
+ header, err := ec.HeaderByNumber(ctx, number)
+ if err != nil {
+ return nil, err
+ }
+ validators, err := ec.GetValidators(ctx, number)
+ if err != nil {
+ return nil, err
+ }
+
+ commit, err := ec.GetCommit(ctx, number.Sub(number, big.NewInt(1)))
+ if err != nil {
+ return nil, err
+ }
+ return &KaiHeader{
+ Header: header,
+ ValidatorSet: validators,
+ Commit: commit,
+ }, nil
+}
+
+func (ec *Client) GetValidators(ctx context.Context, number *big.Int) (*ktypes.ValidatorSet, error) {
+ var valSet *ktypes.ValidatorSet
+ err := ec.c.CallContext(ctx, &valSet, "kai_getValidatorSet", toBlockNumArg(number))
+ if err == nil && valSet == nil {
+ err = ethereum.NotFound
+ }
+ return valSet, err
+}
+
+func (ec *Client) GetCommit(ctx context.Context, number *big.Int) (*ktypes.Commit, error) {
+ var commit *ktypes.Commit
+ err := ec.c.CallContext(ctx, &commit, "kai_getCommit", toBlockNumArg(number))
+ if err == nil && commit == nil {
+ err = ethereum.NotFound
+ }
+ return commit, err
+}
+
+func (ec *Client) GetProof(ctx context.Context, address common.Address, storageKeys []string, number *big.Int) (*kai.AccountResult, error) {
+ var accountR *kai.AccountResult
+ err := ec.c.CallContext(ctx, &accountR, "kai_getProof", address, storageKeys, toBlockNumArg(number), false)
+ if err == nil && accountR == nil {
+ err = ethereum.NotFound
+ }
+ return accountR, err
+}
+func toBlockNumArg(number *big.Int) string {
+ if number == nil {
+ return "latest"
+ }
+ pending := new(big.Int).SetUint64(math.MaxUint64 - 1)
+ if number.Cmp(pending) == 0 {
+ return "pending"
+ }
+ return number.String()
+}
diff --git a/kaiclient/kaiclient_test.go b/kaiclient/kaiclient_test.go
new file mode 100644
index 0000000..0fb2d4e
--- /dev/null
+++ b/kaiclient/kaiclient_test.go
@@ -0,0 +1,370 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package kaiclient
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+const kaiRawRPC = "https://dev-1.kardiachain.io"
+
+func TestGetFullHeader(t *testing.T) {
+ cli, err := Dial(kaiRawRPC)
+ assert.NoError(t, err)
+ ctx := context.Background()
+ header, err := cli.FullHeaderByNumber(ctx, big.NewInt(3))
+ assert.NoError(t, err)
+ assert.Equal(t, header.Commit.Hash().Hex(), header.Header.LastCommitHash.Hex())
+ assert.Equal(t, header.ValidatorSet.Hash().Hex(), header.Header.ValidatorsHash.Hex())
+}
+
+// func TestGetTransaction(t *testing.T) {
+// cli, err := Dial(kaiRawRPC)
+// assert.NoError(t, err)
+// ctx := context.Background()
+// tx, isPending, err := cli.TransactionByHash(ctx, common.HexToHash("0xd84e553e62c61f3c3343d7d215c72616907e50bac9235460ba55e878a59d2399"))
+// t.Logf("tx %+v isPending %v err %v", tx, isPending, err)
+// assert.NoError(t, err)
+// }
+
+// func TestGetTransactionReceipt(t *testing.T) {
+// cli, err := Dial(kaiRawRPC)
+// assert.NoError(t, err)
+// ctx := context.Background()
+// receipt, err := cli.TransactionReceipt(ctx, common.HexToHash("0xd84e553e62c61f3c3343d7d215c72616907e50bac9235460ba55e878a59d2399"))
+// t.Logf("receipt %+v err %v", receipt, err)
+// assert.NoError(t, err)
+// }
+
+// // Verify that Client implements the ethereum interfaces.
+// var (
+// _ = ethereum.ChainReader(&Client{})
+// _ = ethereum.TransactionReader(&Client{})
+// _ = ethereum.ChainStateReader(&Client{})
+// _ = ethereum.ChainSyncReader(&Client{})
+// _ = ethereum.ContractCaller(&Client{})
+// _ = ethereum.GasEstimator(&Client{})
+// _ = ethereum.GasPricer(&Client{})
+// _ = ethereum.LogFilterer(&Client{})
+// _ = ethereum.PendingStateReader(&Client{})
+// // _ = ethereum.PendingStateEventer(&Client{})
+// _ = ethereum.PendingContractCaller(&Client{})
+// )
+
+// func TestToFilterArg(t *testing.T) {
+// blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
+// addresses := []common.Address{
+// common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
+// }
+// blockHash := common.HexToHash(
+// "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
+// )
+
+// for _, testCase := range []struct {
+// name string
+// input ethereum.FilterQuery
+// output interface{}
+// err error
+// }{
+// {
+// "without BlockHash",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// FromBlock: big.NewInt(1),
+// ToBlock: big.NewInt(2),
+// Topics: [][]common.Hash{},
+// },
+// map[string]interface{}{
+// "address": addresses,
+// "fromBlock": "0x1",
+// "toBlock": "0x2",
+// "topics": [][]common.Hash{},
+// },
+// nil,
+// },
+// {
+// "with nil fromBlock and nil toBlock",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// Topics: [][]common.Hash{},
+// },
+// map[string]interface{}{
+// "address": addresses,
+// "fromBlock": "0x0",
+// "toBlock": "latest",
+// "topics": [][]common.Hash{},
+// },
+// nil,
+// },
+// {
+// "with negative fromBlock and negative toBlock",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// FromBlock: big.NewInt(-1),
+// ToBlock: big.NewInt(-1),
+// Topics: [][]common.Hash{},
+// },
+// map[string]interface{}{
+// "address": addresses,
+// "fromBlock": "pending",
+// "toBlock": "pending",
+// "topics": [][]common.Hash{},
+// },
+// nil,
+// },
+// {
+// "with blockhash",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// BlockHash: &blockHash,
+// Topics: [][]common.Hash{},
+// },
+// map[string]interface{}{
+// "address": addresses,
+// "blockHash": blockHash,
+// "topics": [][]common.Hash{},
+// },
+// nil,
+// },
+// {
+// "with blockhash and from block",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// BlockHash: &blockHash,
+// FromBlock: big.NewInt(1),
+// Topics: [][]common.Hash{},
+// },
+// nil,
+// blockHashErr,
+// },
+// {
+// "with blockhash and to block",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// BlockHash: &blockHash,
+// ToBlock: big.NewInt(1),
+// Topics: [][]common.Hash{},
+// },
+// nil,
+// blockHashErr,
+// },
+// {
+// "with blockhash and both from / to block",
+// ethereum.FilterQuery{
+// Addresses: addresses,
+// BlockHash: &blockHash,
+// FromBlock: big.NewInt(1),
+// ToBlock: big.NewInt(2),
+// Topics: [][]common.Hash{},
+// },
+// nil,
+// blockHashErr,
+// },
+// } {
+// t.Run(testCase.name, func(t *testing.T) {
+// output, err := toFilterArg(testCase.input)
+// if (testCase.err == nil) != (err == nil) {
+// t.Fatalf("expected error %v but got %v", testCase.err, err)
+// }
+// if testCase.err != nil {
+// if testCase.err.Error() != err.Error() {
+// t.Fatalf("expected error %v but got %v", testCase.err, err)
+// }
+// } else if !reflect.DeepEqual(testCase.output, output) {
+// t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
+// }
+// })
+// }
+// }
+
+// var (
+// testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+// testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
+// testBalance = big.NewInt(2e10)
+// )
+
+// func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
+// // Generate test chain.
+// genesis, blocks := generateTestChain()
+
+// // Start Ethereum service.
+// var ethservice *eth.Ethereum
+// n, err := node.New(&node.Config{})
+// n.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+// config := ð.Config{Genesis: genesis}
+// config.Ethash.PowMode = ethash.ModeFake
+// ethservice, err = eth.New(ctx, config)
+// return ethservice, err
+// })
+
+// // Import the test chain.
+// if err := n.Start(); err != nil {
+// t.Fatalf("can't start test node: %v", err)
+// }
+// if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
+// t.Fatalf("can't import test blocks: %v", err)
+// }
+// return n, blocks
+// }
+
+// func generateTestChain() (*core.Genesis, []*types.Block) {
+// db := rawdb.NewMemoryDatabase()
+// config := params.AllEthashProtocolChanges
+// genesis := &core.Genesis{
+// Config: config,
+// Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
+// ExtraData: []byte("test genesis"),
+// Timestamp: 9000,
+// }
+// generate := func(i int, g *core.BlockGen) {
+// g.OffsetTime(5)
+// g.SetExtra([]byte("test"))
+// }
+// gblock := genesis.ToBlock(db)
+// engine := ethash.NewFaker()
+// blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
+// blocks = append([]*types.Block{gblock}, blocks...)
+// return genesis, blocks
+// }
+
+// func TestHeader(t *testing.T) {
+// backend, chain := newTestBackend(t)
+// client, _ := backend.Attach()
+// defer backend.Stop()
+// defer client.Close()
+
+// tests := map[string]struct {
+// block *big.Int
+// want *types.Header
+// wantErr error
+// }{
+// "genesis": {
+// block: big.NewInt(0),
+// want: chain[0].Header(),
+// },
+// "first_block": {
+// block: big.NewInt(1),
+// want: chain[1].Header(),
+// },
+// "future_block": {
+// block: big.NewInt(1000000000),
+// want: nil,
+// },
+// }
+// for name, tt := range tests {
+// t.Run(name, func(t *testing.T) {
+// ec := NewClient(client)
+// ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+// defer cancel()
+
+// got, err := ec.HeaderByNumber(ctx, tt.block)
+// if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
+// t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
+// }
+// if got != nil && got.Number.Sign() == 0 {
+// got.Number = big.NewInt(0) // hack to make DeepEqual work
+// }
+// if !reflect.DeepEqual(got, tt.want) {
+// t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want)
+// }
+// })
+// }
+// }
+
+// func TestBalanceAt(t *testing.T) {
+// backend, _ := newTestBackend(t)
+// client, _ := backend.Attach()
+// defer backend.Stop()
+// defer client.Close()
+
+// tests := map[string]struct {
+// account common.Address
+// block *big.Int
+// want *big.Int
+// wantErr error
+// }{
+// "valid_account": {
+// account: testAddr,
+// block: big.NewInt(1),
+// want: testBalance,
+// },
+// "non_existent_account": {
+// account: common.Address{1},
+// block: big.NewInt(1),
+// want: big.NewInt(0),
+// },
+// "future_block": {
+// account: testAddr,
+// block: big.NewInt(1000000000),
+// want: big.NewInt(0),
+// wantErr: errors.New("header not found"),
+// },
+// }
+// for name, tt := range tests {
+// t.Run(name, func(t *testing.T) {
+// ec := NewClient(client)
+// ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+// defer cancel()
+
+// got, err := ec.BalanceAt(ctx, tt.account, tt.block)
+// if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
+// t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
+// }
+// if got.Cmp(tt.want) != 0 {
+// t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
+// }
+// })
+// }
+// }
+
+// func TestTransactionInBlockInterrupted(t *testing.T) {
+// backend, _ := newTestBackend(t)
+// client, _ := backend.Attach()
+// defer backend.Stop()
+// defer client.Close()
+
+// ec := NewClient(client)
+// ctx, cancel := context.WithCancel(context.Background())
+// cancel()
+// tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
+// if tx != nil {
+// t.Fatal("transaction should be nil")
+// }
+// if err == nil {
+// t.Fatal("error should not be nil")
+// }
+// }
+
+// func TestChainID(t *testing.T) {
+// backend, _ := newTestBackend(t)
+// client, _ := backend.Attach()
+// defer backend.Stop()
+// defer client.Close()
+// ec := NewClient(client)
+
+// id, err := ec.ChainID(context.Background())
+// if err != nil {
+// t.Fatalf("unexpected error: %v", err)
+// }
+// if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
+// t.Fatalf("ChainID returned wrong number: %+v", id)
+// }
+// }
diff --git a/log/log.go b/log/log.go
new file mode 100644
index 0000000..2c2a7c7
--- /dev/null
+++ b/log/log.go
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+
+package log
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ Blue = "0;34"
+ Red = "0;31"
+ Green = "0;32"
+ Yellow = "0;33"
+ Cyan = "0;36"
+ Pink = "1;35"
+)
+
+func Color(code, msg string) string {
+ return fmt.Sprintf("\033[%sm%s\033[m", code, msg)
+}
+
+const (
+ TraceLog = iota
+ DebugLog
+ InfoLog
+ WarnLog
+ ErrorLog
+ FatalLog
+ MaxLevelLog
+)
+
+var (
+ levels = map[int]string{
+ DebugLog: Color(Green, "[DEBUG]"),
+ InfoLog: Color(Cyan, "[INFO ]"),
+ WarnLog: Color(Yellow, "[WARN ]"),
+ ErrorLog: Color(Red, "[ERROR]"),
+ FatalLog: Color(Red, "[FATAL]"),
+ TraceLog: Color(Pink, "[TRACE]"),
+ }
+ Stdout = os.Stdout
+)
+
+const (
+ NAME_PREFIX = "LEVEL"
+ CALL_DEPTH = 2
+ DEFAULT_MAX_LOG_SIZE = 20
+ BYTE_TO_MB = 1024 * 1024
+ PATH = "./logoutput/"
+)
+
+func GetGID() uint64 {
+ var buf [64]byte
+ b := buf[:runtime.Stack(buf[:], false)]
+ b = bytes.TrimPrefix(b, []byte("goroutine "))
+ b = b[:bytes.IndexByte(b, ' ')]
+ n, _ := strconv.ParseUint(string(b), 10, 64)
+ return n
+}
+
+var Log *Logger
+
+func init() {
+ //Default print to console
+ InitLog(InfoLog, Stdout)
+}
+
+func LevelName(level int) string {
+ if name, ok := levels[level]; ok {
+ return name
+ }
+ return NAME_PREFIX + strconv.Itoa(level)
+}
+
+func NameLevel(name string) int {
+ for k, v := range levels {
+ if v == name {
+ return k
+ }
+ }
+ var level int
+ if strings.HasPrefix(name, NAME_PREFIX) {
+ level, _ = strconv.Atoi(name[len(NAME_PREFIX):])
+ }
+ return level
+}
+
+type Logger struct {
+ level int
+ logger *log.Logger
+ logFile *os.File
+}
+
+func New(out io.Writer, prefix string, flag, level int, file *os.File) *Logger {
+ return &Logger{
+ level: level,
+ logger: log.New(out, prefix, flag),
+ logFile: file,
+ }
+}
+
+func (l *Logger) SetDebugLevel(level int) error {
+ if level > MaxLevelLog || level < 0 {
+ return errors.New("Invalid Debug Level")
+ }
+
+ l.level = level
+ return nil
+}
+
+func (l *Logger) Output(level int, a ...interface{}) error {
+ if level >= l.level {
+ gid := GetGID()
+ gidStr := strconv.FormatUint(gid, 10)
+
+ a = append([]interface{}{LevelName(level), "GID",
+ gidStr + ","}, a...)
+
+ return l.logger.Output(CALL_DEPTH, fmt.Sprintln(a...))
+ }
+ return nil
+}
+
+func (l *Logger) Outputf(level int, format string, v ...interface{}) error {
+ if level >= l.level {
+ gid := GetGID()
+ v = append([]interface{}{LevelName(level), "GID",
+ gid}, v...)
+
+ return l.logger.Output(CALL_DEPTH, fmt.Sprintf("%s %s %d, "+format+"\n", v...))
+ }
+ return nil
+}
+
+func (l *Logger) Trace(a ...interface{}) {
+ l.Output(TraceLog, a...)
+}
+
+func (l *Logger) Tracef(format string, a ...interface{}) {
+ l.Outputf(TraceLog, format, a...)
+}
+
+func (l *Logger) Debug(a ...interface{}) {
+ l.Output(DebugLog, a...)
+}
+
+func (l *Logger) Debugf(format string, a ...interface{}) {
+ l.Outputf(DebugLog, format, a...)
+}
+
+func (l *Logger) Info(a ...interface{}) {
+ l.Output(InfoLog, a...)
+}
+
+func (l *Logger) Infof(format string, a ...interface{}) {
+ l.Outputf(InfoLog, format, a...)
+}
+
+func (l *Logger) Warn(a ...interface{}) {
+ l.Output(WarnLog, a...)
+}
+
+func (l *Logger) Warnf(format string, a ...interface{}) {
+ l.Outputf(WarnLog, format, a...)
+}
+
+func (l *Logger) Error(a ...interface{}) {
+ l.Output(ErrorLog, a...)
+}
+
+func (l *Logger) Errorf(format string, a ...interface{}) {
+ l.Outputf(ErrorLog, format, a...)
+}
+
+func (l *Logger) Fatal(a ...interface{}) {
+ l.Output(FatalLog, a...)
+}
+
+func (l *Logger) Fatalf(format string, a ...interface{}) {
+ l.Outputf(FatalLog, format, a...)
+}
+
+func Trace(a ...interface{}) {
+ if TraceLog < Log.level {
+ return
+ }
+
+ pc := make([]uintptr, 10)
+ runtime.Callers(2, pc)
+ f := runtime.FuncForPC(pc[0])
+ file, line := f.FileLine(pc[0])
+ fileName := filepath.Base(file)
+
+ nameFull := f.Name()
+ nameEnd := filepath.Ext(nameFull)
+ funcName := strings.TrimPrefix(nameEnd, ".")
+
+ a = append([]interface{}{funcName + "()", fileName + ":" + strconv.Itoa(line)}, a...)
+
+ Log.Trace(a...)
+}
+
+func Tracef(format string, a ...interface{}) {
+ if TraceLog < Log.level {
+ return
+ }
+
+ pc := make([]uintptr, 10)
+ runtime.Callers(2, pc)
+ f := runtime.FuncForPC(pc[0])
+ file, line := f.FileLine(pc[0])
+ fileName := filepath.Base(file)
+
+ nameFull := f.Name()
+ nameEnd := filepath.Ext(nameFull)
+ funcName := strings.TrimPrefix(nameEnd, ".")
+
+ a = append([]interface{}{funcName, fileName, line}, a...)
+
+ Log.Tracef("%s() %s:%d "+format, a...)
+}
+
+func Debug(a ...interface{}) {
+ if DebugLog < Log.level {
+ return
+ }
+
+ pc := make([]uintptr, 10)
+ runtime.Callers(2, pc)
+ f := runtime.FuncForPC(pc[0])
+ file, line := f.FileLine(pc[0])
+ fileName := filepath.Base(file)
+
+ a = append([]interface{}{f.Name(), fileName + ":" + strconv.Itoa(line)}, a...)
+
+ Log.Debug(a...)
+}
+
+func Debugf(format string, a ...interface{}) {
+ if DebugLog < Log.level {
+ return
+ }
+
+ pc := make([]uintptr, 10)
+ runtime.Callers(2, pc)
+ f := runtime.FuncForPC(pc[0])
+ file, line := f.FileLine(pc[0])
+ fileName := filepath.Base(file)
+
+ a = append([]interface{}{f.Name(), fileName, line}, a...)
+
+ Log.Debugf("%s %s:%d "+format, a...)
+}
+
+func Info(a ...interface{}) {
+ Log.Info(a...)
+}
+
+func Warn(a ...interface{}) {
+ Log.Warn(a...)
+}
+
+func Error(a ...interface{}) {
+ Log.Error(a...)
+}
+
+func Fatal(a ...interface{}) {
+ Log.Fatal(a...)
+}
+
+func Infof(format string, a ...interface{}) {
+ Log.Infof(format, a...)
+}
+
+func Warnf(format string, a ...interface{}) {
+ Log.Warnf(format, a...)
+}
+
+func Errorf(format string, a ...interface{}) {
+ Log.Errorf(format, a...)
+}
+
+func Fatalf(format string, a ...interface{}) {
+ Log.Fatalf(format, a...)
+}
+
+func FileOpen(path string) (*os.File, error) {
+ if fi, err := os.Stat(path); err == nil {
+ if !fi.IsDir() {
+ return nil, fmt.Errorf("open %s: not a directory", path)
+ }
+ } else if os.IsNotExist(err) {
+ if err := os.MkdirAll(path, 0766); err != nil {
+ return nil, err
+ }
+ } else {
+ return nil, err
+ }
+
+ var currenttime = time.Now().Format("2006-01-02_15.04.05")
+
+ logfile, err := os.OpenFile(path+currenttime+"_LOG.log", os.O_RDWR|os.O_CREATE, 0666)
+ if err != nil {
+ return nil, err
+ }
+ return logfile, nil
+}
+
+//Init deprecated, use InitLog instead
+func Init(a ...interface{}) {
+ os.Stderr.WriteString("warning: use of deprecated Init. Use InitLog instead\n")
+ InitLog(InfoLog, a...)
+}
+
+func InitLog(logLevel int, a ...interface{}) {
+ writers := []io.Writer{}
+ var logFile *os.File
+ var err error
+ if len(a) == 0 {
+ writers = append(writers, ioutil.Discard)
+ } else {
+ for _, o := range a {
+ switch o.(type) {
+ case string:
+ logFile, err = FileOpen(o.(string))
+ if err != nil {
+ fmt.Println("error: open log file failed")
+ os.Exit(1)
+ }
+ writers = append(writers, logFile)
+ case *os.File:
+ writers = append(writers, o.(*os.File))
+ default:
+ fmt.Println("error: invalid log location")
+ os.Exit(1)
+ }
+ }
+ }
+ fileAndStdoutWrite := io.MultiWriter(writers...)
+ Log = New(fileAndStdoutWrite, "", log.Ldate|log.Lmicroseconds, logLevel, logFile)
+}
+
+func GetLogFileSize() (int64, error) {
+ f, e := Log.logFile.Stat()
+ if e != nil {
+ return 0, e
+ }
+ return f.Size(), nil
+}
+
+func GetMaxLogChangeInterval(maxLogSize int64) int64 {
+ if maxLogSize != 0 {
+ return (maxLogSize * BYTE_TO_MB)
+ } else {
+ return (DEFAULT_MAX_LOG_SIZE * BYTE_TO_MB)
+ }
+}
+
+func CheckIfNeedNewFile() bool {
+ logFileSize, err := GetLogFileSize()
+ maxLogFileSize := GetMaxLogChangeInterval(0)
+ if err != nil {
+ return false
+ }
+ if logFileSize > maxLogFileSize {
+ return true
+ } else {
+ return false
+ }
+}
+
+func ClosePrintLog() error {
+ var err error
+ if Log.logFile != nil {
+ err = Log.logFile.Close()
+ }
+ return err
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..e60ab34
--- /dev/null
+++ b/main.go
@@ -0,0 +1,188 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/signal"
+ "runtime"
+ "syscall"
+
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/polynetwork/kai-relayer/cmd"
+ "github.com/polynetwork/kai-relayer/config"
+ "github.com/polynetwork/kai-relayer/db"
+ "github.com/polynetwork/kai-relayer/kaiclient"
+ "github.com/polynetwork/kai-relayer/log"
+ "github.com/polynetwork/kai-relayer/manager"
+ sdk "github.com/polynetwork/poly-go-sdk"
+ "github.com/urfave/cli"
+)
+
+var ConfigPath string
+var LogDir string
+var StartHeight uint64
+var PolyStartHeight uint64
+var StartForceHeight uint64
+
+func setupApp() *cli.App {
+ app := cli.NewApp()
+ app.Usage = "Kai relayer Service"
+ app.Action = startServer
+ app.Version = config.Version
+ app.Copyright = "Copyright in 2019 The Ontology Authors"
+ app.Flags = []cli.Flag{
+ cmd.LogLevelFlag,
+ cmd.ConfigPathFlag,
+ cmd.KaiStartFlag,
+ cmd.KaiStartForceFlag,
+ cmd.PolyStartFlag,
+ cmd.LogDir,
+ }
+ app.Commands = []cli.Command{}
+ app.Before = func(context *cli.Context) error {
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ return nil
+ }
+ return app
+}
+
+func startServer(ctx *cli.Context) {
+ // get all cmd flag
+ logLevel := ctx.GlobalInt(cmd.GetFlagName(cmd.LogLevelFlag))
+
+ ld := ctx.GlobalString(cmd.GetFlagName(cmd.LogDir))
+ if ld == "" {
+ log.InitLog(logLevel, "./Log/", log.Stdout)
+ } else {
+ log.InitLog(logLevel, ld, log.Stdout)
+ }
+
+ configPath := ctx.GlobalString(cmd.GetFlagName(cmd.ConfigPathFlag))
+ if configPath != "" {
+ ConfigPath = configPath
+ }
+ kaistart := ctx.GlobalUint64(cmd.GetFlagName(cmd.KaiStartFlag))
+ if kaistart > 0 {
+ StartHeight = kaistart
+ }
+
+ StartForceHeight = 0
+ kaistartforce := ctx.GlobalUint64(cmd.GetFlagName(cmd.KaiStartForceFlag))
+ if kaistartforce > 0 {
+ StartForceHeight = kaistartforce
+ }
+ polyStart := ctx.GlobalUint64(cmd.GetFlagName(cmd.PolyStartFlag))
+ if polyStart > 0 {
+ PolyStartHeight = polyStart
+ }
+
+ // read config
+ servConfig := config.NewServiceConfig(ConfigPath)
+ if servConfig == nil {
+ log.Errorf("startServer - create config failed!")
+ return
+ }
+
+ // create poly sdk
+ polySdk := sdk.NewPolySdk()
+ err := setUpPoly(polySdk, servConfig.PolyConfig.RestURL)
+ if err != nil {
+ log.Errorf("startServer - failed to setup poly sdk: %v", err)
+ return
+ }
+
+ // create kai sdk
+ kclient, err := kaiclient.Dial(servConfig.KAIConfig.RestURL)
+ if err != nil {
+ log.Errorf("startServer - cannot dial sync node, err: %s", err)
+ return
+ }
+
+ ethclient, err := ethclient.Dial(servConfig.KAIConfig.RestURL)
+ if err != nil {
+ log.Errorf("startServer - cannot dial sync node ethclient, err: %s", err)
+ return
+ }
+ var boltDB *db.BoltDB
+ if servConfig.BoltDbPath == "" {
+ boltDB, err = db.NewBoltDB("boltdb")
+ } else {
+ boltDB, err = db.NewBoltDB(servConfig.BoltDbPath)
+ }
+ if err != nil {
+ log.Fatalf("db.NewWaitingDB error:%s", err)
+ return
+ }
+
+ initKaiServer(servConfig, polySdk, ethclient, kclient, boltDB)
+ initPolyServer(servConfig, polySdk, ethclient, kclient, boltDB)
+ waitToExit()
+}
+
+func setUpPoly(poly *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 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("waitToExit - KAI relayer received exit signal:%v.", sig.String())
+ close(exit)
+ break
+ }
+ }()
+ <-exit
+}
+
+func initKaiServer(servConfig *config.ServiceConfig, polysdk *sdk.PolySdk, ethclient *ethclient.Client, kclient *kaiclient.Client, boltDB *db.BoltDB) {
+ mgr, err := manager.NewKardiaManager(servConfig, StartHeight, StartForceHeight, polysdk, ethclient, kclient, boltDB)
+ if err != nil {
+ log.Error("initKAIServer - KAI service start err: %s", err.Error())
+ return
+ }
+ go mgr.MonitorChain()
+ go mgr.MonitorDeposit()
+ go mgr.CheckDeposit()
+}
+
+func initPolyServer(servConfig *config.ServiceConfig, polysdk *sdk.PolySdk, ethclient *ethclient.Client, kclient *kaiclient.Client, boltDB *db.BoltDB) {
+ mgr, err := manager.NewPolyManager(servConfig, uint32(PolyStartHeight), polysdk, ethclient, kclient, boltDB)
+ if err != nil {
+ log.Error("initPolyServer - PolyServer service start failed")
+ return
+ }
+ go mgr.MonitorChain()
+}
+
+func main() {
+ log.Infof("main - KAI relayer starting...")
+ if err := setupApp().Run(os.Args); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/manager/kardiachainmanager.go b/manager/kardiachainmanager.go
new file mode 100644
index 0000000..62837b4
--- /dev/null
+++ b/manager/kardiachainmanager.go
@@ -0,0 +1,529 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package manager
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/polynetwork/eth-contracts/go_abi/eccm_abi"
+ "github.com/polynetwork/kai-relayer/config"
+ "github.com/polynetwork/kai-relayer/db"
+ "github.com/polynetwork/kai-relayer/kaiclient"
+
+ "context"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/polynetwork/kai-relayer/log"
+ "github.com/polynetwork/kai-relayer/tools"
+ sdk "github.com/polynetwork/poly-go-sdk"
+ "github.com/polynetwork/poly/common"
+ "github.com/polynetwork/poly/native/service/cross_chain_manager/eth"
+ scom "github.com/polynetwork/poly/native/service/header_sync/common"
+ "github.com/polynetwork/poly/native/service/utils"
+ autils "github.com/polynetwork/poly/native/service/utils"
+)
+
+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
+}
+
+type KardiaManager struct {
+ config *config.ServiceConfig
+ restClient *tools.RestClient
+ client *ethclient.Client
+ kaiclient *kaiclient.Client
+ currentHeight uint64
+ forceHeight uint64
+ lockerContract *bind.BoundContract
+ polySdk *sdk.PolySdk
+ polySigner *sdk.Account
+ exitChan chan int
+ header4sync [][]byte
+ crosstx4sync []*CrossTransfer
+ db *db.BoltDB
+}
+
+func NewKardiaManager(servconfig *config.ServiceConfig, startheight uint64, startforceheight uint64, ontsdk *sdk.PolySdk, ethclient *ethclient.Client, client *kaiclient.Client, boltDB *db.BoltDB) (*KardiaManager, error) {
+ var wallet *sdk.Wallet
+ var err error
+
+ if !common.FileExisted(servconfig.PolyConfig.WalletFile) {
+ wallet, err = ontsdk.CreateWallet(servconfig.PolyConfig.WalletFile)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ wallet, err = ontsdk.OpenWallet(servconfig.PolyConfig.WalletFile)
+ if err != nil {
+ log.Errorf("NewKaiManager - wallet open error: %s", err.Error())
+ return nil, err
+ }
+ }
+ signer, err := wallet.GetDefaultAccount([]byte(servconfig.PolyConfig.WalletPwd))
+ if err != nil || signer == nil {
+ signer, err = wallet.NewDefaultSettingAccount([]byte(servconfig.PolyConfig.WalletPwd))
+ if err != nil {
+ log.Errorf("NewKaiManager - wallet password error")
+ return nil, err
+ }
+
+ err = wallet.Save()
+ if err != nil {
+ return nil, err
+ }
+ }
+ log.Infof("NewKaiManager - poly address: %s", signer.Address.ToBase58())
+
+ mgr := &KardiaManager{
+ config: servconfig,
+ exitChan: make(chan int),
+ currentHeight: startheight,
+ forceHeight: startforceheight,
+ restClient: tools.NewRestClient(),
+ client: ethclient,
+ kaiclient: client,
+ polySdk: ontsdk,
+ polySigner: signer,
+ header4sync: make([][]byte, 0),
+ crosstx4sync: make([]*CrossTransfer, 0),
+ db: boltDB,
+ }
+ err = mgr.init()
+ if err != nil {
+ return nil, err
+ } else {
+ return mgr, nil
+ }
+}
+
+func (this *KardiaManager) MonitorChain() {
+ fetchBlockTicker := time.NewTicker(config.KAI_MONITOR_INTERVAL)
+ var blockHandleResult bool
+ backtrace := uint64(1)
+ for {
+ select {
+ case <-fetchBlockTicker.C:
+ height, err := tools.GetNodeHeight(this.config.KAIConfig.RestURL, this.restClient)
+ if err != nil {
+ log.Infof("MonitorChain - cannot get node height, err: %s", err)
+ continue
+ }
+ if height-this.currentHeight <= config.KAI_USEFUL_BLOCK_NUM {
+ continue
+ }
+ log.Infof("MonitorChain - kai height is %d", height)
+ blockHandleResult = true
+ for this.currentHeight < height-config.KAI_USEFUL_BLOCK_NUM {
+ blockHandleResult = this.handleNewBlock(this.currentHeight + 1)
+ if !blockHandleResult {
+ break
+ }
+ this.currentHeight++
+ // try to commit header if more than 50 headers needed to be syned
+ if len(this.header4sync) > 0 {
+ if this.commitHeader() != 0 {
+ log.Error("MonitorChain - commit header failed.", "height", this.currentHeight)
+ blockHandleResult = false
+ break
+ }
+ this.header4sync = make([][]byte, 0)
+ }
+ }
+ if !blockHandleResult {
+ continue
+ }
+
+ if len(this.header4sync) > 0 {
+ // try to commit lastest header when we are at latest height
+ commitHeaderResult := this.commitHeader()
+ if commitHeaderResult > 0 {
+ log.Error("MonitorChain - commit header failed.", "height", this.currentHeight)
+ continue
+ } else if commitHeaderResult == 0 {
+ backtrace = 1
+ this.header4sync = make([][]byte, 0)
+ continue
+ } else {
+ latestHeight := this.findLastestHeight()
+ if latestHeight == 0 {
+ continue
+ }
+ this.currentHeight = latestHeight - backtrace
+ backtrace++
+ log.Errorf("MonitorChain - back to height: %d", this.currentHeight)
+ this.header4sync = make([][]byte, 0)
+ }
+ }
+ case <-this.exitChan:
+ return
+ }
+ }
+}
+func (this *KardiaManager) init() error {
+ // get latest height
+ latestHeight := this.findLastestHeight()
+ if latestHeight == 0 {
+ return fmt.Errorf("init - the genesis block has not synced!")
+ }
+ log.Infof("init - latest synced height: %d", latestHeight)
+ if this.forceHeight > 0 && this.forceHeight < latestHeight {
+ this.currentHeight = this.forceHeight
+ } else {
+ this.currentHeight = latestHeight
+ }
+ // this.currentHeight = 760565
+ return nil
+}
+
+func (this *KardiaManager) findLastestHeight() uint64 {
+ // try to get key
+ contractAddress := autils.HeaderSyncContractAddress
+ key := append([]byte(scom.EPOCH_SWITCH), utils.GetUint64Bytes(this.config.KAIConfig.SideChainId)...)
+ // try to get storage
+ result, err := this.polySdk.GetStorage(contractAddress.ToHexString(), key)
+ if err != nil {
+ return 0
+ }
+
+ if len(result) == 0 {
+ return 0
+ } else {
+ return binary.LittleEndian.Uint64(result)
+ }
+}
+
+func (this *KardiaManager) handleNewBlock(height uint64) bool {
+ ret := this.handleBlockHeader(height)
+ if !ret {
+ log.Errorf("handleNewBlock - handleBlockHeader on height :%d failed", height)
+ return false
+ }
+ ret = this.fetchLockDepositEvents(height-1, this.client)
+ if !ret {
+ log.Errorf("handleNewBlock - fetchLockDepositEvents on height :%d failed", height)
+ }
+ return true
+}
+
+func (this *KardiaManager) handleBlockHeader(height uint64) bool {
+ ctx := context.Background()
+ number := big.NewInt(int64(height))
+ header, err := this.kaiclient.HeaderByNumber(ctx, number)
+ if err != nil {
+ log.Error("handleBlockHeader - GetNodeHeader on height :%d failed", height, "err", err)
+ return false
+ }
+
+ if header.ValidatorsHash.Equal(header.NextValidatorsHash) {
+ return true
+ }
+
+ val, _ := this.polySdk.GetStorage(utils.CrossChainManagerContractAddress.ToHexString(),
+ append(append([]byte(scom.EPOCH_SWITCH), utils.GetUint64Bytes(this.config.KAIConfig.SideChainId)...),
+ utils.GetUint64Bytes(uint64(header.Height))...))
+ // check if this header is not committed on Poly
+ if len(val) > 0 {
+ return true
+ }
+
+ validators, err := this.kaiclient.GetValidators(ctx, number)
+ if err != nil {
+ log.Error("handleBlockHeader - GetValidators on height :%d failed", height, "err", err)
+ return false
+ }
+
+ commit, err := this.kaiclient.GetCommit(ctx, number.Sub(number, big.NewInt(1)))
+ if err != nil {
+ log.Error("handleBlockHeader - GetCommit on height :%d failed", height, "err", err)
+ return false
+ }
+
+ fullHeader := &kaiclient.KaiHeader{
+ Header: header,
+ ValidatorSet: validators,
+ Commit: commit,
+ }
+ headerBytes, err := json.Marshal(fullHeader)
+ if err != nil {
+ log.Errorf("marshal header on height :%d failed err %s", height, err)
+ return false
+ }
+ this.header4sync = append(this.header4sync, headerBytes)
+ return true
+}
+
+func (this *KardiaManager) fetchLockDepositEvents(height uint64, client *ethclient.Client) bool {
+ lockAddress := ethcommon.HexToAddress(this.config.KAIConfig.ECCMContractAddress)
+ lockContract, err := eccm_abi.NewEthCrossChainManager(lockAddress, client)
+ if err != nil {
+ return false
+ }
+ opt := &bind.FilterOpts{
+ Start: height,
+ End: &height,
+ Context: context.Background(),
+ }
+ events, err := lockContract.FilterCrossChainEvent(opt, nil)
+ if err != nil {
+ log.Errorf("fetchLockDepositEvents - FilterCrossChainEvent error :%s", err.Error())
+ return false
+ }
+ if events == nil {
+ log.Infof("fetchLockDepositEvents - no events found on FilterCrossChainEvent")
+ return false
+ }
+ for events.Next() {
+ evt := events.Event
+ index := big.NewInt(0)
+ index.SetBytes(evt.TxId)
+ crossTx := &CrossTransfer{
+ txIndex: tools.EncodeBigInt(index),
+ txId: evt.Raw.TxHash.Bytes(),
+ toChain: uint32(evt.ToChainId),
+ value: []byte(evt.Rawdata),
+ height: height,
+ }
+ sink := common.NewZeroCopySink(nil)
+ crossTx.Serialization(sink)
+ err = this.db.PutRetry(sink.Bytes())
+ if err != nil {
+ log.Errorf("fetchLockDepositEvents - this.db.PutRetry error: %s", err)
+ }
+ log.Infof("fetchLockDepositEvent - height: %d", height)
+ }
+ return true
+}
+
+func (this *KardiaManager) commitHeader() int {
+ tx, err := this.polySdk.Native.Hs.SyncBlockHeader(
+ this.config.KAIConfig.SideChainId,
+ this.polySigner.Address,
+ this.header4sync,
+ this.polySigner,
+ )
+ if err != nil {
+ log.Warnf("commitHeader - send transaction to poly chain err: %s!", err.Error())
+ errDesc := err.Error()
+ if strings.Contains(errDesc, "get the parent block failed") || strings.Contains(errDesc, "missing required field") {
+ return -1
+ } else {
+ return 1
+ }
+ }
+ tick := time.NewTicker(100 * time.Millisecond)
+ var h uint32
+ for range tick.C {
+ h, _ = this.polySdk.GetBlockHeightByTxHash(tx.ToHexString())
+ curr, _ := this.polySdk.GetCurrentBlockHeight()
+ if h > 0 && curr > h {
+ break
+ }
+ }
+ log.Infof("commitHeader - send transaction %s to poly chain and confirmed on height %d", tx.ToHexString(), h)
+ return 0
+}
+func (this *KardiaManager) MonitorDeposit() {
+ monitorTicker := time.NewTicker(config.KAI_MONITOR_INTERVAL)
+ for {
+ select {
+ case <-monitorTicker.C:
+ if err := this.handleLockDepositEvents(); err != nil {
+ log.Errorf("MonitorChain - handleLockDepositEvents, err: %s", err)
+ }
+ case <-this.exitChan:
+ return
+ }
+ }
+}
+func (this *KardiaManager) handleLockDepositEvents() error {
+ retryList, err := this.db.GetAllRetry()
+ if err != nil {
+ return fmt.Errorf("handleLockDepositEvents - this.db.GetAllRetry error: %s", err)
+ }
+ fmt.Println("----------------->", len(retryList))
+ for _, v := range retryList {
+ time.Sleep(time.Second * 1)
+ crosstx := new(CrossTransfer)
+ err := crosstx.Deserialization(common.NewZeroCopySource(v))
+ if err != nil {
+ log.Errorf("handleLockDepositEvents - retry.Deserialization error: %s", err)
+ continue
+ }
+ //1. decode events
+ key := crosstx.txIndex
+ keyBytes, err := eth.MappingKeyAt(key, "01")
+ if err != nil {
+ log.Errorf("handleLockDepositEvents - MappingKeyAt error:%s\n", err.Error())
+ continue
+ }
+
+ heightHex := hexutil.EncodeBig(big.NewInt(int64(crosstx.height + 1)))
+ proofKey := hexutil.Encode(keyBytes)
+ //2. get proof
+ proof, err := tools.GetProof(this.config.KAIConfig.RestURL, this.config.KAIConfig.ECCDContractAddress, proofKey, heightHex, this.restClient)
+ if err != nil {
+ log.Errorf("handleLockDepositEvents - error :%s\n", err.Error())
+ continue
+ }
+ //3. commit proof to poly
+ txHash, err := this.commitProof(uint32(crosstx.height+1), proof, crosstx.value, crosstx.txId)
+ if err != nil {
+ if strings.Contains(err.Error(), "chooseUtxos, current utxo is not enough") {
+ log.Infof("handleLockDepositEvents - invokeNativeContract error: %s", err)
+ continue
+ } else {
+ if err := this.db.DeleteRetry(v); err != nil {
+ log.Errorf("handleLockDepositEvents - this.db.DeleteRetry error: %s", err)
+ }
+ log.Errorf("handleLockDepositEvents - invokeNativeContract error: %s", err)
+ continue
+ }
+ }
+ //4. put to check db for checking
+ err = this.db.PutCheck(txHash, v)
+ if err != nil {
+ log.Errorf("handleLockDepositEvents - this.db.PutCheck error: %s", err)
+ }
+ err = this.db.DeleteRetry(v)
+ if err != nil {
+ log.Errorf("handleLockDepositEvents - this.db.PutCheck error: %s", err)
+ }
+ log.Infof("handleLockDepositEvents - syncProofToAlia txHash is %s", txHash)
+ }
+ return nil
+}
+func (this *KardiaManager) commitProof(height uint32, proof []byte, value []byte, txhash []byte) (string, error) {
+ ctx := context.Background()
+ header, err := this.kaiclient.FullHeaderByNumber(ctx, big.NewInt(int64(height)))
+ if err != nil {
+ return "", err
+ }
+
+ headerBytes, err := json.Marshal(header)
+ if err != nil {
+ return "", err
+ }
+
+ log.Infof("commit proof, height: %d, proof: %s, value: %s, txhash: %s", height, string(proof), hex.EncodeToString(value), hex.EncodeToString(txhash))
+ tx, err := this.polySdk.Native.Ccm.ImportOuterTransfer(
+ this.config.KAIConfig.SideChainId,
+ value,
+ height,
+ proof,
+ ethcommon.Hex2Bytes(this.polySigner.Address.ToHexString()),
+ headerBytes,
+ this.polySigner)
+ if err != nil {
+ return "", err
+ } else {
+ log.Infof("commitProof - send transaction to poly chain: %s, height: %d", tx.ToHexString(), height)
+ return tx.ToHexString(), nil
+ }
+}
+
+func (this *KardiaManager) CheckDeposit() {
+ checkTicker := time.NewTicker(config.KAI_MONITOR_INTERVAL)
+ for {
+ select {
+ case <-checkTicker.C:
+ // try to check deposit
+ _ = this.checkLockDepositEvents()
+ case <-this.exitChan:
+ return
+ }
+ }
+}
+func (this *KardiaManager) checkLockDepositEvents() error {
+ checkMap, err := this.db.GetAllCheck()
+ if err != nil {
+ return fmt.Errorf("checkLockDepositEvents - this.db.GetAllCheck error: %s", err)
+ }
+ for k, v := range checkMap {
+ time.Sleep(time.Second * 1)
+ event, err := this.polySdk.GetSmartContractEvent(k)
+ if err != nil {
+ return fmt.Errorf("checkLockDepositEvents - this.aliaSdk.GetSmartContractEvent error: %s", err)
+ }
+ if event == nil {
+ log.Infof("checkLockDepositEvents - can not find event of hash %s", k)
+ continue
+ }
+ if event.State != 1 {
+ log.Infof("checkLockDepositEvents - state of tx %s is not success", k)
+ err := this.db.PutRetry(v)
+ if err != nil {
+ log.Errorf("checkLockDepositEvents - this.db.PutRetry error:%s", err)
+ }
+ } else {
+ err := this.db.DeleteCheck(k)
+ if err != nil {
+ log.Errorf("checkLockDepositEvents - this.db.DeleteRetry error:%s", err)
+ }
+ }
+ }
+ return nil
+}
diff --git a/manager/polymanager.go b/manager/polymanager.go
new file mode 100644
index 0000000..44cdcdb
--- /dev/null
+++ b/manager/polymanager.go
@@ -0,0 +1,549 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package manager
+
+import (
+ "context"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "math/rand"
+ "strconv"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ ethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/ontio/ontology-crypto/keypair"
+ "github.com/ontio/ontology-crypto/signature"
+ "github.com/polynetwork/eth-contracts/go_abi/eccd_abi"
+ "github.com/polynetwork/eth-contracts/go_abi/eccm_abi"
+ "github.com/polynetwork/kai-relayer/config"
+ "github.com/polynetwork/kai-relayer/db"
+ "github.com/polynetwork/kai-relayer/kaiclient"
+ "github.com/polynetwork/kai-relayer/log"
+ sdk "github.com/polynetwork/poly-go-sdk"
+ "github.com/polynetwork/poly/common"
+ "github.com/polynetwork/poly/common/password"
+ vconfig "github.com/polynetwork/poly/consensus/vbft/config"
+ common2 "github.com/polynetwork/poly/native/service/cross_chain_manager/common"
+
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum"
+ "github.com/polynetwork/kai-relayer/tools"
+
+ polytypes "github.com/polynetwork/poly/core/types"
+)
+
+const (
+ ChanLen = 64
+)
+
+type PolyManager struct {
+ config *config.ServiceConfig
+ polySdk *sdk.PolySdk
+ currentHeight uint32
+ contractAbi *abi.ABI
+ exitChan chan int
+ db *db.BoltDB
+ ethClient *ethclient.Client
+ senders []*EthSender
+}
+
+func NewPolyManager(servCfg *config.ServiceConfig, startblockHeight uint32, polySdk *sdk.PolySdk, ethclient *ethclient.Client, kaiclient *kaiclient.Client, boltDB *db.BoltDB) (*PolyManager, error) {
+ contractabi, err := abi.JSON(strings.NewReader(eccm_abi.EthCrossChainManagerABI))
+ if err != nil {
+ return nil, err
+ }
+ ks := tools.NewKaiKeyStore(servCfg.KAIConfig)
+ accArr := ks.GetAccounts()
+
+ if len(servCfg.KAIConfig.KeyStorePwdSet) == 0 {
+ fmt.Println("please input the passwords for ethereum keystore: ")
+ for _, v := range accArr {
+ fmt.Printf("For address %s. ", v.Address.String())
+ raw, err := password.GetPassword()
+ if err != nil {
+ log.Fatalf("failed to input password: %v", err)
+ panic(err)
+ }
+ servCfg.KAIConfig.KeyStorePwdSet[strings.ToLower(v.Address.String())] = string(raw)
+ }
+ }
+
+ senders := make([]*EthSender, len(accArr))
+ for i, v := range senders {
+ v = &EthSender{}
+ v.acc = accArr[i]
+ pwd, ok := servCfg.KAIConfig.KeyStorePwdSet[strings.ToLower(v.acc.Address.String())]
+ if !ok {
+ fmt.Printf("Password for address %s is not found in configuration, please input ", v.acc.Address.String())
+ raw, err := password.GetPassword()
+ if err != nil {
+ log.Fatalf("failed to input password: %v", err)
+ panic(err)
+ }
+ pwd = string(raw)
+ }
+
+ if err := ks.TestPwd(v.acc, pwd); err != nil {
+ log.Fatalf("your password %s for account %s is not working: %v", pwd, v.acc.Address.String(), err)
+ panic(err)
+ }
+
+ v.ethClient = ethclient
+ v.keyStore = ks
+ v.pwd = pwd
+ v.config = servCfg
+ v.polySdk = polySdk
+ v.contractAbi = &contractabi
+ v.nonceManager = tools.NewNonceManager(ethclient)
+ v.cmap = make(map[string]chan *EthTxInfo)
+
+ senders[i] = v
+ }
+ return &PolyManager{
+ exitChan: make(chan int),
+ config: servCfg,
+ polySdk: polySdk,
+ currentHeight: startblockHeight,
+ contractAbi: &contractabi,
+ db: boltDB,
+ ethClient: ethclient,
+ senders: senders,
+ }, nil
+}
+
+func (this *PolyManager) findLatestHeight() uint32 {
+ address := ethcommon.HexToAddress(this.config.KAIConfig.ECCDContractAddress)
+ instance, err := eccd_abi.NewEthCrossChainData(address, this.ethClient)
+ if err != nil {
+ log.Errorf("findLatestHeight - new eth cross chain failed: %s", err.Error())
+ return 0
+ }
+ height, err := instance.GetCurEpochStartHeight(nil)
+ if err != nil {
+ log.Errorf("findLatestHeight - GetLatestHeight failed: %s", err.Error())
+ return 0
+ }
+ return uint32(height)
+}
+
+func (this *PolyManager) init() bool {
+ if this.currentHeight > 0 {
+ log.Infof("PolyManager init - start height from flag: %d", this.currentHeight)
+ return true
+ }
+ this.currentHeight = this.db.GetPolyHeight()
+ latestHeight := this.findLatestHeight()
+ if latestHeight > this.currentHeight {
+ this.currentHeight = latestHeight
+ log.Infof("PolyManager init - latest height from ECCM: %d", this.currentHeight)
+ return true
+ }
+ log.Infof("PolyManager init - latest height from DB: %d", this.currentHeight)
+
+ return true
+}
+
+func (this *PolyManager) MonitorChain() {
+ ret := this.init()
+ if ret == false {
+ log.Errorf("MonitorChain - init failed\n")
+ }
+ monitorTicker := time.NewTicker(config.ONT_MONITOR_INTERVAL)
+ var blockHandleResult bool
+ for {
+ select {
+ case <-monitorTicker.C:
+ latestheight, err := this.polySdk.GetCurrentBlockHeight()
+ if err != nil {
+ log.Errorf("MonitorChain - get poly chain block height error: %s", err)
+ continue
+ }
+ latestheight--
+ if latestheight-this.currentHeight < config.ONT_USEFUL_BLOCK_NUM {
+ continue
+ }
+ log.Infof("MonitorChain - poly chain current height: %d", latestheight)
+ blockHandleResult = true
+ for this.currentHeight <= latestheight-config.ONT_USEFUL_BLOCK_NUM {
+ blockHandleResult = this.handleDepositEvents(this.currentHeight)
+ if blockHandleResult == false {
+ break
+ }
+ this.currentHeight++
+ }
+ if err = this.db.UpdatePolyHeight(this.currentHeight - 1); err != nil {
+ log.Errorf("MonitorChain - failed to save height of poly: %v", err)
+ }
+ case <-this.exitChan:
+ return
+ }
+ }
+}
+
+func (this *PolyManager) handleDepositEvents(height uint32) bool {
+ lastEpoch := this.findLatestHeight()
+ hdr, err := this.polySdk.GetHeaderByHeight(height + 1)
+ if err != nil {
+ log.Errorf("handleBlockHeader - GetNodeHeader on height :%d failed", height)
+ return false
+ }
+ isCurr := lastEpoch < height+1
+ isEpoch := hdr.NextBookkeeper != common.ADDRESS_EMPTY
+ var (
+ anchor *polytypes.Header
+ hp string
+ )
+ if !isCurr {
+ anchor, _ = this.polySdk.GetHeaderByHeight(lastEpoch + 1)
+ proof, _ := this.polySdk.GetMerkleProof(height+1, lastEpoch+1)
+ hp = proof.AuditPath
+ } else if isEpoch {
+ anchor, _ = this.polySdk.GetHeaderByHeight(height + 2)
+ proof, _ := this.polySdk.GetMerkleProof(height+1, height+2)
+ hp = proof.AuditPath
+ }
+
+ cnt := 0
+ events, err := this.polySdk.GetSmartContractEventByBlock(height)
+ for err != nil {
+ log.Errorf("handleDepositEvents - get block event at height:%d error: %s", height, err.Error())
+ return false
+ }
+ for _, event := range events {
+ for _, notify := range event.Notify {
+ if notify.ContractAddress == this.config.PolyConfig.EntranceContractAddress {
+ states := notify.States.([]interface{})
+ method, _ := states[0].(string)
+ if method != "makeProof" {
+ continue
+ }
+ tchainid := uint32(states[2].(float64))
+ if tchainid != 2 {
+ continue
+ }
+ cnt++
+ sender := this.selectSender()
+ log.Infof("sender %s is handling poly tx ( hash: %s, height: %d )",
+ sender.acc.Address.String(), event.TxHash, height)
+ if !sender.commitDepositEventsWithHeader(hdr, []byte(states[5].(string)), hp, anchor, event.TxHash) {
+ return false
+ }
+ }
+ }
+ }
+ if cnt == 0 && isEpoch && isCurr {
+ sender := this.selectSender()
+ return sender.commitHeader(hdr)
+ }
+
+ return true
+}
+
+func (this *PolyManager) selectSender() *EthSender {
+ sum := big.NewInt(0)
+ balArr := make([]*big.Int, len(this.senders))
+ for i, v := range this.senders {
+ RETRY:
+ bal, err := v.Balance()
+ if err != nil {
+ log.Errorf("failed to get balance for %s: %v", v.acc.Address.String(), err)
+ time.Sleep(time.Second)
+ goto RETRY
+ }
+ sum.Add(sum, bal)
+ balArr[i] = big.NewInt(sum.Int64())
+ }
+ sum.Rand(rand.New(rand.NewSource(time.Now().Unix())), sum)
+ for i, v := range balArr {
+ res := v.Cmp(sum)
+ if res == 1 || res == 0 {
+ return this.senders[i]
+ }
+ }
+ return this.senders[0]
+}
+
+func (this *PolyManager) Stop() {
+ this.exitChan <- 1
+ close(this.exitChan)
+ log.Infof("poly chain manager exit.")
+}
+
+type EthSender struct {
+ pwd string
+ acc accounts.Account
+ keyStore *tools.KaiKeyStore
+ cmap map[string]chan *EthTxInfo
+ nonceManager *tools.NonceManager
+ ethClient *ethclient.Client
+ polySdk *sdk.PolySdk
+ config *config.ServiceConfig
+ contractAbi *abi.ABI
+}
+
+func (this *EthSender) sendTxToEth(info *EthTxInfo) error {
+ nonce := this.nonceManager.GetAddressNonce(this.acc.Address)
+ tx := types.NewTransaction(nonce, info.contractAddr, big.NewInt(0), info.gasLimit, info.gasPrice, info.txData)
+ signedtx, err := this.keyStore.SignTransaction(tx, this.acc, this.pwd)
+ if err != nil {
+ this.nonceManager.ReturnNonce(this.acc.Address, nonce)
+ return fmt.Errorf("commitDepositEventsWithHeader - sign raw tx error and return nonce %d: %v", nonce, err)
+ }
+ err = this.ethClient.SendTransaction(context.Background(), signedtx)
+ if err != nil {
+ this.nonceManager.ReturnNonce(this.acc.Address, nonce)
+ return fmt.Errorf("commitDepositEventsWithHeader - send transaction error and return nonce %d: %v\n", nonce, err)
+ }
+ hash := signedtx.Hash()
+ isSuccess := this.waitTransactionConfirm(hash)
+ if isSuccess {
+ log.Infof("successful to relay tx to ethereum: (eth_hash: %s, nonce: %d, poly_hash: %s)",
+ hash.String(), nonce, info.polyTxHash)
+ } else {
+ log.Errorf("failed to relay tx to ethereum: (eth_hash: %s, nonce: %d, poly_hash: %s)",
+ hash.String(), nonce, info.polyTxHash)
+ }
+ return nil
+}
+
+func (this *EthSender) commitDepositEventsWithHeader(header *polytypes.Header, key []byte, headerProof string, anchorHeader *polytypes.Header, polyTxHash string) bool {
+ var (
+ sigs []byte
+ auditpath []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...)
+ }
+ }
+ proof, err := this.polySdk.GetCrossStatesProof(header.Height-1, string(key))
+ if err != nil {
+ log.Errorf("commitDepositEventsWithHeader - err: %v", err)
+ return false
+ }
+ auditpath, _ = hex.DecodeString(proof.AuditPath)
+ value, _, _, _ := tools.ParseAuditpath(auditpath)
+ param := &common2.ToMerkleValue{}
+ if err := param.Deserialization(common.NewZeroCopySource(value)); err != nil {
+ log.Errorf("commitDepositEventsWithHeader - failed to deserialize MakeTxParam: %v", err)
+ return false
+ }
+
+ eccdAddr := ethcommon.HexToAddress(this.config.KAIConfig.ECCDContractAddress)
+ eccd, err := eccd_abi.NewEthCrossChainData(eccdAddr, this.ethClient)
+ if err != nil {
+ panic(fmt.Errorf("failed to new eccm: %v", err))
+ }
+ fromTx := [32]byte{}
+ copy(fromTx[:], param.TxHash[:32])
+ res, _ := eccd.CheckIfFromChainTxExist(nil, param.FromChainID, fromTx)
+ if res {
+ log.Debugf("already relayed to eth: ( from_chain_id: %d, from_txhash: %x, param.Txhash: %x)",
+ param.FromChainID, param.TxHash, param.MakeTxParam.TxHash)
+ return true
+ }
+ log.Infof("poly proof with header, height: %d, key: %s, proof: %s", header.Height-1, string(key), proof.AuditPath)
+
+ rawProof, _ := hex.DecodeString(headerProof)
+ var rawAnchor []byte
+ if anchorHeader != nil {
+ rawAnchor = anchorHeader.ToArray()
+ }
+ headerData = header.GetMessage()
+ txData, err := this.contractAbi.Pack("verifyHeaderAndExecuteTx", auditpath, headerData, rawProof, rawAnchor, sigs)
+ if err != nil {
+ log.Errorf("commitDepositEventsWithHeader - err:" + err.Error())
+ return false
+ }
+
+ gasPrice, err := this.ethClient.SuggestGasPrice(context.Background())
+ if err != nil {
+ log.Errorf("commitDepositEventsWithHeader - get suggest sas price failed error: %s", err.Error())
+ return false
+ }
+ contractaddr := ethcommon.HexToAddress(this.config.KAIConfig.ECCMContractAddress)
+ callMsg := ethereum.CallMsg{
+ From: this.acc.Address, To: &contractaddr, Gas: 0, GasPrice: gasPrice,
+ Value: big.NewInt(0), Data: txData,
+ }
+ gasLimit, err := this.ethClient.EstimateGas(context.Background(), callMsg)
+ if err != nil {
+ log.Errorf("commitDepositEventsWithHeader - estimate gas limit error: %s", err.Error())
+ return false
+ }
+
+ k := this.getRouter()
+ c, ok := this.cmap[k]
+ if !ok {
+ c = make(chan *EthTxInfo, ChanLen)
+ this.cmap[k] = c
+ go func() {
+ for v := range c {
+ if err = this.sendTxToEth(v); err != nil {
+ log.Errorf("failed to send tx to ethereum: error: %v, txData: %s", err, hex.EncodeToString(v.txData))
+ }
+ }
+ }()
+ }
+ //TODO: could be blocked
+ c <- &EthTxInfo{
+ txData: txData,
+ contractAddr: contractaddr,
+ gasPrice: gasPrice,
+ gasLimit: gasLimit,
+ polyTxHash: polyTxHash,
+ }
+ return true
+}
+
+func (this *EthSender) commitHeader(header *polytypes.Header) bool {
+ headerdata := header.GetMessage()
+ var (
+ txData []byte
+ txErr error
+ bookkeepers []keypair.PublicKey
+ sigs []byte
+ )
+ gasPrice, err := this.ethClient.SuggestGasPrice(context.Background())
+ if err != nil {
+ log.Errorf("commitHeader - get suggest sas price failed error: %s", err.Error())
+ return false
+ }
+ for _, sig := range header.SigData {
+ temp := make([]byte, len(sig))
+ copy(temp, sig)
+ newsig, _ := signature.ConvertToEthCompatible(temp)
+ sigs = append(sigs, newsig...)
+ }
+
+ blkInfo := &vconfig.VbftBlockInfo{}
+ if err := json.Unmarshal(header.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)...)
+ }
+ txData, txErr = this.contractAbi.Pack("changeBookKeeper", headerdata, publickeys, sigs)
+ if txErr != nil {
+ log.Errorf("commitHeader - err:" + err.Error())
+ return false
+ }
+
+ contractaddr := ethcommon.HexToAddress(this.config.KAIConfig.ECCMContractAddress)
+ callMsg := ethereum.CallMsg{
+ From: this.acc.Address, To: &contractaddr, Gas: 0, GasPrice: gasPrice,
+ Value: big.NewInt(0), Data: txData,
+ }
+
+ gasLimit, err := this.ethClient.EstimateGas(context.Background(), callMsg)
+ if err != nil {
+ log.Errorf("commitHeader - estimate gas limit error: %s", err.Error())
+ return false
+ }
+
+ nonce := this.nonceManager.GetAddressNonce(this.acc.Address)
+ tx := types.NewTransaction(nonce, contractaddr, big.NewInt(0), gasLimit, gasPrice, txData)
+ signedtx, err := this.keyStore.SignTransaction(tx, this.acc, this.pwd)
+ if err != nil {
+ log.Errorf("commitHeader - sign raw tx error: %s", err.Error())
+ return false
+ }
+ if err = this.ethClient.SendTransaction(context.Background(), signedtx); err != nil {
+ log.Errorf("commitHeader - send transaction error:%s\n", err.Error())
+ return false
+ }
+
+ hash := header.Hash()
+ txhash := signedtx.Hash()
+ isSuccess := this.waitTransactionConfirm(txhash)
+ if isSuccess {
+ log.Infof("successful to relay poly header to ethereum: (header_hash: %s, height: %d, eth_txhash: %s, nonce: %d)",
+ hash.ToHexString(), header.Height, txhash.String(), nonce)
+ } else {
+ log.Errorf("failed to relay poly header to ethereum: (header_hash: %s, height: %d, eth_txhash: %s, nonce: %d)",
+ hash.ToHexString(), header.Height, txhash.String(), nonce)
+ }
+ return true
+}
+
+func (this *EthSender) getRouter() string {
+ return strconv.FormatInt(rand.Int63n(this.config.RoutineNum), 10)
+}
+
+func (this *EthSender) Balance() (*big.Int, error) {
+ balance, err := this.ethClient.BalanceAt(context.Background(), this.acc.Address, nil)
+ if err != nil {
+ return nil, err
+ }
+ return balance, nil
+}
+
+// TODO: check the status of tx
+func (this *EthSender) waitTransactionConfirm(hash ethcommon.Hash) bool {
+ for {
+ time.Sleep(time.Second * 1)
+ _, ispending, err := this.ethClient.TransactionByHash(context.Background(), hash)
+ if err != nil {
+ continue
+ }
+ log.Debugf("transaction %s is pending: %b\n", hash.String(), ispending)
+ if ispending == true {
+ continue
+ } else {
+ receipt, err := this.ethClient.TransactionReceipt(context.Background(), hash)
+ if err != nil {
+ continue
+ }
+ return receipt.Status == types.ReceiptStatusSuccessful
+ }
+ }
+}
+
+type EthTxInfo struct {
+ txData []byte
+ gasLimit uint64
+ gasPrice *big.Int
+ contractAddr ethcommon.Address
+ polyTxHash string
+}
diff --git a/tools/kaikeystore.go b/tools/kaikeystore.go
new file mode 100644
index 0000000..e01f9d6
--- /dev/null
+++ b/tools/kaikeystore.go
@@ -0,0 +1,71 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/accounts/keystore"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/polynetwork/kai-relayer/config"
+ "github.com/polynetwork/kai-relayer/log"
+)
+
+type KaiKeyStore struct {
+ ks *keystore.KeyStore
+}
+
+func NewKaiKeyStore(sigConfig *config.KAIConfig) *KaiKeyStore {
+ service := &KaiKeyStore{}
+ capitalKeyStore := keystore.NewKeyStore(sigConfig.KeyStorePath, keystore.StandardScryptN,
+ keystore.StandardScryptP)
+
+ accArr := capitalKeyStore.Accounts()
+ if len(accArr) == 0 {
+ log.Fatal("relayer has no account")
+ panic(fmt.Errorf("relayer has no account"))
+ }
+ str := ""
+ for i, v := range accArr {
+ str += fmt.Sprintf("(no.%d acc: %s), ", i+1, v.Address.String())
+ }
+ log.Infof("relayer are using accounts: [ %s ]", str)
+
+ service.ks = capitalKeyStore
+ return service
+}
+
+func (this *KaiKeyStore) SignTransaction(tx *types.Transaction, acc accounts.Account, pwd string) (*types.Transaction, error) {
+ tx, err := this.ks.SignTxWithPassphrase(acc, pwd, tx, nil)
+ if err != nil {
+ return nil, err
+ }
+ return tx, nil
+}
+
+func (this *KaiKeyStore) GetAccounts() []accounts.Account {
+ return this.ks.Accounts()
+}
+
+func (this *KaiKeyStore) TestPwd(acc accounts.Account, pwd string) error {
+ if err := this.ks.Unlock(acc, pwd); err != nil {
+ return err
+ }
+ _ = this.ks.Lock(acc.Address)
+ return nil
+}
diff --git a/tools/kaikeystore_test.go b/tools/kaikeystore_test.go
new file mode 100644
index 0000000..ab4c683
--- /dev/null
+++ b/tools/kaikeystore_test.go
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "testing"
+)
+
+func TestETHSigner_SignTransaction(t *testing.T) {
+ // cfg := config.NewServiceConfig("./config-debug.json")
+ // ethsigner := NewKaiKeyStore(cfg.KAIConfig)
+ // tx := &types.Transaction{}
+ // tx, err := ethsigner.SignTransaction(tx)
+ // if err != nil {
+ // t.Fatal(err)
+ // }
+ // v, r, s := tx.RawSignatureValues()
+ // if v.BitLen()+r.BitLen()+s.BitLen() <= 0 {
+ // t.Fatal("failed to sign")
+ // }
+}
diff --git a/tools/nouncmanager.go b/tools/nouncmanager.go
new file mode 100644
index 0000000..04b52e3
--- /dev/null
+++ b/tools/nouncmanager.go
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "context"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/polynetwork/kai-relayer/log"
+)
+
+const clear_nonce_interval = 10 * time.Minute
+
+type NonceManager struct {
+ addressNonce map[common.Address]uint64
+ returnedNonce map[common.Address]SortedNonceArr
+ kaiCli *ethclient.Client
+ lock sync.Mutex
+}
+
+func NewNonceManager(kaiCli *ethclient.Client) *NonceManager {
+ nonceManager := &NonceManager{
+ addressNonce: make(map[common.Address]uint64),
+ kaiCli: kaiCli,
+ returnedNonce: make(map[common.Address]SortedNonceArr),
+ }
+ go nonceManager.clearNonce()
+ return nonceManager
+}
+
+// return account nonce, and than nonce++
+func (this *NonceManager) GetAddressNonce(address common.Address) uint64 {
+ this.lock.Lock()
+ defer this.lock.Unlock()
+
+ if this.returnedNonce[address].Len() > 0 {
+ nonce := this.returnedNonce[address][0]
+ this.returnedNonce[address] = this.returnedNonce[address][1:]
+ return nonce
+ }
+
+ // return a new point
+ nonce, ok := this.addressNonce[address]
+ if !ok {
+ // get nonce from eth network
+ uintNonce, err := this.kaiCli.PendingNonceAt(context.Background(), address)
+ if err != nil {
+ log.Errorf("GetAddressNonce: cannot get account %s nonce, err: %s, set it to nil!",
+ address, err)
+ }
+ this.addressNonce[address] = uintNonce
+ nonce = uintNonce
+ }
+ // increase record
+ this.addressNonce[address]++
+ return nonce
+}
+
+func (this *NonceManager) ReturnNonce(addr common.Address, nonce uint64) {
+ arr, ok := this.returnedNonce[addr]
+ if !ok {
+ arr = make([]uint64, 0)
+ }
+ arr = append(arr, nonce)
+ sort.Sort(arr)
+ this.returnedNonce[addr] = arr
+}
+
+func (this *NonceManager) DecreaseAddressNonce(address common.Address) {
+ this.lock.Lock()
+ defer this.lock.Unlock()
+
+ nonce, ok := this.addressNonce[address]
+ if ok && nonce > 0 {
+ this.addressNonce[address]--
+ }
+}
+
+// clear nonce per
+func (this *NonceManager) clearNonce() {
+ for {
+ <-time.After(clear_nonce_interval)
+ this.lock.Lock()
+ for addr, _ := range this.addressNonce {
+ delete(this.addressNonce, addr)
+ }
+ this.lock.Unlock()
+ //log.Infof("clearNonce: clear all cache nonce")
+ }
+}
+
+type SortedNonceArr []uint64
+
+func (arr SortedNonceArr) Less(i, j int) bool {
+ return arr[i] < arr[j]
+}
+
+func (arr SortedNonceArr) Len() int { return len(arr) }
+
+func (arr SortedNonceArr) Swap(i, j int) { arr[i], arr[j] = arr[j], arr[i] }
diff --git a/tools/rest_client.go b/tools/rest_client.go
new file mode 100644
index 0000000..ba5989b
--- /dev/null
+++ b/tools/rest_client.go
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "crypto/tls"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+)
+
+type RestClient struct {
+ Addr string
+ restClient *http.Client
+}
+
+func NewRestClient() *RestClient {
+ return &RestClient{
+ restClient: &http.Client{
+ Transport: &http.Transport{
+ MaxIdleConnsPerHost: 5,
+ DisableKeepAlives: false,
+ IdleConnTimeout: time.Second * 300,
+ ResponseHeaderTimeout: time.Second * 300,
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ },
+ Timeout: time.Second * 300,
+ },
+ }
+}
+
+func (self *RestClient) SetAddr(addr string) *RestClient {
+ self.Addr = addr
+ return self
+}
+
+func (self *RestClient) SetRestClient(restClient *http.Client) *RestClient {
+ self.restClient = restClient
+ return self
+}
+
+func (self *RestClient) SendRestRequest(addr string, data []byte) ([]byte, error) {
+ resp, err := self.restClient.Post(addr, "application/json", strings.NewReader(string(data)))
+ if err != nil {
+ return nil, fmt.Errorf("http post request:%s error:%s", data, err)
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("read rest response body error:%s", err)
+ }
+ return body, nil
+}
diff --git a/tools/rest_client_test.go b/tools/rest_client_test.go
new file mode 100644
index 0000000..bf4ebe1
--- /dev/null
+++ b/tools/rest_client_test.go
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRestClient(t *testing.T) {
+ client := NewRestClient()
+ assert.NotNil(t, client)
+ assert.NotNil(t, client.restClient)
+
+ addr := "ahgakgkajn"
+ client.SetAddr(addr)
+ assert.Equal(t, addr, client.Addr)
+}
diff --git a/tools/util.go b/tools/util.go
new file mode 100644
index 0000000..c9c5852
--- /dev/null
+++ b/tools/util.go
@@ -0,0 +1,286 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "bytes"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "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"
+
+ ktypes "github.com/kardiachain/go-kardia/types"
+)
+
+type jsonError struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data interface{} `json:"data,omitempty"`
+}
+
+type heightReq struct {
+ JsonRpc string `json:"jsonrpc"`
+ Method string `json:"method"`
+ Params []string `json:"params"`
+ Id uint `json:"id"`
+}
+
+type heightRsp struct {
+ JsonRpc string `json:"jsonrpc"`
+ Result uint64 `json:"result,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Id uint `json:"id"`
+}
+
+type proofReq struct {
+ JsonRPC string `json:"jsonrpc"`
+ Method string `json:"method"`
+ Params []interface{} `json:"params"`
+ Id uint `json:"id"`
+}
+
+type proofRsp struct {
+ JsonRPC string `json:"jsonrpc"`
+ Result KAIProof `json:"result,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Id uint `json:"id"`
+}
+
+type KAIProof struct {
+ Address string `json:"address"`
+ Balance string `json:"balance"`
+ CodeHash string `json:"codeHash"`
+ Nonce string `json:"nonce"`
+ StorageHash string `json:"storageHash"`
+ AccountProof []string `json:"accountProof"`
+ StorageProofs []StorageProof `json:"storageProof"`
+}
+
+type StorageProof struct {
+ Key string `json:"key"`
+ Value string `json:"value"`
+ Proof []string `json:"proof"`
+}
+
+type blockReq struct {
+ JsonRpc string `json:"jsonrpc"`
+ Method string `json:"method"`
+ Params []interface{} `json:"params"`
+ Id uint `json:"id"`
+}
+
+type blockRsp struct {
+ JsonRPC string `json:"jsonrpc"`
+ Result *ktypes.Header `json:"result,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Id uint `json:"id"`
+}
+
+type valSetRsp struct {
+ JsonRPC string `json:"jsonrpc"`
+ Result []*ktypes.Validator `json:"result,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Id uint `json:"id"`
+}
+
+type commitRsp struct {
+ JsonRPC string `json:"jsonrpc"`
+ Result *ktypes.Commit `json:"result,omitempty"`
+ Error *jsonError `json:"error,omitempty"`
+ Id uint `json:"id"`
+}
+
+func GetNodeHeader(url string, restClient *RestClient, height uint64) ([]byte, error) {
+ params := []interface{}{fmt.Sprintf("0x%x", height), true}
+ req := &blockReq{
+ JsonRpc: "2.0",
+ Method: "kai_getBlockByNumber",
+ Params: params,
+ Id: 1,
+ }
+ reqdata, err := json.Marshal(req)
+ if err != nil {
+ return nil, fmt.Errorf("GetNodeHeight: marshal req err: %s", err)
+ }
+ rspdata, err := restClient.SendRestRequest(url, reqdata)
+ if err != nil {
+ return nil, fmt.Errorf("GetNodeHeight err: %s", err)
+ }
+ rsp := &blockRsp{}
+ err = json.Unmarshal(rspdata, rsp)
+ if err != nil {
+ return nil, fmt.Errorf("GetNodeHeight, unmarshal resp err: %s", err)
+ }
+ if rsp.Error != nil {
+ return nil, fmt.Errorf("GetNodeHeight, unmarshal resp err: %s", rsp.Error.Message)
+ }
+ return json.Marshal(rsp.Result)
+}
+
+func GetNodeHeight(url string, restClient *RestClient) (uint64, error) {
+ req := &heightReq{
+ JsonRpc: "2.0",
+ Method: "kai_blockNumber",
+ Params: make([]string, 0),
+ Id: 1,
+ }
+ reqData, err := json.Marshal(req)
+ if err != nil {
+ return 0, fmt.Errorf("GetNodeHeight: marshal req err: %s", err)
+ }
+ rspData, err := restClient.SendRestRequest(url, reqData)
+ if err != nil {
+ return 0, fmt.Errorf("GetNodeHeight err: %s", err)
+ }
+ rsp := &heightRsp{}
+ err = json.Unmarshal(rspData, rsp)
+ if err != nil {
+ return 0, fmt.Errorf("GetNodeHeight, unmarshal resp err: %s", err)
+ }
+ if rsp.Error != nil {
+ return 0, fmt.Errorf("GetNodeHeight, unmarshal resp err: %s", rsp.Error.Message)
+ }
+ return rsp.Result, nil
+}
+
+func GetProof(url string, contractAddress string, key string, blockheight string, restClient *RestClient) ([]byte, error) {
+ req := &proofReq{
+ JsonRPC: "2.0",
+ Method: "eth_getProof",
+ Params: []interface{}{contractAddress, []string{key}, blockheight},
+ Id: 1,
+ }
+ reqdata, err := json.Marshal(req)
+ if err != nil {
+ return nil, fmt.Errorf("eth_kaiProof: marshal req err: %s", err)
+ }
+ rspdata, err := restClient.SendRestRequest(url, reqdata)
+ if err != nil {
+ return nil, fmt.Errorf("GetProof: send request err: %s", err)
+ }
+ rsp := &proofRsp{}
+ err = json.Unmarshal(rspdata, rsp)
+ if err != nil {
+ return nil, fmt.Errorf("GetProof, unmarshal resp err: %s", err)
+ }
+ if rsp.Error != nil {
+ return nil, fmt.Errorf("GetNodeHeight, unmarshal resp err: %s", rsp.Error.Message)
+ }
+ result, err := json.Marshal(rsp.Result)
+ if err != nil {
+ return nil, fmt.Errorf("GetProof, Marshal result err: %s", err)
+ }
+ //fmt.Printf("proof res is:%s\n", string(result))
+ return result, nil
+}
+
+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 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 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")
+ }
+}
diff --git a/tools/util_test.go b/tools/util_test.go
new file mode 100644
index 0000000..ab5366f
--- /dev/null
+++ b/tools/util_test.go
@@ -0,0 +1,36 @@
+/*
+* Copyright (C) 2020 The poly network Authors
+* This file is part of The poly network library.
+*
+* The poly network is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* The poly network 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 Lesser General Public License for more details.
+* You should have received a copy of the GNU Lesser General Public License
+* along with The poly network . If not, see .
+ */
+package tools
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestGetProof(t *testing.T) {
+ client := NewRestClient()
+ res, err := GetProof("http://139.219.131.74:10331",
+ "0xf6dc652e2f7ab7a20d1cc4156d5a7122a9e966a5",
+ "0xada5013122d395ba3c54772283fb069b10426056ef8ca54750cb9bb552a59e7d",
+ "0x5e852e",
+ client)
+ if err != nil {
+ fmt.Printf("err:%s\n", err)
+ return
+ }
+ fmt.Printf("res is :%s\n", res)
+}