From 6ecd336e0547d4af64e2dfb6f8569a7bc4663da4 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Mon, 24 Jul 2023 11:07:52 +0530 Subject: [PATCH] ADD: chain.go Signed-off-by: Aditya Kumar Singh --- go.mod | 3 +- go.sum | 4 + orderer/consensus/bdls/chain.go | 44 + .../github.com/BDLS-bft/bdls/.gitattributes | 2 + vendor/github.com/BDLS-bft/bdls/.gitignore | 3 + .../BDLS-bft/bdls/CODE_OF_CONDUCT.md | 8 + .../github.com/BDLS-bft/bdls/CONTRIBUTING.md | 32 + vendor/github.com/BDLS-bft/bdls/LICENSE | 202 ++ .../github.com/BDLS-bft/bdls/MAINTAINERS.md | 12 + vendor/github.com/BDLS-bft/bdls/README.md | 114 ++ vendor/github.com/BDLS-bft/bdls/SECURITY.md | 9 + vendor/github.com/BDLS-bft/bdls/config.go | 72 + vendor/github.com/BDLS-bft/bdls/consensus.go | 1677 +++++++++++++++++ .../BDLS-bft/bdls/crypto/blake2b/blake2b.go | 319 ++++ .../bdls/crypto/blake2b/blake2bAVX2_amd64.go | 37 + .../bdls/crypto/blake2b/blake2bAVX2_amd64.s | 717 +++++++ .../bdls/crypto/blake2b/blake2b_amd64.go | 24 + .../bdls/crypto/blake2b/blake2b_amd64.s | 253 +++ .../bdls/crypto/blake2b/blake2b_f_fuzz.go | 57 + .../bdls/crypto/blake2b/blake2b_generic.go | 180 ++ .../bdls/crypto/blake2b/blake2b_ref.go | 11 + .../BDLS-bft/bdls/crypto/blake2b/blake2x.go | 177 ++ .../BDLS-bft/bdls/crypto/blake2b/register.go | 32 + .../BDLS-bft/bdls/crypto/btcec/README.md | 68 + .../BDLS-bft/bdls/crypto/btcec/btcec.go | 976 ++++++++++ .../BDLS-bft/bdls/crypto/btcec/ciphering.go | 216 +++ .../BDLS-bft/bdls/crypto/btcec/doc.go | 21 + .../BDLS-bft/bdls/crypto/btcec/field.go | 1352 +++++++++++++ .../bdls/crypto/btcec/gensecp256k1.go | 203 ++ .../BDLS-bft/bdls/crypto/btcec/precompute.go | 67 + .../BDLS-bft/bdls/crypto/btcec/privkey.go | 73 + .../BDLS-bft/bdls/crypto/btcec/pubkey.go | 194 ++ .../BDLS-bft/bdls/crypto/btcec/secp256k1.go | 10 + .../BDLS-bft/bdls/crypto/btcec/signature.go | 540 ++++++ vendor/github.com/BDLS-bft/bdls/doc.go | 12 + vendor/github.com/BDLS-bft/bdls/errors.go | 82 + vendor/github.com/BDLS-bft/bdls/ipc_peer.go | 145 ++ vendor/github.com/BDLS-bft/bdls/message.go | 193 ++ vendor/github.com/BDLS-bft/bdls/message.pb.go | 1055 +++++++++++ vendor/github.com/BDLS-bft/bdls/message.proto | 54 + vendor/github.com/BDLS-bft/bdls/peer.go | 17 + vendor/github.com/BDLS-bft/bdls/protogen.sh | 3 + .../BDLS-bft/bdls/timer/timedsched.go | 147 ++ .../github.com/mattn/go-runewidth/.travis.yml | 14 +- .../go-runewidth/{README.mkd => README.md} | 2 +- .../github.com/mattn/go-runewidth/go.test.sh | 12 + .../mattn/go-runewidth/runewidth.go | 738 +------- .../mattn/go-runewidth/runewidth_posix.go | 5 +- .../mattn/go-runewidth/runewidth_table.go | 437 +++++ vendor/modules.txt | 10 +- 50 files changed, 9898 insertions(+), 737 deletions(-) create mode 100644 vendor/github.com/BDLS-bft/bdls/.gitattributes create mode 100644 vendor/github.com/BDLS-bft/bdls/.gitignore create mode 100644 vendor/github.com/BDLS-bft/bdls/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/BDLS-bft/bdls/CONTRIBUTING.md create mode 100644 vendor/github.com/BDLS-bft/bdls/LICENSE create mode 100644 vendor/github.com/BDLS-bft/bdls/MAINTAINERS.md create mode 100644 vendor/github.com/BDLS-bft/bdls/README.md create mode 100644 vendor/github.com/BDLS-bft/bdls/SECURITY.md create mode 100644 vendor/github.com/BDLS-bft/bdls/config.go create mode 100644 vendor/github.com/BDLS-bft/bdls/consensus.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2bAVX2_amd64.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2bAVX2_amd64.s create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b_amd64.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b_amd64.s create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b_f_fuzz.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b_generic.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2b_ref.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/blake2x.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/blake2b/register.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/README.md create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/btcec.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/ciphering.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/doc.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/field.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/gensecp256k1.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/precompute.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/privkey.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/pubkey.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/secp256k1.go create mode 100644 vendor/github.com/BDLS-bft/bdls/crypto/btcec/signature.go create mode 100644 vendor/github.com/BDLS-bft/bdls/doc.go create mode 100644 vendor/github.com/BDLS-bft/bdls/errors.go create mode 100644 vendor/github.com/BDLS-bft/bdls/ipc_peer.go create mode 100644 vendor/github.com/BDLS-bft/bdls/message.go create mode 100644 vendor/github.com/BDLS-bft/bdls/message.pb.go create mode 100644 vendor/github.com/BDLS-bft/bdls/message.proto create mode 100644 vendor/github.com/BDLS-bft/bdls/peer.go create mode 100644 vendor/github.com/BDLS-bft/bdls/protogen.sh create mode 100644 vendor/github.com/BDLS-bft/bdls/timer/timedsched.go rename vendor/github.com/mattn/go-runewidth/{README.mkd => README.md} (82%) create mode 100644 vendor/github.com/mattn/go-runewidth/go.test.sh create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_table.go diff --git a/go.mod b/go.mod index 96cb5455f4d..0e33120f1ee 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/BDLS-bft/bdls v0.0.0-20230426164822-28f164ce5034 // indirect github.com/DataDog/zstd v1.4.5 // indirect github.com/IBM/mathlib v0.0.0-20220112091634-0a7378db6912 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect @@ -83,7 +84,7 @@ require ( github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.1 // indirect - github.com/mattn/go-runewidth v0.0.4 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moby/sys/mount v0.2.0 // indirect diff --git a/go.sum b/go.sum index 36dd9f730b0..3d7c43f3278 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYB dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BDLS-bft/bdls v0.0.0-20230426164822-28f164ce5034 h1:HhyRyqlWnacpLMM18NJQEkFo1On4GUZyOcTPwpj2H7c= +github.com/BDLS-bft/bdls v0.0.0-20230426164822-28f164ce5034/go.mod h1:hesZ3fp+xEnW6dqvjJrbKru9K0v7y/kQloGL7iD4vR4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= @@ -442,6 +444,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-runewidth v0.0.2/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/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= diff --git a/orderer/consensus/bdls/chain.go b/orderer/consensus/bdls/chain.go index 8b137891791..3c1b51ecd44 100644 --- a/orderer/consensus/bdls/chain.go +++ b/orderer/consensus/bdls/chain.go @@ -1 +1,45 @@ +package bdls +import ( + "fmt" + + bdls "github.com/BDLS-bft/bdls" +) + +type Chain struct { + // Chain Struct + config *bdls.Config +} + +func (c *Chain) Start() { + consensus, err := bdls.NewConsensus(c.config) + checkErrNil(err) + fmt.Println(consensus) + +} + +func (c *Chain) Order() { + +} + +func (c *Chain) Configure() { + +} + +func (c *Chain) WaitReady() { + +} + +func (c *Chain) Errored() { + +} + +func (c *Chain) Halt() { + +} + +func checkErrNil(err error) { + if err != nil { + panic(err) + } +} diff --git a/vendor/github.com/BDLS-bft/bdls/.gitattributes b/vendor/github.com/BDLS-bft/bdls/.gitattributes new file mode 100644 index 00000000000..dfe0770424b --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/vendor/github.com/BDLS-bft/bdls/.gitignore b/vendor/github.com/BDLS-bft/bdls/.gitignore new file mode 100644 index 00000000000..2f44eb9dc75 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/.gitignore @@ -0,0 +1,3 @@ + +bdls.test +cpu.out diff --git a/vendor/github.com/BDLS-bft/bdls/CODE_OF_CONDUCT.md b/vendor/github.com/BDLS-bft/bdls/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..339bf98f497 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/CODE_OF_CONDUCT.md @@ -0,0 +1,8 @@ +Code of Conduct Guidelines +========================== + +Please review the Hyperledger [Code of +Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) +before participating. It is important that we keep things civil. + +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. \ No newline at end of file diff --git a/vendor/github.com/BDLS-bft/bdls/CONTRIBUTING.md b/vendor/github.com/BDLS-bft/bdls/CONTRIBUTING.md new file mode 100644 index 00000000000..e876b427df6 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# CONTRIBUTING + +* The integrating efforts to run BDLS as consensus protocol using the Fabric fork: +`https://github.com/BDLS-bft/fabric` + +* You can submit a PR, Issue or contact me directly for any inquiry +```xml +Email: a.alsalih2@gmail.com, +Discord: ahmedalsalih#6158 +``` + +* You can join the Mentorship Project 2023 : +https://wiki.hyperledger.org/display/INTERN/Integrate+new+BFT+protocol+%28BDLS+consensus%29+with+Fabric + + +* Bi-weekly lab meeting. +``` +Next meeting: Thursday, Mar-30, 2023 +9:30am to 10:00am Eastern Time +Repeats: +Every 2 weeks on Thursday +Location: +https://zoom.us/my/hyperledger.community.3?pwd=UE90WHhEaHRqOGEyMkV3cldKa2d2dz09 +``` + +The lab runs bi-weekly open community calls, and you are welcome to join to learn more about what the lab is, how to use it and how to get involved and help out. +You can join the calls every other Thursday at 9:30 AM Eastern at: + + +You can also talk with the developers of the lab in the **`#bdls`** channel on the Hyperledger Discord server at: + +https://chat.hyperledger.org/ diff --git a/vendor/github.com/BDLS-bft/bdls/LICENSE b/vendor/github.com/BDLS-bft/bdls/LICENSE new file mode 100644 index 00000000000..da6debcd2c7 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/BDLS-bft/bdls/MAINTAINERS.md b/vendor/github.com/BDLS-bft/bdls/MAINTAINERS.md new file mode 100644 index 00000000000..fb269b9db67 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/MAINTAINERS.md @@ -0,0 +1,12 @@ +## Maintainers + +### Active Maintainers +| name | Github | Discord | +|-------------------|-----------|----------------| +| Yongge Wang | [@yonggewang](https://github.com/yonggewang) | | +| Ahmed Al Salih | [@ahmed82](https://github.com/ahmed82) | | + +### Emeritus Maintainers +| name | Github | Discord | +|-------------------|-----------|----------------| +| Li Fu | [@xtaci](https://github.com/xtaci) | | diff --git a/vendor/github.com/BDLS-bft/bdls/README.md b/vendor/github.com/BDLS-bft/bdls/README.md new file mode 100644 index 00000000000..18f56d40840 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/README.md @@ -0,0 +1,114 @@ +# BDLS +Efficient BFT in partial synchronous networks + +[![GoDoc][1]][2] [![License][3]][4] [![Build Status][5]][6] [![Go Report Card][7]][8] [![Coverage Statusd][9]][10] [![Sourcegraph][11]][12] + +[1]: https://godoc.org/github.com/ahmed82/bdls?status.svg +[2]: https://godoc.org/github.com/ahmed82/bdls +[3]: https://img.shields.io/badge/License-Apache_2.0-blue.svg +[4]: LICENSE +[5]: https://travis-ci.org/BDLS-bft/bdls.svg?branch=master +[6]: https://travis-ci.org/BDLS-bft/bdls +[7]: https://goreportcard.com/badge/github.com/BDLS-bft/bdls?bdls +[8]: https://goreportcard.com/report/github.com/BDLS-bft/bdls +[9]: https://codecov.io/gh/BDLS-bft/bdls/branch/master/graph/badge.svg +[10]: https://codecov.io/gh/BDLS-bft/bdls +[11]: https://sourcegraph.com/github.com/BDLS-bft/bdls/-/badge.svg +[12]: https://sourcegraph.com/github.com/BDLS-bft/bdls?badge + +# BDLS Consensus +* ## [Contributing info](CONTRIBUTING.md) + +## Introduction + +BDLS is an innovative BFT consensus algorithm that features safety and liveness by +presenting a mathematically proven secure BFT protocol that is resilient in open networks such as +the Internet. BDLS overcomes many problems, such as the deadlock problem caused by unreliable +p2p/broadcast channels. These problems are all very relevant to existing realistic open +network scenarios, and are the focus of extensive work in improving Internet security, but it +is an area largely ignored by most in mainstream BFT protocol design. +(Paper: https://eprint.iacr.org/2019/1460.pdf or https://dl.acm.org/doi/abs/10.1145/3538227 or https://doi.org/10.1145/3538227 or https://www.doi.org/10.1007/978-3-030-91859-0_2 ) + +For this library, to make the runtime behavior of consensus algorithm predictable as function: +y = f(x, t), where 'x' is the message it received, and 't' is the time while being called, + then'y' is the deterministic status of consensus after 'x' and 't' applied to 'f', +it has been designed in a deterministic scheme, without parallel computing, networking, and +the correctness of program implementation can be proven with proper test cases. + +## Features + +1. Pure algorithm implementation in deterministic and predictable behavior, easily to be integrated into existing projects, refer to [DFA](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) for more. +2. Well-tested on various platforms with complicated cases. +3. Auto back-off under heavy payload, guaranteed finalization(worst case gurantee). +4. Easy integratation into Blockchain & non-Blockchain consensus, like [WAL replication](https://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) in database. +5. Builtin network emulation for various network latency with comprehensive statistics. + + + +## Documentation + +For complete documentation, see the associated [Godoc](https://pkg.go.dev/github.com/BDLS-bft/bdls). + + +## Install BDLS on Ubuntu Server 20.04 + +``` +sudo apt-get update +sudo apt-get -y upgrade +sudo apt-get install autoconf automake libtool curl make g++ unzip +cd /tmp +wget https://go.dev/dl/go1.17.5.linux-amd64.tar.gz +sudo tar -xvf go1.17.5.linux-amd64.tar.gz +sudo mv go /usr/local +cd +echo 'export GOROOT=/usr/local/go' >> .profile +echo 'export GOPATH=$HOME/go' >> .profile +echo 'export PATH=$GOPATH/bin:$GOROOT/bin:$PATH' >> .profile +source ~/.profile +go version +go env +git clone https://github.com/hyperledger-labs/bdls.git +cd bdls/ +git checkout master +cd cmd/emucon/ +go build . +./emucon help genkeys +./emucon genkeys --count 4 + +[open four terminals to run four participants. if you log to remote Linux, +you may use tmux commands. In tmux, you can switch termian using "ctrl+b d" +and use "tmux attach -t 0" to enter the terminal. Use "tmux list-session" +to check the current active terminals] + + +./emucon run --id 0 --listen ":4680" +./emucon run --id 1 --listen ":4681" +./emucon run --id 2 --listen ":4682" +./emucon run --id 3 --listen ":4683" + +cd ../.. +go test -v -cpuprofile=cpu.out -memprofile=mem.out -timeout 2h +``` +## Regenerate go.mod and go.sum +``` +rm go.* +go mod init github.com/hyperledger-labs/bdls +go mod tidy +go mod vendor +``` + +See benchmark ourput at: [AMD-NORMAL.TXT](benchmarks/AMD-NORMAL.TXT) and [PI4-OVERLOAD.TXT](benchmarks/PI4-OVERLOAD.TXT) + +## Specification + +1. Consensus messages are specified in [message.proto](message.proto), users of this library can encapsulate this message in a carrier message, like gossip in TCP. +2. Consensus algorithm is **NOT** thread-safe, it **MUST** be protected by some synchronization mechanism, like `sync.Mutex` or `chan` + `goroutine`. + +## Usage + +1. A testing IPC peer -- [ipc_peer.go](ipc_peer.go) +2. A testing TCP node -- [TCP based Consensus Emualtor](cmd/emucon) + +## Status + +On-going diff --git a/vendor/github.com/BDLS-bft/bdls/SECURITY.md b/vendor/github.com/BDLS-bft/bdls/SECURITY.md new file mode 100644 index 00000000000..dfe20518193 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/SECURITY.md @@ -0,0 +1,9 @@ +# Hyperledger Security Policy + +## Reporting a Security Bug + +If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer. + +The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org). + +The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/SEC/Defect+Response) on our [wiki](https://wiki.hyperledger.org). \ No newline at end of file diff --git a/vendor/github.com/BDLS-bft/bdls/config.go b/vendor/github.com/BDLS-bft/bdls/config.go new file mode 100644 index 00000000000..14167a4b0ba --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/config.go @@ -0,0 +1,72 @@ + +package bdls + +import ( + "crypto/ecdsa" + "time" +) + +const ( + // ConfigMinimumParticipants is the minimum number of participant allow in consensus protocol + ConfigMinimumParticipants = 4 +) + +// Config is to config the parameters of BDLS consensus protocol +type Config struct { + // the starting time point for consensus + Epoch time.Time + // CurrentHeight + CurrentHeight uint64 + // PrivateKey + PrivateKey *ecdsa.PrivateKey + // Consensus Group + Participants []Identity + // EnableCommitUnicast sets to true to enable message to be delivered via unicast + // if not(by default), message will be broadcasted + EnableCommitUnicast bool + + // StateCompare is a function from user to compare states, + // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. + // Usually this will lead to block header comparsion in blockchain, or replication log in database, + // users should check fields in block header to make comparison. + StateCompare func(a State, b State) int + + // StateValidate is a function from user to validate the integrity of + // state data. + StateValidate func(State) bool + + // MessageValidator is an external validator to be called when a message inputs into ReceiveMessage + MessageValidator func(c *Consensus, m *Message, signed *SignedProto) bool + + // MessageOutCallback will be called if not nil before a message send out + MessageOutCallback func(m *Message, signed *SignedProto) + + // Identity derviation from ecdsa.PublicKey + // (optional). Default to DefaultPubKeyToIdentity + PubKeyToIdentity func(pubkey *ecdsa.PublicKey) (ret Identity) +} + +// VerifyConfig verifies the integrity of this config when creating new consensus object +func VerifyConfig(c *Config) error { + if c.Epoch.IsZero() { + return ErrConfigEpoch + } + + if c.StateCompare == nil { + return ErrConfigStateCompare + } + + if c.StateValidate == nil { + return ErrConfigStateValidate + } + + if c.PrivateKey == nil { + return ErrConfigPrivateKey + } + + if len(c.Participants) < ConfigMinimumParticipants { + return ErrConfigParticipants + } + + return nil +} diff --git a/vendor/github.com/BDLS-bft/bdls/consensus.go b/vendor/github.com/BDLS-bft/bdls/consensus.go new file mode 100644 index 00000000000..ee6ba09e310 --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/consensus.go @@ -0,0 +1,1677 @@ +package bdls + +import ( + "bytes" + "container/list" + "crypto/ecdsa" + "crypto/elliptic" + "net" + "sort" + "time" + + //"fmt" + "github.com/BDLS-bft/bdls/crypto/blake2b" + + + proto "github.com/gogo/protobuf/proto" +) + +const ( + // the current BDLS protocol version, + // version will be sent along with messages for protocol upgrading. + ProtocolVersion = 1 + // DefaultConsensusLatency is the default propagation latency setting for + // consensus protocol, user can adjust consensus object's latency setting + // via Consensus.SetLatency() + DefaultConsensusLatency = 300 * time.Millisecond + + // MaxConsensusLatency is the ceiling of latencies + MaxConsensusLatency = 10 * time.Second +) + +type ( + // State is the data to participant in consensus. This could be candidate + // blocks in blockchain systems + State []byte + // StateHash = H(State) + StateHash [blake2b.Size256]byte +) + +// defaultHash is the system default hash function +func defaultHash(s State) StateHash { return blake2b.Sum256(s) } + +type ( + // consensusStage defines the status of consensus automata + consensusStage byte +) + +// status definitions for consensus state machine +const ( + // stages are strictly ordered, do not change! + stageRoundChanging consensusStage = iota + stageLock + stageCommit + stageLockRelease +) + +type messageTuple struct { + StateHash StateHash // computed while adding + Message *Message // the decoded message + Signed *SignedProto // the encoded message with signature +} + +// a sorter for messageTuple slice +type tupleSorter struct { + tuples []messageTuple + by func(t1, t2 *messageTuple) bool +} + +// Len implements sort.Interface +func (s *tupleSorter) Len() int { return len(s.tuples) } + +// Swap implements sort.Interface +func (s *tupleSorter) Swap(i, j int) { s.tuples[i], s.tuples[j] = s.tuples[j], s.tuples[i] } + +// Less implements sort.Interface +func (s *tupleSorter) Less(i, j int) bool { return s.by(&s.tuples[i], &s.tuples[j]) } + +// consensusRound maintains exchanging messages in a round. +type consensusRound struct { + c *Consensus // the consensus object belongs to + Stage consensusStage // indicates current status in consensus automata + RoundNumber uint64 // round number + LockedState State // leader's locked state + LockedStateHash StateHash // hash of the leaders's locked state + RoundChangeSent bool // mark if the message of this round has sent + CommitSent bool // mark if this round has sent commit message once + + // NOTE: we MUST keep the original message, to re-marshal the message may + // result in different BITS LAYOUT, and different hash of course. + roundChanges []messageTuple // stores message tuples of this round + commits []messageTuple // stores message tuples of this round + + // track current max proposed state in , we don't have to compute this for + // a non-leader participant, or if there're no more than 2t+1 messages for leader. + MaxProposedState State + MaxProposedCount int +} + +// newConsensusRound creates a new round, and sets the round number +func newConsensusRound(round uint64, c *Consensus) *consensusRound { + r := new(consensusRound) + r.RoundNumber = round + r.c = c + return r +} + +// AddRoundChange adds a message to this round, and +// checks to accept only one message from one participant, +// to prevent multiple proposals attack. +func (r *consensusRound) AddRoundChange(sp *SignedProto, m *Message) bool { + for k := range r.roundChanges { + if r.roundChanges[k].Signed.X == sp.X && r.roundChanges[k].Signed.Y == sp.Y { + return false + } + } + + r.roundChanges = append(r.roundChanges, messageTuple{StateHash: r.c.stateHash(m.State), Message: m, Signed: sp}) + return true +} + +// FindRoundChange will try to find a from a given participant, +// and returns index, -1 if not found +func (r *consensusRound) FindRoundChange(X PubKeyAxis, Y PubKeyAxis) int { + for k := range r.roundChanges { + if r.roundChanges[k].Signed.X == X && r.roundChanges[k].Signed.Y == Y { + return k + } + } + return -1 +} + +// RemoveRoundChange removes the given message at idx +func (r *consensusRound) RemoveRoundChange(idx int) { + // swap to the end and shrink slice + n := len(r.roundChanges) - 1 + r.roundChanges[idx], r.roundChanges[n] = r.roundChanges[n], r.roundChanges[idx] + r.roundChanges[n] = messageTuple{} // set to nil to avoid memory leak + r.roundChanges = r.roundChanges[:n] +} + +// NumRoundChanges returns count of messages. +func (r *consensusRound) NumRoundChanges() int { return len(r.roundChanges) } + +// SignedRoundChanges converts and returns []*SignedProto(as slice) +func (r *consensusRound) SignedRoundChanges() []*SignedProto { + proof := make([]*SignedProto, 0, len(r.roundChanges)) + for k := range r.roundChanges { + proof = append(proof, r.roundChanges[k].Signed) + } + return proof +} + +// RoundChangeStates returns all non-nil state in exchanging round change message as slice +func (r *consensusRound) RoundChangeStates() []State { + states := make([]State, 0, len(r.roundChanges)) + for k := range r.roundChanges { + if r.roundChanges[k].Message.State != nil { + states = append(states, r.roundChanges[k].Message.State) + } + } + return states +} + +// AddCommit adds decoded messages along with its original signed message unchanged, +// also, messages will be de-duplicated to prevent multiple proposals attack. +func (r *consensusRound) AddCommit(sp *SignedProto, m *Message) bool { + for k := range r.commits { + if r.commits[k].Signed.X == sp.X && r.commits[k].Signed.Y == sp.Y { + return false + } + } + r.commits = append(r.commits, messageTuple{StateHash: r.c.stateHash(m.State), Message: m, Signed: sp}) + return true +} + +// NumCommitted counts messages which points to what the leader has locked. +func (r *consensusRound) NumCommitted() int { + var count int + for k := range r.commits { + if r.commits[k].StateHash == r.LockedStateHash { + count++ + } + } + return count +} + +// SignedCommits converts and returns []*SignedProto +func (r *consensusRound) SignedCommits() []*SignedProto { + proof := make([]*SignedProto, 0, len(r.commits)) + for k := range r.commits { + proof = append(proof, r.commits[k].Signed) + } + return proof +} + +// GetMaxProposed finds the most agreed-on non-nil state, if these is any. +func (r *consensusRound) GetMaxProposed() (s State, count int) { + if len(r.roundChanges) == 0 { + return nil, 0 + } + + // sort by hash, to group identical hashes together + // O(n*logn) + sorter := tupleSorter{ + tuples: r.roundChanges, + // sort by it's hash lexicographically + by: func(t1, t2 *messageTuple) bool { + return bytes.Compare(t1.StateHash[:], t2.StateHash[:]) < 0 + }, + } + sort.Sort(&sorter) + + // find the maximum occurred hash + // O(n) + maxCount := 1 + maxState := r.roundChanges[0] + curCount := 1 + + n := len(r.roundChanges) + for i := 1; i < n; i++ { + if r.roundChanges[i].StateHash == r.roundChanges[i-1].StateHash { + curCount++ + } else { + if curCount > maxCount { + maxCount = curCount + maxState = r.roundChanges[i-1] + } + curCount = 1 + } + } + + // if the last hash is the maximum occurred + if curCount > maxCount { + maxCount = curCount + maxState = r.roundChanges[n-1] + } + + return maxState.Message.State, maxCount +} + +// Consensus implements a deterministic BDLS consensus protocol. +// +// It has no internal clocking or IO, and no parallel processing. +// The runtime behavior is predictable and deterministic. +// Users should write their own timing and IO function to feed in +// messages and ticks to trigger timeouts. +type Consensus struct { + latestState State // latest confirmed state of current height + latestHeight uint64 // latest confirmed height + latestRound uint64 // latest confirmed round + latestProof *SignedProto // latest message to prove the state + + unconfirmed []State // data awaiting to be confirmed at next height + + rounds list.List // all rounds at next height(consensus round in progress) + currentRound *consensusRound // current round which has collected >=2t+1 + + // timeouts in different stage + rcTimeout time.Time // roundchange status timeout: Delta_0 + lockTimeout time.Time // lock status timeout: Delta_1 + commitTimeout time.Time // commit status timeout: Delta_2 + lockReleaseTimeout time.Time // lock-release status timeout: Delta_3 + + // locked states, along with its signatures and hashes in tuple + locks []messageTuple + + // the StateCompare function from config + stateCompare func(State, State) int + // the StateValidate function from config + stateValidate func(State) bool + // message in callback + messageValidator func(c *Consensus, m *Message, sp *SignedProto) bool + // message out callback + messageOutCallback func(m *Message, sp *SignedProto) + // public key to identity function + pubKeyToIdentity func(pubkey *ecdsa.PublicKey) Identity + + // the StateHash function to identify a state + stateHash func(State) StateHash + + // private key + privateKey *ecdsa.PrivateKey + // my publickey coodinate + identity Identity + // curve retrieved from private key + curve elliptic.Curve + + // transmission delay + latency time.Duration + + // all connected peers + peers []PeerInterface + + // participants is the consensus group, current leader is r % quorum + participants []Identity + + // count num of individual identities + numIdentities int //[YONGGE WANG' comments:] make sure this is synchronized with []Identity + + // set to true to enable message unicast + enableCommitUnicast bool + + // NOTE: fixed leader for testing purpose + fixedLeader *Identity + + // broadcasting messages being sent to myself + loopback [][]byte + + // the last message which caused round change + lastRoundChangeProof []*SignedProto +} + +// NewConsensus creates a BDLS consensus object to participant in consensus procedure, +// the consensus object returned is data in memory without goroutines or other +// non-deterministic objects, and errors will be returned if there is problem, with +// the given config. +func NewConsensus(config *Config) (*Consensus, error) { + err := VerifyConfig(config) + if err != nil { + return nil, err + } + + c := new(Consensus) + c.init(config) + return c, nil +} + +// init consensus with config +func (c *Consensus) init(config *Config) { + // setting current state & height + c.latestHeight = config.CurrentHeight + c.participants = config.Participants + c.stateCompare = config.StateCompare + c.stateValidate = config.StateValidate + c.messageValidator = config.MessageValidator + c.messageOutCallback = config.MessageOutCallback + c.privateKey = config.PrivateKey + c.pubKeyToIdentity = config.PubKeyToIdentity + c.enableCommitUnicast = config.EnableCommitUnicast + + // if config has not set hash function, use the default + if c.stateHash == nil { + c.stateHash = defaultHash + } + // if config has not set public key to identity function, use the default + if c.pubKeyToIdentity == nil { + c.pubKeyToIdentity = DefaultPubKeyToIdentity + } + c.identity = c.pubKeyToIdentity(&c.privateKey.PublicKey) + c.curve = c.privateKey.Curve + + // initial default parameters settings + c.latency = DefaultConsensusLatency + + // and initiated the first proposal + c.switchRound(0) + c.currentRound.Stage = stageRoundChanging + c.broadcastRoundChange() + // set rcTimeout to lockTimeout + c.rcTimeout = config.Epoch.Add(c.roundchangeDuration(0)) + + // count number of individual identites + ids := make(map[Identity]bool) + for _, id := range c.participants { + ids[id] = true + } + c.numIdentities = len(ids) +} + +// calculates roundchangeDuration +func (c *Consensus) roundchangeDuration(round uint64) time.Duration { + d := 2 * c.latency * (1 << round) + if d > MaxConsensusLatency { + d = MaxConsensusLatency + } + return d +} + +// calculates collectDuration +func (c *Consensus) collectDuration(round uint64) time.Duration { + d := 2 * c.latency * (1 << round) + if d > MaxConsensusLatency { + d = MaxConsensusLatency + } + return d +} + +// calculates lockDuration +func (c *Consensus) lockDuration(round uint64) time.Duration { + d := 4 * c.latency * (1 << round) + if d > MaxConsensusLatency { + d = MaxConsensusLatency + } + return d +} + +// calculates commitDuration +func (c *Consensus) commitDuration(round uint64) time.Duration { + d := 2 * c.latency * (1 << round) + if d > MaxConsensusLatency { + d = MaxConsensusLatency + } + return d +} + +// calculates lockReleaseDuration +func (c *Consensus) lockReleaseDuration(round uint64) time.Duration { + d := 2 * c.latency * (1 << round) + if d > MaxConsensusLatency { + d = MaxConsensusLatency + } + return d +} + +// maximalLocked finds the maximum locked data in this round, +// with regard to StateCompare function in config. +func (c *Consensus) maximalLocked() State { + if len(c.locks) > 0 { + maxState := c.locks[0].Message.State + for i := 1; i < len(c.locks); i++ { + if c.stateCompare(maxState, c.locks[i].Message.State) < 0 { + maxState = c.locks[i].Message.State + } + } + return maxState + } + return nil +} + +// maximalUnconfirmed finds the maximal unconfirmed data with, +// regard to the StateCompare function in config. +func (c *Consensus) maximalUnconfirmed() State { + if len(c.unconfirmed) > 0 { + maxState := c.unconfirmed[0] + for i := 1; i < len(c.unconfirmed); i++ { + if c.stateCompare(maxState, c.unconfirmed[i]) < 0 { + maxState = c.unconfirmed[i] + } + } + return maxState + } + return nil +} + +// verifyMessage verifies message signature against it's & , +// and also checks if the signer is a valid participant. +// returns it's decoded 'Message' object if signature has proved authentic. +// returns nil and error if message has not been correctly signed or from an unknown participant. +func (c *Consensus) verifyMessage(signed *SignedProto) (*Message, error) { + if signed == nil { + return nil, ErrMessageIsEmpty + } + + // check signer's identity, all participants have proven + // public key + knownParticipants := false + coord := c.pubKeyToIdentity(signed.PublicKey(c.curve)) + for k := range c.participants { + if coord == c.participants[k] { + knownParticipants = true + } + } + + if !knownParticipants { + return nil, ErrMessageUnknownParticipant + } + + /* + // public key validation + p := defaultCurve.Params().P + x := new(big.Int).SetBytes(signed.X[:]) + y := new(big.Int).SetBytes(signed.Y[:]) + if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 { + return nil, ErrMessageSignature + } + if !defaultCurve.IsOnCurve(x, y) { + return nil, ErrMessageSignature + } + */ + + // as public key is proven , we don't have to verify the public key + if !signed.Verify(c.curve) { + return nil, ErrMessageSignature + } + + // decode message + m := new(Message) + err := proto.Unmarshal(signed.Message, m) + if err != nil { + return nil, err + } + return m, nil +} + +// verify message +func (c *Consensus) verifyRoundChangeMessage(m *Message) error { + // check message height + if m.Height != c.latestHeight+1 { + return ErrRoundChangeHeightMismatch + } + + // check round in protocol + if m.Round < c.currentRound.RoundNumber { + return ErrRoundChangeRoundLower + } + + // state data validation for non-null + if m.State != nil { + if !c.stateValidate(m.State) { + return ErrRoundChangeStateValidation + } + } + + return nil +} + +// verifyLockMessage verifies proofs from messages, +// a lock message must contain at least 2t+1 individual +// messages on B' +func (c *Consensus) verifyLockMessage(m *Message, signed *SignedProto) error { + // check message height + if m.Height != c.latestHeight+1 { + return ErrLockHeightMismatch + } + + // check round in protocol + if m.Round < c.currentRound.RoundNumber { + return ErrLockRoundLower + } + + // a message from leader MUST include data along with the message + if m.State == nil { + return ErrLockEmptyState + } + + // state data validation + if !c.stateValidate(m.State) { + return ErrLockStateValidation + } + + // make sure this message has been signed by the leader + leaderKey := c.roundLeader(m.Round) + if c.pubKeyToIdentity(signed.PublicKey(c.curve)) != leaderKey { + return ErrLockNotSignedByLeader + } + + // validate proofs enclosed in the message one by one + rcs := make(map[Identity]State) + for _, proof := range m.Proof { + // first we need to verify the signature,and identity of this proof + mProof, err := c.verifyMessage(proof) + if err != nil { + if err == ErrMessageUnknownParticipant { + return ErrLockProofUnknownParticipant + } + return err + } + + // then we need to check the message type + if mProof.Type != MessageType_RoundChange { + return ErrLockProofTypeMismatch + } + + // and we also need to check the height & round field, + // all messages must be in the same round as the lock message + if mProof.Height != m.Height { + return ErrLockProofHeightMismatch + } + + if mProof.Round != m.Round { + return ErrLockProofRoundMismatch + } + + // state data validation in proofs + if mProof.State != nil { + if !c.stateValidate(mProof.State) { + return ErrLockProofStateValidation + } + } + + // use map to guarantee we will only accept at most 1 message from one + // individual participant + rcs[c.pubKeyToIdentity(proof.PublicKey(c.curve))] = mProof.State + } + + // count individual proofs to B', which has already guaranteed to be the maximal one. + var numValidateProofs int + mHash := c.stateHash(m.State) + for _, v := range rcs { + if c.stateHash(v) == mHash { // B' + numValidateProofs++ + } + } + + // check if valid proofs count is less that 2*t+1 + if numValidateProofs < 2*c.t()+1 { + return ErrLockProofInsufficient + } + return nil +} + +// verifyLockReleaseMessage will verify LockRelease field in a messages, +// returns the embedded message if valid +func (c *Consensus) verifyLockReleaseMessage(signed *SignedProto) (*Message, error) { + // not in lock release status, omit this message + if c.currentRound.Stage != stageLockRelease { + return nil, ErrLockReleaseStatus + } + + // verify and decode the embedded lock message + lockmsg, err := c.verifyMessage(signed) + if err != nil { + return nil, err + } + + // recursively verify proofs in lock message + err = c.verifyLockMessage(lockmsg, signed) + if err != nil { + return nil, err + } + return lockmsg, nil +} + +// verifySelectMessage verifies proofs from message MUST contain at least 2t+1 individual messages, but +// proofs from + if m.State != nil { + if !c.stateValidate(m.State) { + return ErrSelectStateValidation + } + } + + // make sure this message has been signed by the leader + leaderKey := c.roundLeader(m.Round) + if c.pubKeyToIdentity(signed.PublicKey(c.curve)) != leaderKey { + return ErrSelectNotSignedByLeader + } + + rcs := make(map[Identity]State) + for _, proof := range m.Proof { + mProof, err := c.verifyMessage(proof) + if err != nil { + if err == ErrMessageUnknownParticipant { + return ErrSelectProofUnknownParticipant + } + return err + } + + if mProof.Type != MessageType_RoundChange { + return ErrSelectProofTypeMismatch + } + + if mProof.Height != m.Height { + return ErrSelectProofHeightMismatch + } + + if mProof.Round != m.Round { + return ErrSelectProofRoundMismatch + } + + // state data validation in proofs + if mProof.State != nil { + if !c.stateValidate(mProof.State) { + return ErrSelectProofStateValidation + } + } + + // we also need to check the B'' selected by leader is the maximal one, + // if data has been proposed. + if mProof.State != nil && m.State != nil { + if c.stateCompare(m.State, mProof.State) < 0 { + return ErrSelectProofNotTheMaximal + } + } + + // we also stores B'' == NULL for counting + rcs[c.pubKeyToIdentity(proof.PublicKey(c.curve))] = mProof.State + } + + // check we have at least 2*t+1 proof + if len(rcs) < 2*c.t()+1 { + return ErrSelectProofInsufficient + } + + // count maximum proofs with B' != NULL with identical data hash, + // to prevent leader cheating on select. + dataProposals := make(map[StateHash]int) + for _, data := range rcs { + if data != nil { + dataProposals[c.stateHash(data)]++ + } + } + + // if m.State == NULL, but there are non-NULL proofs, + // the leader may be cheating + if m.State == nil && len(dataProposals) > 0 { + return ErrSelectStateMismatch + } + + // find the highest proposed B'(not NULL) + var maxProposed int + for _, count := range dataProposals { + if count > maxProposed { + maxProposed = count + } + } + + // if these are more than 2*t+1 valid proofs to B', + // this also suggests that the leader may cheat. + if maxProposed >= 2*c.t()+1 { + return ErrSelectProofExceeded + } + + return nil +} + +// verifyCommitMessage will check if this message is acceptable to consensus +func (c *Consensus) verifyCommitMessage(m *Message) error { + // the leader has to be in COMMIT status to process this message + if c.currentRound.Stage != stageCommit { + return ErrCommitStatus + } + + // a message from participants MUST includes data along with the message + if m.State == nil { + return ErrCommitEmptyState + } + + // state data validation + if !c.stateValidate(m.State) { + return ErrCommitStateValidation + } + + // check height + if m.Height != c.latestHeight+1 { + return ErrCommitHeightMismatch + } + + // only accept commits to current round + if c.currentRound.RoundNumber != m.Round { + return ErrCommitRoundMismatch + } + + // check state match + if c.stateHash(m.State) != c.currentRound.LockedStateHash { + return ErrCommitStateMismatch + } + + return nil +} + +// ValidateDecideMessage validates a message for non-participants, +// the consensus core must be correctly initialized to validate. +// the targetState is to compare the target state enclosed in decide message +func (c *Consensus) ValidateDecideMessage(bts []byte, targetState []byte) error { + signed, err := DecodeSignedMessage(bts) + if err != nil { + return err + } + + return c.validateDecideMessage(signed, targetState) +} + +// DecodeSignedMessage decodes a binary representation of signed consensus message. +func DecodeSignedMessage(bts []byte) (*SignedProto, error) { + signed := new(SignedProto) + err := proto.Unmarshal(bts, signed) + if err != nil { + return nil, err + } + return signed, nil +} + +// DecodeMessage decodes a binary representation of consensus message. +func DecodeMessage(bts []byte) (*Message, error) { + msg := new(Message) + err := proto.Unmarshal(bts, msg) + if err != nil { + return nil, err + } + return msg, nil +} + +// validateDecideMessage validates a decoded message for non-participants, +// the consensus core must be correctly initialized to validate. +func (c *Consensus) validateDecideMessage(signed *SignedProto, targetState []byte) error { + // check message version + if signed.Version != ProtocolVersion { + return ErrMessageVersion + } + + // check message signature & qualifications + m, err := c.verifyMessage(signed) + if err != nil { + return err + } + + // compare state + if !bytes.Equal(m.State, targetState) { + return ErrMismatchedTargetState + } + + // verify decide message + if m.Type == MessageType_Decide { + err := c.verifyDecideMessage(m, signed) + if err != nil { + return err + } + return nil + } + return ErrMessageUnknownMessageType +} + +// verifyDecideMessage verifies proofs from message, which MUST +// contain at least 2t+1 individual messages to B'. +func (c *Consensus) verifyDecideMessage(m *Message, signed *SignedProto) error { + // a message from leader MUST include data along with the message + if m.State == nil { + return ErrDecideEmptyState + } + + // state data validation + if !c.stateValidate(m.State) { + return ErrDecideStateValidation + } + + // check height + if m.Height <= c.latestHeight { + return ErrDecideHeightLower + } + + // make sure this message has been signed by the leader + leaderKey := c.roundLeader(m.Round) + if c.pubKeyToIdentity(signed.PublicKey(c.curve)) != leaderKey { + return ErrDecideNotSignedByLeader + } + + commits := make(map[Identity]State) + for _, proof := range m.Proof { + mProof, err := c.verifyMessage(proof) + if err != nil { + if err == ErrMessageUnknownParticipant { + return ErrDecideProofUnknownParticipant + } + return err + } + + if mProof.Type != MessageType_Commit { + return ErrDecideProofTypeMismatch + } + + if mProof.Height != m.Height { + return ErrDecideProofHeightMismatch + } + + if mProof.Round != m.Round { + return ErrDecideProofRoundMismatch + } + + if !c.stateValidate(mProof.State) { + return ErrDecideProofStateValidation + } + + // state data validation in proofs + if mProof.State != nil { + if !c.stateValidate(mProof.State) { + return ErrSelectProofStateValidation + } + } + + commits[c.pubKeyToIdentity(proof.PublicKey(c.curve))] = mProof.State + } + + // count proofs to m.State + var numValidateProofs int + mHash := c.stateHash(m.State) + for _, v := range commits { + if c.stateHash(v) == mHash { + numValidateProofs++ + } + } + + // check to see if the message has at least 2*t+1 valid proofs, + // if not, the leader may cheat. + if numValidateProofs < 2*c.t()+1 { + return ErrDecideProofInsufficient + } + return nil +} + +// broadcastRoundChange will broadcast messages on +// current round, taking the maximal B' from unconfirmed data. +func (c *Consensus) broadcastRoundChange() { + // if has sent in this round, + // then just ignore. But if we are in roundchanging state, + // we should send repeatedly, for boostrap process. + if c.currentRound.RoundChangeSent && c.currentRound.Stage != stageRoundChanging { + return + } + + // first we need to check if there is any locked data, + // locked data must be sent if there is any. + data := c.maximalLocked() + if data == nil { + // if there's none locked data, we pick the maximum unconfirmed data to propose + data = c.maximalUnconfirmed() + // if still null, return + if data == nil { + return + } + } + + var m Message + m.Type = MessageType_RoundChange + m.Height = c.latestHeight + 1 + m.Round = c.currentRound.RoundNumber + m.State = data + c.broadcast(&m) + c.currentRound.RoundChangeSent = true + //log.Println("broadcast:") +} + +// broadcastLock will broadcast messages on current round, +// the currentRound should have a chosen data in this round. +func (c *Consensus) broadcastLock() { + var m Message + m.Type = MessageType_Lock + m.Height = c.latestHeight + 1 + m.Round = c.currentRound.RoundNumber + m.State = c.currentRound.LockedState + m.Proof = c.currentRound.SignedRoundChanges() + c.broadcast(&m) + //log.Println("broadcast:") +} + +// broadcastLockRelease will broadcast messages, +func (c *Consensus) broadcastLockRelease(signed *SignedProto) { + var m Message + m.Type = MessageType_LockRelease + m.Height = c.latestHeight + 1 + m.Round = c.currentRound.RoundNumber + m.LockRelease = signed + c.broadcast(&m) + //log.Println("broadcast:") +} + +// broadcastSelect will broadcast a ", m.State) +} + +// broadcastDecide will broadcast a message by the leader, +// from current round with proofs. +func (c *Consensus) broadcastDecide() *SignedProto { + var m Message + m.Type = MessageType_Decide + m.Height = c.latestHeight + 1 + m.Round = c.currentRound.RoundNumber + m.State = c.currentRound.LockedState + m.Proof = c.currentRound.SignedCommits() + return c.broadcast(&m) + //log.Println("broadcast:") +} + +// broadcastResync will broadcast a message by the leader, +// from current round with proofs. +func (c *Consensus) broadcastResync() { + if c.lastRoundChangeProof == nil { + return + } + + var m Message + m.Type = MessageType_Resync + // we only care about messages in resync + m.Proof = c.lastRoundChangeProof + c.broadcast(&m) + //log.Println("broadcast:") +} + +// sendCommit will send a message by participants to the leader +// from received message. +func (c *Consensus) sendCommit(msgLock *Message) { + if c.currentRound.CommitSent { + return + } + + var m Message + m.Type = MessageType_Commit + m.Height = msgLock.Height // h + m.Round = msgLock.Round // r + m.State = msgLock.State // B'j + if c.enableCommitUnicast { + c.sendTo(&m, c.roundLeader(m.Round)) + } else { + c.broadcast(&m) + } + c.currentRound.CommitSent = true + //log.Println("send:") +} + +// broadcast signs the message with private key before broadcasting to all peers. +func (c *Consensus) broadcast(m *Message) *SignedProto { + // sign + sp := new(SignedProto) + sp.Version = ProtocolVersion + sp.Sign(m, c.privateKey) + + // message callback + if c.messageOutCallback != nil { + c.messageOutCallback(m, sp) + } + // protobuf marshalling + out, err := proto.Marshal(sp) + if err != nil { + panic(err) + } + + // send to peers one by one + for _, peer := range c.peers { + _ = peer.Send(out) + } + + // we also need to send this message to myself + c.loopback = append(c.loopback, out) + return sp +} + +// sendTo signs the message with private key before transmitting to the peer. +func (c *Consensus) sendTo(m *Message, leader Identity) { + // sign + sp := new(SignedProto) + sp.Version = ProtocolVersion + sp.Sign(m, c.privateKey) + + // message callback + if c.messageOutCallback != nil { + c.messageOutCallback(m, sp) + } + + // protobuf marshalling + out, err := proto.Marshal(sp) + if err != nil { + panic(err) + } + + // we need to send this message to myself (via loopback) if i'm the leader + if leader == c.identity { + c.loopback = append(c.loopback, out) + return + } + + // otherwise, find and transmit to the leader + for _, peer := range c.peers { + if pk := peer.GetPublicKey(); pk != nil { + coord := c.pubKeyToIdentity(pk) + if coord == leader { + // we do not return here to avoid missing re-connected peer. + peer.Send(out) + } + } + } +} + +// propagate broadcasts signed message UNCHANGED to peers. +func (c *Consensus) propagate(bts []byte) { + // send to peers one by one + for _, peer := range c.peers { + _ = peer.Send(bts) + } +} + +// getRound returns the consensus round with given idx, create one if not exists +// if purgeLower has set, all lower rounds will be cleared +func (c *Consensus) getRound(idx uint64, purgeLower bool) *consensusRound { + var next *list.Element + for elem := c.rounds.Front(); elem != nil; elem = next { + next = elem.Next() + r := elem.Value.(*consensusRound) + + if r.RoundNumber < idx { // lower round + // if remove flag has set, remove this round safely, + // usually used by switchRound + if purgeLower { + c.rounds.Remove(elem) + } + continue + } else if idx < r.RoundNumber { // higher round + // insert a new round entry before this round + // to make sure the list is ordered + newr := newConsensusRound(idx, c) + c.rounds.InsertBefore(newr, elem) + return newr + } else if r.RoundNumber == idx { // found entry + return r + } + } + + // looped to the end, we create and push back + newr := newConsensusRound(idx, c) + c.rounds.PushBack(newr) + return newr +} + +// lockRelease updates locks while entering lock-release status +// and will broadcast its max B' if there is any. +func (c *Consensus) lockRelease() { + // only keep the locked B' with the max round number + // while switching to lock-release status + if len(c.locks) > 0 { + max := c.locks[0] + for i := 1; i < len(c.locks); i++ { + if max.Message.Round < c.locks[i].Message.Round { + max = c.locks[i] + } + } + c.locks = []messageTuple{max} + c.broadcastLockRelease(max.Signed) + } +} + +// switchRound sets currentRound to the given idx, and creates new a consensusRound +// if it's not been initialized. +// and all lower rounds will be cleared while switching. +func (c *Consensus) switchRound(round uint64) { c.currentRound = c.getRound(round, true) } + +// roundLeader returns leader's identity for a given round +func (c *Consensus) roundLeader(round uint64) Identity { + // NOTE: fixed leader is for testing + if c.fixedLeader != nil { + return *c.fixedLeader + } + return c.participants[int(round)%len(c.participants)] +} + +// heightSync changes current height to the given height with state +// resets all fields to this new height. +func (c *Consensus) heightSync(height uint64, round uint64, s State, now time.Time) { + c.latestHeight = height // set height + c.latestRound = round // set round + c.latestState = s // set state + + c.currentRound = nil // clean current round pointer + c.lastRoundChangeProof = nil // clean round change proof + c.rounds.Init() // clean all round + c.locks = nil // clean locks + c.unconfirmed = nil // clean all unconfirmed states from previous heights + c.switchRound(0) // start new round at new height + c.currentRound.Stage = stageRoundChanging +} + +// t calculates (n-1)/3 +func (c *Consensus) t() int { return (c.numIdentities - 1) / 3 } + +// Propose adds a new state to unconfirmed queue to particpate in +// consensus at next height. +func (c *Consensus) Propose(s State) { + if s == nil { + return + } + + sHash := c.stateHash(s) + for k := range c.unconfirmed { + if c.stateHash(c.unconfirmed[k]) == sHash { + return + } + } + c.unconfirmed = append(c.unconfirmed, s) +} + +// ReceiveMessage processes incoming consensus messages, and returns error +// if message cannot be processed for some reason. +func (c *Consensus) ReceiveMessage(bts []byte, now time.Time) (err error) { + // messages broadcasted to myself may be queued recursively, and + // we only process these messages in defer to avoid side effects + // while processing. + defer func() { + for len(c.loopback) > 0 { + bts := c.loopback[0] + c.loopback = c.loopback[1:] + // NOTE: message directed to myself ignores error. + _ = c.receiveMessage(bts, now) + } + }() + + return c.receiveMessage(bts, now) +} + +func (c *Consensus) receiveMessage(bts []byte, now time.Time) error { + // unmarshal signed message + signed := new(SignedProto) + err := proto.Unmarshal(bts, signed) + if err != nil { + return err + } + + // check message version + if signed.Version != ProtocolVersion { + return ErrMessageVersion + } + + // check message signature & qualifications + m, err := c.verifyMessage(signed) + if err != nil { + return err + } + + // callback for incoming message + if c.messageValidator != nil { + if !c.messageValidator(c, m, signed) { + return ErrMessageValidator + } + } + + // message switch + switch m.Type { + case MessageType_Nop: + // nop does nothing + return nil + case MessageType_RoundChange: + err := c.verifyRoundChangeMessage(m) + if err != nil { + return err + } + + // for message, we need to find in each round + // to check if this sender has already sent + // we only keep the message from the max round. + // NOTE: we don't touch current round to prevent removing + // valid proofs. + // NOTE: the total messages are bounded to max 2*participants + // at any time, so the loop has O(n) time complexity + var next *list.Element + for elem := c.rounds.Front(); elem != nil; elem = next { + next = elem.Next() + cr := elem.Value.(*consensusRound) + if idx := cr.FindRoundChange(signed.X, signed.Y); idx != -1 { // located! + if m.Round == c.currentRound.RoundNumber { // don't remove now! + continue + } else if cr.RoundNumber > m.Round { + // existing message is higher than incoming message, + // just ignore. + return nil + } else if cr.RoundNumber < m.Round { + // existing message is lower than incoming message, + // remove the existing message from this round. + cr.RemoveRoundChange(idx) + // if no message remained in this round, release + // the round resources too, to prevent OOM attack + if cr.NumRoundChanges() == 0 { + c.rounds.Remove(elem) + } + } + } + } + + // locate to round m.Round. + // NOTE: getRound must not be called before previous checks done + // in order to prevent OOM attack by creating round objects. + round := c.getRound(m.Round, false) + // as we cleared all lower rounds message, we handle the message + // at round m.Round. if this message is not duplicated in m.Round, + // round records message along with its signed message + // to provide proofs in the future. + if round.AddRoundChange(signed, m) { + // During any time of the protocol, if a the Pacemaker of Pj (including Pi) + // receives at least 2t + 1 round-change message (including round-change + // message from himself) for round r (which is larger than its current round + // status), it enters lock status of round r + // + // NOTE: m.Round lower than currentRound.RoundNumber has been tested by + // verifyRoundChangeMessage + // NOTE: lock stage can only be entered once for a single round, malicious + // participant can keep on broadcasting increasing to everyone, + // and old messages will be removed from previous rounds in such + // case, so rounds may possibly satisify 2*t+1 more than once. + // + // Example: P sends r+1 to remove from r, and sends to r again to trigger 2t+1 once + // more to reset timeout. + if round.NumRoundChanges() == 2*c.t()+1 && round.Stage < stageLock { + // switch to this round + c.switchRound(m.Round) + // record this round change proof for resyncing + c.lastRoundChangeProof = c.currentRound.SignedRoundChanges() + + // If Pj has not broadcasted the round-change message yet, + // it broadcasts now. + c.broadcastRoundChange() + + // leader of this round MUST wait on collectDuration, + // to decide to broadcast or message + err := c.verifySelectMessage(m, signed) + if err != nil { + return err + } + + // round will be increased monotonically + if m.Round > c.currentRound.RoundNumber { + c.switchRound(m.Round) + c.lastRoundChangeProof = []*SignedProto{signed} // record this proof for resyncing + } + + // for rounds r' >= r, we must check c.stage to stageLockRelease + // only once to prevent resetting lockReleaseTimeout or shifting c.cstage + if c.currentRound.Stage < stageLockRelease { + c.currentRound.Stage = stageLockRelease + c.lockReleaseTimeout = now.Add(c.commitDuration(m.Round)) + c.lockRelease() + // add to Blockj + c.Propose(m.State) + } + + case MessageType_Lock: + // verify message + err := c.verifyLockMessage(m, signed) + if err != nil { + return err + } + + // round will be increased monotonically + if m.Round > c.currentRound.RoundNumber { + c.switchRound(m.Round) + c.lastRoundChangeProof = []*SignedProto{signed} // record this proof for resyncing + } + + // for rounds r' >= r, we must check to enter commit status + // only once to prevent resetting commitTimeout or shifting c.cstage + if c.currentRound.Stage < stageCommit { + c.currentRound.Stage = stageCommit + c.commitTimeout = now.Add(c.commitDuration(m.Round)) + + mHash := c.stateHash(m.State) + // release any potential lock on B' in this round + // in-place deletion + o := 0 + for i := 0; i < len(c.locks); i++ { + if c.locks[i].StateHash != mHash { + c.locks[o] = c.locks[i] + o++ // o is the new length of c.locks + } + } + c.locks = c.locks[:o] + // append the new element + c.locks = append(c.locks, messageTuple{StateHash: mHash, Message: m, Signed: signed}) + } + + // for any incoming message with r=r', sendCommit will send + // once. + c.sendCommit(m) + + case MessageType_LockRelease: + // verifies the LockRelease field in message. + lockmsg, err := c.verifyLockReleaseMessage(m.LockRelease) + if err != nil { + return err + } + + // length of locks is 0, append and return. + if len(c.locks) == 0 { + c.locks = append(c.locks, messageTuple{StateHash: c.stateHash(lockmsg.State), Message: lockmsg, Signed: m.LockRelease}) + return nil + } + + // remove any locks if lockmsg.r > r' and keep lockmsg.r, + o := 0 + for i := 0; i < len(c.locks); i++ { + if !(lockmsg.Round > c.locks[i].Message.Round) { + // if the round of this lock is not larger than what we + // have kept, ignore and continue. + c.locks[o] = c.locks[i] + o++ + } + } + + // some locks have been removed if o is smaller than original locks length, + // then we keep this lock. + if o < len(c.locks) { + c.locks = c.locks[:o] + c.locks = append(c.locks, messageTuple{StateHash: c.stateHash(lockmsg.State), Message: lockmsg, Signed: m.LockRelease}) + } + + case MessageType_Commit: + // leader process commits message from all participants, + // check to see if I'm the leader of this round to process this message. + leaderKey := c.roundLeader(m.Round) + if leaderKey == c.identity { + // verify commit message. + // NOTE: leader only accept commits for current height & round. + err := c.verifyCommitMessage(m) + if err != nil { + return err + } + + // verifyCommitMessage can guarantee that the message is to currentRound, + // so we're safe to process in current round. + if c.currentRound.AddCommit(signed, m) { + // NOTE: we proceed the following only when AddCommit returns true. + // NumCommitted will only return commits with locked B' + // and ignore non-B' commits. + if c.currentRound.NumCommitted() >= 2*c.t()+1 { + /* + log.Println("======= LEADER'S DECIDE=====") + log.Println("Height:", c.currentHeight+1) + log.Println("Round:", c.currentRound.RoundNumber) + log.Println("State:", State(c.currentRound.LockedState).hash()) + */ + + // broadcast decide will return what it has sent + c.latestProof = c.broadcastDecide() + c.heightSync(c.latestHeight+1, c.currentRound.RoundNumber, c.currentRound.LockedState, now) + // leader should wait for 1 more latency + c.rcTimeout = now.Add(c.roundchangeDuration(0) + c.latency) + // broadcast at new height + c.broadcastRoundChange() + } + } + } + + case MessageType_Decide: + err := c.verifyDecideMessage(m, signed) + if err != nil { + return err + } + + // record this proof for chaining + c.latestProof = signed + + // propagate this message to my neighbour. + // NOTE: verifyDecideMessage() can stop broadcast storm. + c.propagate(bts) + // passive confirmation from the leader. + c.heightSync(m.Height, m.Round, m.State, now) + // non-leader starts waiting for rcTimeout + c.rcTimeout = now.Add(c.roundchangeDuration(0)) + // we sync our height and broadcast new . + c.broadcastRoundChange() + + case MessageType_Resync: + // push the proofs in loopback device + for k := range m.Proof { + // protobuf marshalling + out, err := proto.Marshal(m.Proof[k]) + if err != nil { + panic(err) + } + c.loopback = append(c.loopback, out) + } + + default: + return ErrMessageUnknownMessageType + } + return nil +} + +// Update will process timing event for the state machine, callers +// from outside MUST call this function periodically(like 20ms). +func (c *Consensus) Update(now time.Time) error { + // as in ReceiveMessage, we also need to handle broadcasting messages + // directed to myself. + defer func() { + for len(c.loopback) > 0 { + bts := c.loopback[0] + c.loopback = c.loopback[1:] + _ = c.receiveMessage(bts, now) + } + }() + + // stage switch + switch c.currentRound.Stage { + case stageRoundChanging: + if c.rcTimeout.IsZero() { + panic("roundchanging stage entered, but lockTimeout not set") + } + + if now.After(c.rcTimeout) { + c.broadcastRoundChange() + c.broadcastResync() // we also need to broadcast the round change event message if there is any + c.rcTimeout = now.Add(c.roundchangeDuration(c.currentRound.RoundNumber)) + } + case stageLock: + if c.lockTimeout.IsZero() { + panic("lock stage entered, but lockTimeout not set") + } + // leader's collection, we perform periodically check for or message to participants. + // enqueue all received non-NULL data + states := c.currentRound.RoundChangeStates() + for k := range states { + c.Propose(states[k]) + } + + // broadcast this related + ErrSelectStateValidation = errors.New("the state data validation failed message has another height than expected") + ErrSelectRoundLower = errors.New("the message is not signed by leader") + ErrSelectStateMismatch = errors.New("the message has unknown participant") + ErrSelectProofTypeMismatch = errors.New("the proofs in message has mismatched height") + ErrSelectProofRoundMismatch = errors.New("the proofs in message has invalid state data") + ErrSelectProofNotTheMaximal = errors.New("the proposed state is not the maximal one in the message has insufficient overall proofs") + ErrSelectProofExceeded = errors.New("the message + MessageType_Select MessageType = 3 + // MessageCommit = message + MessageType_Commit MessageType = 4 + // MessageLockRelease = message + MessageType_LockRelease MessageType = 5 + // MessageDecide = message + MessageType_Decide MessageType = 6 + // MessageResync= message + MessageType_Resync MessageType = 7 +) + +var MessageType_name = map[int32]string{ + 0: "Nop", + 1: "RoundChange", + 2: "Lock", + 3: "Select", + 4: "Commit", + 5: "LockRelease", + 6: "Decide", + 7: "Resync", +} + +var MessageType_value = map[string]int32{ + "Nop": 0, + "RoundChange": 1, + "Lock": 2, + "Select": 3, + "Commit": 4, + "LockRelease": 5, + "Decide": 6, + "Resync": 7, +} + +func (x MessageType) String() string { + return proto.EnumName(MessageType_name, int32(x)) +} + +func (MessageType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_33c57e4bae7b9afd, []int{0} +} + +// SignedProto defines a message with signature and it's publickey +type SignedProto struct { + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // the Message encoded raw protobuf in bytes + Message []byte `protobuf:"bytes,2,opt,name=Message,proto3" json:"Message,omitempty"` + // signer's public key + X PubKeyAxis `protobuf:"bytes,3,opt,name=x,proto3,customtype=PubKeyAxis" json:"x"` + Y PubKeyAxis `protobuf:"bytes,4,opt,name=y,proto3,customtype=PubKeyAxis" json:"y"` + // signature r,s for prefix+messages+version+x+y above + R []byte `protobuf:"bytes,5,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,6,opt,name=s,proto3" json:"s,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignedProto) Reset() { *m = SignedProto{} } +func (m *SignedProto) String() string { return proto.CompactTextString(m) } +func (*SignedProto) ProtoMessage() {} +func (*SignedProto) Descriptor() ([]byte, []int) { + return fileDescriptor_33c57e4bae7b9afd, []int{0} +} +func (m *SignedProto) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SignedProto) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SignedProto.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SignedProto) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignedProto.Merge(m, src) +} +func (m *SignedProto) XXX_Size() int { + return m.Size() +} +func (m *SignedProto) XXX_DiscardUnknown() { + xxx_messageInfo_SignedProto.DiscardUnknown(m) +} + +var xxx_messageInfo_SignedProto proto.InternalMessageInfo + +func (m *SignedProto) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *SignedProto) GetMessage() []byte { + if m != nil { + return m.Message + } + return nil +} + +func (m *SignedProto) GetR() []byte { + if m != nil { + return m.R + } + return nil +} + +func (m *SignedProto) GetS() []byte { + if m != nil { + return m.S + } + return nil +} + +// Message defines a consensus message +type Message struct { + // Type of this message + Type MessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=bdls.MessageType" json:"Type,omitempty"` + // Height in consensus + Height uint64 `protobuf:"varint,2,opt,name=Height,proto3" json:"Height,omitempty"` + // Round in consensus + Round uint64 `protobuf:"varint,3,opt,name=Round,proto3" json:"Round,omitempty"` + // Proposed state (optional) + State []byte `protobuf:"bytes,4,opt,name=State,proto3" json:"State,omitempty"` + // Proofs related + Proof []*SignedProto `protobuf:"bytes,5,rep,name=Proof,proto3" json:"Proof,omitempty"` + // for lock-release, it's an embeded message + LockRelease *SignedProto `protobuf:"bytes,6,opt,name=LockRelease,proto3" json:"LockRelease,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_33c57e4bae7b9afd, []int{1} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(m, src) +} +func (m *Message) XXX_Size() int { + return m.Size() +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +func (m *Message) GetType() MessageType { + if m != nil { + return m.Type + } + return MessageType_Nop +} + +func (m *Message) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *Message) GetRound() uint64 { + if m != nil { + return m.Round + } + return 0 +} + +func (m *Message) GetState() []byte { + if m != nil { + return m.State + } + return nil +} + +func (m *Message) GetProof() []*SignedProto { + if m != nil { + return m.Proof + } + return nil +} + +func (m *Message) GetLockRelease() *SignedProto { + if m != nil { + return m.LockRelease + } + return nil +} + +func init() { + proto.RegisterEnum("bdls.MessageType", MessageType_name, MessageType_value) + proto.RegisterType((*SignedProto)(nil), "bdls.SignedProto") + proto.RegisterType((*Message)(nil), "bdls.Message") +} + +func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) } + +var fileDescriptor_33c57e4bae7b9afd = []byte{ + // 381 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcd, 0xaa, 0xda, 0x40, + 0x14, 0xc7, 0x1d, 0xf3, 0x61, 0x39, 0xd1, 0x76, 0x3a, 0x94, 0x32, 0x74, 0xa1, 0x41, 0x28, 0x95, + 0x42, 0x23, 0xd4, 0x27, 0xa8, 0x76, 0x51, 0xe8, 0x07, 0x32, 0xf6, 0x05, 0xf2, 0x71, 0x8c, 0xa1, + 0x26, 0x23, 0x99, 0xa4, 0x98, 0xc7, 0xe9, 0xdb, 0xb8, 0x2c, 0x5d, 0x76, 0x21, 0x17, 0x9f, 0xe4, + 0x32, 0x13, 0xbd, 0x64, 0x71, 0xef, 0xee, 0xfc, 0xce, 0xff, 0x7f, 0xce, 0xf9, 0x27, 0x0c, 0x8c, + 0x72, 0x54, 0x2a, 0x4c, 0x31, 0x38, 0x94, 0xb2, 0x92, 0xcc, 0x8e, 0x92, 0xbd, 0x7a, 0xf3, 0x21, + 0xcd, 0xaa, 0x5d, 0x1d, 0x05, 0xb1, 0xcc, 0xe7, 0xa9, 0x4c, 0xe5, 0xdc, 0x88, 0x51, 0xbd, 0x35, + 0x64, 0xc0, 0x54, 0xed, 0xd0, 0xf4, 0x0f, 0x01, 0x6f, 0x93, 0xa5, 0x05, 0x26, 0x6b, 0xb3, 0x84, + 0xc3, 0xe0, 0x37, 0x96, 0x2a, 0x93, 0x05, 0x27, 0x3e, 0x99, 0x8d, 0xc4, 0x0d, 0xb5, 0xf2, 0xbd, + 0xbd, 0xc7, 0xfb, 0x3e, 0x99, 0x0d, 0xc5, 0x0d, 0x99, 0x0f, 0xe4, 0xc8, 0x2d, 0xdd, 0x5b, 0xb2, + 0xd3, 0x79, 0xd2, 0xfb, 0x7f, 0x9e, 0xc0, 0xba, 0x8e, 0xbe, 0x62, 0xf3, 0xe9, 0x98, 0x29, 0x41, + 0x8e, 0xda, 0xd1, 0x70, 0xfb, 0x69, 0x47, 0xc3, 0x86, 0x40, 0x4a, 0xee, 0x98, 0xbd, 0xa4, 0xd4, + 0xa4, 0xb8, 0xdb, 0x92, 0x9a, 0xfe, 0x23, 0x0f, 0xa7, 0xd9, 0x5b, 0xb0, 0x7f, 0x36, 0x07, 0x34, + 0xe1, 0x9e, 0x7f, 0x7c, 0x19, 0xe8, 0x6f, 0x0e, 0xae, 0xa2, 0x16, 0x84, 0x91, 0xd9, 0x6b, 0x70, + 0xbf, 0x60, 0x96, 0xee, 0x2a, 0x93, 0xd5, 0x16, 0x57, 0x62, 0xaf, 0xc0, 0x11, 0xb2, 0x2e, 0x12, + 0x13, 0xd7, 0x16, 0x2d, 0xe8, 0xee, 0xa6, 0x0a, 0x2b, 0x6c, 0x23, 0x8a, 0x16, 0xd8, 0x3b, 0x70, + 0xd6, 0xa5, 0x94, 0x5b, 0xee, 0xf8, 0xd6, 0xcc, 0xbb, 0xdd, 0xea, 0xfc, 0x2c, 0xd1, 0xea, 0x6c, + 0x01, 0xde, 0x37, 0x19, 0xff, 0x12, 0xb8, 0xc7, 0x50, 0xa1, 0xc9, 0xfd, 0xa8, 0xbd, 0xeb, 0x7a, + 0x5f, 0x82, 0xd7, 0x89, 0xcd, 0x06, 0x60, 0xfd, 0x90, 0x07, 0xda, 0x63, 0x2f, 0xc0, 0x33, 0xa1, + 0x56, 0xbb, 0xb0, 0x48, 0x91, 0x12, 0xf6, 0x0c, 0x6c, 0x3d, 0x47, 0xfb, 0x0c, 0xc0, 0xdd, 0xe0, + 0x1e, 0xe3, 0x8a, 0x5a, 0xba, 0x5e, 0xc9, 0x3c, 0xcf, 0x2a, 0x6a, 0xeb, 0x91, 0xce, 0x66, 0xea, + 0x68, 0xf1, 0x33, 0xc6, 0x59, 0x82, 0xd4, 0xd5, 0xb5, 0x40, 0xd5, 0x14, 0x31, 0x1d, 0x2c, 0x87, + 0xa7, 0xcb, 0x98, 0xfc, 0xbd, 0x8c, 0xc9, 0xdd, 0x65, 0x4c, 0x22, 0xd7, 0xbc, 0x80, 0xc5, 0x7d, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, 0xc3, 0x64, 0x6c, 0x47, 0x02, 0x00, 0x00, +} + +func (m *SignedProto) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SignedProto) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SignedProto) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintMessage(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x32 + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintMessage(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x2a + } + { + size := m.Y.Size() + i -= size + if _, err := m.Y.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMessage(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.X.Size() + i -= size + if _, err := m.X.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMessage(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Message) > 0 { + i -= len(m.Message) + copy(dAtA[i:], m.Message) + i = encodeVarintMessage(dAtA, i, uint64(len(m.Message))) + i-- + dAtA[i] = 0x12 + } + if m.Version != 0 { + i = encodeVarintMessage(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Message) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.LockRelease != nil { + { + size, err := m.LockRelease.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessage(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.Proof) > 0 { + for iNdEx := len(m.Proof) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Proof[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessage(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.State) > 0 { + i -= len(m.State) + copy(dAtA[i:], m.State) + i = encodeVarintMessage(dAtA, i, uint64(len(m.State))) + i-- + dAtA[i] = 0x22 + } + if m.Round != 0 { + i = encodeVarintMessage(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x18 + } + if m.Height != 0 { + i = encodeVarintMessage(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 + } + if m.Type != 0 { + i = encodeVarintMessage(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintMessage(dAtA []byte, offset int, v uint64) int { + offset -= sovMessage(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *SignedProto) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovMessage(uint64(m.Version)) + } + l = len(m.Message) + if l > 0 { + n += 1 + l + sovMessage(uint64(l)) + } + l = m.X.Size() + n += 1 + l + sovMessage(uint64(l)) + l = m.Y.Size() + n += 1 + l + sovMessage(uint64(l)) + l = len(m.R) + if l > 0 { + n += 1 + l + sovMessage(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovMessage(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + sovMessage(uint64(m.Type)) + } + if m.Height != 0 { + n += 1 + sovMessage(uint64(m.Height)) + } + if m.Round != 0 { + n += 1 + sovMessage(uint64(m.Round)) + } + l = len(m.State) + if l > 0 { + n += 1 + l + sovMessage(uint64(l)) + } + if len(m.Proof) > 0 { + for _, e := range m.Proof { + l = e.Size() + n += 1 + l + sovMessage(uint64(l)) + } + } + if m.LockRelease != nil { + l = m.LockRelease.Size() + n += 1 + l + sovMessage(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovMessage(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMessage(x uint64) (n int) { + return sovMessage(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *SignedProto) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SignedProto: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SignedProto: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Message = append(m.Message[:0], dAtA[iNdEx:postIndex]...) + if m.Message == nil { + m.Message = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field X", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.X.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Y", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Y.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMessage(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthMessage + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthMessage + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Message: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Message: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= MessageType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Round", wireType) + } + m.Round = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Round |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field State", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.State = append(m.State[:0], dAtA[iNdEx:postIndex]...) + if m.State == nil { + m.State = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proof = append(m.Proof, &SignedProto{}) + if err := m.Proof[len(m.Proof)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LockRelease", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessage + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessage + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessage + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.LockRelease == nil { + m.LockRelease = &SignedProto{} + } + if err := m.LockRelease.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMessage(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthMessage + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthMessage + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMessage(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessage + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMessage + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMessage + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMessage + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMessage = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMessage = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMessage = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/BDLS-bft/bdls/message.proto b/vendor/github.com/BDLS-bft/bdls/message.proto new file mode 100644 index 00000000000..fa65dcd248e --- /dev/null +++ b/vendor/github.com/BDLS-bft/bdls/message.proto @@ -0,0 +1,54 @@ + +syntax = "proto3"; +package bdls; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +// SignedProto defines a message with signature and it's publickey +message SignedProto { + uint32 version=1; + // the Message encoded raw protobuf in bytes + bytes Message=2; + // signer's public key + bytes x = 3 [(gogoproto.customtype) = "PubKeyAxis", (gogoproto.nullable) = false]; + bytes y = 4 [(gogoproto.customtype) = "PubKeyAxis", (gogoproto.nullable) = false]; + // signature r,s for prefix+messages+version+x+y above + bytes r = 5; + bytes s = 6; +} + +// MessageType defines supported message types +enum MessageType{ + // No operation, for default message type, and keepalive connection + Nop = 0; + // MessageRoundChange = message + RoundChange = 1; + // MessageLock = message + Lock = 2; + // MessageSelect =