├── .editorconfig ├── .github └── workflows │ └── test.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── triedb.rs ├── rustfmt.toml └── src ├── lib.rs ├── nibbleslice.rs ├── node.rs ├── proof.rs ├── skewed.rs ├── snapshot ├── chunk.rs ├── compress.rs ├── error.rs ├── mod.rs └── ordered_heap.rs ├── triedb.rs ├── triedbmut.rs └── triehash.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*.rs] 3 | indent_style=space 4 | indent_size=4 5 | tab_width=8 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=120 10 | insert_final_newline=true 11 | 12 | [.github/**/*.yml] 13 | indent_style=space 14 | indent_size=2 15 | tab_width=8 16 | end_of_line=lf 17 | charset=utf-8 18 | trim_trailing_whitespace=true 19 | insert_final_newline=true 20 | 21 | [*.toml] 22 | indent_style=space 23 | indent_size=4 24 | tab_width=8 25 | end_of_line=lf 26 | charset=utf-8 27 | trim_trailing_whitespace=true 28 | insert_final_newline=true 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: test 4 | 5 | jobs: 6 | clippy: 7 | name: Actions - clippy 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v1 11 | with: 12 | fetch-depth: 1 13 | - uses: actions-rs/toolchain@v1 14 | with: 15 | toolchain: nightly-2020-07-27 16 | components: clippy 17 | profile: minimal 18 | override: true 19 | - run: cargo fetch --verbose 20 | - run: cargo clippy --all --all-targets -- -D warnings 21 | 22 | rustfmt: 23 | name: Actions - rustfmt 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v1 27 | with: 28 | fetch-depth: 1 29 | - uses: actions-rs/toolchain@v1 30 | with: 31 | toolchain: nightly-2020-07-27 32 | components: rustfmt 33 | profile: minimal 34 | override: true 35 | - run: cargo fmt -- --check 36 | 37 | unit-test: 38 | name: Actions - unit test 39 | runs-on: ${{ matrix.os }} 40 | strategy: 41 | matrix: 42 | os: [macOS-latest, ubuntu-latest] 43 | steps: 44 | - uses: actions/checkout@v1 45 | with: 46 | fetch-depth: 1 47 | - uses: actions-rs/toolchain@v1 48 | with: 49 | toolchain: stable 50 | profile: minimal 51 | - run: cargo fetch --verbose 52 | - run: cargo build 53 | - run: cargo test --verbose --all 54 | env: 55 | RUST_BACKTRACE: 1 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "merkle-trie" 3 | version = "0.4.1" 4 | authors = ["CodeChain Team "] 5 | repository = "http://github.com/CodeChain-io/rust-merkle-trie" 6 | license = "AGPL-3.0" 7 | edition = "2018" 8 | 9 | [dependencies] 10 | ccrypto = { package = "codechain-crypto", git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.3.0", tag = "v0.3.0" } 11 | cdb = { package = "codechain-db", git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.2.0", tag = "v0.2.0" } 12 | primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.5.0", tag = "v0.5.1" } 13 | rand = "0.6.1" 14 | rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.5.0", tag = "v0.5.0" } 15 | rlp_derive = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.5.0", tag = "v0.5.0" } 16 | snap = "0.2" 17 | lru-cache = "0.1.2" 18 | 19 | [dev-dependencies] 20 | kvdb = "0.1" 21 | kvdb-rocksdb = "0.1" 22 | standardmap = { package = "trie-standardmap", git = "https://github.com/CodeChain-io/trie-standardmap.git", version = "0.4.0", tag = "v0.4.0" } 23 | tempfile = "3.1.0" 24 | -------------------------------------------------------------------------------- /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 by 637 | 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 | # Merkle-Trie [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) 2 | The merkle trie used by [CodeChain](https://github.com/CodeChain-io/codechain) and [Foundry](https://github.com/CodeChain-io/foundry). 3 | 4 | ## Usage 5 | 6 | The rust-merkle-trie crate provides merkle trie implementations. CodeChain and Foundry use a merkle trie to hold the states with authentication. We differ from the merkle patricia trie in Ethereum; details can be found [here](https://github.com/CodeChain-io/codechain/blob/master/spec/Merkle-Trie.md). 7 | 8 | Let's use the merkle trie to show an example: 9 | 10 | ```rust 11 | use merkle_trie::{Trie, TrieFactory, TrieMut}; 12 | use cdb::MemoryDB; 13 | use primitives::H256; 14 | 15 | // initialize 16 | let mut memdb = MemoryDB::new(); 17 | let mut root = H256::zero(); 18 | let mut trie = TrieDBMut::new(&mut memdb, &mut root); 19 | 20 | // insert 21 | trie.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 22 | assert_eq!(*trie.root(), trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); 23 | 24 | // get 25 | assert_eq!(trie.get(&0x01u8, 0x23]).unwrap().unwrap(), vec!0x01u8, 0x23]); 26 | assert_eq!(t.get(&[0x02u8]), Ok(None)); 27 | 28 | // remove 29 | trie.remove(&0x01u8, 0x23]).unwrap(); 30 | assert_eq!(t.get(&0x01u8, 0x23]), Ok(None)); 31 | ``` 32 | 33 | 34 | ## Build 35 | 36 | Download foundry code 37 | 38 | ```sh 39 | git clone git@github.com:CodeChain-io/rust-merkle-trie.git 40 | cd rust-merkle-trie 41 | ``` 42 | 43 | Build in debug mode 44 | 45 | ```sh 46 | cargo build 47 | ``` 48 | 49 | ## Test 50 | 51 | Developers are strongly encouraged to write unit tests for new code, and to submit new unit tests for old code. Unit tests can be compiled and run with: `cargo test --all`. For more details, please refer to [Unit Tests](https://github.com/CodeChain-io/codechain/wiki/Unit-Tests). 52 | 53 | ## Benchmark 54 | 55 | Official documentation for usage of cargo bench: 56 | https://doc.rust-lang.org/1.15.1/book/benchmark-tests.html 57 | 58 | We can run the benchmark test with `cargo bench`: 59 | 60 | ```sh 61 | cargo bench 62 | ``` -------------------------------------------------------------------------------- /benches/triedb.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | #![feature(test)] 18 | 19 | extern crate test; 20 | 21 | use cdb::{new_journaldb, Algorithm, JournalDB}; 22 | use kvdb::DBTransaction; 23 | use kvdb_rocksdb::{CompactionProfile, Database, DatabaseConfig}; 24 | use merkle_trie::{Trie, TrieFactory, TrieMut}; 25 | use primitives::H256; 26 | use rand::random; 27 | use std::path::Path; 28 | use std::sync::Arc; 29 | use tempfile::{tempdir, TempDir}; 30 | use test::Bencher; 31 | 32 | struct TestDB { 33 | _dir: TempDir, 34 | db: Arc, 35 | journal: Box, 36 | root: H256, 37 | } 38 | 39 | impl TestDB { 40 | // Replicate CodeChain's db config 41 | fn config(path: &Path) -> DatabaseConfig { 42 | let mut config = DatabaseConfig::with_columns(Some(1)); 43 | config.memory_budget = Default::default(); 44 | config.compaction = CompactionProfile::auto(path); 45 | config 46 | } 47 | 48 | fn populate(path: &Path, size: usize) -> H256 { 49 | // Create database 50 | let config = Self::config(path); 51 | let db = Arc::new(Database::open(&config, path.to_str().unwrap()).unwrap()); 52 | let mut journal = new_journaldb(db.clone(), Algorithm::Archive, Some(0)); 53 | let mut root = H256::zero(); 54 | { 55 | let hashdb = journal.as_hashdb_mut(); 56 | let mut trie = TrieFactory::create(hashdb, &mut root); 57 | for i in 0..size { 58 | trie.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); 59 | } 60 | } 61 | let mut batch = DBTransaction::new(); 62 | journal.journal_under(&mut batch, 0, &H256::zero()).unwrap(); 63 | db.write_buffered(batch); 64 | db.flush().unwrap(); 65 | 66 | root 67 | } 68 | 69 | fn new(size: usize) -> Self { 70 | // Create temporary directory 71 | let dir = tempdir().unwrap(); 72 | let root = Self::populate(dir.path(), size); 73 | 74 | // Create database 75 | let config = Self::config(dir.path()); 76 | let db = Arc::new(Database::open(&config, dir.path().to_str().unwrap()).unwrap()); 77 | let journal = new_journaldb(db.clone(), Algorithm::Archive, Some(0)); 78 | 79 | Self { 80 | _dir: dir, 81 | db, 82 | journal, 83 | root, 84 | } 85 | } 86 | 87 | fn trie<'db>(&'db self) -> impl Trie + 'db { 88 | let hashdb = self.journal.as_hashdb(); 89 | TrieFactory::readonly(hashdb, &self.root).unwrap() 90 | } 91 | 92 | fn trie_mut<'db>(&'db mut self) -> impl TrieMut + 'db { 93 | let hashdb = self.journal.as_hashdb_mut(); 94 | TrieFactory::create(hashdb, &mut self.root) 95 | } 96 | 97 | fn flush(&mut self) { 98 | let mut batch = DBTransaction::new(); 99 | self.journal.journal_under(&mut batch, 0, &H256::zero()).unwrap(); 100 | self.db.write_buffered(batch); 101 | self.db.flush().unwrap(); 102 | } 103 | } 104 | 105 | const DB_SIZE: usize = 10000; 106 | const BATCH: usize = 10000; 107 | 108 | #[bench] 109 | fn bench_read_single(b: &mut Bencher) { 110 | let db = TestDB::new(DB_SIZE); 111 | b.iter(|| { 112 | let trie = db.trie(); 113 | let item = random::() % DB_SIZE; 114 | let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); 115 | }); 116 | } 117 | 118 | #[bench] 119 | fn bench_read_multiple(b: &mut Bencher) { 120 | let db = TestDB::new(DB_SIZE); 121 | b.iter(|| { 122 | let trie = db.trie(); 123 | for _ in 0..BATCH { 124 | let item = random::() % DB_SIZE; 125 | let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); 126 | } 127 | }); 128 | } 129 | 130 | #[bench] 131 | fn bench_write_single(b: &mut Bencher) { 132 | let mut db = TestDB::new(DB_SIZE); 133 | b.iter(|| { 134 | { 135 | let mut trie = db.trie_mut(); 136 | let item = random::() % DB_SIZE + DB_SIZE; 137 | let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); 138 | } 139 | db.flush(); 140 | }); 141 | } 142 | 143 | #[bench] 144 | fn bench_write_multiple(b: &mut Bencher) { 145 | let mut db = TestDB::new(DB_SIZE); 146 | b.iter(|| { 147 | { 148 | let mut trie = db.trie_mut(); 149 | for _ in 0..BATCH { 150 | let item = random::() % DB_SIZE + DB_SIZE; 151 | let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); 152 | } 153 | } 154 | db.flush(); 155 | }); 156 | } 157 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | indent_style = "Block" 2 | use_small_heuristics = "Off" # "Default" 3 | binop_separator = "Front" 4 | # combine_control_expr = true 5 | comment_width = 120 # 80 6 | condense_wildcard_suffixes = true # false 7 | control_brace_style = "AlwaysSameLine" 8 | # disable_all_formatting = false 9 | error_on_line_overflow = false # true 10 | # error_on_unformatted = false 11 | fn_args_layout = "Tall" 12 | brace_style = "PreferSameLine" # "SameLineWhere" 13 | empty_item_single_line = true 14 | enum_discrim_align_threshold = 0 15 | fn_single_line = false 16 | # where_single_line = false 17 | force_explicit_abi = true 18 | format_strings = false 19 | format_macro_matchers = false 20 | format_macro_bodies = true 21 | hard_tabs = false 22 | imports_indent = "Block" # "Visual" 23 | imports_layout = "Mixed" 24 | merge_imports = false 25 | match_block_trailing_comma = false 26 | max_width = 120 # 100 27 | merge_derives = true 28 | # force_multiline_blocks = false 29 | newline_style = "Unix" 30 | normalize_comments = false 31 | remove_nested_parens = true 32 | reorder_imports = true 33 | reorder_modules = true 34 | # reorder_impl_items = false 35 | # report_todo = "Never" 36 | # report_fixme = "Never" 37 | space_after_colon = true 38 | space_before_colon = false 39 | struct_field_align_threshold = 0 40 | spaces_around_ranges = false 41 | ## struct_lit_single_line = true 42 | tab_spaces = 4 43 | trailing_comma = "Vertical" 44 | trailing_semicolon = false # true 45 | # type_punctuation_density = "Wide" 46 | use_field_init_shorthand = true # false 47 | use_try_shorthand = true # false 48 | # format_code_in_doc_comments = false 49 | wrap_comments = false 50 | match_arm_blocks = true 51 | overflow_delimited_expr = true 52 | blank_lines_upper_bound = 2 # 1 53 | blank_lines_lower_bound = 0 54 | # required_version 55 | hide_parse_errors = false 56 | color = "Always" # "Auto" 57 | unstable_features = false 58 | # license_template_path 59 | # ignore 60 | edition = "2018" 61 | # version 62 | normalize_doc_attributes = true # false 63 | inline_attribute_width = 0 64 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | #[macro_use] 18 | extern crate rlp_derive; 19 | 20 | mod nibbleslice; 21 | pub mod node; 22 | pub mod proof; 23 | mod skewed; 24 | #[allow(dead_code)] 25 | pub mod snapshot; 26 | pub mod triedb; 27 | pub mod triedbmut; 28 | pub mod triehash; 29 | 30 | pub use crate::node::Node; 31 | pub use crate::proof::CryptoStructure; 32 | pub use crate::skewed::skewed_merkle_root; 33 | use crate::triedb::TrieDB; 34 | use crate::triedbmut::TrieDBMut; 35 | use ccrypto::BLAKE_NULL_RLP; 36 | use cdb::{DBValue, HashDB}; 37 | use primitives::H256; 38 | use std::fmt; 39 | 40 | /// Trie Errors. 41 | /// 42 | /// These borrow the data within them to avoid excessive copying on every 43 | /// trie operation. 44 | #[derive(Debug, PartialEq, Eq, Clone)] 45 | pub enum TrieError { 46 | /// Attempted to create a trie with a state root not in the DB. 47 | InvalidStateRoot(H256), 48 | /// Trie item not found in the database, 49 | IncompleteDatabase(H256), 50 | } 51 | 52 | impl fmt::Display for TrieError { 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 | match self { 55 | TrieError::InvalidStateRoot(root) => write!(f, "Invalid state root: {}", root), 56 | TrieError::IncompleteDatabase(missing) => write!(f, "Database missing expected key: {}", missing), 57 | } 58 | } 59 | } 60 | 61 | pub type Result = ::std::result::Result; 62 | 63 | /// A key-value datastore implemented as a database-backed Merkle trie. 64 | pub trait Trie: CryptoStructure { 65 | /// Return the root of the trie. 66 | fn root(&self) -> &H256; 67 | 68 | /// Is the trie empty? 69 | fn is_empty(&self) -> bool { 70 | *self.root() == BLAKE_NULL_RLP 71 | } 72 | 73 | /// Does the trie contain a given key? 74 | fn contains(&self, key: &[u8]) -> Result { 75 | self.get(key).map(|x| x.is_some()) 76 | } 77 | 78 | /// What is the value of the given key in this trie? 79 | fn get(&self, key: &[u8]) -> Result>; 80 | 81 | /// Does all the nodes in this trie exist in the underlying database? 82 | fn is_complete(&self) -> bool; 83 | } 84 | 85 | /// A key-value datastore implemented as a database-backed modified Merkle tree. 86 | pub trait TrieMut: Trie { 87 | /// Insert a `key`/`value` pair into the trie. An empty value is equivalent to removing 88 | /// `key` from the trie. Returns the old value associated with this key, if it existed. 89 | fn insert(&mut self, key: &[u8], value: &[u8]) -> Result>; 90 | 91 | /// Remove a `key` from the trie. Equivalent to making it equal to the empty 92 | /// value. Returns the old value associated with this key, if it existed. 93 | fn remove(&mut self, key: &[u8]) -> Result>; 94 | } 95 | 96 | pub enum TrieFactory {} 97 | 98 | impl TrieFactory { 99 | /// Create new immutable instance of Trie. 100 | pub fn readonly<'db>(db: &'db dyn HashDB, root: &'db H256) -> Result { 101 | Ok(TrieDB::try_new(db, root)?) 102 | } 103 | 104 | /// Create new mutable instance of Trie. 105 | pub fn create<'db>(db: &'db mut dyn HashDB, root: &'db mut H256) -> impl TrieMut + 'db { 106 | TrieDBMut::new(db, root) 107 | } 108 | 109 | /// Create new mutable instance of trie and check for errors. 110 | pub fn from_existing<'db>(db: &'db mut dyn HashDB, root: &'db mut H256) -> Result { 111 | Ok(TrieDBMut::from_existing(db, root)?) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/nibbleslice.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use std::cmp::*; 18 | use std::fmt; 19 | 20 | #[derive(Eq, Ord, Copy, Clone)] 21 | pub struct NibbleSlice<'a> { 22 | pub data: &'a [u8], 23 | pub offset: usize, 24 | } 25 | 26 | impl<'a, 'view> NibbleSlice<'a> 27 | where 28 | 'a: 'view, 29 | { 30 | /// Create a new nibble slice with the given byte-slice. 31 | pub fn new(data: &'a [u8]) -> Self { 32 | NibbleSlice::new_offset(data, 0) 33 | } 34 | 35 | /// Create a new nibble slice with the given byte-slice with a nibble offset. 36 | pub fn new_offset(data: &'a [u8], offset: usize) -> Self { 37 | NibbleSlice { 38 | data, 39 | offset, 40 | } 41 | } 42 | 43 | /// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`). 44 | pub fn from_encoded(data: &'a [u8]) -> NibbleSlice<'_> { 45 | let offset = if (data[0] & 0b1_0000) == 0b1_0000 { 46 | 1 47 | } else { 48 | 2 49 | }; 50 | Self::new_offset(data, offset) 51 | } 52 | 53 | /// Is this an empty slice? 54 | pub fn is_empty(&self) -> bool { 55 | self.len() == 0 56 | } 57 | 58 | /// Get the length (in nibbles, naturally) of this slice. 59 | pub fn len(&self) -> usize { 60 | self.data.len() * 2 - self.offset 61 | } 62 | 63 | /// Get the nibble at position `i`. 64 | pub fn at(&self, i: usize) -> u8 { 65 | let word = self.data[(self.offset + i) >> 1]; 66 | if (self.offset + i) & 1 == 1 { 67 | word & 0b1111 68 | } else { 69 | word >> 4 70 | } 71 | } 72 | 73 | /// Return object which represents a view on to this slice (further) offset by `i` nibbles. 74 | pub fn mid(&'view self, i: usize) -> NibbleSlice<'a> { 75 | NibbleSlice { 76 | data: self.data, 77 | offset: self.offset + i, 78 | } 79 | } 80 | 81 | /// Do we start with the same nibbles as the whole of `them`? 82 | pub fn starts_with(&self, them: &Self) -> bool { 83 | self.common_prefix(them) == them.len() 84 | } 85 | 86 | /// How many of the same nibbles at the beginning do we match with `them`? 87 | pub fn common_prefix(&self, them: &Self) -> usize { 88 | let s = min(self.len(), them.len()); 89 | let mut i = 0usize; 90 | while i < s { 91 | if self.at(i) != them.at(i) { 92 | break 93 | } 94 | i += 1; 95 | } 96 | i 97 | } 98 | 99 | /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. 100 | pub fn encoded(&self) -> Vec { 101 | let l = self.len(); 102 | let mut r = Vec::new(); 103 | let mut i = l % 2; 104 | r.push(if i == 1 { 105 | 0b1_0000 + self.at(0) 106 | } else { 107 | 0 108 | }); 109 | while i < l { 110 | r.push((self.at(i) << 4) + self.at(i + 1)); 111 | i += 2; 112 | } 113 | r 114 | } 115 | 116 | 117 | /// Encode only the leftmost `n` bytes of the nibble slice in prefixed hex notation, 118 | /// noting whether it `is_leaf`. 119 | pub fn encoded_leftmost(&self, n: usize) -> Vec { 120 | let l = min(self.len(), n); 121 | let mut r = Vec::new(); 122 | let mut i = l % 2; 123 | r.push(if i == 1 { 124 | 0b1_0000 + self.at(0) 125 | } else { 126 | 0 127 | }); 128 | while i < l { 129 | r.push((self.at(i) << 4) + self.at(i + 1)); 130 | i += 2; 131 | } 132 | r 133 | } 134 | 135 | pub fn to_vec(&self) -> Vec { 136 | let mut vec: Vec = Vec::new(); 137 | for i in 0..self.len() { 138 | vec.push(self.at(i)); 139 | } 140 | vec 141 | } 142 | 143 | pub fn from_vec(v: &[u8]) -> (Vec, usize) { 144 | let mut r = Vec::new(); 145 | let l = v.len(); 146 | let mut i = l % 2; 147 | r.push(if i == 1 { 148 | 0b1_0000 + (v[0] & 0b1111) 149 | } else { 150 | 0 151 | }); 152 | while i < l { 153 | r.push(((v[i] & 0b1111) << 4) + (v[i + 1] & 0b1111)); 154 | i += 2; 155 | } 156 | (r, 2 - (l % 2)) 157 | } 158 | } 159 | 160 | impl<'a> PartialEq for NibbleSlice<'a> { 161 | fn eq(&self, them: &Self) -> bool { 162 | self.len() == them.len() && self.starts_with(them) 163 | } 164 | } 165 | 166 | impl<'a> PartialOrd for NibbleSlice<'a> { 167 | fn partial_cmp(&self, them: &Self) -> Option { 168 | let s = min(self.len(), them.len()); 169 | let mut i = 0usize; 170 | while i < s { 171 | match self.at(i).partial_cmp(&them.at(i)).unwrap() { 172 | Ordering::Less => return Some(Ordering::Less), 173 | Ordering::Greater => return Some(Ordering::Greater), 174 | _ => i += 1, 175 | } 176 | } 177 | self.len().partial_cmp(&them.len()) 178 | } 179 | } 180 | 181 | impl<'a> fmt::Debug for NibbleSlice<'a> { 182 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 183 | for i in 0..self.len() { 184 | match i { 185 | 0 => write!(f, "{:01x}", self.at(i))?, 186 | _ => write!(f, "'{:01x}", self.at(i))?, 187 | } 188 | } 189 | Ok(()) 190 | } 191 | } 192 | 193 | #[cfg(test)] 194 | mod tests { 195 | use super::NibbleSlice; 196 | 197 | static D: &[u8; 3] = &[0x01u8, 0x23, 0x45]; 198 | 199 | #[test] 200 | fn basics() { 201 | let n = NibbleSlice::new(D); 202 | assert_eq!(n.len(), 6); 203 | assert!(!n.is_empty()); 204 | 205 | let n = NibbleSlice::new_offset(D, 6); 206 | assert!(n.is_empty()); 207 | 208 | let n = NibbleSlice::new_offset(D, 3); 209 | assert_eq!(n.len(), 3); 210 | for i in 0..3 { 211 | assert_eq!(n.at(i), i as u8 + 3); 212 | } 213 | } 214 | 215 | #[test] 216 | fn mid() { 217 | let n = NibbleSlice::new(D); 218 | let m = n.mid(2); 219 | for i in 0..4 { 220 | assert_eq!(m.at(i), i as u8 + 2); 221 | } 222 | let m = n.mid(3); 223 | for i in 0..3 { 224 | assert_eq!(m.at(i), i as u8 + 3); 225 | } 226 | } 227 | 228 | #[test] 229 | fn encoded() { 230 | let n = NibbleSlice::new(D); 231 | assert_eq!(n.encoded(), vec![0x00, 0x01, 0x23, 0x45]); 232 | assert_eq!(n.mid(1).encoded(), vec![0x11, 0x23, 0x45]); 233 | } 234 | 235 | #[test] 236 | fn from_encoded() { 237 | let n = NibbleSlice::new(D); 238 | assert_eq!(n, NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45])); 239 | assert_eq!(n.mid(1), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45])); 240 | } 241 | 242 | #[test] 243 | fn shared() { 244 | let n = NibbleSlice::new(D); 245 | 246 | let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67]; 247 | let m = NibbleSlice::new(other); 248 | 249 | assert_eq!(n.common_prefix(&m), 4); 250 | assert_eq!(m.common_prefix(&n), 4); 251 | assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3); 252 | assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0); 253 | assert_eq!(n.common_prefix(&m.mid(4)), 6); 254 | assert!(!n.starts_with(&m.mid(4))); 255 | assert!(m.mid(4).starts_with(&n)); 256 | } 257 | 258 | #[test] 259 | fn compare() { 260 | let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45]; 261 | let n = NibbleSlice::new(D); 262 | let m = NibbleSlice::new(other); 263 | 264 | assert!(n != m); 265 | assert!(n > m); 266 | assert!(m < n); 267 | 268 | assert!(n == m.mid(4)); 269 | assert!(n >= m.mid(4)); 270 | assert!(n <= m.mid(4)); 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /src/node.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::nibbleslice::NibbleSlice; 18 | use primitives::H256; 19 | use rlp::*; 20 | 21 | 22 | #[derive(Eq, PartialEq, Debug)] 23 | pub enum Node<'a> { 24 | Leaf(NibbleSlice<'a>, &'a [u8]), 25 | 26 | Branch(NibbleSlice<'a>, Box<[Option; 16]>), 27 | } 28 | 29 | impl<'a> Node<'a> { 30 | /// Decode the `node_rlp` and return the Node. 31 | pub fn decoded(node_rlp: &'a [u8]) -> Option { 32 | let r = Rlp::new(node_rlp); 33 | match r.prototype().unwrap() { 34 | // Empty node 35 | Prototype::Data(0) => None, 36 | // leaf node - first is nibbles and second is value 37 | Prototype::List(2) => { 38 | let slice = NibbleSlice::from_encoded(r.at(0).unwrap().data().unwrap()); 39 | 40 | Some(Node::Leaf(slice, r.at(1).unwrap().data().unwrap())) 41 | } 42 | // branch node - first is nibbles (or empty), the rest 16 are nodes. 43 | Prototype::List(17) => { 44 | let mut nodes = [None; 16]; 45 | debug_assert_eq!(16, nodes.len()); 46 | for (i, node) in nodes.iter_mut().enumerate().map(|(i, node)| (i + 1, node)) { 47 | *node = if r.at(i).unwrap().is_empty() { 48 | None 49 | } else { 50 | Some(r.val_at::(i).unwrap()) 51 | }; 52 | } 53 | 54 | Some(Node::Branch(NibbleSlice::from_encoded(r.at(0).unwrap().data().unwrap()), nodes.into())) 55 | } 56 | 57 | // something went wrong. 58 | _ => panic!("Rlp data is not valid."), 59 | } 60 | } 61 | 62 | /// Encode the node into RLP. 63 | pub fn encoded(node: Self) -> Vec { 64 | match node { 65 | Node::Leaf(slice, value) => { 66 | let mut stream = RlpStream::new_list(2); 67 | stream.append(&&*slice.encoded()); 68 | stream.append(&value); 69 | stream.drain() 70 | } 71 | Node::Branch(slice, nodes) => { 72 | let mut stream = RlpStream::new_list(17); 73 | 74 | stream.append(&&*slice.encoded()); 75 | 76 | for child in nodes.iter() { 77 | if let Some(hash) = child { 78 | stream.append(hash); 79 | } else { 80 | stream.append_empty_data(); 81 | } 82 | } 83 | stream.drain() 84 | } 85 | } 86 | } 87 | 88 | /// Encode the node into RLP. 89 | /// What the difference with above `encoded()` is length of nibblepath encoded 90 | pub fn encoded_until(node: Self, size: usize) -> Vec { 91 | match node { 92 | Node::Leaf(slice, value) => { 93 | let mut stream = RlpStream::new_list(2); 94 | stream.append(&&*slice.encoded_leftmost(size)); 95 | stream.append(&&*value); 96 | stream.drain() 97 | } 98 | Node::Branch(slice, nodes) => { 99 | let mut stream = RlpStream::new_list(17); 100 | 101 | stream.append(&&*slice.encoded_leftmost(size)); 102 | 103 | for child in nodes.iter() { 104 | if let Some(hash) = child { 105 | stream.append(hash); 106 | } else { 107 | stream.append_empty_data(); 108 | } 109 | } 110 | stream.drain() 111 | } 112 | } 113 | } 114 | 115 | pub fn mid(self, offset: usize) -> Self { 116 | match self { 117 | Node::Leaf(partial, value) => Node::Leaf(partial.mid(offset), value), 118 | Node::Branch(partial, child) => Node::Branch(partial.mid(offset), child), 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/proof.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::nibbleslice::NibbleSlice; 18 | use crate::node::Node; 19 | use ccrypto::{blake256, BLAKE_NULL_RLP}; 20 | use primitives::Bytes; 21 | use primitives::H256; 22 | 23 | // Unit of a proof. 24 | //#[derive(Clone, Eq, PartialEq, Debug, RlpEncodable, RlpDecodable)] 25 | #[derive(Clone, Eq, PartialEq, Debug)] 26 | pub struct CryptoProofUnit { 27 | pub root: H256, 28 | pub key: Bytes, 29 | pub value: Option, // None in case of absence 30 | } 31 | 32 | #[derive(Clone, Eq, PartialEq, Debug)] 33 | pub struct CryptoProof(pub Vec); 34 | 35 | pub trait CryptoStructure { 36 | fn make_proof(&self, key: &[u8]) -> crate::Result<(CryptoProofUnit, CryptoProof)>; 37 | } 38 | 39 | /// A verification logic of TrieDB's Merkle proof. 40 | /// For the format of proof, check the make_proof() function. 41 | /// It verifies the proof with a given unit of test. 42 | /// It should never abort or fail, but only return 'false' as a result of getting an invalid or ill-formed proof. 43 | pub fn verify(proof: &CryptoProof, test: &CryptoProofUnit) -> bool { 44 | // step1: verify the value 45 | fn step1(proof: &CryptoProof, test: &CryptoProofUnit) -> bool { 46 | match Node::decoded(&proof.0.last().unwrap()) { 47 | Some(x) => match x { 48 | Node::Leaf(_, value) => test.value.as_ref().unwrap() == &value, 49 | _ => false, 50 | }, 51 | _ => false, 52 | } 53 | }; 54 | 55 | // step2: verify the root 56 | fn step2(proof: &CryptoProof, test: &CryptoProofUnit) -> bool { 57 | blake256(&proof.0[0]) == test.root 58 | }; 59 | 60 | // step3 (presence): verify the key 61 | fn step3_p(proof: &CryptoProof, test: &CryptoProofUnit) -> bool { 62 | fn verify_branch(path: &NibbleSlice<'_>, hash: &H256, proof: &[Bytes]) -> bool { 63 | if *hash != blake256(&proof[0]) { 64 | return false 65 | } 66 | match Node::decoded(&proof[0]) { 67 | Some(Node::Leaf(partial, _)) => path == &partial, 68 | Some(Node::Branch(partial, table)) => { 69 | if proof.len() < 2 { 70 | // detect ill-formed proof 71 | return false 72 | } 73 | if !path.starts_with(&partial) { 74 | return false 75 | } 76 | match table[path.at(partial.len()) as usize] { 77 | Some(x) => verify_branch(&path.mid(partial.len() + 1), &x, &proof[1..]), 78 | None => false, 79 | } 80 | } 81 | None => false, 82 | } 83 | }; 84 | let path = blake256(&test.key); 85 | verify_branch(&NibbleSlice::new(path.as_bytes()), &test.root, &proof.0) 86 | }; 87 | 88 | // step3 (absence): verify the key. 89 | fn step3_a(proof: &CryptoProof, test: &CryptoProofUnit) -> bool { 90 | fn verify_branch(path: &NibbleSlice<'_>, hash: &H256, proof: &[Bytes]) -> bool { 91 | if *hash != blake256(&proof[0]) { 92 | return false 93 | } 94 | match Node::decoded(&proof[0]) { 95 | Some(Node::Leaf(partial, _)) => path != &partial, // special case : there is only one leaf node in the trie, 96 | Some(Node::Branch(partial, children)) => { 97 | if !path.starts_with(&partial) { 98 | return false 99 | } 100 | match children[path.at(partial.len()) as usize] { 101 | Some(x) => proof.len() >= 2 && verify_branch(&path.mid(partial.len() + 1), &x, &proof[1..]), 102 | None => proof.len() == 1, 103 | } 104 | } 105 | None => false, 106 | } 107 | }; 108 | let path = blake256(&test.key); 109 | verify_branch(&NibbleSlice::new(path.as_bytes()), &test.root, &proof.0) 110 | }; 111 | 112 | if proof.0.is_empty() { 113 | return test.root == BLAKE_NULL_RLP && test.value.is_none() // special case of an empty trie. 114 | } 115 | if test.value.is_some() { 116 | step1(proof, test) && step2(proof, test) && step3_p(proof, test) 117 | } else { 118 | step2(proof, test) && step3_a(proof, test) 119 | } 120 | } 121 | 122 | 123 | #[cfg(test)] 124 | mod tests { 125 | extern crate rand; 126 | 127 | use super::*; 128 | use crate::*; 129 | use cdb::MemoryDB; 130 | use rand::{rngs::StdRng, Rng}; 131 | 132 | fn simple_test<'db>(t: &TrieDB<'db>, key: Bytes, value: Option<&[u8]>, key_proof: &[u8], result: bool) { 133 | let unit = CryptoProofUnit { 134 | root: *t.root(), 135 | key, 136 | value: value.map(|x| x.to_vec()), 137 | }; 138 | let proof = t.make_proof(key_proof).unwrap(); 139 | assert_eq!(verify(&proof.1, &unit), result); 140 | } 141 | 142 | #[test] 143 | fn empty_trie() { 144 | let iteration = 100; 145 | let seed = [0 as u8; 32]; 146 | let mut rng: StdRng = rand::SeedableRng::from_seed(seed); 147 | 148 | for _ in 0..iteration { 149 | let mut memdb = MemoryDB::new(); 150 | let mut root = H256::zero(); 151 | TrieDBMut::new(&mut memdb, &mut root); 152 | 153 | // unused pair 154 | let k1 = format!("{}", rng.gen::()); 155 | let v1 = format!("{}", rng.gen::()); 156 | let (keyu, valu) = { (k1.as_bytes(), v1.as_bytes()) }; 157 | 158 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 159 | 160 | simple_test(&t, keyu.to_vec(), Some(valu), &keyu, false); 161 | simple_test(&t, keyu.to_vec(), None, &keyu, true); 162 | } 163 | } 164 | 165 | #[test] 166 | fn single_trie() { 167 | let iteration = 100; 168 | let seed = [0 as u8; 32]; 169 | let mut rng: StdRng = rand::SeedableRng::from_seed(seed); 170 | 171 | for _ in 0..iteration { 172 | let mut memdb = MemoryDB::new(); 173 | let mut root = H256::zero(); 174 | let mut mt = TrieDBMut::new(&mut memdb, &mut root); 175 | 176 | // unused pair 177 | let ku = format!("{}", rng.gen::()); 178 | let vu = format!("{}", rng.gen::()); 179 | let (keyu, valu) = (ku.as_bytes(), vu.as_bytes()); 180 | 181 | let k1 = format!("{}", rng.gen::()); 182 | let v1 = format!("{}", rng.gen::()); 183 | let (key1, val1) = (k1.as_bytes(), v1.as_bytes()); 184 | mt.insert(key1, val1).unwrap(); 185 | 186 | if key1 == keyu || val1 == valu { 187 | continue 188 | } 189 | 190 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 191 | 192 | // Be careful: there are some case where the proof is not unique. 193 | simple_test(&t, key1.to_vec(), Some(val1), &key1, true); 194 | simple_test(&t, key1.to_vec(), Some(val1), &keyu, true); //be careful! 195 | simple_test(&t, key1.to_vec(), Some(valu), &key1, false); 196 | simple_test(&t, key1.to_vec(), Some(valu), &keyu, false); 197 | simple_test(&t, key1.to_vec(), None, &key1, false); 198 | simple_test(&t, key1.to_vec(), None, &keyu, false); 199 | simple_test(&t, keyu.to_vec(), Some(val1), &key1, false); 200 | simple_test(&t, keyu.to_vec(), Some(val1), &keyu, false); 201 | simple_test(&t, keyu.to_vec(), Some(valu), &key1, false); 202 | simple_test(&t, keyu.to_vec(), Some(valu), &keyu, false); 203 | simple_test(&t, keyu.to_vec(), None, &key1, true); //be careful! 204 | simple_test(&t, keyu.to_vec(), None, &keyu, true); 205 | } 206 | } 207 | 208 | #[test] 209 | fn some_trie() { 210 | let iteration = 100; 211 | let size = 234; 212 | let seed = [0 as u8; 32]; 213 | let mut rng: StdRng = rand::SeedableRng::from_seed(seed); 214 | 215 | for _ in 0..iteration { 216 | let mut memdb = MemoryDB::new(); 217 | let mut root = H256::zero(); 218 | let mut mt = TrieDBMut::new(&mut memdb, &mut root); 219 | 220 | // unused pair 221 | let ku = format!("{}", rng.gen::()); 222 | let vu = format!("{}", rng.gen::()); 223 | let (keyu, valu) = (ku.as_bytes(), vu.as_bytes()); 224 | 225 | let k1 = format!("{}", rng.gen::()); 226 | let v1 = format!("{}", rng.gen::()); 227 | let (key1, val1) = (k1.as_bytes(), v1.as_bytes()); 228 | mt.insert(key1, val1).unwrap(); 229 | 230 | let k2 = format!("{}", rng.gen::()); 231 | let v2 = format!("{}", rng.gen::()); 232 | let (key2, val2) = (k2.as_bytes(), v2.as_bytes()); 233 | mt.insert(key2, val2).unwrap(); 234 | 235 | if key1 == keyu || val1 == valu || key2 == keyu || val2 == valu { 236 | continue 237 | } 238 | 239 | let mut flag = true; 240 | for _ in 0..size { 241 | let k = format!("{}", rng.gen::()); 242 | let v = format!("{}", rng.gen::()); 243 | mt.insert(k.as_bytes(), v.as_bytes()).unwrap(); 244 | if k.as_bytes() == keyu || v.as_bytes() == valu { 245 | flag = false; 246 | break 247 | } 248 | } 249 | if !flag { 250 | continue // skip this iteration 251 | } 252 | 253 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 254 | 255 | simple_test(&t, key1.to_vec(), Some(val1), &key1, true); 256 | simple_test(&t, key1.to_vec(), Some(val1), &key2, false); 257 | simple_test(&t, key1.to_vec(), Some(val1), &keyu, false); 258 | simple_test(&t, key1.to_vec(), Some(val2), &key1, false); 259 | simple_test(&t, key1.to_vec(), Some(val2), &key2, false); 260 | simple_test(&t, key1.to_vec(), Some(val2), &keyu, false); 261 | simple_test(&t, key1.to_vec(), None, &key1, false); 262 | simple_test(&t, key1.to_vec(), None, &key2, false); 263 | simple_test(&t, key1.to_vec(), None, &keyu, false); 264 | 265 | simple_test(&t, keyu.to_vec(), Some(val1), &key1, false); 266 | simple_test(&t, keyu.to_vec(), Some(val1), &key2, false); 267 | simple_test(&t, keyu.to_vec(), Some(val1), &keyu, false); 268 | simple_test(&t, keyu.to_vec(), None, &key1, false); 269 | simple_test(&t, keyu.to_vec(), None, &key2, false); 270 | simple_test(&t, keyu.to_vec(), None, &keyu, true); 271 | } 272 | } 273 | 274 | // proof is created manually here 275 | #[test] 276 | fn some_malicious() { 277 | // TODO 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/skewed.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018, 2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use ccrypto::Blake; 18 | use std::ops::BitXor; 19 | 20 | // skewed_merkle_root(base, vec![input0, input1, input2, input3]) 21 | // will creates the tree as below 22 | // 23 | // root 24 | // / \ 25 | // h0 input3 26 | // / \ 27 | // h1 input2 28 | // / \ 29 | // h2 input1 30 | // / \ 31 | // base input0 32 | // 33 | // and returns the root. 34 | // This function calls hash function twice per depth. One is hashing input. This hashing makes input 35 | // to the fixed size. And the other is for merkling. 36 | 37 | pub fn skewed_merkle_root(base: Out, inputs: Iter) -> Out 38 | where 39 | Iter: IntoIterator, 40 | In: AsRef<[u8]>, 41 | Xor: AsRef<[u8]>, 42 | Out: BitXor + Blake, { 43 | inputs.into_iter().fold(base, |acc, input| { 44 | let xor = acc ^ Blake::blake(input); 45 | Blake::blake(&xor) 46 | }) 47 | } 48 | 49 | #[cfg(test)] 50 | mod tests { 51 | use std::vec::Vec; 52 | 53 | use primitives::H256; 54 | 55 | use super::*; 56 | 57 | #[test] 58 | fn empty_is_zero() { 59 | let result = skewed_merkle_root::, _, _, _>(H256::zero(), vec![]); 60 | assert_eq!(H256::zero(), result); 61 | } 62 | 63 | #[test] 64 | fn one_is_hash_of_blake() { 65 | let item = H256::from_low_u64_ne(1000); 66 | let result = skewed_merkle_root(H256::zero(), vec![item]); 67 | assert_eq!(H256::blake(H256::blake(item)), result); 68 | } 69 | 70 | #[test] 71 | fn skewed_merkle_trie_of_two_elements() { 72 | let item0 = H256::from_low_u64_ne(1000); 73 | let item1 = H256::from_low_u64_ne(1000); 74 | let expected = H256::blake(H256::blake(H256::blake(&item0)) ^ H256::blake(&item1)); 75 | let result = skewed_merkle_root(H256::zero(), vec![item0, item1]); 76 | assert_eq!(expected, result); 77 | } 78 | 79 | #[test] 80 | fn skewed_merkle_trie_of_three_elements() { 81 | let item0 = vec![0xCA, 0xFE]; 82 | let item2 = vec![ 83 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 84 | 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 85 | 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 86 | 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 87 | 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 88 | 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 89 | 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 90 | 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 91 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 92 | 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 93 | 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 94 | 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 95 | 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 96 | 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 97 | 0xFC, 0xFD, 0xFE, 0xFF, 98 | ]; 99 | let item1 = vec![0xBE, 0xBE]; 100 | let expected = 101 | H256::blake(H256::blake(H256::blake(H256::blake(&item0)) ^ H256::blake(&item1)) ^ H256::blake(&item2)); 102 | let result = skewed_merkle_root(H256::zero(), vec![item0, item1, item2]); 103 | assert_eq!(expected, result); 104 | } 105 | 106 | #[test] 107 | fn skewed_merkle_trie_is_incremental() { 108 | let total: Vec = vec![0xCAFE, 0xDEAD, 0xBEEF_CAFE, 0xDEAD_BEEF, 0xDEAD_BEEF_CAFE, 0xBEEF, 0xBEBE, 0xFEED]; 109 | let total: Vec = total.into_iter().map(H256::from_low_u64_ne).collect(); 110 | 111 | let parent: Vec = total.iter().take(4).map(Clone::clone).collect(); 112 | let parent_output = skewed_merkle_root(H256::zero(), parent); 113 | 114 | let current: Vec = total.iter().skip(4).map(Clone::clone).collect(); 115 | let calculated: H256 = skewed_merkle_root(parent_output, current); 116 | 117 | let expected: H256 = skewed_merkle_root(H256::zero(), total); 118 | 119 | assert_eq!(calculated, expected); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/snapshot/chunk.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use super::error::{ChunkError, Error}; 18 | use super::{DecodedPathSlice, PathSlice, CHUNK_HEIGHT}; 19 | use crate::nibbleslice::NibbleSlice; 20 | use crate::{Node, TrieDBMut}; 21 | use ccrypto::BLAKE_NULL_RLP; 22 | use cdb::{DBValue, HashDB, MemoryDB}; 23 | use primitives::H256; 24 | use std::collections::VecDeque; 25 | use std::convert::From; 26 | 27 | #[derive(RlpEncodable, RlpDecodable, Eq, PartialEq)] 28 | pub struct TerminalNode { 29 | // Relative path from the chunk root. 30 | pub path_slice: PathSlice, 31 | pub node_rlp: Vec, 32 | } 33 | 34 | impl std::fmt::Debug for TerminalNode { 35 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 36 | let path_slice = NibbleSlice::from_encoded(&self.path_slice); 37 | f.debug_struct("TerminalNode") 38 | .field("path_slice", &path_slice) 39 | .field("node_rlp", &NodeDebugAdaptor { 40 | rlp: &self.node_rlp, 41 | }) 42 | .finish() 43 | } 44 | } 45 | 46 | struct NodeDebugAdaptor<'a> { 47 | rlp: &'a [u8], 48 | } 49 | 50 | impl<'a> std::fmt::Debug for NodeDebugAdaptor<'a> { 51 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 52 | match Node::decoded(&self.rlp) { 53 | Some(node) => write!(f, "{:?}", &node), 54 | None => write!(f, "{:?}", self.rlp), 55 | } 56 | } 57 | } 58 | 59 | /// An unverified chunk from the network 60 | #[derive(Debug)] 61 | pub struct RawChunk { 62 | pub nodes: Vec, 63 | } 64 | 65 | /// Fully recovered, and re-hydrated chunk. 66 | pub struct RecoveredChunk { 67 | pub(crate) root: H256, 68 | /// contains all nodes including non-terminal nodes and terminal nodes. 69 | /// You can blindly pour all items in `nodes` into `HashDB`. 70 | pub(crate) nodes: Vec<(H256, DBValue)>, 71 | /// Their path slices are relative to this chunk root. 72 | pub(crate) unresolved_chunks: Vec, 73 | } 74 | 75 | impl RawChunk { 76 | /// Verify and recover the chunk 77 | pub fn recover(&self, expected_chunk_root: H256) -> Result { 78 | let mut memorydb = MemoryDB::new(); 79 | let mut chunk_root = H256::zero(); 80 | 81 | { 82 | let mut trie = TrieDBMut::new(&mut memorydb, &mut chunk_root); 83 | for node in self.nodes.iter() { 84 | let old_val = match Node::decoded(&node.node_rlp) { 85 | Some(Node::Branch(slice, child)) => { 86 | let encoded = DecodedPathSlice::from_encoded(&node.path_slice).with_slice(slice).encode(); 87 | trie.insert_raw(Node::Branch(NibbleSlice::from_encoded(&encoded), child))? 88 | } 89 | Some(Node::Leaf(slice, data)) => { 90 | let encoded = DecodedPathSlice::from_encoded(&node.path_slice).with_slice(slice).encode(); 91 | trie.insert_raw(Node::Leaf(NibbleSlice::from_encoded(&encoded), data))? 92 | } 93 | None => return Err(ChunkError::InvalidContent.into()), 94 | }; 95 | 96 | if let Some(old_val) = old_val { 97 | if old_val != node.node_rlp.as_slice() { 98 | return Err(ChunkError::InvalidContent.into()) 99 | } 100 | } 101 | } 102 | } 103 | 104 | // Some nodes in the chunk is different from the expected. 105 | if chunk_root != expected_chunk_root { 106 | return Err(ChunkError::ChunkRootMismatch { 107 | expected: expected_chunk_root, 108 | actual: chunk_root, 109 | } 110 | .into()) 111 | } 112 | 113 | let mut nodes = Vec::new(); 114 | let mut unresolved_chunks = Vec::new(); 115 | let mut queue: VecDeque = VecDeque::from(vec![NodePath::new(chunk_root)]); 116 | while let Some(path) = queue.pop_front() { 117 | let node = match memorydb.get(&path.key) { 118 | Some(x) => x, 119 | None => { 120 | // all unresolved should depth == CHUNK_HEIGHT + 1 121 | if path.depth != CHUNK_HEIGHT + 1 { 122 | return Err(ChunkError::InvalidHeight.into()) 123 | } 124 | 125 | unresolved_chunks.push(UnresolvedChunk::from(path)); 126 | continue 127 | } 128 | }; 129 | 130 | if path.depth > CHUNK_HEIGHT { 131 | return Err(ChunkError::InvalidHeight.into()) 132 | } 133 | nodes.push((path.key, node.clone())); 134 | 135 | let node = Node::decoded(&node).expect("Chunk root was verified; Node can't be wrong"); 136 | if let Node::Branch(slice, children) = node { 137 | for (index, child) in children.iter().enumerate() { 138 | if let Some(child) = child { 139 | queue.push_back(path.with_slice_and_index(slice, index, *child)); 140 | } 141 | } 142 | } 143 | } 144 | 145 | Ok(RecoveredChunk { 146 | root: expected_chunk_root, 147 | nodes, 148 | unresolved_chunks, 149 | }) 150 | } 151 | } 152 | 153 | impl std::fmt::Debug for RecoveredChunk { 154 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 155 | struct Adapter<'a>(&'a [(H256, DBValue)]); 156 | impl<'a> std::fmt::Debug for Adapter<'a> { 157 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 158 | f.debug_list() 159 | .entries(self.0.iter().map(|(hash, rlp)| { 160 | (hash, NodeDebugAdaptor { 161 | rlp, 162 | }) 163 | })) 164 | .finish() 165 | } 166 | } 167 | 168 | f.debug_struct("RecoveredChunk") 169 | .field("root", &self.root) 170 | .field("nodes", &Adapter(&self.nodes)) 171 | .field("unresolved_chunks", &self.unresolved_chunks) 172 | .finish() 173 | } 174 | } 175 | 176 | /// Chunk obtained from the state db. 177 | #[derive(Debug)] 178 | pub struct Chunk { 179 | pub root: H256, 180 | pub terminal_nodes: Vec, 181 | } 182 | 183 | impl Chunk { 184 | pub(crate) fn from_chunk_root(db: &dyn HashDB, chunk_root: H256) -> Chunk { 185 | let mut unresolved: VecDeque = VecDeque::from(vec![NodePath::new(chunk_root)]); 186 | let mut terminal_nodes: Vec = Vec::new(); 187 | while let Some(path) = unresolved.pop_front() { 188 | assert!(path.key != BLAKE_NULL_RLP, "Empty DB"); 189 | assert!(path.depth <= CHUNK_HEIGHT); 190 | let node = db.get(&path.key).expect("Can't find the node in a db. DB is inconsistent"); 191 | let node_decoded = Node::decoded(&node).expect("Node cannot be decoded. DB is inconsistent"); 192 | 193 | match node_decoded { 194 | // Continue to BFS 195 | Node::Branch(slice, ref children) if path.depth < CHUNK_HEIGHT => { 196 | for (i, hash) in children.iter().enumerate() { 197 | if let Some(hash) = hash { 198 | unresolved.push_back(path.with_slice_and_index(slice, i, *hash)); 199 | } 200 | } 201 | } 202 | // Reached the terminal node. Branch at path.depth == CHUNK_HEIGHT || Leaf 203 | _ => terminal_nodes.push(TerminalNode { 204 | path_slice: path.path_slice.encode(), 205 | node_rlp: node.to_vec(), 206 | }), 207 | }; 208 | } 209 | Chunk { 210 | root: chunk_root, 211 | terminal_nodes, 212 | } 213 | } 214 | 215 | // Returns path slices to unresolved chunk roots relative to this chunk root 216 | pub(crate) fn unresolved_chunks(&self) -> Vec { 217 | let mut result = Vec::new(); 218 | for node in self.terminal_nodes.iter() { 219 | let decoded = Node::decoded(&node.node_rlp).expect("All terminal nodes should be valid"); 220 | if let Node::Branch(slice, children) = decoded { 221 | for (i, child) in children.iter().enumerate() { 222 | if let Some(child) = child { 223 | result.push(UnresolvedChunk { 224 | path_slice: DecodedPathSlice::from_encoded(&node.path_slice).with_slice_and_index(slice, i), 225 | chunk_root: *child, 226 | }) 227 | } 228 | } 229 | } 230 | } 231 | result 232 | } 233 | 234 | #[cfg(test)] 235 | pub(crate) fn into_raw_chunk(self) -> RawChunk { 236 | RawChunk { 237 | nodes: self.terminal_nodes, 238 | } 239 | } 240 | } 241 | 242 | /// path slice to `chunk_root` is relative to the root of originating chunk. 243 | #[derive(Debug)] 244 | pub(crate) struct UnresolvedChunk { 245 | pub path_slice: DecodedPathSlice, 246 | pub chunk_root: H256, 247 | } 248 | 249 | impl From for UnresolvedChunk { 250 | fn from(path: NodePath) -> Self { 251 | Self { 252 | path_slice: path.path_slice, 253 | chunk_root: path.key, 254 | } 255 | } 256 | } 257 | 258 | #[derive(Debug)] 259 | struct NodePath { 260 | // path slice to the node relative to chunk_root 261 | path_slice: DecodedPathSlice, 262 | depth: usize, 263 | key: H256, 264 | } 265 | 266 | impl NodePath { 267 | fn new(key: H256) -> NodePath { 268 | NodePath { 269 | path_slice: DecodedPathSlice::new(), 270 | depth: 1, 271 | key, 272 | } 273 | } 274 | 275 | fn with_slice_and_index(&self, slice: NibbleSlice, index: usize, key: H256) -> NodePath { 276 | NodePath { 277 | path_slice: self.path_slice.with_slice_and_index(slice, index), 278 | depth: self.depth + 1, 279 | key, 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /src/snapshot/compress.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use super::chunk::{Chunk, RawChunk}; 18 | use super::error::{ChunkError, Error}; 19 | use super::CHUNK_MAX_NODES; 20 | use rlp::{Rlp, RlpStream}; 21 | use std::io::{Cursor, Read, Write}; 22 | 23 | pub struct ChunkDecompressor { 24 | read: R, 25 | } 26 | 27 | impl ChunkDecompressor { 28 | pub fn new(read: R) -> Self { 29 | ChunkDecompressor { 30 | read, 31 | } 32 | } 33 | } 34 | 35 | impl<'a> ChunkDecompressor> { 36 | pub fn from_slice(slice: &'a [u8]) -> Self { 37 | ChunkDecompressor::new(Cursor::new(slice)) 38 | } 39 | } 40 | 41 | impl ChunkDecompressor 42 | where 43 | R: Read + Clone, 44 | { 45 | pub fn decompress(self) -> Result { 46 | let mut buf = Vec::new(); 47 | 48 | let mut snappy = snap::Reader::new(self.read); 49 | snappy.read_to_end(&mut buf)?; 50 | 51 | let rlp = Rlp::new(&buf); 52 | let len = rlp.item_count()?; 53 | if len > CHUNK_MAX_NODES { 54 | return Err(ChunkError::TooBig.into()) 55 | } 56 | 57 | Ok(RawChunk { 58 | nodes: rlp.as_list()?, 59 | }) 60 | } 61 | } 62 | 63 | pub struct ChunkCompressor { 64 | write: W, 65 | } 66 | 67 | impl ChunkCompressor { 68 | pub fn new(write: W) -> Self { 69 | ChunkCompressor { 70 | write, 71 | } 72 | } 73 | } 74 | 75 | impl ChunkCompressor 76 | where 77 | W: Write, 78 | { 79 | pub fn compress_chunk(self, chunk: &Chunk) -> Result<(), Error> { 80 | let mut rlp = RlpStream::new_list(chunk.terminal_nodes.len()); 81 | for node in chunk.terminal_nodes.iter() { 82 | rlp.append(node); 83 | } 84 | let mut snappy = snap::Writer::new(self.write); 85 | snappy.write_all(rlp.as_raw())?; 86 | Ok(()) 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod test { 92 | use super::*; 93 | use crate::snapshot::chunk::{Chunk, TerminalNode}; 94 | 95 | #[test] 96 | fn test_compress_decompress() { 97 | let chunk = Chunk { 98 | root: Default::default(), 99 | terminal_nodes: vec![ 100 | (TerminalNode { 101 | path_slice: b"12345".to_vec(), 102 | node_rlp: b"45678".to_vec(), 103 | }), 104 | (TerminalNode { 105 | path_slice: b"56789".to_vec(), 106 | node_rlp: b"123abc".to_vec(), 107 | }), 108 | ], 109 | }; 110 | 111 | let mut buffer = Vec::new(); 112 | ChunkCompressor::new(&mut buffer).compress_chunk(&chunk).unwrap(); 113 | let decompressed = ChunkDecompressor::from_slice(&buffer).decompress().unwrap(); 114 | 115 | assert_eq!(chunk.terminal_nodes, decompressed.nodes); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/snapshot/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::TrieError; 18 | use primitives::H256; 19 | use rlp::DecoderError as RlpDecoderError; 20 | use std::fmt::{Display, Formatter}; 21 | use std::io::Error as IoError; 22 | 23 | #[derive(Debug)] 24 | pub enum Error { 25 | IoError(IoError), 26 | RlpDecoderError(RlpDecoderError), 27 | TrieError(TrieError), 28 | ChunkError(ChunkError), 29 | } 30 | 31 | impl From for Error { 32 | fn from(err: IoError) -> Self { 33 | Error::IoError(err) 34 | } 35 | } 36 | 37 | impl From for Error { 38 | fn from(err: RlpDecoderError) -> Self { 39 | Error::RlpDecoderError(err) 40 | } 41 | } 42 | 43 | impl From for Error { 44 | fn from(err: TrieError) -> Self { 45 | Error::TrieError(err) 46 | } 47 | } 48 | 49 | impl From for Error { 50 | fn from(err: ChunkError) -> Self { 51 | Error::ChunkError(err) 52 | } 53 | } 54 | 55 | impl Display for Error { 56 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { 57 | match self { 58 | Error::IoError(err) => write!(f, "IoError: {}", err), 59 | Error::RlpDecoderError(err) => write!(f, "RlpDecoderError: {}", err), 60 | Error::TrieError(err) => write!(f, "TrieError: {}", err), 61 | Error::ChunkError(err) => write!(f, "ChunkError: {}", err), 62 | } 63 | } 64 | } 65 | 66 | #[derive(Debug)] 67 | pub enum ChunkError { 68 | TooBig, 69 | InvalidHeight, 70 | ChunkRootMismatch { 71 | expected: H256, 72 | actual: H256, 73 | }, 74 | InvalidContent, 75 | } 76 | 77 | impl Display for ChunkError { 78 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { 79 | match self { 80 | ChunkError::TooBig => write!(f, "Chunk has too many elements"), 81 | ChunkError::InvalidHeight => write!(f, "Chunk height is unexpected height"), 82 | ChunkError::ChunkRootMismatch { 83 | expected, 84 | actual, 85 | } => write!(f, "Chunk root is different from expected. expected: {}, actual: {}", expected, actual), 86 | ChunkError::InvalidContent => write!(f, "Chunk content is invalid"), 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/snapshot/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | mod chunk; 18 | mod compress; 19 | mod error; 20 | mod ordered_heap; 21 | 22 | use self::chunk::{Chunk, RecoveredChunk, UnresolvedChunk}; 23 | pub use self::compress::{ChunkCompressor, ChunkDecompressor}; 24 | pub use self::error::Error; 25 | use self::ordered_heap::OrderedHeap; 26 | use crate::nibbleslice::NibbleSlice; 27 | use ccrypto::BLAKE_NULL_RLP; 28 | use cdb::HashDB; 29 | use primitives::H256; 30 | use std::cmp::Ordering; 31 | 32 | const CHUNK_HEIGHT: usize = 3; 33 | const CHUNK_MAX_NODES: usize = 256; // 16 ^ (CHUNK_HEIGHT-1) 34 | 35 | /// Example: 36 | /// use codechain_merkle::snapshot::Restore; 37 | /// let mut rm = Restore::new(root); 38 | /// while let Some(root) = rm.next_to_feed() { 39 | /// let raw_chunk = request(block_hash, root)?; 40 | /// let chunk = raw_chunk.recover(root)?; 41 | /// rm.feed(db, chunk); 42 | /// } 43 | pub struct Restore { 44 | pending: Option, 45 | unresolved: OrderedHeap>, 46 | } 47 | 48 | impl Restore { 49 | pub fn new(merkle_root: H256) -> Self { 50 | let mut result = Restore { 51 | pending: None, 52 | unresolved: OrderedHeap::new(), 53 | }; 54 | if merkle_root != BLAKE_NULL_RLP { 55 | result.unresolved.push(ChunkPathPrefix::new(merkle_root).into()); 56 | } 57 | result 58 | } 59 | 60 | pub fn feed(&mut self, db: &mut dyn HashDB, chunk: RecoveredChunk) { 61 | let pending_path = self.pending.take().expect("feed() should be called after next()"); 62 | assert_eq!(pending_path.chunk_root, chunk.root, "Unexpected chunk"); 63 | 64 | // Pour nodes into the DB 65 | for (_, value) in chunk.nodes { 66 | db.insert(&value); 67 | } 68 | 69 | // Extend search paths 70 | for unresolved in chunk.unresolved_chunks { 71 | self.unresolved.push(pending_path.with_unresolved_chunk(&unresolved).into()); 72 | } 73 | 74 | self.pending = None; 75 | } 76 | 77 | pub fn next_to_feed(&mut self) -> Option { 78 | if let Some(pending) = &self.pending { 79 | Some(pending.chunk_root) 80 | } else if let Some(path) = self.unresolved.pop() { 81 | let chunk_root = path.chunk_root; 82 | self.pending = Some(path.0); 83 | 84 | Some(chunk_root) 85 | } else { 86 | None 87 | } 88 | } 89 | } 90 | 91 | impl std::fmt::Debug for Restore { 92 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 93 | f.debug_struct("Restore").field("pending", &self.pending).field("unresolved", &"<...>".to_string()).finish() 94 | } 95 | } 96 | 97 | /// Example: 98 | /// use std::fs::File; 99 | /// use codechain_merkle::snapshot::Snapshot; 100 | /// 101 | /// for chunk in Snapshot::from_hashdb(db, root) { 102 | /// let mut file = File::create(format!("{}/{}", block_id, chunk.root))?; 103 | /// let mut compressor = ChunkCompressor::new(&mut file); 104 | /// compressor.compress(chunk); 105 | /// } 106 | pub struct Snapshot<'a> { 107 | db: &'a dyn HashDB, 108 | remaining: OrderedHeap>, 109 | } 110 | 111 | impl<'a> Snapshot<'a> { 112 | pub fn from_hashdb(db: &'a dyn HashDB, chunk_root: H256) -> Self { 113 | let mut result = Snapshot { 114 | db, 115 | remaining: OrderedHeap::new(), 116 | }; 117 | if chunk_root != BLAKE_NULL_RLP { 118 | result.remaining.push(ChunkPathPrefix::new(chunk_root).into()); 119 | } 120 | result 121 | } 122 | } 123 | 124 | impl<'a> Iterator for Snapshot<'a> { 125 | type Item = Chunk; 126 | 127 | fn next(&mut self) -> Option { 128 | if let Some(path) = self.remaining.pop() { 129 | let chunk = Chunk::from_chunk_root(self.db, path.chunk_root); 130 | for unresolved in chunk.unresolved_chunks() { 131 | self.remaining.push(path.with_unresolved_chunk(&unresolved).into()); 132 | } 133 | Some(chunk) 134 | } else { 135 | None 136 | } 137 | } 138 | } 139 | 140 | 141 | #[derive(Debug)] 142 | struct ChunkPathPrefix { 143 | // Absolute path prefix of the chunk root 144 | path_prefix: DecodedPathSlice, 145 | depth: usize, 146 | chunk_root: H256, 147 | } 148 | 149 | impl ChunkPathPrefix { 150 | fn new(chunk_root: H256) -> ChunkPathPrefix { 151 | ChunkPathPrefix { 152 | path_prefix: DecodedPathSlice::new(), 153 | depth: 1, 154 | chunk_root, 155 | } 156 | } 157 | 158 | fn with_unresolved_chunk(&self, unresolved: &UnresolvedChunk) -> ChunkPathPrefix { 159 | ChunkPathPrefix { 160 | path_prefix: self.path_prefix.with_path_slice(&unresolved.path_slice), 161 | depth: self.depth + 1, 162 | chunk_root: unresolved.chunk_root, 163 | } 164 | } 165 | } 166 | 167 | impl Ord for DepthFirst { 168 | fn cmp(&self, other: &Self) -> Ordering { 169 | self.0.depth.cmp(&other.0.depth) 170 | } 171 | } 172 | 173 | impl From for DepthFirst { 174 | fn from(path: ChunkPathPrefix) -> Self { 175 | DepthFirst(path) 176 | } 177 | } 178 | 179 | /// Encoded value by NibbleSlice::encoded() 180 | pub type PathSlice = Vec; 181 | 182 | /// for item i, i in 0..16 183 | pub(crate) struct DecodedPathSlice(Vec); 184 | 185 | impl DecodedPathSlice { 186 | fn new() -> DecodedPathSlice { 187 | DecodedPathSlice(Vec::new()) 188 | } 189 | 190 | fn from_encoded(slice: &[u8]) -> DecodedPathSlice { 191 | DecodedPathSlice(NibbleSlice::from_encoded(slice).to_vec()) 192 | } 193 | 194 | fn with_slice_and_index(&self, slice: NibbleSlice, i: usize) -> DecodedPathSlice { 195 | assert!(i < 16); 196 | let mut v = self.0.clone(); 197 | v.append(&mut slice.to_vec()); 198 | v.push(i as u8); 199 | DecodedPathSlice(v) 200 | } 201 | 202 | fn with_slice(&self, slice: NibbleSlice) -> DecodedPathSlice { 203 | let mut v = self.0.clone(); 204 | v.append(&mut slice.to_vec()); 205 | DecodedPathSlice(v) 206 | } 207 | 208 | fn with_path_slice(&self, path_slice: &DecodedPathSlice) -> DecodedPathSlice { 209 | let mut v = self.0.clone(); 210 | v.extend(path_slice.0.as_slice()); 211 | DecodedPathSlice(v) 212 | } 213 | 214 | fn encode(&self) -> PathSlice { 215 | let (encoded, _) = NibbleSlice::from_vec(&self.0); 216 | encoded.to_vec() 217 | } 218 | } 219 | 220 | impl std::fmt::Debug for DecodedPathSlice { 221 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 222 | let (encoded, _) = NibbleSlice::from_vec(&self.0); 223 | let nibble_slice = NibbleSlice::from_encoded(&encoded); 224 | writeln!(f, "{:?}", nibble_slice) 225 | } 226 | } 227 | 228 | #[derive(Debug)] 229 | struct DepthFirst(T); 230 | 231 | impl PartialOrd for DepthFirst 232 | where 233 | Self: Ord, 234 | { 235 | fn partial_cmp(&self, other: &Self) -> Option { 236 | Some(self.cmp(&other)) 237 | } 238 | } 239 | 240 | impl PartialEq for DepthFirst 241 | where 242 | Self: Ord, 243 | { 244 | fn eq(&self, other: &Self) -> bool { 245 | self.cmp(other) == Ordering::Equal 246 | } 247 | } 248 | 249 | impl Eq for DepthFirst where Self: Ord {} 250 | 251 | impl std::ops::Deref for DepthFirst { 252 | type Target = T; 253 | 254 | fn deref(&self) -> &Self::Target { 255 | &self.0 256 | } 257 | } 258 | 259 | #[cfg(test)] 260 | mod tests { 261 | use super::*; 262 | 263 | use std::collections::HashMap; 264 | use std::iter::FromIterator; 265 | 266 | use cdb::MemoryDB; 267 | use primitives::{Bytes, H256}; 268 | use standardmap::{Alphabet, StandardMap, ValueMode}; 269 | 270 | use super::chunk::RawChunk; 271 | use crate::{Trie, TrieDB, TrieDBMut, TrieMut}; 272 | 273 | fn random_insert_and_restore_with_count(count: usize) { 274 | let standard_map = StandardMap { 275 | alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), 276 | min_key: 5, 277 | journal_key: 0, 278 | value_mode: ValueMode::Index, 279 | count, 280 | } 281 | .make_with(&mut H256::zero()); 282 | // Unique standard map 283 | let unique_map: HashMap = HashMap::from_iter(standard_map.into_iter()); 284 | 285 | let mut root = H256::zero(); 286 | let chunks: HashMap = { 287 | // We will throw out `db` after snapshot. 288 | let mut db = MemoryDB::new(); 289 | let mut trie = TrieDBMut::new(&mut db, &mut root); 290 | for (key, value) in &unique_map { 291 | trie.insert(key, value).unwrap(); 292 | } 293 | 294 | Snapshot::from_hashdb(&db, root).map(|chunk| (chunk.root, chunk.into_raw_chunk())).collect() 295 | }; 296 | dbg!(chunks.len()); 297 | 298 | let mut db = MemoryDB::new(); 299 | let mut recover = Restore::new(root); 300 | while let Some(chunk_root) = recover.next_to_feed() { 301 | let recovered = chunks[&chunk_root].recover(chunk_root).unwrap(); 302 | recover.feed(&mut db, recovered); 303 | } 304 | 305 | let trie = TrieDB::try_new(&db, &root).unwrap(); 306 | for (key, value) in &unique_map { 307 | assert_eq!(trie.get(key).unwrap().as_ref(), Some(value)); 308 | } 309 | } 310 | 311 | #[test] 312 | fn random_insert_and_restore_0() { 313 | random_insert_and_restore_with_count(0); 314 | } 315 | 316 | #[test] 317 | fn random_insert_and_restore_1() { 318 | random_insert_and_restore_with_count(1); 319 | } 320 | 321 | #[test] 322 | fn random_insert_and_restore_2() { 323 | random_insert_and_restore_with_count(2); 324 | } 325 | 326 | #[test] 327 | fn random_insert_and_restore_100() { 328 | random_insert_and_restore_with_count(100); 329 | } 330 | 331 | #[test] 332 | fn random_insert_and_restore_10000() { 333 | random_insert_and_restore_with_count(10_000); 334 | } 335 | 336 | #[test] 337 | #[ignore] 338 | fn random_insert_and_restore_100000() { 339 | random_insert_and_restore_with_count(100_000); 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/snapshot/ordered_heap.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; 18 | use std::collections::BinaryHeap; 19 | 20 | pub struct OrderedHeap { 21 | heap: BinaryHeap>, 22 | seq: usize, 23 | } 24 | 25 | impl OrderedHeap { 26 | pub fn new() -> OrderedHeap { 27 | OrderedHeap { 28 | heap: BinaryHeap::new(), 29 | seq: 0, 30 | } 31 | } 32 | 33 | pub fn push(&mut self, value: T) { 34 | self.heap.push(OrderedHeapEntry { 35 | seq: self.seq, 36 | value, 37 | }); 38 | self.seq += 1; 39 | } 40 | 41 | pub fn pop(&mut self) -> Option { 42 | self.heap.pop().map(|x| x.value) 43 | } 44 | } 45 | 46 | #[derive(Debug, Clone)] 47 | struct OrderedHeapEntry { 48 | seq: usize, 49 | value: T, 50 | } 51 | 52 | impl Ord for OrderedHeapEntry { 53 | fn cmp(&self, other: &Self) -> Ordering { 54 | self.value.cmp(&other.value).then(self.seq.cmp(&other.seq).reverse()) 55 | } 56 | } 57 | 58 | impl PartialOrd for OrderedHeapEntry 59 | where 60 | Self: Ord, 61 | { 62 | fn partial_cmp(&self, other: &Self) -> Option { 63 | Some(self.cmp(&other)) 64 | } 65 | } 66 | 67 | impl PartialEq for OrderedHeapEntry 68 | where 69 | Self: Ord, 70 | { 71 | fn eq(&self, other: &Self) -> bool { 72 | self.cmp(other) == Ordering::Equal 73 | } 74 | } 75 | 76 | impl Eq for OrderedHeapEntry where Self: Ord {} 77 | -------------------------------------------------------------------------------- /src/triedb.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::nibbleslice::NibbleSlice; 18 | use crate::node::Node as RlpNode; 19 | use crate::proof::{CryptoProof, CryptoProofUnit, CryptoStructure}; 20 | use crate::{Node, Trie, TrieError}; 21 | use ccrypto::{blake256, BLAKE_NULL_RLP}; 22 | use cdb::HashDB; 23 | use lru_cache::LruCache; 24 | use primitives::Bytes; 25 | use primitives::H256; 26 | use std::cell::RefCell; 27 | 28 | /// A `Trie` implementation using a generic `HashDB` backing database. 29 | /// 30 | /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object. 31 | /// Use `get` and `contains` to query values associated with keys in the trie. 32 | /// 33 | /// # Example 34 | /// ``` 35 | /// use cdb::*; 36 | /// use merkle_trie::*; 37 | /// use primitives::H256; 38 | /// 39 | /// let mut memdb = MemoryDB::new(); 40 | /// let mut root = H256::zero(); 41 | /// TrieFactory::create(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap(); 42 | /// let t = TrieFactory::readonly(&memdb, &root).unwrap(); 43 | /// assert!(t.contains(b"foo").unwrap()); 44 | /// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar".to_vec()); 45 | /// ``` 46 | 47 | pub(crate) struct TrieDB<'db> { 48 | db: &'db dyn HashDB, 49 | root: &'db H256, 50 | cache: RefCell>>, 51 | } 52 | 53 | /// Description of what kind of query will be made to the trie. 54 | type Query = dyn Fn(&[u8]) -> T; 55 | 56 | impl<'db> TrieDB<'db> { 57 | /// Create a new trie with the backing database `db` and `root` 58 | /// Returns an error if `root` does not exist 59 | pub fn try_new(db: &'db dyn HashDB, root: &'db H256) -> crate::Result { 60 | let cache: RefCell>> = RefCell::new(LruCache::new(3000)); 61 | if !db.contains(root) { 62 | Err(TrieError::InvalidStateRoot(*root)) 63 | } else { 64 | Ok(TrieDB { 65 | db, 66 | root, 67 | cache, 68 | }) 69 | } 70 | } 71 | 72 | /// Get auxiliary 73 | fn get_aux( 74 | &self, 75 | path: &NibbleSlice<'_>, 76 | cur_node_hash: Option, 77 | query: &Query, 78 | ) -> crate::Result> { 79 | match cur_node_hash { 80 | Some(hash) => { 81 | // FIXME: Refactoring is required to reduce access to the cache. 82 | // the current code queries the cache twice when the data is cached. 83 | let node_rlp; 84 | let decoded_rlp = if self.cache.borrow_mut().contains_key(&hash) { 85 | node_rlp = self.cache.borrow_mut().get_mut(&hash).unwrap().to_vec(); 86 | RlpNode::decoded(&node_rlp) 87 | } else { 88 | node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; 89 | self.cache.borrow_mut().insert(hash, (&*node_rlp).to_vec()); 90 | RlpNode::decoded(&node_rlp) 91 | }; 92 | 93 | match decoded_rlp { 94 | Some(RlpNode::Leaf(partial, value)) => { 95 | if &partial == path { 96 | Ok(Some(query(value))) 97 | } else { 98 | Ok(None) 99 | } 100 | } 101 | Some(RlpNode::Branch(partial, children)) => { 102 | if path.starts_with(&partial) { 103 | self.get_aux(&path.mid(partial.len() + 1), children[path.at(partial.len()) as usize], query) 104 | } else { 105 | Ok(None) 106 | } 107 | } 108 | None => Ok(None), 109 | } 110 | } 111 | None => Ok(None), 112 | } 113 | } 114 | 115 | /// Check if every leaf of the trie starting from `hash` exists 116 | fn is_complete_aux(&self, hash: &H256) -> bool { 117 | if let Some(node_rlp) = self.db.get(hash) { 118 | match RlpNode::decoded(node_rlp.as_ref()) { 119 | Some(RlpNode::Branch(.., children)) => { 120 | children.iter().flatten().all(|child| self.is_complete_aux(child)) 121 | } 122 | Some(RlpNode::Leaf(..)) => true, 123 | None => false, 124 | } 125 | } else { 126 | false 127 | } 128 | } 129 | } 130 | 131 | impl<'db> Trie for TrieDB<'db> { 132 | fn root(&self) -> &H256 { 133 | self.root 134 | } 135 | 136 | fn get(&self, key: &[u8]) -> Result>, TrieError> { 137 | let path = blake256(key); 138 | let root = *self.root; 139 | 140 | self.get_aux(&NibbleSlice::new(path.as_bytes()), Some(root), &|bytes| bytes.to_vec()) 141 | } 142 | 143 | fn is_complete(&self) -> bool { 144 | *self.root == BLAKE_NULL_RLP || self.is_complete_aux(self.root) 145 | } 146 | } 147 | 148 | impl<'db> CryptoStructure for TrieDB<'db> { 149 | /// A proof creation logic for TrieDB. 150 | /// A proof is basically a list of serialized trie nodes, Vec. 151 | /// It starts from the one closest to the root and to the leaf. (It may not reach the leaf in absence case.) 152 | /// Each node can be decoded with RLP. (Note that RLP doesn't guarantee format detail, so you must check our serialization code.) 153 | /// In case of precense, the list will contain a path from the root to the leaf with the key. 154 | /// In case of absence, the list will contain a path to the last node that matches the key. 155 | // 156 | // (A: [nil]) 157 | // / \ 158 | // (B, g) \ 159 | // / \ \ 160 | // (C, iant) (D, mail) (E, clang) 161 | // 162 | // Here, the proof of key 'gmail' will be [(RLP encoding of A), (RLP encoding of B), (RLP encoding of D)] 163 | // Here, the proof of key 'galbi' (absence) will be [(RLP encoding of A), (RLP encoding of B)] 164 | fn make_proof(&self, key: &[u8]) -> crate::Result<(CryptoProofUnit, CryptoProof)> { 165 | // it creates a reversed proof for the sake of a more efficient push() operation. (than concat) 166 | fn make_proof_upto( 167 | db: &dyn HashDB, 168 | path: &NibbleSlice<'_>, 169 | hash: &H256, 170 | ) -> crate::Result<(Option, Vec)> { 171 | let node_rlp = db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(*hash))?; 172 | 173 | match Node::decoded(&node_rlp) { 174 | Some(Node::Leaf(partial, value)) => { 175 | if &partial == path { 176 | Ok((Some(value.to_vec()), vec![node_rlp])) 177 | } else { 178 | Ok((None, vec![node_rlp])) 179 | } 180 | } 181 | Some(Node::Branch(partial, children)) => { 182 | if path.starts_with(&partial) { 183 | match children[path.at(partial.len()) as usize] { 184 | Some(x) => { 185 | let (value, mut reversed_proof) = 186 | make_proof_upto(db, &path.mid(partial.len() + 1), &x)?; 187 | reversed_proof.push(node_rlp); 188 | Ok((value, reversed_proof)) 189 | } 190 | None => Ok((None, vec![node_rlp])), 191 | } 192 | } else { 193 | Ok((None, Vec::new())) 194 | } 195 | } 196 | None => Ok((None, Vec::new())), // empty trie 197 | } 198 | } 199 | let path = blake256(key); 200 | let (value, reversed_proof) = make_proof_upto(self.db, &NibbleSlice::new(path.as_bytes()), self.root())?; 201 | let unit = CryptoProofUnit { 202 | root: *self.root(), 203 | key: key.to_vec(), 204 | value, 205 | }; 206 | Ok((unit, CryptoProof(reversed_proof.iter().rev().cloned().collect()))) 207 | } 208 | } 209 | 210 | #[cfg(test)] 211 | mod tests { 212 | use cdb::MemoryDB; 213 | 214 | use super::*; 215 | use crate::*; 216 | 217 | fn delete_any_child(db: &mut MemoryDB, root: &H256) { 218 | let node_rlp = db.get(root).unwrap(); 219 | match RlpNode::decoded(&node_rlp).unwrap() { 220 | RlpNode::Leaf(..) => { 221 | db.remove(root); 222 | } 223 | RlpNode::Branch(.., children) => { 224 | let first_child = children.iter().find(|c| c.is_some()).unwrap().unwrap(); 225 | db.remove(&first_child); 226 | } 227 | } 228 | } 229 | 230 | #[test] 231 | fn get() { 232 | let mut memdb = MemoryDB::new(); 233 | let mut root = H256::zero(); 234 | { 235 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 236 | t.insert(b"A", b"ABC").unwrap(); 237 | t.insert(b"B", b"ABCBA").unwrap(); 238 | } 239 | 240 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 241 | assert_eq!(t.get(b"A"), Ok(Some(b"ABC".to_vec()))); 242 | assert_eq!(t.get(b"B"), Ok(Some(b"ABCBA".to_vec()))); 243 | assert_eq!(t.get(b"C"), Ok(None)); 244 | } 245 | 246 | #[test] 247 | fn is_complete_success() { 248 | let mut memdb = MemoryDB::new(); 249 | let mut root = H256::zero(); 250 | { 251 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 252 | t.insert(b"A", b"ABC").unwrap(); 253 | t.insert(b"B", b"ABCBA").unwrap(); 254 | } 255 | 256 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 257 | assert!(t.is_complete()); 258 | } 259 | 260 | #[test] 261 | fn is_complete_fail() { 262 | let mut memdb = MemoryDB::new(); 263 | let mut root = H256::zero(); 264 | { 265 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 266 | t.insert(b"A", b"ABC").unwrap(); 267 | t.insert(b"B", b"ABCBA").unwrap(); 268 | } 269 | delete_any_child(&mut memdb, &root); 270 | 271 | let t = TrieDB::try_new(&memdb, &root).unwrap(); 272 | assert!(!t.is_complete()); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/triedbmut.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | use crate::nibbleslice::NibbleSlice; 18 | use crate::node::Node as RlpNode; 19 | use crate::proof::{CryptoProof, CryptoProofUnit, CryptoStructure}; 20 | use crate::triedb::TrieDB; 21 | use crate::{Trie, TrieError, TrieMut}; 22 | use ccrypto::{blake256, BLAKE_NULL_RLP}; 23 | use cdb::{DBValue, HashDB}; 24 | use lru_cache::LruCache; 25 | use primitives::H256; 26 | use std::fmt; 27 | 28 | fn empty_children() -> [Option; 16] { 29 | [None; 16] 30 | } 31 | 32 | pub(crate) struct TrieDBMut<'a> { 33 | db: &'a mut dyn HashDB, 34 | // When Trie is empty, root has None. 35 | root: &'a mut H256, 36 | cache: LruCache>, 37 | } 38 | 39 | impl<'a> TrieDBMut<'a> { 40 | /// Create a new trie with backing database `db` and empty `root`. 41 | pub fn new(db: &'a mut dyn HashDB, root: &'a mut H256) -> Self { 42 | *root = BLAKE_NULL_RLP; 43 | 44 | let cache: LruCache> = LruCache::new(3000); 45 | TrieDBMut { 46 | db, 47 | root, 48 | cache, 49 | } 50 | } 51 | 52 | /// Create a new trie with the backing database `db` and `root. 53 | /// Returns an error if `root` does not exist. 54 | pub fn from_existing(db: &'a mut dyn HashDB, root: &'a mut H256) -> crate::Result { 55 | if !db.contains(root) { 56 | return Err(TrieError::InvalidStateRoot(*root)) 57 | } 58 | 59 | let cache: LruCache> = LruCache::new(3000); 60 | Ok(TrieDBMut { 61 | db, 62 | root, 63 | cache, 64 | }) 65 | } 66 | 67 | /// Insert auxiliary 68 | fn insert_aux( 69 | &mut self, 70 | path: NibbleSlice<'_>, 71 | insert_value: &[u8], 72 | cur_node_hash: Option, 73 | old_val: &mut Option, 74 | ) -> crate::Result { 75 | match cur_node_hash { 76 | Some(hash) => { 77 | // FIXME: Refactoring is required to reduce access to the cache. 78 | // the current code queries the cache twice when the data is cached. 79 | let node_rlp; 80 | let decoded_rlp = if self.cache.contains_key(&hash) { 81 | node_rlp = self.cache.get_mut(&hash).unwrap().to_vec(); 82 | RlpNode::decoded(&node_rlp) 83 | } else { 84 | node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; 85 | self.cache.insert(hash, (&*node_rlp).to_vec()); 86 | RlpNode::decoded(&node_rlp) 87 | }; 88 | 89 | match decoded_rlp { 90 | Some(RlpNode::Leaf(partial, value)) => { 91 | // Renew the Leaf 92 | if partial == path { 93 | let node = RlpNode::Leaf(path, insert_value); 94 | let node_rlp = RlpNode::encoded(node); 95 | let hash = self.db.insert(&node_rlp); 96 | 97 | self.cache.insert(hash, node_rlp); 98 | *old_val = Some(value.to_vec()); 99 | 100 | Ok(hash) 101 | } else { 102 | // Make branch node and insert Leaves 103 | let common = partial.common_prefix(&path); 104 | let mut new_child = empty_children(); 105 | let new_partial = partial.mid(common); 106 | let new_path = path.mid(common); 107 | 108 | new_child[new_partial.at(0) as usize] = Some(self.insert_aux( 109 | new_partial.mid(1), 110 | value, 111 | new_child[new_partial.at(0) as usize], 112 | old_val, 113 | )?); 114 | new_child[new_path.at(0) as usize] = Some(self.insert_aux( 115 | new_path.mid(1), 116 | insert_value, 117 | new_child[new_path.at(0) as usize], 118 | old_val, 119 | )?); 120 | 121 | let node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common); 122 | let hash = self.db.insert(&node_rlp); 123 | self.cache.insert(hash, node_rlp); 124 | 125 | Ok(hash) 126 | } 127 | } 128 | Some(RlpNode::Branch(partial, mut children)) => { 129 | let common = partial.common_prefix(&path); 130 | 131 | // Make new branch node and insert leaf and branch with new path 132 | if common < partial.len() { 133 | let mut new_child = empty_children(); 134 | let new_partial = partial.mid(common); 135 | let new_path = path.mid(common); 136 | let o_branch = RlpNode::Branch(new_partial.mid(1), children); 137 | 138 | let mut node_rlp = RlpNode::encoded(o_branch); 139 | let b_hash = self.db.insert(&node_rlp); 140 | self.cache.insert(b_hash, node_rlp); 141 | 142 | new_child[new_partial.at(0) as usize] = Some(b_hash); 143 | new_child[new_path.at(0) as usize] = Some(self.insert_aux( 144 | new_path.mid(1), 145 | insert_value, 146 | new_child[new_path.at(0) as usize], 147 | old_val, 148 | )?); 149 | 150 | node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common); 151 | let hash = self.db.insert(&node_rlp); 152 | self.cache.insert(hash, node_rlp); 153 | 154 | Ok(hash) 155 | } else { 156 | // Insert leaf into the branch node 157 | let new_path = path.mid(common); 158 | 159 | children[new_path.at(0) as usize] = Some(self.insert_aux( 160 | new_path.mid(1), 161 | insert_value, 162 | children[new_path.at(0) as usize], 163 | old_val, 164 | )?); 165 | 166 | let new_branch = RlpNode::Branch(partial, children); 167 | let node_rlp = RlpNode::encoded(new_branch); 168 | let hash = self.db.insert(&node_rlp); 169 | self.cache.insert(hash, node_rlp); 170 | 171 | Ok(hash) 172 | } 173 | } 174 | None => { 175 | let node = RlpNode::Leaf(path, insert_value); 176 | let node_rlp = RlpNode::encoded(node); 177 | let hash = self.db.insert(&node_rlp); 178 | self.cache.insert(hash, node_rlp); 179 | 180 | Ok(hash) 181 | } 182 | } 183 | } 184 | None => { 185 | let node = RlpNode::Leaf(path, insert_value); 186 | let node_rlp = RlpNode::encoded(node); 187 | let hash = self.db.insert(&node_rlp); 188 | self.cache.insert(hash, node_rlp); 189 | 190 | Ok(hash) 191 | } 192 | } 193 | } 194 | 195 | pub(crate) fn insert_raw(&mut self, node: RlpNode) -> crate::Result> { 196 | let mut old_val = None; 197 | let cur_hash = *self.root; 198 | *self.root = self.insert_raw_aux(node, Some(cur_hash), &mut old_val)?; 199 | 200 | Ok(old_val) 201 | } 202 | 203 | fn insert_raw_aux( 204 | &mut self, 205 | node: RlpNode, 206 | cur_node_hash: Option, 207 | old_val: &mut Option, 208 | ) -> crate::Result { 209 | let path = match &node { 210 | RlpNode::Leaf(slice, _) | RlpNode::Branch(slice, _) => slice, 211 | }; 212 | 213 | match cur_node_hash { 214 | Some(hash) => { 215 | let existing_node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; 216 | match RlpNode::decoded(&existing_node_rlp) { 217 | Some(RlpNode::Leaf(partial, value)) => { 218 | // Renew the Leaf 219 | if &partial == path { 220 | let hash = self.db.insert(&RlpNode::encoded(node)); 221 | *old_val = Some(existing_node_rlp); 222 | Ok(hash) 223 | } else { 224 | // Make branch node and insert Leaves 225 | let common = partial.common_prefix(&path); 226 | let mut new_child = empty_children(); 227 | let new_partial = partial.mid(common); 228 | let new_path = path.mid(common); 229 | new_child[new_partial.at(0) as usize] = Some(self.insert_aux( 230 | new_partial.mid(1), 231 | value, 232 | new_child[new_partial.at(0) as usize], 233 | old_val, 234 | )?); 235 | new_child[new_path.at(0) as usize] = Some(self.insert_raw_aux( 236 | node.mid(common + 1), 237 | new_child[new_path.at(0) as usize], 238 | old_val, 239 | )?); 240 | 241 | let hash = self 242 | .db 243 | .insert(&RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common)); 244 | 245 | Ok(hash) 246 | } 247 | } 248 | Some(RlpNode::Branch(partial, mut children)) => { 249 | let common = partial.common_prefix(&path); 250 | 251 | // Make new branch node and insert leaf and branch with new path 252 | if common < partial.len() { 253 | let mut new_child = empty_children(); 254 | let new_partial = partial.mid(common); 255 | let new_path = path.mid(common); 256 | let o_branch = RlpNode::Branch(new_partial.mid(1), children); 257 | 258 | let b_hash = self.db.insert(&RlpNode::encoded(o_branch)); 259 | 260 | new_child[new_partial.at(0) as usize] = Some(b_hash); 261 | new_child[new_path.at(0) as usize] = Some(self.insert_raw_aux( 262 | node.mid(common + 1), 263 | new_child[new_path.at(0) as usize], 264 | old_val, 265 | )?); 266 | 267 | let hash = self 268 | .db 269 | .insert(&RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common)); 270 | 271 | Ok(hash) 272 | } else { 273 | // Insert leaf into the branch node 274 | let new_path = path.mid(common); 275 | 276 | children[new_path.at(0) as usize] = Some(self.insert_raw_aux( 277 | node.mid(common + 1), 278 | children[new_path.at(0) as usize], 279 | old_val, 280 | )?); 281 | 282 | let new_branch = RlpNode::Branch(partial, children); 283 | let node_rlp = RlpNode::encoded(new_branch); 284 | let hash = self.db.insert(&node_rlp); 285 | 286 | Ok(hash) 287 | } 288 | } 289 | None => { 290 | let hash = self.db.insert(&RlpNode::encoded(node)); 291 | Ok(hash) 292 | } 293 | } 294 | } 295 | None => { 296 | let hash = self.db.insert(&RlpNode::encoded(node)); 297 | Ok(hash) 298 | } 299 | } 300 | } 301 | 302 | /// Remove auxiliary 303 | fn remove_aux( 304 | &mut self, 305 | path: &NibbleSlice<'_>, 306 | cur_node_hash: Option, 307 | old_val: &mut Option, 308 | ) -> crate::Result> { 309 | match cur_node_hash { 310 | Some(hash) => { 311 | let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; 312 | 313 | match RlpNode::decoded(&node_rlp) { 314 | Some(RlpNode::Leaf(partial, value)) => { 315 | if path == &partial { 316 | *old_val = Some(value.to_vec()); 317 | 318 | Ok(None) 319 | } else { 320 | Ok(cur_node_hash) 321 | } 322 | } 323 | Some(RlpNode::Branch(partial, mut children)) => { 324 | if path.starts_with(&partial) { 325 | let new_path = path.mid(partial.len()); 326 | children[new_path.at(0) as usize] = 327 | self.remove_aux(&new_path.mid(1), children[new_path.at(0) as usize], old_val)?; 328 | 329 | if children[new_path.at(0) as usize] == None { 330 | // Fix the node 331 | let child_count = children.iter().filter(|x| x.is_none()).count(); 332 | 333 | match child_count { 334 | 16 => { 335 | // Branch can be removed 336 | Ok(None) 337 | } 338 | 15 => { 339 | // Transform the branch into Leaf 340 | let index = children 341 | .iter() 342 | .position(Option::is_some) 343 | .expect("Can not find leaf in the branch"); 344 | let new_leaf_hash = children[index].expect("Index is wrong"); 345 | let new_leaf_data = self 346 | .db 347 | .get(&new_leaf_hash) 348 | .ok_or_else(|| TrieError::IncompleteDatabase(hash))?; 349 | let new_leaf_node = RlpNode::decoded(&new_leaf_data); 350 | 351 | match new_leaf_node { 352 | None => Err(TrieError::IncompleteDatabase(hash)), 353 | Some(RlpNode::Leaf(child_partial, child_value)) => { 354 | let mut vec = partial.to_vec(); 355 | vec.push(index as u8); 356 | vec.append(&mut child_partial.to_vec()); 357 | 358 | let (new_partial, offset) = NibbleSlice::from_vec(&vec); 359 | let new_leaf = RlpNode::Leaf( 360 | NibbleSlice::new_offset(&new_partial, offset), 361 | child_value, 362 | ); 363 | let node_rlp = RlpNode::encoded(new_leaf); 364 | let new_hash = self.db.insert(&node_rlp); 365 | 366 | Ok(Some(new_hash)) 367 | } 368 | Some(RlpNode::Branch(child_partial, children)) => { 369 | let mut vec = partial.to_vec(); 370 | vec.push(index as u8); 371 | vec.append(&mut child_partial.to_vec()); 372 | 373 | let (new_partial, offset) = NibbleSlice::from_vec(&vec); 374 | let new_branch = RlpNode::Branch( 375 | NibbleSlice::new_offset(&new_partial, offset), 376 | children, 377 | ); 378 | let node_rlp = RlpNode::encoded(new_branch); 379 | let new_hash = self.db.insert(&node_rlp); 380 | 381 | Ok(Some(new_hash)) 382 | } 383 | } 384 | } 385 | _ => { 386 | let new_branch = RlpNode::Branch(partial, children); 387 | let node_rlp = RlpNode::encoded(new_branch); 388 | let new_hash = self.db.insert(&node_rlp); 389 | 390 | Ok(Some(new_hash)) 391 | } 392 | } 393 | } else { 394 | let new_branch = RlpNode::Branch(partial, children); 395 | let node_rlp = RlpNode::encoded(new_branch); 396 | let new_hash = self.db.insert(&node_rlp); 397 | 398 | Ok(Some(new_hash)) 399 | } 400 | } else { 401 | Ok(cur_node_hash) 402 | } 403 | } 404 | None => Ok(cur_node_hash), 405 | } 406 | } 407 | None => Ok(cur_node_hash), 408 | } 409 | } 410 | } 411 | 412 | impl<'a> fmt::Display for RlpNode<'a> { 413 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 414 | match self { 415 | RlpNode::Leaf(partial, value) => writeln!(f, "Leaf - key({:?}), value({:?})", partial, value), 416 | RlpNode::Branch(partial, children) => { 417 | writeln!(f, "Branch - path({:?})", partial)?; 418 | 419 | debug_assert_eq!(16, children.len()); 420 | for (i, child) in children.iter().enumerate() { 421 | writeln!(f, "child {} - hash({:?})", i, child)?; 422 | } 423 | Ok(()) 424 | } 425 | } 426 | } 427 | } 428 | 429 | impl<'db> CryptoStructure for TrieDBMut<'db> { 430 | fn make_proof(&self, key: &[u8]) -> crate::Result<(CryptoProofUnit, CryptoProof)> { 431 | let t = TrieDB::try_new(self.db, self.root)?; 432 | t.make_proof(key) 433 | } 434 | } 435 | 436 | impl<'a> Trie for TrieDBMut<'a> { 437 | fn root(&self) -> &H256 { 438 | self.root 439 | } 440 | 441 | fn is_empty(&self) -> bool { 442 | *self.root == BLAKE_NULL_RLP 443 | } 444 | 445 | fn get(&self, key: &[u8]) -> crate::Result> { 446 | let t = TrieDB::try_new(self.db, self.root)?; 447 | 448 | t.get(key) 449 | } 450 | 451 | fn is_complete(&self) -> bool { 452 | TrieDB::try_new(self.db, self.root).map(|t| t.is_complete()).unwrap_or(false) 453 | } 454 | } 455 | 456 | impl<'a> TrieMut for TrieDBMut<'a> { 457 | fn insert(&mut self, key: &[u8], value: &[u8]) -> crate::Result> { 458 | let path = blake256(key); 459 | let mut old_val = None; 460 | let cur_hash = *self.root; 461 | *self.root = self.insert_aux(NibbleSlice::new(path.as_bytes()), value, Some(cur_hash), &mut old_val)?; 462 | 463 | Ok(old_val) 464 | } 465 | 466 | fn remove(&mut self, key: &[u8]) -> crate::Result> { 467 | let path = blake256(key); 468 | let mut old_val = None; 469 | let cur_hash = *self.root; 470 | 471 | *self.root = match self.remove_aux(&NibbleSlice::new(path.as_bytes()), Some(cur_hash), &mut old_val)? { 472 | Some(hash) => hash, 473 | None => BLAKE_NULL_RLP, 474 | }; 475 | 476 | Ok(old_val) 477 | } 478 | } 479 | 480 | 481 | #[cfg(test)] 482 | mod tests { 483 | use ccrypto::BLAKE_NULL_RLP; 484 | use cdb::*; 485 | use standardmap::*; 486 | 487 | use crate::triehash::trie_root; 488 | use crate::TrieMut; 489 | 490 | use super::*; 491 | 492 | fn populate_trie<'db>(db: &'db mut dyn HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { 493 | let mut t = TrieDBMut::new(db, root); 494 | for (key, val) in v { 495 | t.insert(key, val).unwrap(); 496 | } 497 | t 498 | } 499 | 500 | fn unpopulate_trie(t: &mut TrieDBMut<'_>, v: &[(Vec, Vec)]) { 501 | for i in v { 502 | let key: &[u8] = &i.0; 503 | t.remove(key).unwrap(); 504 | } 505 | } 506 | 507 | #[test] 508 | fn playpen() { 509 | let mut seed = H256::zero(); 510 | for test_i in 0..10 { 511 | if test_i % 50 == 0 { 512 | println!("{:?} of 10000 stress tests done", test_i); 513 | } 514 | let x = StandardMap { 515 | alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), 516 | min_key: 5, 517 | journal_key: 0, 518 | value_mode: ValueMode::Index, 519 | count: 100, 520 | } 521 | .make_with(&mut seed); 522 | 523 | let real = trie_root(x.clone()); 524 | let mut memdb = MemoryDB::new(); 525 | let mut root = H256::zero(); 526 | let mut memtrie = populate_trie(&mut memdb, &mut root, &x); 527 | 528 | if *memtrie.root() != real { 529 | println!("TRIE MISMATCH"); 530 | println!(); 531 | println!("{:?} vs {:?}", memtrie.root(), real); 532 | for i in &x { 533 | println!("{:?} -> {:?}", i.0, i.1); 534 | } 535 | } 536 | assert_eq!(*memtrie.root(), real); 537 | unpopulate_trie(&mut memtrie, &x); 538 | 539 | if *memtrie.root() != BLAKE_NULL_RLP { 540 | println!("- TRIE MISMATCH"); 541 | println!(); 542 | println!("{:?} vs {:?}", memtrie.root(), real); 543 | for i in &x { 544 | println!("{:?} -> {:?}", i.0, i.1); 545 | } 546 | } 547 | assert_eq!(*memtrie.root(), BLAKE_NULL_RLP); 548 | } 549 | } 550 | 551 | #[test] 552 | fn init() { 553 | let mut memdb = MemoryDB::new(); 554 | let mut root = H256::zero(); 555 | let t = TrieDBMut::new(&mut memdb, &mut root); 556 | assert_eq!(*t.root(), BLAKE_NULL_RLP); 557 | } 558 | 559 | #[test] 560 | fn insert_on_empty() { 561 | let mut memdb = MemoryDB::new(); 562 | let mut root = H256::zero(); 563 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 564 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 565 | assert_eq!(*t.root(), trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); 566 | } 567 | 568 | #[test] 569 | fn remove_to_empty() { 570 | let big_value = b"00000000000000000000000000000000"; 571 | 572 | let mut memdb = MemoryDB::new(); 573 | let mut root = H256::zero(); 574 | let mut t1 = TrieDBMut::new(&mut memdb, &mut root); 575 | t1.insert(&[0x01, 0x23], big_value).unwrap(); 576 | t1.insert(&[0x01, 0x34], big_value).unwrap(); 577 | let mut memdb2 = MemoryDB::new(); 578 | let mut root2 = H256::zero(); 579 | let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2); 580 | t2.insert(&[0x01], big_value).unwrap(); 581 | t2.insert(&[0x01, 0x23], big_value).unwrap(); 582 | t2.insert(&[0x01, 0x34], big_value).unwrap(); 583 | t2.remove(&[0x01]).unwrap(); 584 | } 585 | 586 | #[test] 587 | fn insert_replace_root() { 588 | let mut memdb = MemoryDB::new(); 589 | let mut root = H256::zero(); 590 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 591 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 592 | t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap(); 593 | assert_eq!(*t.root(), trie_root(vec![(vec![0x01u8, 0x23], vec![0x23u8, 0x45])])); 594 | } 595 | 596 | #[test] 597 | fn insert_make_branch_root() { 598 | let mut memdb = MemoryDB::new(); 599 | let mut root = H256::zero(); 600 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 601 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 602 | t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap(); 603 | assert_eq!( 604 | *t.root(), 605 | trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x11u8, 0x23], vec![0x11u8, 0x23])]) 606 | ); 607 | } 608 | 609 | #[test] 610 | fn insert_into_branch_root() { 611 | let mut memdb = MemoryDB::new(); 612 | let mut root = H256::zero(); 613 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 614 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 615 | t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); 616 | t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); 617 | assert_eq!( 618 | *t.root(), 619 | trie_root(vec![ 620 | (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), 621 | (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), 622 | (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), 623 | ]) 624 | ); 625 | } 626 | 627 | #[test] 628 | fn insert_value_into_branch_root() { 629 | let mut memdb = MemoryDB::new(); 630 | let mut root = H256::zero(); 631 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 632 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 633 | t.insert(&[], &[0x0]).unwrap(); 634 | assert_eq!(*t.root(), trie_root(vec![(vec![], vec![0x0]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); 635 | } 636 | 637 | #[test] 638 | fn insert_split_leaf() { 639 | let mut memdb = MemoryDB::new(); 640 | let mut root = H256::zero(); 641 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 642 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 643 | t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap(); 644 | assert_eq!( 645 | *t.root(), 646 | trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x34], vec![0x01u8, 0x34])]) 647 | ); 648 | } 649 | 650 | #[test] 651 | fn insert_split_extenstion() { 652 | let mut memdb = MemoryDB::new(); 653 | let mut root = H256::zero(); 654 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 655 | t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap(); 656 | t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap(); 657 | t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap(); 658 | assert_eq!( 659 | *t.root(), 660 | trie_root(vec![ 661 | (vec![0x01, 0x23, 0x45], vec![0x01]), 662 | (vec![0x01, 0xf3, 0x45], vec![0x02]), 663 | (vec![0x01, 0xf3, 0xf5], vec![0x03]), 664 | ]) 665 | ); 666 | } 667 | 668 | #[test] 669 | fn insert_big_value() { 670 | let big_value0 = b"00000000000000000000000000000000"; 671 | let big_value1 = b"11111111111111111111111111111111"; 672 | 673 | let mut memdb = MemoryDB::new(); 674 | let mut root = H256::zero(); 675 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 676 | t.insert(&[0x01u8, 0x23], big_value0).unwrap(); 677 | t.insert(&[0x11u8, 0x23], big_value1).unwrap(); 678 | assert_eq!( 679 | *t.root(), 680 | trie_root(vec![(vec![0x01u8, 0x23], big_value0.to_vec()), (vec![0x11u8, 0x23], big_value1.to_vec())]) 681 | ); 682 | } 683 | 684 | #[test] 685 | fn insert_duplicate_value() { 686 | let big_value = b"00000000000000000000000000000000"; 687 | 688 | let mut memdb = MemoryDB::new(); 689 | let mut root = H256::zero(); 690 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 691 | t.insert(&[0x01u8, 0x23], big_value).unwrap(); 692 | t.insert(&[0x11u8, 0x23], big_value).unwrap(); 693 | assert_eq!( 694 | *t.root(), 695 | trie_root(vec![(vec![0x01u8, 0x23], big_value.to_vec()), (vec![0x11u8, 0x23], big_value.to_vec())]) 696 | ); 697 | } 698 | 699 | #[test] 700 | fn empty() { 701 | let mut memdb = MemoryDB::new(); 702 | let mut root = H256::zero(); 703 | let t = TrieDBMut::new(&mut memdb, &mut root); 704 | assert_eq!(t.get(&[0x5]), Ok(None)); 705 | } 706 | 707 | #[test] 708 | fn one() { 709 | let mut memdb = MemoryDB::new(); 710 | let mut root = H256::zero(); 711 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 712 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 713 | assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), vec![0x1u8, 0x23]); 714 | 715 | assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), vec![0x1u8, 0x23]); 716 | } 717 | 718 | #[test] 719 | fn three() { 720 | let mut memdb = MemoryDB::new(); 721 | let mut root = H256::zero(); 722 | let mut t = TrieDBMut::new(&mut memdb, &mut root); 723 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 724 | t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); 725 | t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); 726 | assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), vec![0x01u8, 0x23]); 727 | assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), vec![0xf1u8, 0x23]); 728 | assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), vec![0x81u8, 0x23]); 729 | assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); 730 | 731 | assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), vec![0x01u8, 0x23]); 732 | assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), vec![0xf1u8, 0x23]); 733 | assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), vec![0x81u8, 0x23]); 734 | assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); 735 | } 736 | 737 | #[test] 738 | fn stress() { 739 | let mut seed = H256::zero(); 740 | for _ in 0..50 { 741 | let x = StandardMap { 742 | alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), 743 | min_key: 5, 744 | journal_key: 0, 745 | value_mode: ValueMode::Index, 746 | count: 4, 747 | } 748 | .make_with(&mut seed); 749 | 750 | let real = trie_root(x.clone()); 751 | let mut memdb = MemoryDB::new(); 752 | let mut root = H256::zero(); 753 | let memtrie = populate_trie(&mut memdb, &mut root, &x); 754 | let mut y = x.clone(); 755 | y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); 756 | let mut memdb2 = MemoryDB::new(); 757 | let mut root2 = H256::zero(); 758 | let memtrie_sorted = populate_trie(&mut memdb2, &mut root2, &y); 759 | if *memtrie.root() != real || *memtrie_sorted.root() != real { 760 | println!("TRIE MISMATCH"); 761 | println!(); 762 | println!("ORIGINAL... {:?}", memtrie.root()); 763 | for i in &x { 764 | println!("{:?} -> {:?}", i.0, i.1); 765 | } 766 | println!("SORTED... {:?}", memtrie_sorted.root()); 767 | for i in &y { 768 | println!("{:?} -> {:?}", i.0, i.1); 769 | } 770 | } 771 | assert_eq!(*memtrie.root(), real); 772 | assert_eq!(*memtrie_sorted.root(), real); 773 | } 774 | } 775 | 776 | #[test] 777 | fn trie_existing() { 778 | let mut root = H256::zero(); 779 | let mut db = MemoryDB::new(); 780 | { 781 | let mut t = TrieDBMut::new(&mut db, &mut root); 782 | t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); 783 | } 784 | 785 | { 786 | let _ = TrieDBMut::from_existing(&mut db, &mut root); 787 | } 788 | } 789 | 790 | #[test] 791 | fn from_null_rlp_succeeds() { 792 | let mut root = BLAKE_NULL_RLP; 793 | let mut db = MemoryDB::new(); 794 | TrieDBMut::from_existing(&mut db, &mut root).unwrap(); 795 | } 796 | 797 | #[test] 798 | #[should_panic] 799 | fn from_zero_fails() { 800 | let mut root = H256::zero(); 801 | let mut db = MemoryDB::new(); 802 | TrieDBMut::from_existing(&mut db, &mut root).unwrap(); 803 | } 804 | 805 | #[test] 806 | #[ignore] 807 | fn insert_empty() { 808 | let mut seed = H256::zero(); 809 | let x = StandardMap { 810 | alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), 811 | min_key: 5, 812 | journal_key: 0, 813 | value_mode: ValueMode::Index, 814 | count: 4, 815 | } 816 | .make_with(&mut seed); 817 | 818 | let mut db = MemoryDB::new(); 819 | let mut root = H256::zero(); 820 | let mut t = TrieDBMut::new(&mut db, &mut root); 821 | for &(ref key, ref value) in &x { 822 | t.insert(key, value).unwrap(); 823 | } 824 | 825 | assert_eq!(*t.root(), trie_root(x.clone())); 826 | 827 | for &(ref key, _) in &x { 828 | t.insert(key, &[]).unwrap(); 829 | } 830 | 831 | assert!(t.is_empty()); 832 | assert_eq!(*t.root(), BLAKE_NULL_RLP); 833 | } 834 | 835 | #[test] 836 | fn return_old_values() { 837 | let mut seed = H256::zero(); 838 | let x = StandardMap { 839 | alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), 840 | min_key: 5, 841 | journal_key: 0, 842 | value_mode: ValueMode::Index, 843 | count: 4, 844 | } 845 | .make_with(&mut seed); 846 | 847 | let mut db = MemoryDB::new(); 848 | let mut root = H256::zero(); 849 | let mut t = TrieDBMut::new(&mut db, &mut root); 850 | for &(ref key, ref value) in &x { 851 | assert!(t.insert(key, value).unwrap().is_none()); 852 | assert_eq!(t.insert(key, value).unwrap(), Some(value.clone())); 853 | } 854 | 855 | for (key, value) in x { 856 | assert_eq!(t.remove(&key).unwrap(), Some(value)); 857 | assert!(t.remove(&key).unwrap().is_none()); 858 | } 859 | } 860 | } 861 | -------------------------------------------------------------------------------- /src/triehash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018, 2020 Kodebox, Inc. 2 | // This file is part of CodeChain. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . 16 | 17 | //! Generetes trie root. 18 | //! 19 | //! This module should be used to generate trie root hash. 20 | 21 | use ccrypto::blake256; 22 | use primitives::H256; 23 | use rlp::RlpStream; 24 | use std::cmp; 25 | use std::collections::BTreeMap; 26 | 27 | fn shared_prefix_len(first: &[T], second: &[T]) -> usize { 28 | let len = cmp::min(first.len(), second.len()); 29 | (0..len).take_while(|&i| first[i] == second[i]).count() 30 | } 31 | 32 | /// Generates a trie root hash for a vector of key-values 33 | pub fn trie_root(input: I) -> H256 34 | where 35 | I: IntoIterator, 36 | A: AsRef<[u8]> + Ord, 37 | B: AsRef<[u8]>, { 38 | // Make key into hash value, which is blake256(key) 39 | let gen_input: Vec<_> = input.into_iter().map(|(k, v)| (blake256(k), v)).collect(); 40 | let gen_input: Vec<_> = gen_input 41 | // first put elements into btree to sort them and to remove duplicates 42 | .into_iter() 43 | .collect::>() 44 | // then move them to a vector 45 | .into_iter() 46 | .map(|(k, v)| (as_nibbles(k.as_ref()), v) ) 47 | .collect(); 48 | 49 | gen_trie_root(&gen_input) 50 | } 51 | 52 | fn gen_trie_root, B: AsRef<[u8]>>(input: &[(A, B)]) -> H256 { 53 | let mut stream = RlpStream::new(); 54 | hash256rlp(input, 0, &mut stream); 55 | blake256(stream.out()) 56 | } 57 | 58 | /// Hex-prefix Notation. First nibble has flags: oddness = 2^0 59 | /// 60 | /// Input values are in range `[0, 0xf]`. 61 | /// 62 | /// ```markdown 63 | /// [0,0,1,2,3,4,5] 0x10012345 // 7 > 4 64 | /// [0,1,2,3,4,5] 0x00012345 // 6 > 4 65 | /// [1,2,3,4,5] 0x112345 // 5 > 3 66 | /// [0,0,1,2,3,4] 0x00001234 // 6 > 3 67 | /// [0,1,2,3,4] 0x101234 // 5 > 3 68 | /// [1,2,3,4] 0x001234 // 4 > 3 69 | /// ``` 70 | fn hex_prefix_encode(nibbles: &[u8]) -> Vec { 71 | let inlen = nibbles.len(); 72 | let oddness_factor = inlen % 2; 73 | // next even number divided by two 74 | let reslen = (inlen + 2) >> 1; 75 | let mut res = Vec::with_capacity(reslen); 76 | 77 | let first_byte = { 78 | let mut bits = (oddness_factor as u8) << 4; 79 | if oddness_factor == 1 { 80 | bits += nibbles[0]; 81 | } 82 | bits 83 | }; 84 | 85 | res.push(first_byte); 86 | 87 | let mut offset = oddness_factor; 88 | while offset < inlen { 89 | let byte = (nibbles[offset] << 4) + nibbles[offset + 1]; 90 | res.push(byte); 91 | offset += 2; 92 | } 93 | 94 | res 95 | } 96 | 97 | /// Converts slice of bytes to nibbles. 98 | fn as_nibbles(bytes: &[u8]) -> Vec { 99 | let mut res = Vec::with_capacity(bytes.len() * 2); 100 | for byte in bytes { 101 | res.push(*byte >> 4); 102 | res.push(*byte & 0b1111); 103 | } 104 | res 105 | } 106 | 107 | fn hash256rlp, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { 108 | let inlen = input.len(); 109 | 110 | // in case of empty slice, just append empty data 111 | if inlen == 0 { 112 | stream.append_empty_data(); 113 | return 114 | } 115 | 116 | // take slices 117 | let key: &[u8] = &input[0].0.as_ref(); 118 | let value: &[u8] = &input[0].1.as_ref(); 119 | 120 | // if the slice contains just one item, append the suffix of the key 121 | // and then append value 122 | if inlen == 1 { 123 | stream.begin_list(2); 124 | stream.append(&hex_prefix_encode(&key[pre_len..])); 125 | stream.append(&value); 126 | return 127 | } 128 | 129 | // get length of the longest shared prefix in slice keys 130 | let shared_prefix = input.iter() 131 | // skip first element 132 | .skip(1) 133 | // get minimum number of shared nibbles between first and each successive 134 | .fold(key.len(), | acc, &(ref k, _) | { 135 | cmp::min(shared_prefix_len(key, k.as_ref()), acc) 136 | }); 137 | 138 | // an item for every possible nibble/suffix 139 | // + 1 for data 140 | stream.begin_list(17); 141 | 142 | // Append partial path as a first element of branch 143 | stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix])); 144 | 145 | let mut begin: usize = 0; 146 | 147 | // iterate over all possible nibbles 148 | for i in 0..16 { 149 | // count how many successive elements have same next nibble 150 | let len = if begin < input.len() { 151 | input[begin..].iter().take_while(|pair| pair.0.as_ref()[shared_prefix] == i).count() 152 | } else { 153 | 0 154 | }; 155 | 156 | // if at least 1 successive element has the same nibble 157 | // append their suffixes 158 | match len { 159 | 0 => { 160 | stream.append_empty_data(); 161 | } 162 | _ => hash256aux(&input[begin..(begin + len)], shared_prefix + 1, stream), 163 | } 164 | begin += len; 165 | } 166 | } 167 | 168 | fn hash256aux, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { 169 | let mut s = RlpStream::new(); 170 | hash256rlp(input, pre_len, &mut s); 171 | let out = s.out(); 172 | 173 | stream.append(&blake256(out)); 174 | } 175 | 176 | 177 | #[cfg(test)] 178 | mod tests { 179 | use super::*; 180 | 181 | #[test] 182 | fn nibbles() { 183 | let v = vec![0x31, 0x23, 0x45]; 184 | let e = vec![3, 1, 2, 3, 4, 5]; 185 | assert_eq!(as_nibbles(&v), e); 186 | 187 | // A => 65 => 0x41 => [4, 1] 188 | let v: Vec = From::from("A"); 189 | let e = vec![4, 1]; 190 | assert_eq!(as_nibbles(&v), e); 191 | } 192 | 193 | #[test] 194 | fn _hex_prefix_encode() { 195 | let v = vec![0, 0, 1, 2, 3, 4, 5]; 196 | let e = vec![0x10, 0x01, 0x23, 0x45]; 197 | let h = hex_prefix_encode(&v); 198 | assert_eq!(h, e); 199 | 200 | let v = vec![0, 1, 2, 3, 4, 5]; 201 | let e = vec![0x00, 0x01, 0x23, 0x45]; 202 | let h = hex_prefix_encode(&v); 203 | assert_eq!(h, e); 204 | 205 | let v = vec![1, 2, 3, 4]; 206 | let e = vec![0x00, 0x12, 0x34]; 207 | let h = hex_prefix_encode(&v); 208 | assert_eq!(h, e); 209 | } 210 | 211 | #[test] 212 | fn triehash_out_of_order() { 213 | assert_eq!( 214 | trie_root(vec![ 215 | (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), 216 | (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), 217 | (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), 218 | ]), 219 | trie_root(vec![ 220 | (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), 221 | (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), 222 | (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), 223 | ]) 224 | ); 225 | } 226 | 227 | #[test] 228 | fn shared_prefix() { 229 | let a = vec![1, 2, 3, 4, 5, 6]; 230 | let b = vec![4, 2, 3, 4, 5, 6]; 231 | assert_eq!(shared_prefix_len(&a, &b), 0); 232 | } 233 | 234 | #[test] 235 | fn shared_prefix2() { 236 | let a = vec![1, 2, 3, 3, 5]; 237 | let b = vec![1, 2, 3]; 238 | assert_eq!(shared_prefix_len(&a, &b), 3); 239 | } 240 | 241 | #[test] 242 | fn shared_prefix3() { 243 | let a = vec![1, 2, 3, 4, 5, 6]; 244 | let b = vec![1, 2, 3, 4, 5, 6]; 245 | assert_eq!(shared_prefix_len(&a, &b), 6); 246 | } 247 | } 248 | --------------------------------------------------------------------------------