├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── block.rs ├── examples ├── serde.rs └── ternary.rs ├── rust-toolchain ├── src ├── blockchain.rs ├── estimator.rs ├── justification.rs ├── lib.rs ├── message.rs ├── tests_common │ ├── blockdata.rs │ ├── integer.rs │ ├── mod.rs │ ├── utils.rs │ └── vote_count.rs ├── util │ ├── hash.rs │ ├── id.rs │ ├── mod.rs │ └── weight.rs └── validator.rs └── tests ├── binary.rs ├── blockchain.rs ├── common ├── binary.rs └── mod.rs ├── generative_tests.rs ├── integer.rs └── tools └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | *.log 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Official framework image. Look for the different tagged releases at: 2 | # https://hub.docker.com/r/library/node/tags/ 3 | image: rust:1.35.0 4 | 5 | before_script: 6 | - cargo version --verbose 7 | - rustup component add rustfmt 8 | - rustup component add clippy 9 | 10 | stages: 11 | - linting 12 | - build 13 | - tests 14 | - examples 15 | 16 | fmt: 17 | stage: linting 18 | script: 19 | # When running with --check, Rustfmt will exit with 0 if Rustfmt would 20 | # not make any formatting changes to the input, and 1 if Rustfmt would 21 | # make changes. 22 | - cargo fmt --all --verbose -- --check --verbose 23 | 24 | clippy: 25 | stage: linting 26 | script: 27 | - cargo clippy --all-targets --all-features -- -D warnings 28 | 29 | build: 30 | stage: build 31 | script: 32 | - cargo build --verbose 33 | 34 | tests: 35 | stage: tests 36 | script: 37 | - cargo test 38 | 39 | generative-tests: 40 | stage: tests 41 | script: 42 | - cargo test --test generative_tests --features "integration_test" 43 | 44 | build-doc: 45 | stage: tests 46 | script: 47 | - cargo doc 48 | 49 | serde: 50 | stage: examples 51 | script: 52 | - cargo run --example serde 53 | 54 | ternary: 55 | stage: examples 56 | script: 57 | - cargo run --example ternary 58 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "visualization"] 2 | path = visualization 3 | url = git@gitlab.com:TrueLevel/casper/playground/casper-visualization.git 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # Core CBC Casper 2 | # Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | # Authors: pZ4 , 4 | # Lederstrumpf, 5 | # h4sh3d 6 | # roflolilolmao 7 | # 8 | # This file is part of Core CBC Casper. 9 | # 10 | # Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | # of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | # version 3 of the License, or (at your option) any later version. 13 | # 14 | # Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | # PURPOSE. See the GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | # Rust Library. If not, see . 20 | 21 | [package] 22 | name = "core_cbc_casper" 23 | description = "Abstractly defines the CBC Casper message stucture and defines functions for the construction and proper execution of protocols of the Casper family." 24 | version = "0.1.0" 25 | license-file = "LICENSE" 26 | authors = ["pZ4 ", "Lederstrumpf", "h4sh3d ", "roflolilolmao "] 27 | repository = "https://github.com/TrueLevelSA/core-cbc-casper" 28 | readme = "README.md" 29 | keywords = ["CBC", "Casper", "Blockchain"] 30 | 31 | edition = "2018" 32 | 33 | [dependencies] 34 | rayon = "1.3.0" 35 | digest = "0.7" 36 | serde = { version = "1.0", features = ["rc"] } 37 | serde_derive = "1.0" 38 | bincode = "1.0.1" 39 | blake2 = "0.7" 40 | itertools = "0.7.8" 41 | proptest = { version = "0.9", optional = true } 42 | rand = { version = "0.6", optional = true } 43 | 44 | [dependencies.fixed-hash] 45 | version = "0.3" 46 | features = ["libc"] 47 | default-features = false 48 | 49 | [features] 50 | integration_test = ["proptest", "rand"] 51 | 52 | [dev-dependencies] 53 | criterion = "0.2" 54 | 55 | [[bench]] 56 | name = "block" 57 | harness = false 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![pipeline status](https://gitlab.com/TrueLevel/casper/core-cbc/badges/master/pipeline.svg)](https://gitlab.com/TrueLevel/casper/core-cbc/commits/master) [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) 2 | 3 | Core CBC Casper 4 | === 5 | 6 | Abstract message library for CBC Casper, written in Rust. 7 | 8 | **DISCLAIMER:** This library is experimental, under development, not reviewed, 9 | and might change dramatically. 10 | 11 | The purpose of this library is to abstractly define the CBC Casper, as defined 12 | in [Introducing the "minimal" CBC Casper Consensus 13 | Protocols](https://github.com/cbc-casper/cbc-casper-paper), message stucture and 14 | define functions for the construction and proper execution of protocols of the 15 | casper family. We aimed at pushing as much functionality as possible directly to 16 | the abstract message layer, in such a way that a developer can create a protocol 17 | fairly easy using this library. 18 | 19 | The design decision is to be as general as possible, and leave all specifics for 20 | the implementer of the protocol. For the time being, we aim at mathematical 21 | correctness and mostly purely functional protocol executions, rather than on 22 | performance. The idea is to have a mathematically correct and possibly 23 | inefficient implementations of functions that can be used as ground truth for 24 | comparing with efficient implementations. 25 | 26 | ## Using the library 27 | 28 | To benefit from the CBC Casper safety proofs this library builds upon, 29 | the `validator::ValidatorName` and `estimmator::Estimator` traits must be 30 | implemented. 31 | 32 | We also present a basic blockchain implementation heavily under developement. 33 | You can also find another implementation of an integer consensus in `tests/`. 34 | 35 | But in order to get started using the library, the best way is to study the 36 | examples in the documentation and in the examples folder (under development). 37 | It is also instructive to read and run the tests. 38 | 39 | ### Cargo 40 | 41 | You can use this library in your dependencies with 42 | 43 | ``` 44 | [dependencies] 45 | core_cbc_casper = "0.1" 46 | ``` 47 | 48 | ## Example 49 | 50 | We present an example of naive consensus protocol: a ternary consensus that uses 51 | the generic type `message::Message` implementation to 52 | generate the protocol. 53 | 54 | ## Known limitations 55 | 56 | ### Performance 57 | 58 | As mentioned earlier, our current focus is on the correctness of the 59 | implementation rather than on performance. 60 | 61 | ### Error handling 62 | 63 | The error handling has had poor focus for now. Potential points of failure must be 64 | properly studied and fixed if necessary before the library can be considered to be 65 | ready for production. 66 | 67 | ## Tests 68 | 69 | We use the crate `proptest` to generate property tests. The library has a 70 | feature `integration_test` used by the proptest framework. To run specifically 71 | the `proptest` tests use: 72 | 73 | ``` 74 | cargo test --test generative_tests --features "integration_test" 75 | ``` 76 | 77 | To run the other tests simply use `cargo test`. 78 | 79 | ## Benchmarking 80 | 81 | We use the crate `criterion` for benchmarking. The library provides statistical 82 | insight into performance regression and improvement, and optionally depends on 83 | `gnuplot` to plot detailed graphs of benchmarks results. To run the benchmark, use: 84 | 85 | ``` 86 | cargo bench 87 | ``` 88 | 89 | ### Artefacts 90 | The plots and saved data are stored under `target/criterion/$BENCHMARK_NAME/`. 91 | 92 | The `new` folder contains the statistics for the last benchmarking run, while the `base` folder 93 | contains those for the last run on the `base` baseline (see [Command-Line 94 | Options](./command_line_options.md#baselines) for more information on baselines). The plots are in 95 | the `report` folder. Criterion.rs only keeps historical data for the last run. The `report/both` 96 | folder contains plots which show both runs on one plot, while the `report/change` folder contains 97 | plots showing the differences between the last two runs. This example shows the plots produced by 98 | the default `bench_function` benchmark method. Other methods may produce additional charts, which 99 | will be detailed in their respective pages. 100 | 101 | For further reading, reference [Plots & Graphs](https://bheisler.github.io/criterion.rs/book/user_guide/plots_and_graphs.html) 102 | 103 | ## Contributing 104 | 105 | At this point the development of this library is only internal. If you want to 106 | contribute please contact one of the authors of the library (see Cargo.toml). 107 | 108 | ### Code Format 109 | 110 | We use `rustfmt` default configuration to ensure a coherent code format in the 111 | entire project. Install `rustfmt` with `rustup component add rustfmt`. 112 | 113 | ### Code Linting 114 | 115 | We use `clippy` to ensure the code base is as clean and functional as possible. 116 | Install it with `rustup component add clippy` and run it with `cargo clippy --all-targets 117 | --all-features -- -D warnings`. 118 | 119 | ## More on CBC Casper 120 | 121 | To read more about CBC Casper: 122 | * [Casper CBC, Simplified!]( 123 | https://medium.com/@aditya.asgaonkar/casper-cbc-simplified-2370922f9aa6), 124 | by Aditya Asgaonkar. 125 | -------------------------------------------------------------------------------- /benches/block.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | #[macro_use] 22 | extern crate criterion; 23 | 24 | use core_cbc_casper::estimator::Estimator; 25 | use core_cbc_casper::justification::LatestMessagesHonest; 26 | use core_cbc_casper::message; 27 | use core_cbc_casper::util::weight::{WeightUnit, Zero}; 28 | use core_cbc_casper::validator; 29 | use core_cbc_casper::Block; 30 | use core_cbc_casper::ValidatorNameBlockData; 31 | use criterion::{black_box, Criterion}; 32 | 33 | type Validator = u8; 34 | 35 | #[derive(Debug, Hash, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, serde_derive::Serialize)] 36 | pub enum Value { 37 | Zero = 0, 38 | One = 1, 39 | Two = 2, 40 | } 41 | 42 | impl validator::ValidatorName for Value {} 43 | 44 | impl From<((Value, U), (Value, U), (Value, U))> for Value { 45 | /// If equality between two or tree values exists, last value is 46 | /// prefered, then second value, and first value 47 | /// 48 | /// v1: w1 > w2, w1 > w3 49 | /// v2: w2 >= w1, w2 > w3 50 | /// v3: w3 >= w1, w3 >= w1 51 | /// 52 | fn from(val: ((Value, U), (Value, U), (Value, U))) -> Self { 53 | let ((v1, w1), (v2, w2), (v3, w3)) = val; 54 | let mut max = v3; 55 | let mut weight = w3; 56 | if w2 > weight { 57 | max = v2; 58 | weight = w2; 59 | } 60 | if w1 > weight { 61 | max = v1; 62 | } 63 | max 64 | } 65 | } 66 | 67 | #[derive(Debug)] 68 | pub struct Error(&'static str); 69 | 70 | impl std::fmt::Display for Error { 71 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 72 | writeln!(f, "{}", self.0) 73 | } 74 | } 75 | 76 | impl std::error::Error for Error {} 77 | 78 | impl std::convert::From<&'static str> for Error { 79 | fn from(string: &'static str) -> Self { 80 | Error(string) 81 | } 82 | } 83 | 84 | impl Estimator for Value { 85 | type ValidatorName = Validator; 86 | type Error = Error; 87 | 88 | fn estimate( 89 | latest_messages: &LatestMessagesHonest, 90 | validators_weights: &validator::Weights, 91 | ) -> Result { 92 | let res: Self = latest_messages 93 | .iter() 94 | .map(|message| { 95 | ( 96 | message.estimate(), 97 | validators_weights.weight(message.sender()), 98 | ) 99 | }) 100 | .fold( 101 | ( 102 | (Value::Zero, >::ZERO), 103 | (Value::One, >::ZERO), 104 | (Value::Two, >::ZERO), 105 | ), 106 | |acc, tuple| match tuple { 107 | (Value::Zero, Ok(weight)) => (((acc.0).0, (acc.0).1 + weight), acc.1, acc.2), 108 | (Value::One, Ok(weight)) => (acc.0, ((acc.1).0, (acc.1).1 + weight), acc.2), 109 | (Value::Two, Ok(weight)) => (acc.0, acc.1, ((acc.2).0, (acc.2).1 + weight)), 110 | _ => acc, // No weight for the given validator, do nothing 111 | }, 112 | ) 113 | .into(); 114 | Ok(res) 115 | } 116 | } 117 | 118 | fn block_new(c: &mut Criterion) { 119 | c.bench_function_over_inputs( 120 | "Block::new", 121 | |b, loops| { 122 | b.iter(|| { 123 | let mut block = None; 124 | for _ in 0..(**loops) { 125 | block = Some(Block::new(block, ValidatorNameBlockData::new(0))); 126 | } 127 | }); 128 | }, 129 | &[1_000, 10 * 1_000, 100 * 1_000], 130 | ); 131 | } 132 | 133 | fn block_from_prevblock_message(c: &mut Criterion) { 134 | type Message = message::Message; 135 | 136 | c.bench_function_over_inputs( 137 | "Block::from_prevblock_message", 138 | |b, loops| { 139 | use std::collections::HashSet; 140 | 141 | use core_cbc_casper::justification::{Justification, LatestMessages}; 142 | 143 | let validators: Vec = (1..=4).collect(); 144 | let weights = [0.6, 1.0, 2.0, 1.3]; 145 | 146 | let validators_weights = validator::Weights::new( 147 | validators 148 | .iter() 149 | .cloned() 150 | .zip(weights.iter().cloned()) 151 | .collect(), 152 | ); 153 | 154 | let mut weights = validator::State::new( 155 | validators_weights, 156 | 0.0, 157 | LatestMessages::empty(), 158 | 1.0, 159 | HashSet::new(), 160 | ); 161 | let block = Block::new(None, ValidatorNameBlockData::new(0)); 162 | let mut message = Message::new(1, Justification::empty(), Value::One); 163 | for _ in 0..=(**loops) { 164 | weights.update(&[&message]); 165 | message = Message::from_validator_state(1, &weights).unwrap(); 166 | } 167 | 168 | b.iter(|| { 169 | Block::from_prevblock_message(black_box(None), black_box(block.clone())); 170 | }); 171 | }, 172 | &[100, 1_000, 10_000], 173 | ); 174 | } 175 | 176 | fn block_is_member(c: &mut Criterion) { 177 | c.bench_function_over_inputs( 178 | "Block::is_member", 179 | |b, loops| { 180 | let first_block = Block::new(None, ValidatorNameBlockData::new(0)); 181 | let mut block = Block::new(Some(first_block.clone()), ValidatorNameBlockData::new(0)); 182 | for _ in 0..(**loops) { 183 | block = Block::new(Some(block), ValidatorNameBlockData::new(0)); 184 | } 185 | b.iter(|| first_block.is_member(&block)); 186 | }, 187 | &[10, 100, 1_000], 188 | ); 189 | } 190 | 191 | fn block_estimate(c: &mut Criterion) { 192 | use core_cbc_casper::justification::{Justification, LatestMessages}; 193 | use core_cbc_casper::message::Message; 194 | use std::collections::HashSet; 195 | 196 | let weights = validator::Weights::new( 197 | vec![(0, 1.0), (1, 2.0), (2, 4.0), (3, 8.0), (4, 16.0)] 198 | .into_iter() 199 | .collect(), 200 | ); 201 | let genesis = Block::new(None, ValidatorNameBlockData::new(0)); 202 | let block_1 = Block::new(Some(genesis.clone()), ValidatorNameBlockData::new(1)); 203 | let block_2 = Block::new(Some(genesis.clone()), ValidatorNameBlockData::new(2)); 204 | let block_3 = Block::new(Some(genesis.clone()), ValidatorNameBlockData::new(3)); 205 | let block_4 = Block::new(Some(genesis.clone()), ValidatorNameBlockData::new(4)); 206 | 207 | let block_5 = Block::new(Some(block_4.clone()), ValidatorNameBlockData::new(0)); 208 | let block_6 = Block::new(Some(block_2.clone()), ValidatorNameBlockData::new(3)); 209 | 210 | let block_7 = Block::new(Some(block_5.clone()), ValidatorNameBlockData::new(2)); 211 | let block_8 = Block::new(Some(block_6.clone()), ValidatorNameBlockData::new(4)); 212 | 213 | let mut justification = Justification::empty(); 214 | justification.insert(Message::new(0, justification.clone(), genesis)); 215 | justification.insert(Message::new(1, justification.clone(), block_1)); 216 | justification.insert(Message::new(2, justification.clone(), block_2)); 217 | justification.insert(Message::new(3, justification.clone(), block_3)); 218 | justification.insert(Message::new(4, justification.clone(), block_4)); 219 | justification.insert(Message::new(0, justification.clone(), block_5)); 220 | justification.insert(Message::new(3, justification.clone(), block_6)); 221 | justification.insert(Message::new(2, justification.clone(), block_7)); 222 | justification.insert(Message::new(4, justification.clone(), block_8)); 223 | let latest_messages = LatestMessages::from(&justification); 224 | let latest_honest_messages = 225 | LatestMessagesHonest::from_latest_messages(&latest_messages, &HashSet::new()); 226 | 227 | c.bench_function("Block::estimate", move |b| { 228 | b.iter(|| Block::estimate(black_box(&latest_honest_messages), black_box(&weights))); 229 | }); 230 | } 231 | 232 | criterion_group!( 233 | benches, 234 | block_new, 235 | block_from_prevblock_message, 236 | block_is_member, 237 | block_estimate, 238 | ); 239 | criterion_main!(benches); 240 | -------------------------------------------------------------------------------- /examples/serde.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | #[macro_use] 22 | extern crate serde_derive; 23 | 24 | extern crate bincode; 25 | extern crate blake2; 26 | extern crate core_cbc_casper; 27 | extern crate itertools; 28 | extern crate serde; 29 | 30 | use core_cbc_casper::util::hash::Hash; 31 | use core_cbc_casper::util::id::Id; 32 | 33 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 34 | struct Example { 35 | count: u64, 36 | int: i64, 37 | } 38 | 39 | impl Id for Example { 40 | type ID = Hash; 41 | } 42 | 43 | fn main() { 44 | let example = Example { count: 10, int: -4 }; 45 | println!("{:?}", example); 46 | println!("ID {:?}", example.id()); 47 | let serialized = example.serialize(); 48 | println!("BIN {:?}", serialized); 49 | let deserialized = Example::deserialize(&serialized[..]); 50 | println!("{:?}", deserialized); 51 | assert_eq!(example, deserialized.unwrap()); 52 | } 53 | -------------------------------------------------------------------------------- /examples/ternary.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | extern crate core_cbc_casper; 22 | 23 | use std::convert::From; 24 | 25 | use core_cbc_casper::estimator::Estimator; 26 | use core_cbc_casper::justification::LatestMessagesHonest; 27 | use core_cbc_casper::message; 28 | use core_cbc_casper::util::weight::{WeightUnit, Zero}; 29 | use core_cbc_casper::validator; 30 | 31 | type Validator = u32; 32 | 33 | pub type Message = message::Message; 34 | 35 | #[derive(Debug, Hash, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, serde_derive::Serialize)] 36 | pub enum Value { 37 | Zero = 0, 38 | One = 1, 39 | Two = 2, 40 | } 41 | 42 | impl From<((Value, U), (Value, U), (Value, U))> for Value { 43 | /// If equality between two or tree values exists, last value is 44 | /// prefered, then second value, and first value 45 | /// 46 | /// v1: w1 > w2, w1 > w3 47 | /// v2: w2 >= w1, w2 > w3 48 | /// v3: w3 >= w1, w3 >= w1 49 | /// 50 | fn from(values: ((Value, U), (Value, U), (Value, U))) -> Self { 51 | let ((v1, w1), (v2, w2), (v3, w3)) = values; 52 | let mut max = v3; 53 | let mut weight = w3; 54 | if w2 > weight { 55 | max = v2; 56 | weight = w2; 57 | } 58 | if w1 > weight { 59 | max = v1; 60 | } 61 | max 62 | } 63 | } 64 | 65 | #[derive(Debug)] 66 | pub struct Error(&'static str); 67 | 68 | impl std::fmt::Display for Error { 69 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 70 | writeln!(f, "{}", self.0) 71 | } 72 | } 73 | 74 | impl std::error::Error for Error {} 75 | 76 | impl std::convert::From<&'static str> for Error { 77 | fn from(string: &'static str) -> Self { 78 | Error(string) 79 | } 80 | } 81 | 82 | impl Estimator for Value { 83 | type ValidatorName = Validator; 84 | type Error = Error; 85 | 86 | fn estimate( 87 | latest_messages: &LatestMessagesHonest, 88 | validators_weights: &validator::Weights, 89 | ) -> Result { 90 | let res: Self = latest_messages 91 | .iter() 92 | .map(|message| { 93 | ( 94 | message.estimate(), 95 | validators_weights.weight(message.sender()), 96 | ) 97 | }) 98 | .fold( 99 | ( 100 | (Value::Zero, >::ZERO), 101 | (Value::One, >::ZERO), 102 | (Value::Two, >::ZERO), 103 | ), 104 | |acc, tuple| match tuple { 105 | (Value::Zero, Ok(weight)) => (((acc.0).0, (acc.0).1 + weight), acc.1, acc.2), 106 | (Value::One, Ok(weight)) => (acc.0, ((acc.1).0, (acc.1).1 + weight), acc.2), 107 | (Value::Two, Ok(weight)) => (acc.0, acc.1, ((acc.2).0, (acc.2).1 + weight)), 108 | _ => acc, // No weight for the given validator, do nothing 109 | }, 110 | ) 111 | .into(); 112 | Ok(res) 113 | } 114 | } 115 | 116 | fn main() { 117 | use std::collections::HashSet; 118 | 119 | use core_cbc_casper::justification::{Justification, LatestMessages}; 120 | 121 | let validators: Vec = (1..=4).collect(); 122 | let weights = [0.6, 1.0, 2.0, 1.3]; 123 | 124 | let validators_weights = validator::Weights::new( 125 | validators 126 | .iter() 127 | .cloned() 128 | .zip(weights.iter().cloned()) 129 | .collect(), 130 | ); 131 | 132 | let validator_state = validator::State::new( 133 | validators_weights, 134 | 0.0, 135 | LatestMessages::empty(), 136 | 1.0, 137 | HashSet::new(), 138 | ); 139 | 140 | // 1: (1) (2) 141 | // 2: (2) (0) 142 | // 3: (0) (0) (0) 143 | // 4: (1) (0) 144 | 145 | let message1 = Message::new(1, Justification::empty(), Value::One); 146 | let message2 = Message::new(2, Justification::empty(), Value::Two); 147 | let message3 = Message::new(3, Justification::empty(), Value::Zero); 148 | let message4 = Message::new(4, Justification::empty(), Value::One); 149 | let mut validator_state_clone = validator_state.clone(); 150 | validator_state_clone.update(&[&message1, &message2]); 151 | let message5 = Message::from_validator_state(1, &validator_state_clone).unwrap(); 152 | let mut validator_state_clone = validator_state.clone(); 153 | validator_state_clone.update(&[&message3, &message4]); 154 | let message6 = Message::from_validator_state(3, &validator_state_clone).unwrap(); 155 | let mut validator_state_clone = validator_state.clone(); 156 | validator_state_clone.update(&[&message2, &message5, &message6]); 157 | let message7 = Message::from_validator_state(2, &validator_state_clone).unwrap(); 158 | let mut validator_state_clone = validator_state.clone(); 159 | validator_state_clone.update(&[&message7, &message6]); 160 | let message8 = Message::from_validator_state(3, &validator_state_clone).unwrap(); 161 | let mut validator_state_clone = validator_state; 162 | validator_state_clone.update(&[&message4, &message6]); 163 | let message9 = Message::from_validator_state(4, &validator_state_clone).unwrap(); 164 | 165 | assert_eq!(message5.estimate(), &Value::Two); 166 | assert_eq!(message6.estimate(), &Value::Zero); 167 | assert_eq!(message7.estimate(), &Value::Zero); 168 | assert_eq!(message8.estimate(), &Value::Zero); 169 | assert_eq!(message9.estimate(), &Value::Zero); 170 | } 171 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | stable 2 | -------------------------------------------------------------------------------- /src/estimator.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::error::Error; 22 | use std::fmt::Debug; 23 | use std::hash::Hash; 24 | 25 | use crate::justification::LatestMessagesHonest; 26 | use crate::util::weight::WeightUnit; 27 | use crate::validator; 28 | 29 | /// Describes an estimate, or a value of the consensus at a certain time. Implementing this trait 30 | /// allows to produce an estimate given the set of [`latest messages`] and the set of [`validators`] and 31 | /// their [`weights`]. 32 | /// 33 | /// [`latest messages`]: ../justification/struct.LatestMessages.html 34 | /// [`validators`]: ../validator/trait.ValidatorName.html 35 | /// [`weights`]: ../validator/struct.Weights.html 36 | /// 37 | /// # Example 38 | /// 39 | /// This lengthy example showcases how to declare a simple type implementing the Estimator trait. 40 | /// 41 | /// ``` 42 | /// use core_cbc_casper::message::Message; 43 | /// use core_cbc_casper::validator; 44 | /// use core_cbc_casper::justification::{LatestMessagesHonest, LatestMessages, Justification}; 45 | /// use core_cbc_casper::estimator::Estimator; 46 | /// use core_cbc_casper::util::weight::WeightUnit; 47 | /// 48 | /// use std::collections::HashSet; 49 | /// 50 | /// // An error type is needed for the different ways the estimate functions could fail. This 51 | /// // example is too minimalistic for this to be a concern. 52 | /// #[derive(Debug)] 53 | /// pub struct Error(); 54 | /// 55 | /// impl std::error::Error for Error{}; 56 | /// 57 | /// impl std::fmt::Display for Error { 58 | /// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 59 | /// writeln!(f, "Error!") 60 | /// } 61 | /// } 62 | /// 63 | /// type Validator = u64; 64 | /// 65 | /// // The value type we declare is a trivial boolean wrapper with a single function for the 66 | /// // estimate function. 67 | /// #[derive(Debug, Hash, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, serde_derive::Serialize)] 68 | /// struct Value { 69 | /// boolean: bool, 70 | /// }; 71 | /// 72 | /// impl Value { 73 | /// fn and(&self, other: &Self) -> Self { 74 | /// Value { boolean: self.boolean && other.boolean } 75 | /// } 76 | /// } 77 | /// 78 | /// impl Estimator for Value { 79 | /// type ValidatorName = Validator; 80 | /// type Error = Error; 81 | /// 82 | /// // This example's simple estimate function estimates `true` if every input message is 83 | /// // `true`, otherwise the result is `false`. 84 | /// fn estimate( 85 | /// latest_messages: &LatestMessagesHonest, 86 | /// validators_weights: &validator::Weights, 87 | /// ) -> Result { 88 | /// Ok(latest_messages 89 | /// .iter() 90 | /// .fold(Value { boolean: true }, |acc, message| { 91 | /// acc.and(message.estimate()) 92 | /// }) 93 | /// ) 94 | /// } 95 | /// } 96 | /// 97 | /// let weights = validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()); 98 | /// 99 | /// let mut latest_messages = LatestMessages::empty(); 100 | /// latest_messages.update(&Message::new(0, Justification::empty(), Value { boolean: true })); 101 | /// latest_messages.update(&Message::new(1, Justification::empty(), Value { boolean: true })); 102 | /// 103 | /// assert!( 104 | /// Value::estimate( 105 | /// &LatestMessagesHonest::from_latest_messages( 106 | /// &latest_messages, 107 | /// &HashSet::new(), 108 | /// ), 109 | /// &weights, 110 | /// ).unwrap().boolean 111 | /// ); 112 | /// 113 | /// latest_messages.update(&Message::new(2, Justification::empty(), Value { boolean: false })); 114 | /// 115 | /// assert!( 116 | /// !Value::estimate( 117 | /// &LatestMessagesHonest::from_latest_messages( 118 | /// &latest_messages, 119 | /// &HashSet::new(), 120 | /// ), 121 | /// &weights, 122 | /// ).unwrap().boolean 123 | /// ); 124 | /// ``` 125 | pub trait Estimator: Hash + Eq + Clone + Send + Sync + Debug + serde::Serialize { 126 | type ValidatorName: validator::ValidatorName; 127 | type Error: Error; 128 | 129 | /// Chooses an estimate from a set of latest messages. 130 | fn estimate( 131 | latest_messages: &LatestMessagesHonest, 132 | validators_weights: &validator::Weights, 133 | ) -> Result; 134 | } 135 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | //! Core CBC Casper 22 | //! === 23 | //! 24 | //! Abstract message library for CBC Casper, written in Rust. 25 | //! 26 | //! **DISCLAIMER:** This library is experimental, under development, not reviewed, 27 | //! and might change dramatically. 28 | //! 29 | //! The purpose of this library is to abstractly define the CBC Casper, as defined 30 | //! in [Introducing the "minimal" CBC Casper Consensus 31 | //! Protocols](https://github.com/cbc-casper/cbc-casper-paper), message stucture and 32 | //! define functions for the construction and proper execution of protocols of the 33 | //! casper family. We aimed at pushing as much functionality as possible directly to 34 | //! the abstract message layer, in such a way that a developer can create a protocol 35 | //! fairly easy using this library. 36 | //! 37 | //! The design decision is to be as general as possible, and leave all specifics for 38 | //! the implementer of the protocol. For the time being, we aim at mathematical 39 | //! correctness and mostly purely functional protocol executions, rather than on 40 | //! performance. The idea is to have a mathematically correct and possibly 41 | //! inefficient implementations of functions that can be used as ground truth for 42 | //! comparing with efficient implementations. 43 | //! 44 | //! ## Using the library 45 | //! 46 | //! To benefit from the CBC Casper safety proofs this library builds upon, 47 | //! the `validator::ValidatorName` and `estimmator::Estimator` traits must be 48 | //! implemented. 49 | //! 50 | //! We also present a basic blockchain implementation heavily under developement. 51 | //! You can also find another implementation of an integer consensus in `tests/`. 52 | //! 53 | //! But in order to get started using the library, the best way is to study the 54 | //! examples in the documentation and in the examples folder (under development). 55 | //! It is also instructive to read and run the tests. 56 | //! 57 | //! ### Cargo 58 | //! 59 | //! You can use this library in your dependencies with 60 | //! 61 | //! ```text 62 | //! [dependencies] 63 | //! core_cbc_casper = "0.1" 64 | //! ``` 65 | //! 66 | //! ## Example 67 | //! 68 | //! We present an example of naive consensus protocol: a ternary consensus that uses 69 | //! the generic type `message::Message` implementation to 70 | //! generate the protocol. 71 | //! 72 | //! ## Known limitations 73 | //! 74 | //! ### Performance 75 | //! 76 | //! As mentioned earlier, our current focus is on the correctness of the 77 | //! implementation rather than on performance. 78 | //! 79 | //! ### Error handling 80 | //! 81 | //! The error handling has had poor focus for now. Potential points of failure must be 82 | //! properly studied and fixed if necessary before the library can be considered to be 83 | //! ready for production. 84 | //! 85 | //! ## Tests 86 | //! 87 | //! We use the crate `proptest` to generate property tests. The library has a 88 | //! feature `integration_test` used by the proptest framework. To run specifically 89 | //! the `proptest` tests use: 90 | //! 91 | //! ```text 92 | //! cargo test --test generative_tests --features "integration_test" 93 | //! ``` 94 | //! 95 | //! To run the other tests simply use `cargo test`. 96 | //! 97 | //! ## Benchmarking 98 | //! 99 | //! We use the crate `criterion` for benchmarking. The library provides statistical 100 | //! insight into performance regression and improvement, and optionally depends on 101 | //! `gnuplot` to plot detailed graphs of benchmarks results. To run the benchmark, use: 102 | //! 103 | //! ```text 104 | //! cargo bench 105 | //! ``` 106 | //! 107 | //! ### Artefacts 108 | //! The plots and saved data are stored under `target/criterion/$BENCHMARK_NAME/`. 109 | //! 110 | //! The `new` folder contains the statistics for the last benchmarking run, while the `base` folder 111 | //! contains those for the last run on the `base` baseline (see [Command-Line 112 | //! Options](./command_line_options.md#baselines) for more information on baselines). The plots are in 113 | //! the `report` folder. Criterion.rs only keeps historical data for the last run. The `report/both` 114 | //! folder contains plots which show both runs on one plot, while the `report/change` folder contains 115 | //! plots showing the differences between the last two runs. This example shows the plots produced by 116 | //! the default `bench_function` benchmark method. Other methods may produce additional charts, which 117 | //! will be detailed in their respective pages. 118 | //! 119 | //! For further reading, reference [Plots & Graphs](https://bheisler.github.io/criterion.rs/book/user_guide/plots_and_graphs.html) 120 | //! 121 | //! ## Contributing 122 | //! 123 | //! At this point the development of this library is only internal. If you want to 124 | //! contribute please contact one of the authors of the library (see Cargo.toml). 125 | //! 126 | //! ### Code Format 127 | //! 128 | //! We use `rustfmt` default configuration to ensure a coherent code format in the 129 | //! entire project. Install `rustfmt` with `rustup component add rustfmt`. 130 | //! 131 | //! ### Code Linting 132 | //! 133 | //! We use `clippy` to ensure the code base is as clean and functional as possible. 134 | //! Install it with `rustup component add clippy` and run it with `cargo clippy --all-targets 135 | //! --all-features -- -D warnings`. 136 | //! 137 | //! ## More on CBC Casper 138 | //! 139 | //! To read more about CBC Casper: 140 | //! * [Casper CBC, Simplified!]( 141 | //! https://medium.com/@aditya.asgaonkar/casper-cbc-simplified-2370922f9aa6), 142 | //! by Aditya Asgaonkar. 143 | 144 | extern crate digest; 145 | #[cfg(feature = "integration_test")] 146 | extern crate proptest; 147 | #[cfg(feature = "integration_test")] 148 | extern crate rand; 149 | extern crate rayon; 150 | 151 | extern crate bincode; 152 | extern crate blake2; 153 | extern crate itertools; 154 | extern crate serde; 155 | extern crate serde_derive; 156 | 157 | /// The tests_common module is privately exported to use the macros 158 | /// in tests_common/utils and to publicly export VoteCount for the 159 | /// integration and property tests. 160 | #[macro_use] 161 | mod tests_common; 162 | 163 | /// Implementation of basic types for a casper based blockchain consensus mechanism. 164 | pub mod blockchain; 165 | pub mod estimator; 166 | /// Justifications are supposed to “justify” the proposed values. Justifications of messages 167 | /// are sets of messages that validators has seen and acknowledged while generating messages. 168 | pub mod justification; 169 | /// Messages are generated and passed around by validators in the effort of trying to reach 170 | /// consensus. 171 | pub mod message; 172 | /// Utility module for various types and components. 173 | pub mod util; 174 | /// The consensus forming peers nodes in the network are called validators. 175 | pub mod validator; 176 | 177 | pub use blockchain::Block; 178 | pub use justification::Justification; 179 | pub use validator::State; 180 | 181 | pub use tests_common::blockdata::ValidatorNameBlockData; 182 | pub use tests_common::integer::IntegerWrapper; 183 | pub use tests_common::vote_count::VoteCount; 184 | -------------------------------------------------------------------------------- /src/message.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::collections::HashSet; 22 | use std::fmt::Debug; 23 | use std::sync::{Arc, RwLock}; 24 | 25 | use rayon::prelude::*; 26 | use serde::Serialize; 27 | 28 | use crate::estimator::Estimator; 29 | use crate::justification::{Justification, LatestMessagesHonest}; 30 | use crate::util::hash::Hash; 31 | use crate::util::id::Id; 32 | use crate::util::weight::WeightUnit; 33 | use crate::validator; 34 | 35 | #[derive(Debug)] 36 | pub enum Error { 37 | Estimator(E), 38 | NoNewMessage, 39 | } 40 | 41 | impl std::fmt::Display for Error { 42 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 43 | match self { 44 | Error::Estimator(err) => std::fmt::Display::fmt(&err, f), 45 | Error::NoNewMessage => writeln!(f, "No message could be added to the state"), 46 | } 47 | } 48 | } 49 | 50 | impl std::error::Error for Error {} 51 | 52 | // Mathematical definition of a casper message with (value, validator, justification). 53 | #[derive(Clone, Eq, PartialEq)] 54 | struct ProtoMessage { 55 | estimate: E, 56 | sender: E::ValidatorName, 57 | justification: Justification, 58 | } 59 | 60 | impl Id for ProtoMessage { 61 | type ID = Hash; 62 | } 63 | 64 | impl Serialize for ProtoMessage { 65 | fn serialize(&self, serializer: T) -> Result { 66 | use serde::ser::SerializeStruct; 67 | 68 | let mut message = serializer.serialize_struct("Message", 3)?; 69 | let justification: Vec<_> = self.justification.iter().map(Message::id).collect(); 70 | message.serialize_field("sender", &self.sender)?; 71 | message.serialize_field("estimate", &self.estimate)?; 72 | message.serialize_field("justification", &justification)?; 73 | message.end() 74 | } 75 | } 76 | 77 | /// Concrete Casper message containing a value as [`Estimator`], a 78 | /// validator as [`ValidatorName`], and a justification as [`Justification`]. 79 | /// 80 | /// # Example 81 | /// 82 | /// Using the [`VoteCount`] type message type for brevity's sake. 83 | /// 84 | /// ``` 85 | /// use core_cbc_casper::VoteCount; 86 | /// use core_cbc_casper::justification::Justification; 87 | /// 88 | /// // Creating a vote message 89 | /// let vote_message = VoteCount::create_vote_message(0, true); 90 | /// 91 | /// assert_eq!(vote_message.sender(), &(0 as u32)); 92 | /// assert_eq!(vote_message.justification(), &Justification::empty()); 93 | /// assert_eq!(vote_message.estimate(), &VoteCount { yes: 1, no: 0 }); 94 | /// ``` 95 | /// 96 | /// Message values must implement [`Estimator`] to be valid for a `message::Message` and to produce 97 | /// estimates. 98 | /// 99 | /// [`Estimator`]: ../estimator/trait.Estimator.html 100 | /// [`ValidatorName`]: ../validator/trait.ValidatorName.html 101 | /// [`Justification`]: ../justification/struct.Justification.html 102 | /// [`VoteCount`]: ../struct.VoteCount.html 103 | #[derive(Eq, Clone)] 104 | pub struct Message(Arc>, Hash); 105 | 106 | impl Message { 107 | pub fn sender(&self) -> &E::ValidatorName { 108 | &self.0.sender 109 | } 110 | 111 | pub fn estimate(&self) -> &E { 112 | &self.0.estimate 113 | } 114 | 115 | pub fn justification(&self) -> &Justification { 116 | &self.0.justification 117 | } 118 | 119 | pub fn new(sender: E::ValidatorName, justification: Justification, estimate: E) -> Self { 120 | let proto = ProtoMessage { 121 | sender, 122 | justification, 123 | estimate, 124 | }; 125 | // Message is not mutable, id is computed only once at creation 126 | let id = proto.id(); 127 | Message(Arc::new(proto), id) 128 | } 129 | 130 | /// Creates a message from newly received messages contained in 131 | /// [`validator_state`], which is used to compute the [`latest honest messages`]. 132 | /// 133 | /// [`validator_state`]: ../validator/struct.State.html 134 | /// [`latest honest messages`]: ../justification/struct.LatestMessagesHonest.html 135 | pub fn from_validator_state( 136 | sender: E::ValidatorName, 137 | validator_state: &validator::State, 138 | ) -> Result> { 139 | let latest_messages_honest = LatestMessagesHonest::from_latest_messages( 140 | validator_state.latests_messages(), 141 | validator_state.equivocators(), 142 | ); 143 | 144 | if latest_messages_honest.is_empty() { 145 | Err(Error::NoNewMessage) 146 | } else { 147 | let justification = Justification::from(latest_messages_honest.clone()); 148 | 149 | let estimate = 150 | latest_messages_honest.make_estimate(&validator_state.validators_weights()); 151 | estimate 152 | .map(|estimate| Self::new(sender, justification, estimate)) 153 | .map_err(Error::Estimator) 154 | } 155 | } 156 | 157 | /// Parses every messages accessible from `self` and `other` by iterating over messages' 158 | /// [`justifications`] and returns true if any of those messages is an equivocation with 159 | /// another one. This method can only be used to know that a random validator is 160 | /// equivocating but not which one. 161 | /// 162 | /// This method is currently broken as it does not always find equivocations that should be 163 | /// accessible from the given messages. It is not commutative. It compares messages with 164 | /// themselves. 165 | /// 166 | /// [`justifications`]: ../justification/struct.Justification.html 167 | pub fn equivocates_indirect( 168 | &self, 169 | other: &Self, 170 | mut equivocators: HashSet, 171 | ) -> (bool, HashSet) { 172 | let is_equivocation = self.equivocates(other); 173 | let init = if is_equivocation { 174 | equivocators.insert(self.sender().clone()); 175 | (true, equivocators) 176 | } else { 177 | (false, equivocators) 178 | }; 179 | self.justification().iter().fold( 180 | init, 181 | |(acc_has_equivocations, acc_equivocators), self_prime| { 182 | // Note the rotation between other and self, done because descending only on self, 183 | // thus other has to become self on the recursion to get its justification visited. 184 | let (has_equivocation, equivocators) = 185 | other.equivocates_indirect(self_prime, acc_equivocators.clone()); 186 | let acc_equivocators = acc_equivocators.union(&equivocators).cloned().collect(); 187 | (acc_has_equivocations || has_equivocation, acc_equivocators) 188 | }, 189 | ) 190 | } 191 | 192 | /// Math definition of the equivocation. 193 | pub fn equivocates(&self, other: &Self) -> bool { 194 | self != other 195 | && self.sender() == other.sender() 196 | && !other.depends(self) 197 | && !self.depends(other) 198 | } 199 | 200 | /// Checks whether self depends on other or not. Returns true if other is somewhere in the 201 | /// [`justification`] of self. Then recursively checks the justifications of the messages in the 202 | /// [`justification`] of self. This check is heavy and works well only with messages where the 203 | /// dependency is found on the surface, which is what it was designed for. 204 | /// 205 | /// [`justification`]: ../justification/struct.Justification.html 206 | pub fn depends(&self, other: &Self) -> bool { 207 | // Although the recursion ends supposedly only at genesis message, the trick is the 208 | // following: it short-circuits while descending on the dependency tree, if it finds a 209 | // dependent message. when dealing with honest validators, this would return true very 210 | // fast. all the new derived branches of the justification will be evaluated in parallel. 211 | // Say a message is justified by two other messages, then the two other messages will be 212 | // processed on different threads. This applies recursively, so if each of the two 213 | // messages have say three messages in their justifications, then each of the two threads 214 | // will spawn three new threads to process each of the messages. Thus, highly 215 | // parallelizable. When it shortcuts because in one thread a dependency was found, the 216 | // function returns true and all the computation on the other threads will be cancelled. 217 | fn recurse( 218 | lhs: &Message, 219 | rhs: &Message, 220 | visited: Arc>>>, 221 | ) -> bool { 222 | let justification = lhs.justification(); 223 | 224 | // Math definition of dependency 225 | justification.contains(rhs) 226 | || justification 227 | .par_iter() 228 | .filter(|lhs_prime| { 229 | visited 230 | .read() 231 | .map(|v| !v.contains(lhs_prime)) 232 | .ok() 233 | .unwrap_or(true) 234 | }) 235 | .any(|lhs_prime| { 236 | let visited_prime = visited.clone(); 237 | let _ = visited_prime 238 | .write() 239 | .map(|mut v| v.insert(lhs_prime.clone())) 240 | .ok(); 241 | recurse(lhs_prime, rhs, visited_prime) 242 | }) 243 | } 244 | let visited = Arc::new(RwLock::new(HashSet::new())); 245 | recurse(self, other, visited) 246 | } 247 | } 248 | 249 | impl Id for Message { 250 | type ID = Hash; 251 | 252 | // Redefine id to not recompute the hash every time 253 | fn id(&self) -> Self::ID { 254 | self.1 255 | } 256 | } 257 | 258 | impl Serialize for Message { 259 | fn serialize(&self, serializer: T) -> Result { 260 | serde::Serialize::serialize(&self.0, serializer) 261 | } 262 | } 263 | 264 | impl std::hash::Hash for Message { 265 | fn hash(&self, state: &mut H) { 266 | self.id().hash(state) 267 | } 268 | } 269 | 270 | impl PartialEq for Message { 271 | fn eq(&self, other: &Self) -> bool { 272 | Arc::ptr_eq(&self.0, &other.0) || self.id() == other.id() 273 | } 274 | } 275 | 276 | impl Debug for Message { 277 | // Note: format used for rendering illustrative gifs from generative tests; modify with care. 278 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 279 | write!(f, "M{:?}({:?})", self.sender(), self.estimate().clone()) 280 | } 281 | } 282 | 283 | #[cfg(test)] 284 | mod test { 285 | use super::*; 286 | 287 | use crate::tests_common::vote_count::VoteCount; 288 | 289 | use std::collections::HashSet; 290 | use std::iter::FromIterator; 291 | 292 | use crate::justification::LatestMessages; 293 | use crate::validator; 294 | 295 | #[test] 296 | fn message_equality() { 297 | let validator_state = validator::State::new( 298 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 299 | 0.0, 300 | LatestMessages::empty(), 301 | 0.0, 302 | HashSet::new(), 303 | ); 304 | 305 | let v0 = &VoteCount::create_vote_message(0, false); 306 | let v1 = &VoteCount::create_vote_message(1, true); 307 | let v0_prime = &VoteCount::create_vote_message(0, true); 308 | let v0_duplicate = &VoteCount::create_vote_message(0, false); 309 | 310 | let mut validator_state_clone = validator_state.clone(); 311 | validator_state_clone.update(&[v0]); 312 | let m0 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 313 | 314 | let mut validator_state_clone = validator_state.clone(); 315 | validator_state_clone.update(&[v0]); 316 | let message1 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 317 | 318 | let mut validator_state_clone = validator_state.clone(); 319 | validator_state_clone.update(&[v0]); 320 | let message2 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 321 | 322 | let mut validator_state_clone = validator_state; 323 | validator_state_clone.update(&[v0, &m0]); 324 | let message3 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 325 | 326 | assert_eq!(v0, v0_duplicate, "v0 and v0_duplicate should be equal"); 327 | assert_ne!(v0, v0_prime, "v0 and v0_prime should NOT be equal"); 328 | assert_ne!(v0, v1, "v0 and v1 should NOT be equal"); 329 | assert_eq!(message1, message2, "messages should be equal"); 330 | assert_ne!( 331 | message1, message3, 332 | "message1 should be different than message3" 333 | ); 334 | } 335 | 336 | #[test] 337 | fn message_depends() { 338 | let validator_state = validator::State::new( 339 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 340 | 0.0, 341 | LatestMessages::empty(), 342 | 0.0, 343 | HashSet::new(), 344 | ); 345 | 346 | let v0 = &VoteCount::create_vote_message(0, false); 347 | let v0_prime = &VoteCount::create_vote_message(0, true); 348 | 349 | let mut validator_state_clone = validator_state.clone(); 350 | validator_state_clone.update(&[v0]); 351 | let m0 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 352 | 353 | let mut validator_state_clone = validator_state.clone(); 354 | validator_state_clone.update(&[&v0]); 355 | let m0_2 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 356 | 357 | let mut validator_state_clone = validator_state; 358 | validator_state_clone.update(&[v0, &m0_2]); 359 | let m1 = Message::from_validator_state(0, &validator_state_clone).unwrap(); 360 | 361 | assert!( 362 | !v0.depends(v0_prime), 363 | "v0 does NOT depend on v0_prime as they are equivocating" 364 | ); 365 | assert!( 366 | !m0.depends(&m0), 367 | "m0 does NOT depend on itself directly, by our impl choice" 368 | ); 369 | assert!(!m0.depends(v0_prime), "m0 depends on v0 directly"); 370 | assert!(m0.depends(v0), "m0 depends on v0 directly"); 371 | assert!(m1.depends(&m0), "m1 DOES depend on m0"); 372 | assert!(!m0.depends(&m1), "but m0 does NOT depend on m1"); 373 | assert!(m1.depends(v0), "m1 depends on v0 through m0"); 374 | } 375 | 376 | #[test] 377 | fn message_equivocates() { 378 | let mut validator_state = validator::State::new( 379 | validator::Weights::new(vec![(0, 1.0), (1, 1.0)].into_iter().collect()), 380 | 0.0, 381 | LatestMessages::empty(), 382 | 0.0, 383 | HashSet::new(), 384 | ); 385 | 386 | let v0 = &VoteCount::create_vote_message(0, false); 387 | let v0_prime = &VoteCount::create_vote_message(0, true); 388 | let v1 = &VoteCount::create_vote_message(1, true); 389 | 390 | validator_state.update(&[&v0]); 391 | let m0 = Message::from_validator_state(0, &validator_state).unwrap(); 392 | 393 | assert!(!v0.equivocates(v0), "should be all good"); 394 | assert!(!v1.equivocates(&m0), "should be all good"); 395 | assert!(!m0.equivocates(v1), "should be all good"); 396 | assert!(v0.equivocates(v0_prime), "should be a direct equivocation"); 397 | assert!( 398 | m0.equivocates(v0_prime), 399 | "should be an indirect equivocation, equivocates to m0 through v0" 400 | ); 401 | } 402 | 403 | #[test] 404 | fn message_equivocates_indirect_direct_equivocation() { 405 | let v0 = VoteCount::create_vote_message(0, false); 406 | let v0_prime = VoteCount::create_vote_message(0, true); 407 | 408 | assert!(v0.equivocates_indirect(&v0_prime, HashSet::new()).0); 409 | } 410 | 411 | #[test] 412 | fn message_equivocates_indirect_semi_direct() { 413 | let mut validator_state = validator::State::new( 414 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 415 | 0.0, 416 | LatestMessages::empty(), 417 | 0.0, 418 | HashSet::new(), 419 | ); 420 | 421 | // v0 v1 422 | // | | 423 | // m1 | 424 | // m2 425 | // 426 | // validator 1 is equivocating 427 | 428 | let v0 = VoteCount::create_vote_message(0, false); 429 | let v1 = VoteCount::create_vote_message(1, true); 430 | 431 | validator_state.update(&[&v0]); 432 | let m1 = Message::from_validator_state(1, &validator_state).unwrap(); 433 | 434 | validator_state.update(&[&v1]); 435 | let m2 = Message::from_validator_state(2, &validator_state).unwrap(); 436 | 437 | assert!(m2.equivocates_indirect(&m1, HashSet::new()).0); 438 | 439 | // Cannot see future messages 440 | assert!(!m2.equivocates_indirect(&v0, HashSet::new()).0); 441 | assert!(!v0.equivocates_indirect(&v1, HashSet::new()).0); 442 | } 443 | 444 | #[test] 445 | fn message_equivocates_indirect_commutativity() { 446 | let mut validator_state = validator::State::new( 447 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 448 | 0.0, 449 | LatestMessages::empty(), 450 | 0.0, 451 | HashSet::new(), 452 | ); 453 | 454 | // v0 v1 455 | // | | 456 | // m1 | 457 | // m2 458 | // 459 | // validator 1 is equivocating 460 | 461 | let v0 = VoteCount::create_vote_message(0, false); 462 | let v1 = VoteCount::create_vote_message(1, true); 463 | 464 | validator_state.update(&[&v0]); 465 | let m1 = Message::from_validator_state(1, &validator_state).unwrap(); 466 | 467 | validator_state.update(&[&v1]); 468 | let m2 = Message::from_validator_state(2, &validator_state).unwrap(); 469 | 470 | // Messages are tried for equivocation in the following order: 471 | // 1. for m1.equivocates_indirect(m2): 472 | // 1. m1 _|_ m2 473 | // 2. m2 _|_ v0 474 | // 3. v0 _|_ v0 475 | // 4. v0 _|_ v1 476 | // 477 | // 2. for m2.equivocates_indirect(m1): 478 | // 1. m2 _|_ m1 479 | // 2. m1 _|_ v0 480 | // 3. v0 _|_ v0 481 | // 4. m1 _|_ v1 482 | // 5. v1 _|_ v0 483 | // 484 | // We can see that: 485 | // 1. The method is not commutative; 486 | // 2. It does not try every combinations of messages; 487 | // 3. It compares v0 with itself in both instances. 488 | 489 | assert!(!m1.equivocates_indirect(&m2, HashSet::new()).0); 490 | assert!(m2.equivocates_indirect(&m1, HashSet::new()).0); 491 | } 492 | 493 | #[test] 494 | fn message_equivocates_indirect_total_indirection() { 495 | let mut validator_state = validator::State::new( 496 | validator::Weights::new( 497 | vec![(0, 1.0), (1, 1.0), (2, 1.0), (3, 1.0)] 498 | .into_iter() 499 | .collect(), 500 | ), 501 | 0.0, 502 | LatestMessages::empty(), 503 | 0.0, 504 | HashSet::new(), 505 | ); 506 | 507 | // v0 v1 508 | // | | 509 | // m1 | 510 | // | m2 511 | // m3 512 | // 513 | // validator 1 is equivocating 514 | 515 | let v0 = VoteCount::create_vote_message(0, false); 516 | let v1 = VoteCount::create_vote_message(1, true); 517 | 518 | let mut validator_state_clone = validator_state.clone(); 519 | validator_state_clone.update(&[&v0]); 520 | let m1 = Message::from_validator_state(1, &validator_state_clone).unwrap(); 521 | 522 | validator_state_clone.update(&[&v1]); 523 | let m2 = Message::from_validator_state(2, &validator_state_clone).unwrap(); 524 | 525 | validator_state.update(&[&m1]); 526 | let m3 = Message::from_validator_state(3, &validator_state).unwrap(); 527 | 528 | // In this case, only 1 is equivocating. m1 and v1 are independant of each other. Neither 529 | // m2 or m3 are faulty messages but they are on different protocol branches created by 530 | // 1's equivocation. 531 | assert!(m2.equivocates_indirect(&m3, HashSet::new()).0); 532 | } 533 | 534 | #[test] 535 | fn from_validator_state() { 536 | let v0 = VoteCount::create_vote_message(0, false); 537 | let v1 = VoteCount::create_vote_message(1, false); 538 | let v2 = VoteCount::create_vote_message(2, true); 539 | 540 | let mut latest_messages = LatestMessages::empty(); 541 | latest_messages.update(&v0); 542 | latest_messages.update(&v1); 543 | latest_messages.update(&v2); 544 | 545 | let res = Message::from_validator_state( 546 | 0, 547 | &validator::State::new( 548 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 549 | 0.0, 550 | latest_messages, 551 | 0.0, 552 | HashSet::new(), 553 | ), 554 | ) 555 | .expect("No errors expected"); 556 | 557 | assert_eq!(*res.estimate(), VoteCount { yes: 1, no: 2 }); 558 | assert_eq!(*res.sender(), 0); 559 | assert_eq!( 560 | HashSet::<&Message>::from_iter(res.justification().iter()), 561 | HashSet::from_iter(vec![&v0, &v1, &v2]), 562 | ); 563 | } 564 | 565 | #[test] 566 | fn from_validator_state_duplicates() { 567 | let v0 = VoteCount::create_vote_message(0, true); 568 | let v0_prime = VoteCount::create_vote_message(0, true); 569 | 570 | let mut latest_messages = LatestMessages::empty(); 571 | latest_messages.update(&v0); 572 | latest_messages.update(&v0_prime); 573 | 574 | let res = Message::from_validator_state( 575 | 0, 576 | &validator::State::new( 577 | validator::Weights::new(vec![(0, 1.0)].into_iter().collect()), 578 | 0.0, 579 | latest_messages, 580 | 0.0, 581 | HashSet::new(), 582 | ), 583 | ) 584 | .expect("No errors expected"); 585 | 586 | assert_eq!(*res.estimate(), VoteCount { yes: 1, no: 0 }); 587 | assert_eq!(*res.sender(), 0); 588 | assert_eq!( 589 | HashSet::<&Message>::from_iter(res.justification().iter()), 590 | HashSet::from_iter(vec![&v0]), 591 | ); 592 | } 593 | 594 | #[test] 595 | fn from_validator_state_equivocator() { 596 | let v0 = VoteCount::create_vote_message(0, false); 597 | let v0_prime = VoteCount::create_vote_message(0, true); 598 | let v1 = VoteCount::create_vote_message(1, true); 599 | 600 | let mut latest_messages = LatestMessages::empty(); 601 | latest_messages.update(&v0); 602 | latest_messages.update(&v0_prime); 603 | latest_messages.update(&v1); 604 | 605 | let res = Message::from_validator_state( 606 | 2, 607 | &validator::State::new( 608 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 609 | 0.0, 610 | latest_messages, 611 | 4.0, 612 | HashSet::new(), 613 | ), 614 | ) 615 | .expect("No errors expected"); 616 | 617 | // No messages from the equivator in the justification. The 618 | // result is the same as from_validator_state_equivocator_at_threshhold 619 | // because from_validator_state uses the latest honest messages. 620 | assert_eq!(*res.sender(), 2); 621 | assert_eq!(*res.estimate(), VoteCount { yes: 1, no: 0 }); 622 | assert_eq!( 623 | HashSet::<&Message>::from_iter(res.justification().iter()), 624 | HashSet::from_iter(vec![&v1]), 625 | ); 626 | } 627 | 628 | #[test] 629 | fn from_validator_state_equivocator_at_threshhold() { 630 | let v0 = VoteCount::create_vote_message(0, false); 631 | let v0_prime = VoteCount::create_vote_message(0, true); 632 | let v1 = VoteCount::create_vote_message(1, true); 633 | 634 | let mut latest_messages = LatestMessages::empty(); 635 | latest_messages.update(&v0); 636 | latest_messages.update(&v0_prime); 637 | latest_messages.update(&v1); 638 | 639 | let res = Message::from_validator_state( 640 | 2, 641 | &validator::State::new( 642 | validator::Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()), 643 | 0.0, 644 | latest_messages, 645 | 0.0, 646 | HashSet::new(), 647 | ), 648 | ) 649 | .expect("No errors expected"); 650 | 651 | // No messages from the equivator in the justification. 652 | assert_eq!(*res.sender(), 2); 653 | assert_eq!(*res.estimate(), VoteCount { yes: 1, no: 0 }); 654 | assert_eq!( 655 | HashSet::<&Message>::from_iter(res.justification().iter()), 656 | HashSet::from_iter(vec![&v1]), 657 | ); 658 | } 659 | 660 | #[test] 661 | fn from_validator_state_only_equivocations() { 662 | // With an equivocator and only his messages in the State, 663 | // from_validator_state returns an error. 664 | 665 | let v0 = VoteCount::create_vote_message(0, false); 666 | let v0_prime = VoteCount::create_vote_message(0, true); 667 | 668 | let mut latest_messages = LatestMessages::empty(); 669 | latest_messages.update(&v0); 670 | latest_messages.update(&v0_prime); 671 | 672 | let res = Message::::from_validator_state( 673 | 0, 674 | &validator::State::new( 675 | validator::Weights::new(vec![(0, 1.0)].into_iter().collect()), 676 | 0.0, 677 | latest_messages, 678 | 0.0, 679 | HashSet::new(), 680 | ), 681 | ); 682 | match res { 683 | Err(Error::NoNewMessage) => (), 684 | _ => panic!("Expected NoNewMessage"), 685 | } 686 | } 687 | } 688 | -------------------------------------------------------------------------------- /src/tests_common/blockdata.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use crate::blockchain::BlockData; 22 | use crate::validator::ValidatorName; 23 | 24 | /// This block data structure contains the name of the validator that created that block. This is 25 | /// used by the tests in order to have a simple data structure. 26 | /// 27 | /// Implements [`BlockData`]. 28 | /// 29 | /// [`BlockData`]: blockchain/trait.BlockData.html 30 | /// 31 | /// # Example 32 | /// 33 | /// ``` 34 | /// use core_cbc_casper::blockchain::BlockData; 35 | /// use core_cbc_casper::ValidatorNameBlockData; 36 | /// use core_cbc_casper::validator::ValidatorName; 37 | /// 38 | /// // Using u32 as the ValidatorName, which is implemented in `core_cbc_casper::validator`. 39 | /// let data = ValidatorNameBlockData::::new(13); 40 | /// assert_eq!( 41 | /// *data.validator_name(), 42 | /// 13 43 | /// ); 44 | /// ``` 45 | #[derive(std::hash::Hash, Clone, Eq, PartialEq, Default)] 46 | pub struct ValidatorNameBlockData { 47 | validator_name: V, 48 | } 49 | 50 | impl ValidatorNameBlockData { 51 | pub fn new(validator_name: V) -> Self { 52 | ValidatorNameBlockData { validator_name } 53 | } 54 | } 55 | 56 | impl BlockData for ValidatorNameBlockData { 57 | type ValidatorName = V; 58 | 59 | fn validator_name(&self) -> &Self::ValidatorName { 60 | &self.validator_name 61 | } 62 | } 63 | 64 | impl serde::Serialize for ValidatorNameBlockData { 65 | fn serialize(&self, serializer: S) -> Result { 66 | use serde::ser::SerializeStruct; 67 | 68 | let mut s = serializer.serialize_struct("ValidatorNameBlockData", 1)?; 69 | s.serialize_field("validator_name", &self.validator_name)?; 70 | s.end() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/tests_common/integer.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::collections::HashSet; 22 | use std::iter::FromIterator; 23 | 24 | use crate::estimator::Estimator; 25 | use crate::justification::LatestMessagesHonest; 26 | use crate::message::Message; 27 | use crate::util::weight::{WeightUnit, Zero}; 28 | use crate::validator; 29 | 30 | type Validator = u32; 31 | 32 | #[derive(Clone, Eq, Debug, Ord, PartialOrd, PartialEq, Hash, serde_derive::Serialize)] 33 | pub struct IntegerWrapper(pub u32); 34 | 35 | impl IntegerWrapper { 36 | pub fn new(estimate: u32) -> Self { 37 | IntegerWrapper(estimate) 38 | } 39 | } 40 | 41 | #[cfg(feature = "integration_test")] 42 | impl From for IntegerWrapper { 43 | fn from(_validator: V) -> Self { 44 | IntegerWrapper::new(u32::default()) 45 | } 46 | } 47 | 48 | #[derive(Clone, Eq, Debug, Ord, PartialOrd, PartialEq, Hash)] 49 | pub struct Tx; 50 | 51 | #[derive(Debug, PartialEq)] 52 | pub struct Error(&'static str); 53 | 54 | impl std::fmt::Display for Error { 55 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 56 | writeln!(f, "{}", self.0) 57 | } 58 | } 59 | 60 | impl std::error::Error for Error {} 61 | 62 | impl std::convert::From<&'static str> for Error { 63 | fn from(string: &'static str) -> Self { 64 | Error(string) 65 | } 66 | } 67 | 68 | /// the goal here is to find the weighted median of all the values 69 | impl Estimator for IntegerWrapper { 70 | type ValidatorName = Validator; 71 | type Error = Error; 72 | 73 | fn estimate( 74 | latest_messages: &LatestMessagesHonest, 75 | validators_weights: &validator::Weights, 76 | ) -> Result { 77 | let mut messages_sorted_by_estimate = Vec::from_iter(latest_messages.iter().fold( 78 | HashSet::new(), 79 | |mut latest, latest_from_validator| { 80 | latest.insert(latest_from_validator); 81 | latest 82 | }, 83 | )); 84 | messages_sorted_by_estimate.sort_unstable_by(|a, b| a.estimate().cmp(&b.estimate())); 85 | 86 | // get the total weight of the validators of the messages 87 | // in the set 88 | let total_weight = messages_sorted_by_estimate 89 | .iter() 90 | .fold(>::ZERO, |acc, weight| { 91 | acc + validators_weights.weight(weight.sender()).unwrap_or(U::NAN) 92 | }); 93 | 94 | let mut running_weight = >::ZERO; 95 | let mut message_iter = messages_sorted_by_estimate.iter(); 96 | let mut current_message: Result<&&Message, &str> = Err("no message"); 97 | 98 | // since the messages are ordered according to their estimates, 99 | // whichever estimate is found after iterating over half of the total weight 100 | // is the consensus 101 | while running_weight + running_weight < total_weight { 102 | current_message = message_iter.next().ok_or("no next message"); 103 | running_weight += current_message 104 | .and_then(|message| { 105 | validators_weights 106 | .weight(message.sender()) 107 | .map_err(|_| "Can't unwrap weight") 108 | }) 109 | .unwrap_or(U::NAN) 110 | } 111 | 112 | // return said estimate 113 | current_message 114 | .map(|message| message.estimate().clone()) 115 | .map_err(From::from) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/tests_common/mod.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | pub mod blockdata; 22 | pub mod integer; 23 | pub mod vote_count; 24 | 25 | #[macro_use] 26 | pub mod utils; 27 | -------------------------------------------------------------------------------- /src/tests_common/utils.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | #[cfg(test)] 22 | macro_rules! float_eq { 23 | ($lhs:expr, $rhs:expr) => {{ 24 | assert!( 25 | f32::abs($lhs - $rhs) < std::f32::EPSILON, 26 | format!("float_eq: {} and {} aren't equal", $lhs, $rhs), 27 | ) 28 | }}; 29 | ($lhs:expr, $rhs:expr, $message:expr) => {{ 30 | assert!( 31 | f32::abs($lhs - $rhs) < std::f32::EPSILON, 32 | format!( 33 | "float_eq: {} and {} aren't equal. Provided message: {}", 34 | $lhs, $rhs, $message 35 | ), 36 | ) 37 | }}; 38 | } 39 | -------------------------------------------------------------------------------- /src/tests_common/vote_count.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::collections::HashSet; 22 | use std::fmt::{Debug, Formatter}; 23 | use std::ops::Add; 24 | 25 | #[cfg(feature = "integration_test")] 26 | use proptest::prelude::*; 27 | 28 | use crate::estimator::Estimator; 29 | use crate::justification::{Justification, LatestMessagesHonest}; 30 | use crate::message; 31 | use crate::util::weight::{WeightUnit, Zero}; 32 | use crate::validator; 33 | 34 | /// This structure represents votes count values. It implements the [`Estimator`] trait. 35 | /// Its purpose is to have a simple type (but complex enough) for the different tests and examples 36 | /// of this crate. 37 | /// 38 | /// [`Estimator`]: ../estimator/trait.Estimator.html 39 | /// 40 | /// # Example 41 | /// 42 | /// ``` 43 | /// use core_cbc_casper::VoteCount; 44 | /// 45 | /// assert_eq!( 46 | /// *VoteCount::create_vote_message(0, true).estimate(), 47 | /// VoteCount { yes: 1, no: 0 }, 48 | /// ); 49 | /// ``` 50 | #[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Default, serde_derive::Serialize)] 51 | pub struct VoteCount { 52 | pub yes: u32, 53 | pub no: u32, 54 | } 55 | 56 | #[cfg(feature = "integration_test")] 57 | impl From for VoteCount { 58 | fn from(_validator: V) -> Self { 59 | VoteCount::default() 60 | } 61 | } 62 | 63 | impl Zero for VoteCount { 64 | const ZERO: Self = Self { yes: 0, no: 0 }; 65 | } 66 | 67 | impl Add for VoteCount { 68 | type Output = Self; 69 | fn add(self, other: Self) -> Self { 70 | VoteCount { 71 | yes: self.yes + other.yes, 72 | no: self.no + other.no, 73 | } 74 | } 75 | } 76 | 77 | impl Debug for VoteCount { 78 | fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { 79 | write!(f, "y{:?}/n{:?}", self.yes, self.no) 80 | } 81 | } 82 | 83 | impl VoteCount { 84 | #[allow(dead_code)] 85 | #[cfg(feature = "integration_test")] 86 | pub fn arbitrary() -> BoxedStrategy { 87 | prop::sample::select(vec![ 88 | VoteCount { yes: 1, no: 0 }, 89 | VoteCount { yes: 0, no: 1 }, 90 | ]) 91 | .boxed() 92 | } 93 | 94 | // makes sure nobody adds more than one vote to their unjustified VoteCount 95 | // object. if they did, their vote is invalid and will be ignored 96 | fn is_valid(self) -> bool { 97 | // these two are the only allowed votes (unjustified messages) 98 | match self { 99 | VoteCount { yes: 1, no: 0 } => true, 100 | VoteCount { yes: 0, no: 1 } => true, 101 | _ => false, 102 | } 103 | } 104 | 105 | // used to create an equivocation vote 106 | pub fn toggled_vote(self) -> Self { 107 | // these two are the only allowed votes (unjustified messages) 108 | match self { 109 | VoteCount { yes: 1, no: 0 } => VoteCount { yes: 0, no: 1 }, 110 | VoteCount { yes: 0, no: 1 } => VoteCount { yes: 1, no: 0 }, 111 | _ => VoteCount::ZERO, 112 | } 113 | } 114 | 115 | /// Creates a new empty vote message, issued by the validator 116 | /// with no justification 117 | pub fn create_vote_message(validator: u32, vote: bool) -> message::Message { 118 | let justification = Justification::empty(); 119 | let estimate = if vote { 120 | VoteCount { yes: 1, no: 0 } 121 | } else { 122 | VoteCount { yes: 0, no: 1 } 123 | }; 124 | 125 | message::Message::new(validator, justification, estimate) 126 | } 127 | 128 | fn get_vote_messages( 129 | latest_messages: &LatestMessagesHonest, 130 | ) -> HashSet> { 131 | fn recursor( 132 | latest_messages: &Justification, 133 | acc: HashSet>, 134 | ) -> HashSet> { 135 | latest_messages.iter().fold(acc, |mut acc_prime, message| { 136 | match message.justification().len() { 137 | 0 => { 138 | // vote found, vote is a message with 0 justification 139 | let estimate = *message.estimate(); 140 | if estimate.is_valid() { 141 | let equivocation = message::Message::new( 142 | *message.sender(), 143 | message.justification().clone(), 144 | estimate.toggled_vote(), 145 | ); 146 | // search for the equivocation of the current latest_messages 147 | match acc_prime.get(&equivocation) { 148 | // remove the equivoted vote, none of the pair 149 | // will stay on the set 150 | Some(_) => { 151 | println!("equiv: {:?}", equivocation); 152 | acc_prime.remove(&equivocation) 153 | } 154 | // add the vote 155 | None => { 156 | // println!("no_equiv: {:?}", equivocation); 157 | acc_prime.insert((*message).clone()) 158 | } 159 | }; 160 | } 161 | acc_prime // returns it 162 | } 163 | _ => recursor(message.justification(), acc_prime), 164 | } 165 | }) 166 | } 167 | 168 | let justification = 169 | latest_messages 170 | .iter() 171 | .fold(Justification::empty(), |mut acc, message| { 172 | acc.insert(message.clone()); 173 | acc 174 | }); 175 | // start recursion 176 | recursor(&justification, HashSet::new()) 177 | } 178 | } 179 | 180 | type Voter = u32; 181 | 182 | //impl Validator for Voter {} 183 | 184 | #[derive(Debug)] 185 | pub struct Error(&'static str); 186 | 187 | impl std::fmt::Display for Error { 188 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 189 | writeln!(f, "{}", self.0) 190 | } 191 | } 192 | 193 | impl std::error::Error for Error {} 194 | 195 | impl std::convert::From<&'static str> for Error { 196 | fn from(string: &'static str) -> Self { 197 | Error(string) 198 | } 199 | } 200 | 201 | impl Estimator for VoteCount { 202 | // the estimator just counts votes, which in this case are the unjustified 203 | // messages 204 | type ValidatorName = Voter; 205 | type Error = Error; 206 | 207 | // Data could be anything, as it will not be used, will just pass None to 208 | // make_estimate, as it takes an Option 209 | // type Data = Self; 210 | 211 | fn estimate( 212 | latest_messages: &LatestMessagesHonest, 213 | _weights: &validator::Weights, // all voters have same weight 214 | ) -> Result { 215 | // the estimates are actually the original votes of each of the voters / 216 | // validators 217 | 218 | let votes = Self::get_vote_messages(latest_messages); 219 | let votes = votes 220 | .iter() 221 | .fold(Self::ZERO, |acc, vote| acc + *vote.estimate()); 222 | Ok(votes) 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/util/hash.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | fixed_hash::construct_fixed_hash!( 22 | pub struct Hash(64); 23 | ); 24 | 25 | impl serde::Serialize for Hash { 26 | fn serialize(&self, serializer: T) -> Result { 27 | serializer.serialize_bytes(&self.0) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/util/id.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | /// Define how to serialize an arbitrary structure into as stream of bytes. The 22 | /// serialization can be performed with any standard or non-standard formats but 23 | /// the **serialization MUST ensure that only one representation is valid.** 24 | /// 25 | /// Define a content able to identifie its content with an ID. The structure 26 | /// must be serializable with no malleability to ensure unique valid identifiers 27 | /// for every unique valid content. 28 | /// 29 | /// Define how to deserialize an arbitrary byte stream. **If the byte stream is 30 | /// not the unique valid representation of the structure, deserialization MUST 31 | /// fail.** 32 | /// 33 | /// ## Serialization malleability 34 | /// 35 | /// If a structure can be represented with multiple valid byte streams, then the 36 | /// content identifier is not anymore unique. The implementation MUST ensure 37 | /// only one unique valid representation. To ensure non-malleability we allow 38 | /// deserialization to fail. 39 | /// 40 | /// # Example 41 | /// 42 | /// ``` 43 | /// extern crate bincode; 44 | /// extern crate blake2; 45 | /// extern crate itertools; 46 | /// extern crate serde; 47 | /// 48 | /// use core_cbc_casper::util::hash::Hash; 49 | /// use core_cbc_casper::util::id::Id; 50 | /// 51 | /// #[derive(serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Debug)] 52 | /// struct Example { 53 | /// count: u64, 54 | /// int: i64, 55 | /// } 56 | /// 57 | /// impl Id for Example { 58 | /// type ID = Hash; 59 | /// } 60 | /// 61 | /// let example = Example { count: 10, int: -4 }; 62 | /// let serialized = example.serialize(); 63 | /// let deserialized = Example::deserialize(&serialized[..]); 64 | /// assert_eq!(example, deserialized.unwrap()); 65 | /// ``` 66 | pub trait Id: serde::Serialize { 67 | // /// Define the type of the ID generated by `id`. 68 | type ID: From<[u8; 64]> + Ord; 69 | 70 | /// Define the hashing algorithm used to get content ID based on the 71 | /// serialization provided by the default `id` method. 72 | fn hash(data: &[u8]) -> Self::ID { 73 | use blake2::{Blake2b, Digest}; 74 | let mut res = [0u8; 64]; 75 | res.copy_from_slice(&Blake2b::digest(data)); 76 | Self::ID::from(res) 77 | } 78 | 79 | fn serialize(&self) -> Vec { 80 | bincode::serialize(self).unwrap() 81 | } 82 | 83 | fn deserialize<'z>(bin: &'z [u8]) -> Result 84 | where 85 | Self: Sized + serde::Deserialize<'z>, 86 | { 87 | bincode::deserialize(bin) 88 | } 89 | 90 | /// The default method for getting the content ID is based on the 91 | /// serialization of the content. This method can be overriden by other 92 | /// mechanisms such as random or counter IDs. 93 | fn id(&self) -> Self::ID { 94 | let ser = ::serialize(self); 95 | Self::hash(&ser[..]) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/util/mod.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | pub mod hash; 22 | pub mod id; 23 | pub mod weight; 24 | -------------------------------------------------------------------------------- /src/util/weight.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::cmp::Ordering; 22 | use std::fmt::{self, Display}; 23 | use std::ops::{Add, AddAssign, Sub, SubAssign}; 24 | 25 | /// Defines how to compare the trait type to zero. 26 | /// 27 | /// This trait is implemented for the basic types u8, u16, u32, u64, i8, i16, i32, and i64. 28 | /// # Example 29 | /// 30 | /// ``` 31 | /// use core_cbc_casper::util::weight::Zero; 32 | /// 33 | /// #[derive(Copy, Clone, PartialEq)] 34 | /// struct IntWrapper { 35 | /// value: i32, 36 | /// } 37 | /// 38 | /// impl Zero for IntWrapper { 39 | /// const ZERO: Self = Self { value: 0 }; 40 | /// } 41 | /// 42 | /// assert!(IntWrapper::is_zero(&IntWrapper { value: 0 })); 43 | /// ``` 44 | pub trait Zero { 45 | const ZERO: T; 46 | 47 | /// Returns whether or not the value is equal to zero. 48 | fn is_zero(val: &T) -> bool { 49 | val == &Self::ZERO 50 | } 51 | } 52 | 53 | macro_rules! impl_zero { 54 | ( $x:ty, $z:expr ) => { 55 | impl Zero<$x> for $x { 56 | const ZERO: Self = $z; 57 | 58 | fn is_zero(val: &Self) -> bool { 59 | *val == $z 60 | } 61 | } 62 | }; 63 | } 64 | 65 | impl_zero!(u8, 0u8); 66 | impl_zero!(u16, 0u16); 67 | impl_zero!(u32, 0u32); 68 | impl_zero!(u64, 0u64); 69 | impl_zero!(i8, 0i8); 70 | impl_zero!(i16, 0i16); 71 | impl_zero!(i32, 0i32); 72 | impl_zero!(i64, 0i64); 73 | 74 | macro_rules! impl_weight_float { 75 | ( $x:ident, $z:expr ) => { 76 | impl Zero<$x> for $x { 77 | const ZERO: Self = $z; 78 | 79 | fn is_zero(val: &Self) -> bool { 80 | val > &-::std::$x::EPSILON && val < &::std::$x::EPSILON 81 | } 82 | } 83 | 84 | impl WeightUnit for $x { 85 | const NAN: Self = ::std::$x::NAN; 86 | const INFINITY: Self = ::std::$x::INFINITY; 87 | } 88 | }; 89 | } 90 | 91 | impl_weight_float!(f32, 0f32); 92 | impl_weight_float!(f64, 0f64); 93 | 94 | /// Weight units for the validators. 95 | /// 96 | /// # Example 97 | /// 98 | /// The best example is the implementation of [`Weight`]. 99 | /// 100 | /// [`Weight`]: enum.Weight.html 101 | pub trait WeightUnit 102 | where 103 | Self: Zero 104 | + Add 105 | + AddAssign 106 | + Sub 107 | + SubAssign 108 | + Sized 109 | + PartialEq 110 | + PartialOrd 111 | + Copy, 112 | { 113 | /// Represent not a number 114 | const NAN: Self; 115 | /// Points to infinity 116 | const INFINITY: Self; 117 | } 118 | 119 | /// Generic implementation of weight with any units that implement `std::ops::Add` and 120 | /// `std::ops::Sub`. This type wraps the unit in a system with an infinity point and a 121 | /// "not a number" point used by the algorithms. 122 | /// 123 | /// Implements [`WeightUnit`] and [`Zero`]. 124 | /// 125 | /// [`WeightUnit`]: trait.WeightUnit.html 126 | /// [`Zero`]: trait.Zero.html 127 | /// 128 | /// # Example 129 | /// 130 | /// ``` 131 | /// use core_cbc_casper::util::weight::Weight::{self, *}; 132 | /// 133 | /// assert_eq!(Unit(2), Unit(1) + Unit(1)); 134 | /// assert_eq!(Infinity, Unit(1) + Infinity); 135 | /// assert_eq!(Weight::::NaN.to_string(), (Unit(1) + NaN).to_string()); 136 | /// ``` 137 | #[derive(Clone, Copy)] 138 | pub enum Weight 139 | where 140 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 141 | { 142 | Unit(T), 143 | Infinity, 144 | NaN, 145 | } 146 | 147 | impl Zero> for Weight 148 | where 149 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 150 | { 151 | const ZERO: Self = Weight::Unit(>::ZERO); 152 | 153 | fn is_zero(val: &Self) -> bool { 154 | use Weight::*; 155 | 156 | match val { 157 | Unit(u) => *u == >::ZERO, 158 | _ => false, 159 | } 160 | } 161 | } 162 | 163 | impl PartialEq for Weight 164 | where 165 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 166 | { 167 | fn eq(&self, other: &Self) -> bool { 168 | use Weight::*; 169 | 170 | match self { 171 | Unit(lhs) => match other { 172 | Unit(rhs) => lhs == rhs, 173 | _ => false, 174 | }, 175 | Infinity => match other { 176 | // Inf equal Inf 177 | Infinity => true, 178 | // not equal to weight or NaN 179 | _ => false, 180 | }, 181 | // NaN never equal to something 182 | NaN => false, 183 | } 184 | } 185 | } 186 | 187 | impl PartialOrd for Weight 188 | where 189 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 190 | { 191 | fn partial_cmp(&self, other: &Self) -> Option { 192 | use Weight::*; 193 | 194 | match self { 195 | Unit(lhs) => match other { 196 | Unit(rhs) => lhs.partial_cmp(rhs), 197 | // number always smaller than infinity 198 | Infinity => Some(Ordering::Less), 199 | // NaN is not comparable 200 | NaN => None, 201 | }, 202 | Infinity => match other { 203 | Unit(_) => Some(Ordering::Greater), 204 | // Inf is equal to Inf 205 | Infinity => Some(Ordering::Equal), 206 | // NaN is not comparable 207 | NaN => None, 208 | }, 209 | // NaN is not comparable 210 | NaN => None, 211 | } 212 | } 213 | } 214 | 215 | impl Add for Weight 216 | where 217 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 218 | { 219 | type Output = Self; 220 | 221 | fn add(self, other: Self) -> Self { 222 | use Weight::*; 223 | 224 | match self { 225 | Unit(lhs) => match other { 226 | Unit(rhs) => Unit(lhs + rhs), 227 | Infinity => Infinity, 228 | NaN => NaN, 229 | }, 230 | Infinity => match other { 231 | // NaN is always NaN 232 | NaN => NaN, 233 | // not NaN + Infinity is always Infinity 234 | _ => Infinity, 235 | }, 236 | NaN => NaN, 237 | } 238 | } 239 | } 240 | 241 | impl AddAssign for Weight 242 | where 243 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 244 | { 245 | fn add_assign(&mut self, other: Self) { 246 | *self = *self + other; 247 | } 248 | } 249 | 250 | impl Sub for Weight 251 | where 252 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 253 | { 254 | type Output = Self; 255 | 256 | fn sub(self, other: Self) -> Self { 257 | use Weight::*; 258 | 259 | match self { 260 | Unit(lhs) => match other { 261 | Unit(rhs) => Unit(lhs - rhs), 262 | Infinity => Infinity, 263 | NaN => NaN, 264 | }, 265 | Infinity => match other { 266 | // NaN is always NaN 267 | NaN => NaN, 268 | // Infinity - Infinity is not a number 269 | Infinity => NaN, 270 | // Infinity - x is still infinity 271 | Unit(_) => Infinity, 272 | }, 273 | NaN => NaN, 274 | } 275 | } 276 | } 277 | 278 | impl SubAssign for Weight 279 | where 280 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 281 | { 282 | fn sub_assign(&mut self, other: Self) { 283 | *self = *self - other; 284 | } 285 | } 286 | 287 | impl Display for Weight 288 | where 289 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 290 | { 291 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 292 | use Weight::*; 293 | match self { 294 | Unit(int) => write!(f, "{}", int), 295 | Infinity => write!(f, "inf"), 296 | NaN => write!(f, "NaN"), 297 | } 298 | } 299 | } 300 | 301 | impl fmt::Debug for Weight 302 | where 303 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 304 | { 305 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 306 | write!(f, "{}", self) 307 | } 308 | } 309 | 310 | impl WeightUnit for Weight 311 | where 312 | T: Zero + Add + Sub + PartialEq + PartialOrd + Copy + Display, 313 | { 314 | const NAN: Self = Weight::NaN; 315 | const INFINITY: Self = Weight::Infinity; 316 | } 317 | 318 | #[cfg(test)] 319 | mod tests { 320 | use super::Weight::{self, *}; 321 | 322 | // NaN is converted into string because NaN != NaN and then failed to pass 323 | // the tests. 324 | 325 | #[test] 326 | fn addition() { 327 | assert_eq!(Unit(2), Unit(1) + Unit(1)); 328 | assert_eq!(Infinity, Unit(1) + Infinity); 329 | assert_eq!(Weight::::NaN.to_string(), (Unit(1) + NaN).to_string()); 330 | assert_eq!( 331 | Weight::::NaN.to_string(), 332 | (Weight::::NaN + Weight::::NaN).to_string() 333 | ); 334 | assert_eq!(Infinity, Infinity + Unit(1)); 335 | assert_eq!( 336 | Weight::::NaN.to_string(), 337 | (Infinity + Weight::::NaN).to_string() 338 | ); 339 | assert_eq!(Weight::::Infinity, Infinity + Infinity); 340 | } 341 | 342 | #[test] 343 | #[allow(clippy::eq_op)] 344 | fn substraction() { 345 | assert_eq!(Unit(0), Unit(1) - Unit(1)); 346 | assert_eq!(Infinity, Unit(1) - Infinity); 347 | assert_eq!(Weight::::NaN.to_string(), (Unit(1) - NaN).to_string()); 348 | assert_eq!( 349 | Weight::::NaN.to_string(), 350 | (Weight::::NaN - Weight::::NaN).to_string() 351 | ); 352 | assert_eq!(Infinity, Infinity - Unit(1)); 353 | assert_eq!( 354 | Weight::::NaN.to_string(), 355 | (Infinity - Weight::::NaN).to_string() 356 | ); 357 | assert_eq!( 358 | Weight::::NaN.to_string(), 359 | (Infinity - Weight::::Infinity).to_string() 360 | ); 361 | } 362 | 363 | #[test] 364 | #[allow(clippy::eq_op)] 365 | fn equality() { 366 | assert_eq!(true, Unit(1) == Unit(1)); 367 | assert_eq!(false, Unit(1) == Infinity); 368 | assert_eq!(false, Unit(1) == NaN); 369 | assert_eq!(false, Weight::::NaN == Weight::::NaN); 370 | assert_eq!(false, Infinity == Weight::::NaN); 371 | assert_eq!(true, Infinity == Weight::::Infinity); 372 | } 373 | 374 | #[test] 375 | #[allow(clippy::eq_op)] 376 | fn greater() { 377 | assert_eq!(false, Unit(1) > Unit(1)); 378 | assert_eq!(true, Unit(1) >= Unit(1)); 379 | assert_eq!(false, Unit(1) > Weight::::Infinity); 380 | assert_eq!(false, Unit(1) >= Weight::::Infinity); 381 | assert_eq!(false, Unit(1) > Weight::::NaN); 382 | assert_eq!(false, Unit(1) >= Weight::::NaN); 383 | assert_eq!(false, Weight::::NaN > Weight::::NaN); 384 | assert_eq!(false, Weight::::NaN >= Weight::::NaN); 385 | assert_eq!(false, Weight::::Infinity > Weight::::NaN); 386 | assert_eq!(false, Weight::::Infinity >= Weight::::NaN); 387 | assert_eq!(true, Weight::::Infinity > Unit(1)); 388 | assert_eq!(true, Weight::::Infinity >= Unit(1)); 389 | assert_eq!(false, Weight::::Infinity > Weight::::Infinity); 390 | assert_eq!(true, Weight::::Infinity >= Weight::::Infinity); 391 | } 392 | 393 | #[test] 394 | #[allow(clippy::eq_op)] 395 | fn smaller() { 396 | assert_eq!(true, Unit(1) <= Unit(1)); 397 | assert_eq!(false, Unit(1) < Unit(1)); 398 | assert_eq!(true, Unit(1) <= Weight::::Infinity); 399 | assert_eq!(true, Unit(1) < Weight::::Infinity); 400 | assert_eq!(false, Unit(1) <= Weight::::NaN); 401 | assert_eq!(false, Unit(1) < Weight::::NaN); 402 | assert_eq!(false, Weight::::NaN <= Weight::::NaN); 403 | assert_eq!(false, Weight::::NaN < Weight::::NaN); 404 | assert_eq!(false, Weight::::NaN <= Weight::::Infinity); 405 | assert_eq!(false, Weight::::NaN < Weight::::Infinity); 406 | assert_eq!(false, Weight::::NaN <= Unit(1)); 407 | assert_eq!(false, Weight::::NaN < Unit(1)); 408 | assert_eq!(false, Weight::::Infinity <= Weight::::NaN); 409 | assert_eq!(false, Weight::::Infinity < Weight::::NaN); 410 | assert_eq!(true, Weight::::Infinity <= Weight::::Infinity); 411 | assert_eq!(false, Weight::::Infinity < Weight::::Infinity); 412 | assert_eq!(false, Weight::::Infinity <= Unit(1)); 413 | assert_eq!(false, Weight::::Infinity < Unit(1)); 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /src/validator.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::cmp::Ordering; 22 | use std::collections::{HashMap, HashSet}; 23 | use std::fmt::Debug; 24 | use std::hash::Hash; 25 | use std::sync::{Arc, LockResult, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; 26 | 27 | use crate::estimator::Estimator; 28 | use crate::justification::LatestMessages; 29 | use crate::message::Message; 30 | use crate::util::id::Id; 31 | use crate::util::weight::{WeightUnit, Zero}; 32 | 33 | /// All casper actors that send [`messages`], aka validators, have to implement the validator name 34 | /// trait. This trait serves as an identifier for validators. 35 | /// 36 | /// The basic types u8, u32, u64, i8, i32, and i64 implement ValidatorName trivially. 37 | /// 38 | /// [`messages`]: ../message/struct.Message.html 39 | /// 40 | /// # Example 41 | /// 42 | /// ``` 43 | /// use core_cbc_casper::validator::Weights; 44 | /// use core_cbc_casper::validator::ValidatorName; 45 | /// 46 | /// #[derive(Hash, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, serde_derive::Serialize)] 47 | /// struct StringName { 48 | /// name: String, 49 | /// } 50 | /// 51 | /// // Implementing the ValidatorName trait for a string wrapper. 52 | /// impl ValidatorName for StringName {}; 53 | /// 54 | /// let weights = Weights::new( 55 | /// vec![(StringName { name: "John".to_string() }, 1.0)].into_iter().collect(), 56 | /// ); 57 | /// 58 | /// // We can find the weight a validator in a Weights structure using its name. 59 | /// assert_eq!( 60 | /// weights.weight(&StringName { name: "John".to_string() }).unwrap(), 61 | /// 1.0, 62 | /// ); 63 | /// ``` 64 | pub trait ValidatorName: Hash + Clone + Ord + Eq + Send + Sync + Debug + serde::Serialize {} 65 | 66 | // Default implementations for simple types. 67 | impl ValidatorName for u8 {} 68 | impl ValidatorName for u32 {} 69 | impl ValidatorName for u64 {} 70 | impl ValidatorName for i8 {} 71 | impl ValidatorName for i32 {} 72 | impl ValidatorName for i64 {} 73 | 74 | /// Inner state of a [`validator`]. This represents the validator's view of the network. 75 | /// 76 | /// [`validator`]: trait.ValidatorName.html 77 | /// 78 | /// # Example 79 | /// 80 | /// Using the [`VoteCount`] type message type for brevity's sake. 81 | /// 82 | /// [`VoteCount`]: ../struct.VoteCount.html 83 | /// 84 | /// ``` 85 | /// use core_cbc_casper::justification::LatestMessages; 86 | /// use core_cbc_casper::validator::{State, Weights}; 87 | /// use core_cbc_casper::VoteCount; 88 | /// 89 | /// use std::collections::HashSet; 90 | /// use std::iter::FromIterator; 91 | /// 92 | /// let mut state = State::new( 93 | /// Weights::new(vec![(0, 1.0)].into_iter().collect()), 94 | /// 0.0, 95 | /// LatestMessages::empty(), 96 | /// 2.0, 97 | /// HashSet::new(), 98 | /// ); 99 | /// 100 | /// state.update(&[ 101 | /// &VoteCount::create_vote_message(0, true), 102 | /// &VoteCount::create_vote_message(0, false), 103 | /// ]); 104 | /// 105 | /// assert_eq!( 106 | /// *state.latests_messages().get(&0).unwrap(), 107 | /// HashSet::from_iter(vec![ 108 | /// VoteCount::create_vote_message(0, true), 109 | /// VoteCount::create_vote_message(0, false), 110 | /// ]), 111 | /// ); 112 | /// assert_eq!( 113 | /// *state.equivocators(), 114 | /// HashSet::from_iter(vec![0]), 115 | /// ); 116 | /// ``` 117 | #[derive(Debug, Clone)] 118 | pub struct State 119 | where 120 | E: Estimator, 121 | U: WeightUnit, 122 | { 123 | /// Current state total fault weight 124 | pub(crate) state_fault_weight: U, 125 | /// Fault tolerance threshold 126 | pub(crate) thr: U, 127 | /// Current validator set, mapped to their respective weights 128 | pub(crate) validators_weights: Weights, 129 | pub(crate) latest_messages: LatestMessages, 130 | pub(crate) equivocators: HashSet, 131 | } 132 | 133 | /// Error returned from the [`insert`], [`validators`] and [`weight`] function 134 | /// on a [`Weights`] 135 | /// 136 | /// [`insert`]: struct.Weights.html#method.insert 137 | /// [`validators`]: struct.Weights.html#method.validators 138 | /// [`weight`]: struct.Weights.html#method.weight 139 | /// [`Weights`]: struct.Weights.html 140 | pub enum Error<'rwlock, T> { 141 | WriteLockError(PoisonError>), 142 | ReadLockError(PoisonError>), 143 | NotFound, 144 | } 145 | 146 | impl<'rwlock, T> std::error::Error for Error<'rwlock, T> {} 147 | 148 | impl<'rwlock, T> std::fmt::Display for Error<'rwlock, T> { 149 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 150 | match self { 151 | Error::NotFound => writeln!(f, "Validator weight not found"), 152 | Error::WriteLockError(p_err) => std::fmt::Display::fmt(p_err, f), 153 | Error::ReadLockError(p_err) => std::fmt::Display::fmt(p_err, f), 154 | } 155 | } 156 | } 157 | 158 | impl<'rwlock, T> std::fmt::Debug for Error<'rwlock, T> { 159 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 160 | match self { 161 | Error::NotFound => writeln!(f, "Validator weight not found"), 162 | Error::WriteLockError(p_err) => std::fmt::Display::fmt(p_err, f), 163 | Error::ReadLockError(p_err) => std::fmt::Display::fmt(p_err, f), 164 | } 165 | } 166 | } 167 | 168 | impl State 169 | where 170 | E: Estimator, 171 | U: WeightUnit, 172 | { 173 | pub fn new( 174 | validators_weights: Weights, 175 | state_fault_weight: U, 176 | latest_messages: LatestMessages, 177 | thr: U, 178 | equivocators: HashSet, 179 | ) -> Self { 180 | State { 181 | validators_weights, 182 | equivocators, 183 | state_fault_weight, 184 | thr, 185 | latest_messages, 186 | } 187 | } 188 | 189 | pub fn new_with_default_state( 190 | default_state: Self, 191 | validators_weights: Option>, 192 | state_fault_weight: Option, 193 | latest_messages: Option>, 194 | thr: Option, 195 | equivocators: Option>, 196 | ) -> Self { 197 | State { 198 | validators_weights: validators_weights.unwrap_or(default_state.validators_weights), 199 | state_fault_weight: state_fault_weight.unwrap_or(default_state.state_fault_weight), 200 | latest_messages: latest_messages.unwrap_or(default_state.latest_messages), 201 | thr: thr.unwrap_or(default_state.thr), 202 | equivocators: equivocators.unwrap_or(default_state.equivocators), 203 | } 204 | } 205 | 206 | /// Adds messages to the state's [`latests_messages`]. Returns true if 207 | /// all messages added are valid latest messages. 208 | /// 209 | /// [`latests_messages`]: ../justification/struct.LatestMessages.html 210 | pub fn update(&mut self, messages: &[&Message]) -> bool { 211 | messages.iter().fold(true, |acc, message| { 212 | let sender = message.sender(); 213 | let weight = self 214 | .validators_weights 215 | .weight(sender) 216 | .unwrap_or(U::INFINITY); 217 | 218 | let update_success = self.latest_messages.update(message); 219 | 220 | if self.latest_messages.equivocate(message) 221 | && weight + self.state_fault_weight <= self.thr 222 | && self.equivocators.insert(sender.clone()) 223 | { 224 | self.state_fault_weight += weight; 225 | } 226 | 227 | acc && update_success 228 | }) 229 | } 230 | 231 | pub fn equivocators(&self) -> &HashSet { 232 | &self.equivocators 233 | } 234 | 235 | pub fn validators_weights(&self) -> &Weights { 236 | &self.validators_weights 237 | } 238 | 239 | pub fn latests_messages(&self) -> &LatestMessages { 240 | &self.latest_messages 241 | } 242 | 243 | pub fn latests_messages_as_mut(&mut self) -> &mut LatestMessages { 244 | &mut self.latest_messages 245 | } 246 | 247 | pub fn fault_weight(&self) -> U { 248 | self.state_fault_weight 249 | } 250 | 251 | /// Returns a vector containing sorted messages. They are sorted by the fault weight they would 252 | /// introduce in the state. If they would not be introduced because their validators are either 253 | /// honest or already equivocating, they are tie-breaked using the messages' hashes. 254 | pub fn sort_by_faultweight<'z>( 255 | &self, 256 | messages: &HashSet<&'z Message>, 257 | ) -> Vec<&'z Message> { 258 | let mut messages_sorted_by_faultw: Vec<_> = messages 259 | .iter() 260 | .filter_map(|&message| { 261 | // equivocations in relation to state 262 | let sender = message.sender(); 263 | if !self.equivocators.contains(sender) && self.latest_messages.equivocate(message) { 264 | self.validators_weights 265 | .weight(sender) 266 | .map(|weight| (message, weight)) 267 | .ok() 268 | } else { 269 | Some((message, >::ZERO)) 270 | } 271 | }) 272 | .collect(); 273 | 274 | messages_sorted_by_faultw.sort_unstable_by(|(m0, w0), (m1, w1)| match w0.partial_cmp(w1) { 275 | None | Some(Ordering::Equal) => m0.id().cmp(&m1.id()), 276 | Some(ord) => ord, 277 | }); 278 | 279 | messages_sorted_by_faultw 280 | .iter() 281 | .map(|(message, _)| message) 282 | .cloned() 283 | .collect() 284 | } 285 | } 286 | 287 | /// This type maps [`validators`] with their [`weights`]. 288 | /// 289 | /// [`validators`]: trait.ValidatorName.html 290 | /// [`weights`]: ../util/weight/trait.WeightUnit.html 291 | /// 292 | /// # Example 293 | /// 294 | /// ``` 295 | /// use core_cbc_casper::validator::Weights; 296 | /// 297 | /// let weights = Weights::new(vec![(0, 1.0), (1, 2.0), (2, 4.0)].into_iter().collect()); 298 | /// 299 | /// assert_eq!( 300 | /// weights.sum_all_weights(), 301 | /// 7.0, 302 | /// ); 303 | /// ``` 304 | #[derive(Clone, Debug)] 305 | pub struct Weights(Arc>>); 306 | 307 | impl Weights { 308 | /// Creates a new `Weights` struct from a `HashMap` of [`ValidatorName`] to [`WeightUnit`]. 309 | /// 310 | /// [`ValidatorName`]: trait.ValidatorName.html 311 | /// [`WeightUnit`]: ../util/weight/trait.WeightUnit.html 312 | pub fn new(weights: HashMap) -> Self { 313 | Weights(Arc::new(RwLock::new(weights))) 314 | } 315 | 316 | /// Same as RwLock read function. Locks the Rwlock with read access. 317 | fn read(&self) -> LockResult>> { 318 | self.0.read() 319 | } 320 | 321 | /// Same as RwLock write function. Locks the RwLock with write access. 322 | fn write(&self) -> LockResult>> { 323 | self.0.write() 324 | } 325 | 326 | /// Returns success of insertion. Failure happens if we cannot acquire the lock to write data. 327 | pub fn insert(&mut self, validator: V, weight: U) -> Result>> { 328 | self.write() 329 | .map_err(Error::WriteLockError) 330 | .map(|mut hash_map| { 331 | hash_map.insert(validator, weight); 332 | true 333 | }) 334 | } 335 | 336 | /// Picks validators with positive weights strictly greater than zero. 337 | /// Failure happens if we cannot acquire the lock to read data. 338 | pub fn validators(&self) -> Result, Error>> { 339 | self.read().map_err(Error::ReadLockError).map(|hash_map| { 340 | hash_map 341 | .iter() 342 | .filter_map(|(validator, &weight)| { 343 | if weight > >::ZERO { 344 | Some(validator.clone()) 345 | } else { 346 | None 347 | } 348 | }) 349 | .collect() 350 | }) 351 | } 352 | 353 | /// Gets the weight of the validator. Returns an error in case there is a 354 | /// reading error or the validator does not exist. 355 | pub fn weight(&self, validator: &V) -> Result>> { 356 | self.read() 357 | .map_err(Error::ReadLockError) 358 | .and_then(|hash_map| { 359 | hash_map 360 | .get(validator) 361 | .map(Clone::clone) 362 | .ok_or(Error::NotFound) 363 | }) 364 | } 365 | 366 | /// Returns the total weight of all the given validators. 367 | pub fn sum_weight_validators(&self, validators: &HashSet) -> U { 368 | validators 369 | .iter() 370 | .fold(>::ZERO, |acc, validator| { 371 | acc + self.weight(validator).unwrap_or(U::NAN) 372 | }) 373 | } 374 | 375 | /// Returns the total weight of all the validators in `self`. 376 | pub fn sum_all_weights(&self) -> U { 377 | if let Ok(validators) = self.validators() { 378 | self.sum_weight_validators(&validators) 379 | } else { 380 | U::NAN 381 | } 382 | } 383 | } 384 | 385 | #[cfg(test)] 386 | mod tests { 387 | use super::*; 388 | 389 | use crate::VoteCount; 390 | 391 | use std::iter::FromIterator; 392 | 393 | #[test] 394 | fn weights_validators_include_positive_weight() { 395 | let weights = Weights::new(vec![(0, 1.0), (1, 1.0), (2, 1.0)].into_iter().collect()); 396 | assert_eq!( 397 | weights.validators().unwrap(), 398 | vec![0, 1, 2].into_iter().collect(), 399 | "should include validators with valid, positive weight" 400 | ); 401 | } 402 | 403 | #[test] 404 | fn weights_validators_exclude_zero_weighted_validators() { 405 | let weights = Weights::new(vec![(0, 0.0), (1, 1.0), (2, 1.0)].into_iter().collect()); 406 | assert_eq!( 407 | weights.validators().unwrap(), 408 | vec![1, 2].into_iter().collect(), 409 | "should exclude validators with 0 weight" 410 | ); 411 | } 412 | 413 | #[test] 414 | fn weights_validators_exclude_negative_weights() { 415 | let weights = Weights::new(vec![(0, 1.0), (1, -1.0), (2, 1.0)].into_iter().collect()); 416 | assert_eq!( 417 | weights.validators().unwrap(), 418 | vec![0, 2].into_iter().collect(), 419 | "should exclude validators with negative weight" 420 | ); 421 | } 422 | 423 | #[test] 424 | fn weights_validators_exclude_nan_weights() { 425 | let weights = Weights::new( 426 | vec![(0, f32::NAN), (1, 1.0), (2, 1.0)] 427 | .into_iter() 428 | .collect(), 429 | ); 430 | assert_eq!( 431 | weights.validators().unwrap(), 432 | vec![1, 2].into_iter().collect(), 433 | "should exclude validators with NAN weight" 434 | ); 435 | } 436 | 437 | #[test] 438 | fn weights_validators_include_infinity_weighted_validators() { 439 | let weights = Weights::new( 440 | vec![(0, f32::INFINITY), (1, 1.0), (2, 1.0)] 441 | .into_iter() 442 | .collect(), 443 | ); 444 | assert_eq!( 445 | weights.validators().unwrap(), 446 | vec![0, 1, 2].into_iter().collect(), 447 | "should include validators with INFINITY weight" 448 | ); 449 | } 450 | 451 | #[test] 452 | fn weights_weight() { 453 | let weights = Weights::new( 454 | vec![(0, 1.0), (1, -1.0), (2, f32::INFINITY)] 455 | .into_iter() 456 | .collect(), 457 | ); 458 | // Accessing the weights directly does not hide anything 459 | float_eq!(weights.weight(&0).unwrap(), 1.0); 460 | float_eq!(weights.weight(&1).unwrap(), -1.0); 461 | assert!(weights.weight(&2).unwrap().is_infinite()); 462 | } 463 | 464 | #[test] 465 | fn weights_weight_not_found() { 466 | let weights = Weights::::new(vec![].into_iter().collect()); 467 | match weights.weight(&0) { 468 | Err(Error::NotFound) => (), 469 | _ => panic!("Expected Error::NotFound"), 470 | }; 471 | } 472 | 473 | #[test] 474 | fn weights_sum_weight_validators() { 475 | let weights = Weights::new( 476 | vec![(0, 1.0), (1, -1.0), (2, 3.3), (3, f32::INFINITY)] 477 | .into_iter() 478 | .collect(), 479 | ); 480 | assert!(weights 481 | .sum_weight_validators(&HashSet::from_iter(vec![0, 1, 3])) 482 | .is_infinite()); 483 | float_eq!( 484 | weights.sum_weight_validators(&HashSet::from_iter(vec![0, 1])), 485 | 0.0 486 | ); 487 | float_eq!( 488 | weights.sum_weight_validators(&HashSet::from_iter(vec![0, 2])), 489 | 4.3 490 | ); 491 | assert!(weights 492 | .sum_weight_validators(&HashSet::from_iter(vec![4])) 493 | .is_nan()); 494 | } 495 | 496 | #[test] 497 | fn weights_sum_all_weights() { 498 | let weights = Weights::new(vec![(0, 2.0), (1, -1.0), (2, 3.3)].into_iter().collect()); 499 | // Does not account for negatively weigthed validators 500 | float_eq!( 501 | weights.sum_all_weights(), 502 | weights.sum_weight_validators(&HashSet::from_iter(vec![0, 2])) 503 | ); 504 | } 505 | 506 | #[test] 507 | fn validator_state_update() { 508 | let mut validator_state = State::new( 509 | Weights::new(vec![(0, 1.0), (1, 1.0)].into_iter().collect()), 510 | 0.0, 511 | LatestMessages::empty(), 512 | 2.0, 513 | HashSet::new(), 514 | ); 515 | 516 | let v0 = VoteCount::create_vote_message(0, false); 517 | let v1 = VoteCount::create_vote_message(1, true); 518 | 519 | let all_valid = validator_state.update(&[&v0, &v1]); 520 | 521 | let hs0 = validator_state 522 | .latests_messages() 523 | .get(&0) 524 | .expect("state should contain validator 0"); 525 | let hs1 = validator_state 526 | .latests_messages() 527 | .get(&1) 528 | .expect("state should contain validator 1"); 529 | 530 | assert!(all_valid, "messages should not be all valid messages"); 531 | assert_eq!( 532 | hs0.len(), 533 | 1, 534 | "validator_state should have only 1 message for validator 0", 535 | ); 536 | assert_eq!( 537 | hs1.len(), 538 | 1, 539 | "validator_state should have only 1 message for validator 1", 540 | ); 541 | assert!(hs0.contains(&v0), "validator_state should contain v0"); 542 | assert!(hs1.contains(&v1), "validator_state should contain v1"); 543 | float_eq!( 544 | validator_state.fault_weight(), 545 | 0.0, 546 | "fault weight should be 0" 547 | ); 548 | assert!( 549 | validator_state.equivocators().is_empty(), 550 | "no equivocators should exist", 551 | ); 552 | } 553 | 554 | #[test] 555 | fn validator_state_update_equivocate_under_threshold() { 556 | let mut validator_state = State::new( 557 | Weights::new(vec![(0, 1.0), (1, 1.0)].into_iter().collect()), 558 | 0.0, 559 | LatestMessages::empty(), 560 | 2.0, 561 | HashSet::new(), 562 | ); 563 | 564 | let v0 = VoteCount::create_vote_message(0, false); 565 | let v0_prime = VoteCount::create_vote_message(0, true); 566 | let v1 = VoteCount::create_vote_message(1, true); 567 | 568 | let all_valid = validator_state.update(&[&v0, &v0_prime, &v1]); 569 | 570 | let hs0 = validator_state 571 | .latests_messages() 572 | .get(&0) 573 | .expect("state should contain validator 0"); 574 | let hs1 = validator_state 575 | .latests_messages() 576 | .get(&1) 577 | .expect("state should contain validator 1"); 578 | 579 | assert!(all_valid, "messages should not be all valid messages"); 580 | assert_eq!( 581 | hs0.len(), 582 | 2, 583 | "validator_state should have 2 messages for validator 0", 584 | ); 585 | assert_eq!( 586 | hs1.len(), 587 | 1, 588 | "validator_state should have only 1 message for validator 1", 589 | ); 590 | assert!(hs0.contains(&v0), "validator_state should contain v0"); 591 | assert!( 592 | hs0.contains(&v0_prime), 593 | "validator_state should contain v0_prime", 594 | ); 595 | assert!(hs1.contains(&v1), "validator_state should contain v1"); 596 | float_eq!( 597 | validator_state.fault_weight(), 598 | 1.0, 599 | "fault weight should be 1" 600 | ); 601 | assert!( 602 | validator_state.equivocators().contains(&0), 603 | "validator 0 should be in equivocators", 604 | ); 605 | } 606 | 607 | #[test] 608 | fn validator_state_update_equivocate_at_threshold() { 609 | let mut validator_state = State::new( 610 | Weights::new(vec![(0, 1.0), (1, 1.0)].into_iter().collect()), 611 | 0.0, 612 | LatestMessages::empty(), 613 | 0.0, 614 | HashSet::new(), 615 | ); 616 | 617 | let v0 = VoteCount::create_vote_message(0, false); 618 | let v0_prime = VoteCount::create_vote_message(0, true); 619 | let v1 = VoteCount::create_vote_message(1, true); 620 | 621 | let all_valid = validator_state.update(&[&v0, &v0_prime, &v1]); 622 | 623 | let hs0 = validator_state 624 | .latests_messages() 625 | .get(&0) 626 | .expect("state should contain validator 0"); 627 | let hs1 = validator_state 628 | .latests_messages() 629 | .get(&1) 630 | .expect("state should contain validator 1"); 631 | 632 | assert!(all_valid, "messages should not be all valid messages"); 633 | assert_eq!( 634 | hs0.len(), 635 | 2, 636 | "validator_state should have 2 messages for validator 0", 637 | ); 638 | assert_eq!( 639 | hs1.len(), 640 | 1, 641 | "validator_state should have only 1 message for validator 1", 642 | ); 643 | assert!(hs0.contains(&v0), "validator_state should contain v0"); 644 | assert!( 645 | hs0.contains(&v0_prime), 646 | "validator_state should contain v0_prime", 647 | ); 648 | assert!(hs1.contains(&v1), "validator_state should contain v1"); 649 | float_eq!( 650 | validator_state.fault_weight(), 651 | 0.0, 652 | "fault weight should be 0" 653 | ); 654 | assert!( 655 | validator_state.equivocators().is_empty(), 656 | "validator 0 should not be in equivocators" 657 | ); 658 | } 659 | 660 | #[test] 661 | fn state_sort_by_faultweight_unknown_equivocators() { 662 | let v0_prime = VoteCount::create_vote_message(0, false); 663 | let v1_prime = VoteCount::create_vote_message(1, true); 664 | let v2_prime = VoteCount::create_vote_message(2, true); 665 | 666 | let get_sorted_vec_with_weights = |weights: Vec<(u32, f32)>| { 667 | let mut state = State::new( 668 | Weights::new(weights.into_iter().collect()), 669 | 0.0, 670 | LatestMessages::empty(), 671 | 10.0, 672 | HashSet::new(), 673 | ); 674 | let v0 = VoteCount::create_vote_message(0, true); 675 | let v1 = VoteCount::create_vote_message(1, false); 676 | let v2 = VoteCount::create_vote_message(2, false); 677 | state.update(&[&v0, &v1, &v2]); 678 | state.sort_by_faultweight(&HashSet::from_iter(vec![&v0_prime, &v1_prime, &v2_prime])) 679 | }; 680 | 681 | // As v0_prime, v1_prime and v2_prime would change the fault weight, the weight of their 682 | // validators influence the sort. 683 | assert_eq!( 684 | get_sorted_vec_with_weights(vec![(0, 1.0), (1, 2.0), (2, 3.0)]), 685 | [&v0_prime, &v1_prime, &v2_prime] 686 | ); 687 | assert_eq!( 688 | get_sorted_vec_with_weights(vec![(0, 2.0), (1, 1.0), (2, 3.0)]), 689 | [&v1_prime, &v0_prime, &v2_prime] 690 | ); 691 | } 692 | 693 | #[test] 694 | fn state_sort_by_faultweight_known_equivocators() { 695 | fn test_with_weights(weights: Vec<(u32, f32)>) { 696 | let mut state = State::new( 697 | Weights::new(weights.into_iter().collect()), 698 | 0.0, 699 | LatestMessages::empty(), 700 | 10.0, 701 | HashSet::new(), 702 | ); 703 | let v0 = VoteCount::create_vote_message(0, true); 704 | let v0_prime = VoteCount::create_vote_message(0, false); 705 | let v1 = VoteCount::create_vote_message(1, false); 706 | let v1_prime = VoteCount::create_vote_message(1, true); 707 | let v2 = VoteCount::create_vote_message(2, false); 708 | let v2_prime = VoteCount::create_vote_message(2, true); 709 | state.update(&[&v0, &v0_prime, &v1, &v1_prime, &v2, &v2_prime]); 710 | 711 | // As all three validators are known equivocators and they could not change the current 712 | // fault weight, they are sorted by the tie-breaker. This means they are sorted by the 713 | // messages' hashes. 714 | assert_eq!( 715 | state.sort_by_faultweight(&HashSet::from_iter(vec![&v0, &v1, &v2])), 716 | [&v2, &v0, &v1] 717 | ); 718 | 719 | // Comparing the hashes 720 | assert!(v2.id() < v0.id()); 721 | assert!(v0.id() < v1.id()); 722 | } 723 | 724 | // Weights have no influence 725 | test_with_weights(vec![(0, 2.0), (1, 1.0), (2, 3.0)]); 726 | test_with_weights(vec![(0, 2.0), (1, 4.0), (2, 3.0)]); 727 | } 728 | 729 | #[test] 730 | fn state_sort_by_faultweight_no_fault() { 731 | fn test_with_weights(weights: Vec<(u32, f32)>) { 732 | let mut state = State::new( 733 | Weights::new(weights.into_iter().collect()), 734 | 0.0, 735 | LatestMessages::empty(), 736 | 1.0, 737 | HashSet::new(), 738 | ); 739 | let v0 = VoteCount::create_vote_message(0, true); 740 | let v1 = VoteCount::create_vote_message(1, false); 741 | let v2 = VoteCount::create_vote_message(2, false); 742 | state.update(&[&v0, &v1, &v2]); 743 | 744 | // As all three validators haven't equivocated, they are sorted by the tie-breaker. 745 | // This means they are sorted by the messages' hashes. 746 | assert_eq!( 747 | state.sort_by_faultweight(&HashSet::from_iter(vec![&v0, &v1, &v2])), 748 | [&v2, &v0, &v1] 749 | ); 750 | 751 | // Comparing the hashes 752 | assert!(v2.id() < v0.id()); 753 | assert!(v0.id() < v1.id()); 754 | } 755 | 756 | // Weights have no influence 757 | test_with_weights(vec![(0, 2.0), (1, 1.0), (2, 3.0)]); 758 | test_with_weights(vec![(0, 2.0), (1, 4.0), (2, 3.0)]); 759 | } 760 | } 761 | -------------------------------------------------------------------------------- /tests/binary.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | extern crate core_cbc_casper; 22 | 23 | mod common; 24 | use common::binary::*; 25 | 26 | use std::collections::HashSet; 27 | 28 | use core_cbc_casper::estimator::Estimator; 29 | use core_cbc_casper::justification::{Justification, LatestMessages, LatestMessagesHonest}; 30 | use core_cbc_casper::message::Message; 31 | use core_cbc_casper::validator; 32 | 33 | #[test] 34 | fn equal_weight() { 35 | let validators: Vec = (0..4).collect(); 36 | let weights = [1.0, 1.0, 1.0, 1.0]; 37 | 38 | let validators_weights = validator::Weights::new( 39 | validators 40 | .iter() 41 | .cloned() 42 | .zip(weights.iter().cloned()) 43 | .collect(), 44 | ); 45 | 46 | let validator_state = validator::State::new( 47 | validators_weights.clone(), 48 | 0.0, 49 | LatestMessages::empty(), 50 | 1.0, 51 | HashSet::new(), 52 | ); 53 | 54 | let m0 = Message::new(validators[0], Justification::empty(), BoolWrapper(false)); 55 | let m1 = Message::new(validators[1], Justification::empty(), BoolWrapper(true)); 56 | let m2 = Message::new(validators[2], Justification::empty(), BoolWrapper(false)); 57 | let mut validator_state_clone = validator_state.clone(); 58 | validator_state_clone.update(&[&m0, &m1]); 59 | let m3 = Message::from_validator_state(validators[0], &validator_state_clone).unwrap(); 60 | 61 | assert_eq!( 62 | BoolWrapper::estimate( 63 | &LatestMessagesHonest::from_latest_messages( 64 | &LatestMessages::from(&Justification::empty()), 65 | validator_state.equivocators() 66 | ), 67 | &validators_weights, 68 | ) 69 | .unwrap(), 70 | BoolWrapper(true) 71 | ); 72 | let mut j0 = Justification::from_messages(vec![m0, m1], &mut validator_state.clone()); 73 | // s0 and s1 vote. since tie-breaker is `true`, get `true` 74 | assert_eq!( 75 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 76 | .unwrap(), 77 | BoolWrapper(true) 78 | ); 79 | j0.faulty_insert(&m2, &mut validator_state.clone()); 80 | // `false` now has weight 2.0, while true has weight `1.0` 81 | assert_eq!( 82 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 83 | .unwrap(), 84 | BoolWrapper(false) 85 | ); 86 | j0.faulty_insert(&m3, &mut validator_state.clone()); 87 | assert_eq!( 88 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 89 | .unwrap(), 90 | BoolWrapper(true) 91 | ); 92 | } 93 | 94 | #[test] 95 | fn vote_swaying() { 96 | let validators: Vec = (0..5).collect(); 97 | let weights = [1.0, 1.0, 1.0, 1.0, 1.0]; 98 | 99 | let validators_weights = validator::Weights::new( 100 | validators 101 | .iter() 102 | .cloned() 103 | .zip(weights.iter().cloned()) 104 | .collect(), 105 | ); 106 | 107 | let validator_state = validator::State::new( 108 | validators_weights.clone(), 109 | 0.0, 110 | LatestMessages::empty(), 111 | 1.0, 112 | HashSet::new(), 113 | ); 114 | 115 | let m0 = Message::new(validators[0], Justification::empty(), BoolWrapper(false)); 116 | let m1 = Message::new(validators[1], Justification::empty(), BoolWrapper(true)); 117 | let m2 = Message::new(validators[2], Justification::empty(), BoolWrapper(true)); 118 | let m3 = Message::new(validators[3], Justification::empty(), BoolWrapper(false)); 119 | let m4 = Message::new(validators[4], Justification::empty(), BoolWrapper(false)); 120 | 121 | let mut j0 = Justification::from_messages( 122 | vec![m0.clone(), m1.clone(), m2.clone(), m3, m4], 123 | &mut validator_state.clone(), 124 | ); 125 | 126 | // Honest result of vote: false 127 | assert_eq!( 128 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 129 | .unwrap(), 130 | BoolWrapper(false) 131 | ); 132 | 133 | // Assume validator 0 has seen messages from validator 1 and validator 2 and reveals this in a 134 | // published message. 135 | let mut validator_state_clone = validator_state.clone(); 136 | validator_state_clone.update(&[&m0, &m1, &m2]); 137 | let m5 = Message::from_validator_state(validators[0], &validator_state_clone).unwrap(); 138 | 139 | j0.faulty_insert(&m5, &mut validator_state.clone()); 140 | // Validator 0 now "votes" in the other direction and sways the result: true 141 | assert_eq!( 142 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 143 | .unwrap(), 144 | BoolWrapper(true) 145 | ); 146 | } 147 | -------------------------------------------------------------------------------- /tests/blockchain.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | extern crate core_cbc_casper; 22 | 23 | use std::collections::HashSet; 24 | 25 | use core_cbc_casper::blockchain::Block; 26 | use core_cbc_casper::justification::{Justification, LatestMessages}; 27 | use core_cbc_casper::message::Message; 28 | use core_cbc_casper::validator; 29 | use core_cbc_casper::ValidatorNameBlockData; 30 | 31 | #[test] 32 | fn partial_view() { 33 | // Test cases where not all validators see all messages. 34 | let validators: Vec = (0..5).collect(); 35 | let weights = [1.0, 1.0, 2.0, 1.0, 1.1]; 36 | 37 | let mut state = validator::State::new( 38 | validator::Weights::new( 39 | validators 40 | .iter() 41 | .cloned() 42 | .zip(weights.iter().cloned()) 43 | .collect(), 44 | ), 45 | 0.0, 46 | LatestMessages::empty(), 47 | 1.0, 48 | HashSet::new(), 49 | ); 50 | 51 | let genesis_block = Block::new(None, ValidatorNameBlockData::new(0)); 52 | let latest_messages = Justification::empty(); 53 | let genesis_block_message = Message::new(validators[0], latest_messages, genesis_block.clone()); 54 | // (s0, w=1.0) gen 55 | // (s1, w=1.0) 56 | // (s2, w=2.0) 57 | // (s3, w=1.0) 58 | // (s4, w=1.1) 59 | 60 | assert_eq!( 61 | &Block::from(&genesis_block_message), 62 | &genesis_block, 63 | "genesis block with None as prevblock" 64 | ); 65 | 66 | state.update(&[&genesis_block_message]); 67 | let m1 = Message::from_validator_state(validators[1], &state.clone()).unwrap(); 68 | // (s0, w=1.0) gen 69 | // (s1, w=1.0) \--m1 70 | // (s2, w=2.0) 71 | // (s3, w=1.0) 72 | // (s4, w=1.1) 73 | 74 | state.update(&[&genesis_block_message]); 75 | let m2 = Message::from_validator_state(validators[2], &state.clone()).unwrap(); 76 | // (s0, w=1.0) gen 77 | // (s1, w=1.0) |\--m1 78 | // (s2, w=2.0) \---m2 79 | // (s3, w=1.0) 80 | // (s4, w=1.1) 81 | 82 | state.update(&[&m1, &m2]); 83 | let m3 = Message::from_validator_state(validators[3], &state.clone()).unwrap(); 84 | // (s0, w=1.0) gen 85 | // (s1, w=1.0) |\--m1 86 | // (s2, w=2.0) \---m2 87 | // (s3, w=1.0) \---m3 88 | // (s4, w=1.1) 89 | 90 | assert_eq!( 91 | m3.estimate(), 92 | &Block::new(Some(Block::from(&m2)), ValidatorNameBlockData::new(0)), 93 | "should build on top of m2 as validators[2] has more weight" 94 | ); 95 | 96 | state.update(&[&m1]); 97 | let m4 = Message::from_validator_state(validators[4], &state.clone()).unwrap(); 98 | // (s0, w=1.0) gen 99 | // (s1, w=1.0) |\--m1-------\ 100 | // (s2, w=2.0) \---m2 | 101 | // (s3, w=1.0) \---m3 | 102 | // (s4, w=1.1) m4 103 | 104 | assert_eq!( 105 | m4.estimate(), 106 | &Block::new(Some(Block::from(&m1)), ValidatorNameBlockData::new(0)), 107 | "should build on top of m1 as thats the only message it saw" 108 | ); 109 | 110 | state.update(&[&m3, &m2]); 111 | let m5 = Message::from_validator_state(validators[0], &state).unwrap(); 112 | // (s0, w=1.0) gen m5 113 | // (s1, w=1.0) |\--m1-------\ | 114 | // (s2, w=2.0) \---m2 | | 115 | // (s3, w=1.0) \---m3--|---/ 116 | // (s4, w=1.1) m4 117 | 118 | assert_eq!( 119 | m5.estimate(), 120 | &Block::new(Some(Block::from(&m3)), ValidatorNameBlockData::new(0)), 121 | "should build on top of m3" 122 | ); 123 | 124 | let block = Block::from(&m3); 125 | assert_eq!( 126 | block, 127 | Block::new(Some(Block::from(&m2)), ValidatorNameBlockData::new(0)) 128 | ); 129 | } 130 | 131 | #[test] 132 | fn full_view() { 133 | // Test a case where the last validator see all messages and build on top of the heaviest 134 | // one. 135 | let validators: Vec = (0..7).collect(); 136 | let weights = [1.0, 1.0, 1.0, 1.0, 1.0, 1.1, 1.0]; 137 | 138 | let mut state = validator::State::new( 139 | validator::Weights::new( 140 | validators 141 | .iter() 142 | .cloned() 143 | .zip(weights.iter().cloned()) 144 | .collect(), 145 | ), 146 | 0.0, 147 | LatestMessages::empty(), 148 | 1.0, 149 | HashSet::new(), 150 | ); 151 | 152 | let genesis_block = Block::new(None, ValidatorNameBlockData::new(0)); 153 | let latest_messages = Justification::empty(); 154 | let genesis_block_message = Message::new(validators[0], latest_messages, genesis_block); 155 | // (sg, w=1.0) gen 156 | // (s0, w=1.0) 157 | // (s1, w=1.0) 158 | // (s2, w=1.0) 159 | // (s3, w=1.0) 160 | // (s4, w=1.1) 161 | // (s5, w=1.0) 162 | 163 | state.update(&[&genesis_block_message]); 164 | let m0 = Message::from_validator_state(validators[1], &state).unwrap(); 165 | // (sg, w=1.0) gen 166 | // (s0, w=1.0) \--m0 167 | // (s1, w=1.0) 168 | // (s2, w=1.0) 169 | // (s3, w=1.0) 170 | // (s4, w=1.1) 171 | // (s5, w=1.0) 172 | 173 | state.update(&[&m0]); 174 | let m1 = Message::from_validator_state(validators[2], &state).unwrap(); 175 | // (sg, w=1.0) gen 176 | // (s0, w=1.0) \--m0 177 | // (s1, w=1.0) \--m1 178 | // (s2, w=1.0) 179 | // (s3, w=1.0) 180 | // (s4, w=1.1) 181 | // (s5, w=1.0) 182 | 183 | state.update(&[&genesis_block_message]); 184 | let m2 = Message::from_validator_state(validators[3], &state).unwrap(); 185 | // (sg, w=1.0) gen 186 | // (s0, w=1.0) |\--m0 187 | // (s1, w=1.0) | \--m1 188 | // (s2, w=1.0) \-----------m2 189 | // (s3, w=1.0) 190 | // (s4, w=1.1) 191 | // (s5, w=1.0) 192 | 193 | state.update(&[&m2]); 194 | let m3 = Message::from_validator_state(validators[4], &state).unwrap(); 195 | // (sg, w=1.0) gen 196 | // (s0, w=1.0) |\--m0 197 | // (s1, w=1.0) | \--m1 198 | // (s2, w=1.0) \-----------m2 199 | // (s3, w=1.0) \--m3 200 | // (s4, w=1.1) 201 | // (s5, w=1.0) 202 | 203 | state.update(&[&m2]); 204 | let m4 = Message::from_validator_state(validators[5], &state).unwrap(); 205 | // (sg, w=1.0) gen 206 | // (s0, w=1.0) |\--m0 207 | // (s1, w=1.0) | \--m1 208 | // (s2, w=1.0) \-----------m2 209 | // (s3, w=1.0) |\--m3 210 | // (s4, w=1.1) \-------m4 211 | // (s5, w=1.0) 212 | 213 | state.update(&[&m0, &m1, &m2, &m3, &m4]); 214 | let m5 = Message::from_validator_state(validators[6], &state).unwrap(); 215 | // (sg, w=1.0) gen 216 | // (s0, w=1.0) |\--m0 217 | // (s1, w=1.0) | \--m1 218 | // (s2, w=1.0) \-----------m2 219 | // (s3, w=1.0) |\--m3 220 | // (s4, w=1.1) \-------m4 221 | // (s5, w=1.0) \--m5 222 | 223 | assert_eq!( 224 | m5.estimate(), 225 | &Block::new(Some(Block::from(&m4)), ValidatorNameBlockData::new(0)), 226 | "should build on top of b4" 227 | ); 228 | } 229 | -------------------------------------------------------------------------------- /tests/common/binary.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use core_cbc_casper::estimator::Estimator; 22 | use core_cbc_casper::justification::LatestMessagesHonest; 23 | use core_cbc_casper::util::weight::{WeightUnit, Zero}; 24 | use core_cbc_casper::validator; 25 | 26 | type Validator = u32; 27 | 28 | #[derive(Clone, Eq, PartialEq, Debug, Hash, serde_derive::Serialize)] 29 | pub struct BoolWrapper(pub bool); 30 | 31 | #[cfg(feature = "integration_test")] 32 | impl BoolWrapper { 33 | pub fn new(estimate: bool) -> Self { 34 | BoolWrapper(estimate) 35 | } 36 | } 37 | 38 | #[cfg(feature = "integration_test")] 39 | impl From for BoolWrapper { 40 | fn from(_validator: V) -> Self { 41 | BoolWrapper::new(bool::default()) 42 | } 43 | } 44 | 45 | #[derive(Debug)] 46 | pub struct Error(&'static str); 47 | 48 | impl std::fmt::Display for Error { 49 | fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 50 | writeln!(formatter, "{}", self.0) 51 | } 52 | } 53 | 54 | impl std::error::Error for Error {} 55 | 56 | impl std::convert::From<&'static str> for Error { 57 | fn from(string: &'static str) -> Self { 58 | Error(string) 59 | } 60 | } 61 | 62 | impl Estimator for BoolWrapper { 63 | type ValidatorName = Validator; 64 | type Error = Error; 65 | 66 | /// Weighted count of the votes contained in the latest messages. 67 | fn estimate( 68 | latest_messages: &LatestMessagesHonest, 69 | validators_weights: &validator::Weights, 70 | ) -> Result { 71 | // loop over all the latest messages 72 | let (true_w, false_w) = latest_messages.iter().fold( 73 | (>::ZERO, >::ZERO), 74 | |(true_w, false_w), message| { 75 | // Get the weight for the validator 76 | let validator_weight = validators_weights 77 | .weight(message.sender()) 78 | .unwrap_or(U::NAN); 79 | 80 | // Add the weight to the right accumulator 81 | if message.estimate().0 { 82 | (true_w + validator_weight, false_w) 83 | } else { 84 | (true_w, false_w + validator_weight) 85 | } 86 | }, 87 | ); 88 | 89 | Ok(BoolWrapper(true_w >= false_w)) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | pub mod binary; 22 | -------------------------------------------------------------------------------- /tests/integer.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | extern crate core_cbc_casper; 22 | 23 | use std::collections::HashSet; 24 | 25 | use core_cbc_casper::IntegerWrapper; 26 | 27 | use core_cbc_casper::estimator::Estimator; 28 | use core_cbc_casper::justification::{Justification, LatestMessages, LatestMessagesHonest}; 29 | use core_cbc_casper::message::Message; 30 | use core_cbc_casper::validator; 31 | 32 | #[test] 33 | fn equal_weight() { 34 | let validators: Vec = (0..4).collect(); 35 | let weights = [1.0, 1.0, 1.0, 1.0]; 36 | 37 | let validators_weights = validator::Weights::new( 38 | validators 39 | .iter() 40 | .cloned() 41 | .zip(weights.iter().cloned()) 42 | .collect(), 43 | ); 44 | 45 | let validator_state = validator::State::new( 46 | validators_weights.clone(), 47 | 0.0, 48 | LatestMessages::empty(), 49 | 1.0, 50 | HashSet::new(), 51 | ); 52 | 53 | assert_eq!( 54 | IntegerWrapper::estimate( 55 | &LatestMessagesHonest::from_latest_messages( 56 | &LatestMessages::from(&Justification::empty()), 57 | validator_state.equivocators() 58 | ), 59 | &validators_weights, 60 | ), 61 | Err("no message".into()) 62 | ); 63 | 64 | let m0 = Message::new(validators[0], Justification::empty(), IntegerWrapper(1)); 65 | let m1 = Message::new(validators[1], Justification::empty(), IntegerWrapper(2)); 66 | let m2 = Message::new(validators[2], Justification::empty(), IntegerWrapper(3)); 67 | let mut validator_state_clone = validator_state.clone(); 68 | validator_state_clone.update(&[&m0, &m1, &m2]); 69 | let m3 = Message::from_validator_state(validators[0], &validator_state_clone).unwrap(); 70 | 71 | let mut j0 = Justification::from_messages(vec![m0, m1], &mut validator_state.clone()); 72 | assert_eq!( 73 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 74 | .unwrap(), 75 | IntegerWrapper(1) 76 | ); 77 | 78 | j0.faulty_insert(&m2, &mut validator_state.clone()); 79 | assert_eq!( 80 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 81 | .unwrap(), 82 | IntegerWrapper(2) 83 | ); 84 | 85 | j0.faulty_insert(&m3, &mut validator_state.clone()); 86 | assert_eq!( 87 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 88 | .unwrap(), 89 | IntegerWrapper(2) 90 | ); 91 | } 92 | 93 | /// The first validator has most of the weight. 94 | #[test] 95 | fn uneven_weights_1() { 96 | let validators: Vec = (0..4).collect(); 97 | let weights = [4.0, 1.0, 1.0, 1.0]; 98 | 99 | let validators_weights = validator::Weights::new( 100 | validators 101 | .iter() 102 | .cloned() 103 | .zip(weights.iter().cloned()) 104 | .collect(), 105 | ); 106 | 107 | let validator_state = validator::State::new( 108 | validators_weights.clone(), 109 | 0.0, 110 | LatestMessages::empty(), 111 | 1.0, 112 | HashSet::new(), 113 | ); 114 | 115 | assert_eq!( 116 | IntegerWrapper::estimate( 117 | &LatestMessagesHonest::from_latest_messages( 118 | &LatestMessages::from(&Justification::empty()), 119 | validator_state.equivocators() 120 | ), 121 | &validators_weights, 122 | ), 123 | Err("no message".into()) 124 | ); 125 | 126 | let m0 = Message::new(validators[0], Justification::empty(), IntegerWrapper(1)); 127 | let m1 = Message::new(validators[1], Justification::empty(), IntegerWrapper(2)); 128 | let m2 = Message::new(validators[2], Justification::empty(), IntegerWrapper(3)); 129 | let mut validator_state_clone = validator_state.clone(); 130 | validator_state_clone.update(&[&m0, &m1, &m2]); 131 | let m3 = Message::from_validator_state(validators[0], &validator_state_clone).unwrap(); 132 | 133 | let mut j0 = Justification::from_messages(vec![m0, m1], &mut validator_state.clone()); 134 | assert_eq!( 135 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 136 | .unwrap(), 137 | IntegerWrapper(1) 138 | ); 139 | 140 | j0.faulty_insert(&m2, &mut validator_state.clone()); 141 | assert_eq!( 142 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 143 | .unwrap(), 144 | IntegerWrapper(1) 145 | ); 146 | 147 | j0.faulty_insert(&m3, &mut validator_state.clone()); 148 | assert_eq!( 149 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 150 | .unwrap(), 151 | IntegerWrapper(1) 152 | ); 153 | } 154 | 155 | /// The fourth validator has most of the weight. 156 | #[test] 157 | fn uneven_weights_4() { 158 | let validators: Vec = (0..4).collect(); 159 | let weights = [1.0, 1.0, 1.0, 4.0]; 160 | 161 | let validators_weights = validator::Weights::new( 162 | validators 163 | .iter() 164 | .cloned() 165 | .zip(weights.iter().cloned()) 166 | .collect(), 167 | ); 168 | 169 | let validator_state = validator::State::new( 170 | validators_weights.clone(), 171 | 0.0, 172 | LatestMessages::empty(), 173 | 1.0, 174 | HashSet::new(), 175 | ); 176 | 177 | assert_eq!( 178 | IntegerWrapper::estimate( 179 | &LatestMessagesHonest::from_latest_messages( 180 | &LatestMessages::from(&Justification::empty()), 181 | validator_state.equivocators() 182 | ), 183 | &validators_weights, 184 | ), 185 | Err("no message".into()) 186 | ); 187 | 188 | let m0 = Message::new(validators[0], Justification::empty(), IntegerWrapper(1)); 189 | let m1 = Message::new(validators[1], Justification::empty(), IntegerWrapper(2)); 190 | let m2 = Message::new(validators[2], Justification::empty(), IntegerWrapper(3)); 191 | let m3 = Message::new(validators[3], Justification::empty(), IntegerWrapper(4)); 192 | 193 | let mut validator_state_clone = validator_state.clone(); 194 | validator_state_clone.update(&[&m0, &m1, &m2, &m3]); 195 | let m4 = Message::from_validator_state(validators[3], &validator_state_clone).unwrap(); 196 | 197 | let mut j0 = Justification::from_messages(vec![m0, m1], &mut validator_state.clone()); 198 | assert_eq!( 199 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 200 | .unwrap(), 201 | IntegerWrapper(1) 202 | ); 203 | 204 | j0.faulty_insert(&m2, &mut validator_state.clone()); 205 | assert_eq!( 206 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 207 | .unwrap(), 208 | IntegerWrapper(2) 209 | ); 210 | 211 | j0.faulty_insert(&m3, &mut validator_state.clone()); 212 | assert_eq!( 213 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 214 | .unwrap(), 215 | IntegerWrapper(4) 216 | ); 217 | 218 | j0.faulty_insert(&m4, &mut validator_state.clone()); 219 | assert_eq!( 220 | j0.make_estimate(validator_state.equivocators(), &validators_weights) 221 | .unwrap(), 222 | IntegerWrapper(4) 223 | ); 224 | } 225 | -------------------------------------------------------------------------------- /tests/tools/mod.rs: -------------------------------------------------------------------------------- 1 | // Core CBC Casper 2 | // Copyright (C) 2018 - 2020 Coordination Technology Ltd. 3 | // Authors: pZ4 , 4 | // Lederstrumpf, 5 | // h4sh3d 6 | // roflolilolmao 7 | // 8 | // This file is part of Core CBC Casper. 9 | // 10 | // Core CBC Casper is free software: you can redistribute it and/or modify it under the terms 11 | // of the GNU Affero General Public License as published by the Free Software Foundation, either 12 | // version 3 of the License, or (at your option) any later version. 13 | // 14 | // Core CBC Casper is distributed in the hope that it will be useful, but WITHOUT ANY 15 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 16 | // PURPOSE. See the GNU Affero General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU Affero General Public License along with the Core CBC 19 | // Rust Library. If not, see . 20 | 21 | use std::fmt; 22 | 23 | use core_cbc_casper::blockchain::Block; 24 | use core_cbc_casper::estimator::Estimator; 25 | use core_cbc_casper::justification::LatestMessagesHonest; 26 | use core_cbc_casper::validator; 27 | 28 | use core_cbc_casper::ValidatorNameBlockData; 29 | 30 | pub struct ChainData { 31 | pub chain_id: u32, 32 | pub nb_nodes: u32, 33 | pub node_id: u32, 34 | pub consensus_height: i64, 35 | pub longest_chain: u32, 36 | pub nb_messages: usize, 37 | } 38 | 39 | impl fmt::Display for ChainData { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | write!( 42 | f, 43 | "{};{};{};{};{};{}", 44 | self.chain_id, 45 | self.nb_nodes, 46 | self.node_id, 47 | self.consensus_height, 48 | self.longest_chain, 49 | self.nb_messages 50 | ) 51 | } 52 | } 53 | 54 | impl ChainData { 55 | pub fn new( 56 | chain_id: u32, 57 | nb_nodes: u32, 58 | node_id: u32, 59 | consensus_height: i64, 60 | longest_chain: u32, 61 | nb_messages: usize, 62 | ) -> ChainData { 63 | ChainData { 64 | chain_id, 65 | nb_nodes, 66 | node_id, 67 | consensus_height, 68 | longest_chain, 69 | nb_messages, 70 | } 71 | } 72 | } 73 | 74 | /// Returns the height of the GHOST-selected chain. 75 | pub fn get_height_selected_chain( 76 | latest_messages_honest: &LatestMessagesHonest>>, 77 | validator_state: &validator::State>, f64>, 78 | ) -> u32 { 79 | let selected_block = Block::estimate( 80 | &latest_messages_honest, 81 | validator_state.validators_weights(), 82 | ) 83 | .unwrap() 84 | .prevblock() 85 | .ok_or(core_cbc_casper::blockchain::Error); 86 | fn reduce(block: &Block>, i: u32) -> u32 { 87 | match block.prevblock() { 88 | Some(previous_block) => reduce(&previous_block, i + 1), 89 | None => i, 90 | } 91 | } 92 | match selected_block { 93 | Ok(block) => reduce(&block, 1), 94 | _ => 0, 95 | } 96 | } 97 | --------------------------------------------------------------------------------