├── mvm ├── tests │ ├── assets │ │ ├── .gitignore │ │ ├── scripts │ │ │ ├── TxTest.move │ │ │ ├── Abort.move │ │ │ ├── StoreScript.move │ │ │ ├── EmitEvent.move │ │ │ ├── Signers.move │ │ │ ├── PontInfo.move │ │ │ ├── SignerOrder.move │ │ │ ├── ReflectScript.move │ │ │ ├── SysResources.move │ │ │ └── Transfer.move │ │ ├── sources │ │ │ ├── ReflectTest.move │ │ │ ├── ScriptBook.move │ │ │ ├── Abort.move │ │ │ ├── Foo.move │ │ │ ├── EventProxy.move │ │ │ └── Store.move │ │ ├── Move.toml │ │ └── build_assets.sh │ ├── codec.rs │ ├── common │ │ └── mod.rs │ ├── genesis.rs │ └── gas_bench.rs ├── src │ ├── io │ │ ├── mod.rs │ │ ├── config.rs │ │ ├── context.rs │ │ ├── traits.rs │ │ ├── key.rs │ │ ├── state.rs │ │ └── session.rs │ ├── lib.rs │ └── error.rs ├── build.rs └── Cargo.toml ├── bcs ├── .gitignore ├── CHANGELOG.md ├── SECURITY.md ├── CODE_OF_CONDUCT.md ├── README.tpl ├── src │ ├── test_helpers.rs │ └── error.rs ├── CONTRIBUTING.md ├── benches │ └── bcs_bench.rs └── Cargo.toml ├── rustfmt.toml ├── types ├── src │ ├── account_address.rs │ ├── test_helpers │ │ └── empty_script.mv │ ├── resources │ │ ├── mod.rs │ │ └── currency_info.rs │ ├── account_config │ │ ├── mod.rs │ │ └── constants │ │ │ ├── account.rs │ │ │ ├── mod.rs │ │ │ ├── addresses.rs │ │ │ ├── event.rs │ │ │ ├── coins.rs │ │ │ └── diem.rs │ ├── lib.rs │ ├── on_chain_config │ │ ├── diem_version.rs │ │ ├── registered_currencies.rs │ │ ├── vm_config.rs │ │ └── vm_publishing_option.rs │ └── event.rs └── Cargo.toml ├── .gitignore ├── language ├── move-vm │ ├── types │ │ ├── src │ │ │ ├── natives │ │ │ │ └── mod.rs │ │ │ ├── unit_tests │ │ │ │ ├── mod.rs │ │ │ │ └── identifier_prop_tests.rs │ │ │ ├── loaded_data │ │ │ │ ├── mod.rs │ │ │ │ └── runtime_types.rs │ │ │ ├── values │ │ │ │ ├── mod.rs │ │ │ │ ├── value_prop_tests.rs │ │ │ │ └── value_tests.rs │ │ │ ├── lib.rs │ │ │ └── data_store.rs │ │ └── Cargo.toml │ ├── runtime │ │ ├── src │ │ │ ├── unit_tests │ │ │ │ └── mod.rs │ │ │ ├── lib.rs │ │ │ ├── logging.rs │ │ │ └── move_vm.rs │ │ └── Cargo.toml │ └── test-utils │ │ ├── src │ │ └── lib.rs │ │ └── Cargo.toml ├── move-core │ └── types │ │ ├── src │ │ ├── unit_tests │ │ │ ├── mod.rs │ │ │ ├── language_storage_test.rs │ │ │ └── address_test.rs │ │ ├── lib.rs │ │ ├── move_resource.rs │ │ ├── proptest_types.rs │ │ ├── resolver.rs │ │ └── errmap.rs │ │ └── Cargo.toml ├── move-binary-format │ ├── src │ │ ├── unit_tests │ │ │ ├── invalid_script_no_signature.mv │ │ │ ├── mod.rs │ │ │ ├── binary_tests.rs │ │ │ └── signature_token_tests.rs │ │ ├── internals.rs │ │ ├── cursor.rs │ │ ├── constant.rs │ │ └── proptest_types │ │ │ └── constants.rs │ ├── serializer-tests │ │ ├── src │ │ │ └── lib.rs │ │ ├── Cargo.toml │ │ └── tests │ │ │ ├── serializer_tests.rs │ │ │ └── serializer_tests.proptest-regressions │ ├── Cargo.toml │ └── README.md ├── move-stdlib │ ├── src │ │ ├── lib.rs │ │ └── natives │ │ │ ├── signer.rs │ │ │ ├── unit_test.rs │ │ │ ├── event.rs │ │ │ ├── reflect.rs │ │ │ ├── account.rs │ │ │ ├── debug.rs │ │ │ ├── hash.rs │ │ │ ├── bcs.rs │ │ │ ├── signature.rs │ │ │ └── mod.rs │ └── Cargo.toml ├── bytecode-verifier │ ├── invalid-mutations │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── helpers.rs │ │ │ └── signature.rs │ │ └── Cargo.toml │ ├── bytecode-verifier-tests │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── unit_tests │ │ │ │ ├── mod.rs │ │ │ │ ├── resources_tests.rs │ │ │ │ ├── struct_defs_tests.rs │ │ │ │ ├── ability_field_requirements_tests.rs │ │ │ │ ├── duplication_tests.rs │ │ │ │ ├── multi_pass_tests.rs │ │ │ │ ├── negative_stack_size_tests.rs │ │ │ │ ├── code_unit_tests.rs │ │ │ │ └── control_flow_tests.rs │ │ │ └── support │ │ │ │ └── mod.rs │ │ └── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── friends.rs │ │ ├── ability_field_requirements.rs │ │ ├── constants.rs │ │ └── verifier.rs │ └── Cargo.toml └── borrow-graph │ ├── src │ ├── lib.rs │ ├── shared.rs │ └── paths.rs │ └── Cargo.toml ├── mirai-annotations └── Cargo.toml ├── crypto ├── crypto │ ├── src │ │ ├── unit_tests │ │ │ ├── mod.rs │ │ │ ├── compilation │ │ │ │ ├── cross_test_trait_obj.rs │ │ │ │ ├── cross_test_trait_obj_pub.rs │ │ │ │ ├── cross_test_trait_obj_sig.rs │ │ │ │ ├── small_kdf.rs │ │ │ │ └── cross_test.rs │ │ │ └── cryptohasher.rs │ │ └── lib.rs │ ├── Cargo.toml │ └── README.md └── crypto-derive │ ├── Cargo.toml │ └── src │ └── hasher.rs ├── common ├── cell │ ├── src │ │ ├── lib.rs │ │ └── lazy.rs │ └── Cargo.toml ├── proptest-helpers │ ├── src │ │ ├── unit_tests.rs │ │ ├── unit_tests │ │ │ ├── pick_idx_tests.rs │ │ │ └── growing_subset_tests.rs │ │ └── value_generator.rs │ ├── Cargo.toml │ └── proptest-regressions │ │ └── unit_tests │ │ ├── growing_subset_tests.txt │ │ └── repeat_vec_tests.txt ├── fallible │ ├── src │ │ ├── lib.rs │ │ └── copy_from_slice.rs │ └── Cargo.toml ├── nibble │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── short-hex-str │ └── Cargo.toml ├── stdlib ├── Cargo.toml ├── src │ └── lib.rs ├── build.rs └── build_std.sh ├── clippy.toml ├── README.md ├── Makefile ├── Cargo.toml └── .github └── workflows └── tests.yml /mvm/tests/assets/.gitignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /bcs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | use_field_init_shorthand = true 3 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/TxTest.move: -------------------------------------------------------------------------------- 1 | script { 2 | fun tx_test(_val: u64) {} 3 | } -------------------------------------------------------------------------------- /types/src/account_address.rs: -------------------------------------------------------------------------------- 1 | pub use move_core_types::account_address::AccountAddress; 2 | -------------------------------------------------------------------------------- /mvm/tests/assets/sources/ReflectTest.move: -------------------------------------------------------------------------------- 1 | module TestAddr::ReflectTest { 2 | struct Mod {} 3 | } 4 | -------------------------------------------------------------------------------- /mvm/tests/assets/sources/ScriptBook.move: -------------------------------------------------------------------------------- 1 | module Assets::ScriptBook { 2 | public (script) fun test() {} 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | .cargo 4 | /stdlib/move-stdlib 5 | /stdlib/pont-stdlib 6 | /mvm/tests/assets/artifacts -------------------------------------------------------------------------------- /types/src/test_helpers/empty_script.mv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pontem-network/sp-move-vm/HEAD/types/src/test_helpers/empty_script.mv -------------------------------------------------------------------------------- /mvm/tests/assets/sources/Abort.move: -------------------------------------------------------------------------------- 1 | module Assets::Abort { 2 | public fun error(code: u64) { 3 | abort code 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /types/src/resources/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod currency_info; 5 | -------------------------------------------------------------------------------- /bcs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.1.0] - 2020-11-17 4 | - Initial release. 5 | 6 | [v0.1.0]: https://github.com/libra/lcs/releases/tag/v0.1.0 7 | -------------------------------------------------------------------------------- /mvm/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod balance; 2 | pub mod config; 3 | pub mod context; 4 | pub mod key; 5 | pub mod session; 6 | pub mod state; 7 | pub mod traits; 8 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/Abort.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Assets::Abort; 3 | 4 | fun error(_signer: signer) { 5 | Abort::error(13); 6 | } 7 | } -------------------------------------------------------------------------------- /language/move-vm/types/src/natives/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod function; 5 | -------------------------------------------------------------------------------- /mirai-annotations/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mirai-annotations" 3 | publish = false 4 | version = "0.1.0" 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod cryptohasher; 5 | mod hash_test; 6 | -------------------------------------------------------------------------------- /language/move-vm/runtime/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod vm_arguments_tests; 5 | -------------------------------------------------------------------------------- /types/src/account_config/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod constants; 5 | pub use constants::*; 6 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/StoreScript.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Assets::Store; 3 | 4 | fun store_u64(account: signer, val: u64) { 5 | Store::store_u64(&account, val); 6 | } 7 | } -------------------------------------------------------------------------------- /language/move-core/types/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod identifier_test; 5 | mod language_storage_test; 6 | -------------------------------------------------------------------------------- /common/cell/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | extern crate alloc; 4 | mod lazy; 5 | mod once_cell; 6 | 7 | pub use crate::once_cell::OnceCell; 8 | pub use lazy::Lazy; 9 | -------------------------------------------------------------------------------- /language/move-vm/types/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[cfg(feature = "fuzzing")] 5 | mod identifier_prop_tests; 6 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/EmitEvent.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Assets::EventProxy; 3 | 4 | fun emit_event(signer: signer, val: u64) { 5 | EventProxy::emit_event(&signer, val); 6 | } 7 | } -------------------------------------------------------------------------------- /mvm/tests/assets/sources/Foo.move: -------------------------------------------------------------------------------- 1 | module Assets::Foo { 2 | use Assets::Store; 3 | 4 | public fun foo(account: &signer, val: u64) { 5 | Store::store_u64(account, val); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /stdlib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stdlib" 3 | version = "0.1.0" 4 | authors = [ 5 | "Dm. Yakushev ", 6 | ] 7 | edition = "2018" 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /language/move-binary-format/src/unit_tests/invalid_script_no_signature.mv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pontem-network/sp-move-vm/HEAD/language/move-binary-format/src/unit_tests/invalid_script_no_signature.mv -------------------------------------------------------------------------------- /bcs/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policies and Procedures 2 | 3 | Please see Libra's 4 | [security policies](https://developers.libra.org/docs/policies/security) and 5 | procedures for reporting vulnerabilities. 6 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/Signers.move: -------------------------------------------------------------------------------- 1 | script { 2 | fun rt_signers(_rt: signer) { 3 | } 4 | } 5 | 6 | 7 | script { 8 | fun signers_tr_with_user(_rt: signer, _usr: signer) { 9 | } 10 | } -------------------------------------------------------------------------------- /common/proptest-helpers/src/unit_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod growing_subset_tests; 5 | mod pick_idx_tests; 6 | mod repeat_vec_tests; 7 | -------------------------------------------------------------------------------- /common/fallible/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | extern crate alloc; 5 | 6 | pub mod copy_from_slice; 7 | -------------------------------------------------------------------------------- /language/move-stdlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | 5 | extern crate alloc; 6 | pub mod natives; 7 | -------------------------------------------------------------------------------- /language/move-binary-format/serializer-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | 6 | // Empty src/lib.rs to get rusty-tags working. 7 | -------------------------------------------------------------------------------- /types/src/account_config/constants/account.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub use move_core_types::vm_status::known_locations::{ACCOUNT_MODULE, ACCOUNT_MODULE_IDENTIFIER}; 5 | -------------------------------------------------------------------------------- /language/move-binary-format/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod binary_tests; 5 | mod deserializer_tests; 6 | mod number_tests; 7 | mod signature_token_tests; 8 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/PontInfo.move: -------------------------------------------------------------------------------- 1 | script { 2 | use PontemFramework::Token; 3 | use PontemFramework::NOX::NOX; 4 | 5 | fun pont_info(expected: u128) { 6 | assert!(expected == Token::total_value(), 1); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/compilation/cross_test_trait_obj.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use diem_crypto::traits::*; 5 | 6 | fn main() { 7 | let mut l: Vec> = vec![]; 8 | } 9 | -------------------------------------------------------------------------------- /language/move-vm/test-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![allow(clippy::new_without_default)] 5 | 6 | mod storage; 7 | 8 | pub use storage::{BlankStorage, DeltaStorage, InMemoryStorage}; 9 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | # cyclomatic complexity is not always useful 2 | cognitive-complexity-threshold = 100 3 | # types are used for safety encoding 4 | type-complexity-threshold = 10000 5 | # manipulating complex states machines in consensus 6 | too-many-arguments-threshold = 13 7 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/compilation/cross_test_trait_obj_pub.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use diem_crypto::traits::*; 5 | 6 | fn main() { 7 | let mut l: Vec> = vec![]; 8 | } 9 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/compilation/cross_test_trait_obj_sig.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use diem_crypto::traits::*; 5 | 6 | fn main() { 7 | let mut l: Vec> = vec![]; 8 | } 9 | -------------------------------------------------------------------------------- /language/bytecode-verifier/invalid-mutations/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | extern crate alloc; 6 | 7 | pub mod bounds; 8 | mod helpers; 9 | pub mod signature; 10 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | 6 | #[cfg(test)] 7 | pub mod support; 8 | 9 | #[cfg(test)] 10 | pub mod unit_tests; 11 | -------------------------------------------------------------------------------- /bcs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The project has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://developers.libra.org/docs/policies/code-of-conduct) so that you can understand what actions will and will not be tolerated. 4 | -------------------------------------------------------------------------------- /language/move-vm/types/src/loaded_data/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Loaded definition of code data used in runtime. 4 | //! 5 | //! This module contains the loaded definition of code data used in runtime. 6 | 7 | pub mod runtime_types; 8 | -------------------------------------------------------------------------------- /language/move-vm/types/src/values/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod values_impl; 5 | 6 | #[cfg(test)] 7 | mod value_tests; 8 | 9 | #[cfg(all(test, feature = "fuzzing"))] 10 | mod value_prop_tests; 11 | 12 | pub use values_impl::*; 13 | -------------------------------------------------------------------------------- /stdlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub fn stdlib_package() -> &'static [u8] { 4 | include_bytes!("../move-stdlib/build/MoveStdlib/bundles/MoveStdlib.pac") 5 | } 6 | 7 | pub fn pont_stdlib_package() -> &'static [u8] { 8 | include_bytes!("../pont-stdlib/build/PontStdlib/bundles/PontStdlib.pac") 9 | } 10 | -------------------------------------------------------------------------------- /language/borrow-graph/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | #![cfg_attr(not(feature = "std"), no_std)] 6 | 7 | #[macro_use] 8 | extern crate alloc; 9 | 10 | pub mod graph; 11 | mod paths; 12 | pub mod references; 13 | mod shared; 14 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/compilation/small_kdf.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | fn main() { 5 | // Test for ripemd160, output_length < 256 6 | let ripemd = diem_crypto::hkdf::Hkdf::::extract(None, &[]); 7 | assert!(ripemd.is_ok()); 8 | } 9 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/SignerOrder.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Std::Signer; 3 | 4 | fun signer_order(s1: signer, s2: signer, s3: signer) { 5 | assert!(Signer::address_of(&s1) == @0x1, 1); 6 | assert!(Signer::address_of(&s2) == @0x2, 2); 7 | assert!(Signer::address_of(&s3) == @0x3, 3); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mvm/tests/codec.rs: -------------------------------------------------------------------------------- 1 | use move_core_types::identifier::Identifier; 2 | use parity_scale_codec::{Decode, Encode}; 3 | 4 | #[test] 5 | pub fn test_identifier() { 6 | let ident = Identifier::new("Test_Ident").unwrap(); 7 | let buffer = ident.encode(); 8 | assert_eq!(ident, Identifier::decode(&mut buffer.as_ref()).unwrap()) 9 | } 10 | -------------------------------------------------------------------------------- /common/fallible/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fallible" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem diem-infallible" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [features] 13 | std = [] -------------------------------------------------------------------------------- /types/src/account_config/constants/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod account; 5 | pub mod addresses; 6 | pub mod coins; 7 | pub mod diem; 8 | pub mod event; 9 | 10 | pub use account::*; 11 | pub use addresses::*; 12 | pub use coins::*; 13 | pub use diem::*; 14 | pub use event::*; 15 | -------------------------------------------------------------------------------- /language/borrow-graph/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "borrow-graph" 3 | version = "0.0.1" 4 | authors = ["Libra Association "] 5 | publish = false 6 | edition = "2018" 7 | license = "Apache-2.0" 8 | 9 | [dependencies] 10 | mirai-annotations = { path = "../../mirai-annotations" } 11 | 12 | [features] 13 | default = ["std"] 14 | std = [ 15 | ] 16 | -------------------------------------------------------------------------------- /language/borrow-graph/src/shared.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | use alloc::collections::{BTreeMap, BTreeSet}; 4 | 5 | pub fn remap_set(set: &mut BTreeSet, id_map: &BTreeMap) { 6 | for (old, new) in id_map { 7 | if set.remove(old) { 8 | set.insert(*new); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bcs/README.tpl: -------------------------------------------------------------------------------- 1 | {{readme}} 2 | 3 | ## Contributing 4 | 5 | See the [CONTRIBUTING](CONTRIBUTING.md) file for how to help out. 6 | 7 | ## License 8 | 9 | This project is available under the terms of either the [Apache 2.0 license](LICENSE). 10 | 11 | 17 | -------------------------------------------------------------------------------- /bcs/src/test_helpers.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub fn assert_canonical_encode_decode(t: T) 5 | where 6 | T: serde::Serialize + serde::de::DeserializeOwned + core::fmt::Debug + PartialEq, 7 | { 8 | let bytes = crate::to_bytes(&t).unwrap(); 9 | let s: T = crate::from_bytes(&bytes).unwrap(); 10 | assert_eq!(t, s); 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Move VM 2 | 3 | **Warning:** The repository contains a very out-of-date Move VM version. It can contain bugs or security issues. Use at your own risk. 4 | 5 | This is modified version of [Diem Move VM](https://github.com/diem/diem). 6 | 7 | ## Differences 8 | - `no_std` compatible 9 | - `wasm32` target compatible 10 | - Extended account address size up to 32 bytes. 11 | Ready for use in Substrate pallet. 12 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/ReflectScript.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Std::Reflect; 3 | 4 | fun test_reflect(expected_addr: address, expected_mod_name: vector, expected_struct_name: vector) { 5 | assert!(expected_addr == Reflect::mod_address_of(), 2); 6 | assert!(expected_mod_name == Reflect::mod_name_of(), 3); 7 | assert!(expected_struct_name == Reflect::type_name_of(), 4); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/SysResources.move: -------------------------------------------------------------------------------- 1 | script { 2 | use Assets::Store; 3 | use PontemFramework::PontBlock; 4 | use PontemFramework::PontTimestamp; 5 | 6 | fun store_system_resources(addr_for_block: signer, addr_for_timestamp: signer) { 7 | Store::store_u64(&addr_for_block, PontBlock::get_current_block_height()); 8 | Store::store_u64(&addr_for_timestamp, PontTimestamp::now_microseconds()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /types/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![cfg_attr(not(feature = "std"), no_std)] 5 | 6 | #[macro_use] 7 | extern crate alloc; 8 | 9 | pub mod access_path; 10 | pub mod account_address; 11 | pub mod account_config; 12 | pub mod chain_id; 13 | pub mod event; 14 | pub mod on_chain_config; 15 | pub mod resources; 16 | 17 | pub use account_address::AccountAddress as PeerId; 18 | -------------------------------------------------------------------------------- /common/proptest-helpers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diem-proptest-helpers" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem proptest helpers" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | crossbeam = "0.8.0" 14 | proptest = "1.0.0" 15 | proptest-derive = "0.2.0" 16 | -------------------------------------------------------------------------------- /mvm/tests/assets/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assets" 3 | version = "0.0.1" 4 | authors = [] 5 | dialect = "Pont" 6 | dove_version = ">=1.5.4" 7 | 8 | [addresses] 9 | Assets = "0x1" 10 | TestAddr = "0x13" 11 | 12 | [dependencies.PontStdlib] 13 | git = "https://github.com/pontem-network/pont-stdlib.git" 14 | rev = "release-v1.0.0" 15 | 16 | [dependencies.MoveStdlib] 17 | git = "https://github.com/pontem-network/move-stdlib.git" 18 | rev = "release-v1.0.0" 19 | -------------------------------------------------------------------------------- /language/move-binary-format/src/internals.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Types meant for use by other parts of this crate, and by other crates that are designed to 5 | //! work with the internals of these data structures. 6 | 7 | use crate::IndexKind; 8 | 9 | /// Represents a module index. 10 | pub trait ModuleIndex { 11 | const KIND: IndexKind; 12 | 13 | fn into_index(self) -> usize; 14 | } 15 | -------------------------------------------------------------------------------- /language/move-core/types/src/unit_tests/language_storage_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::language_storage::ModuleId; 5 | use bcs::test_helpers::assert_canonical_encode_decode; 6 | use proptest::prelude::*; 7 | 8 | proptest! { 9 | #[test] 10 | fn test_module_id_canonical_roundtrip(module_id in any::()) { 11 | assert_canonical_encode_decode(module_id); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /stdlib/build.rs: -------------------------------------------------------------------------------- 1 | use std::process::{Command, Stdio}; 2 | 3 | fn main() { 4 | run(".", "bash", &["./build_std.sh"]); 5 | } 6 | 7 | pub fn run(path: &str, cmd: &str, args: &[&str]) { 8 | let status = Command::new(cmd) 9 | .current_dir(path) 10 | .args(args) 11 | .stdout(Stdio::piped()) 12 | .status() 13 | .unwrap(); 14 | if !status.success() { 15 | panic!("Failed to run {} {} {:?}", path, cmd, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /common/cell/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cell" 3 | version = "0.1.0" 4 | authors = [ 5 | "Alex Koz. ", 6 | "Dm. Yakushev ", 7 | ] 8 | edition = "2018" 9 | publish = false 10 | license = "Apache-2.0" 11 | 12 | 13 | [dependencies] 14 | once_cell = { version = "1.5.2", default-features = false, features = ["unstable", "alloc"] } 15 | 16 | [features] 17 | default = ["std"] 18 | std = [ 19 | "once_cell/std" 20 | ] 21 | -------------------------------------------------------------------------------- /common/proptest-helpers/proptest-regressions/unit_tests/growing_subset_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 359a34b159ab61ae7a56bbfc3b030b5b398e3ba5125801854a9333e16b0049af # shrinks to inputs = [(0, 0)] 8 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod ability_field_requirements_tests; 5 | pub mod bounds_tests; 6 | pub mod code_unit_tests; 7 | pub mod constants_tests; 8 | pub mod control_flow_tests; 9 | pub mod duplication_tests; 10 | pub mod generic_ops_tests; 11 | pub mod multi_pass_tests; 12 | pub mod negative_stack_size_tests; 13 | pub mod signature_tests; 14 | pub mod struct_defs_tests; 15 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/resources_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bytecode_verifier::ResourceTransitiveChecker; 5 | use proptest::prelude::*; 6 | use vm::file_format::CompiledModule; 7 | 8 | proptest! { 9 | #[test] 10 | fn valid_resource_transitivity(module in CompiledModule::valid_strategy(20)) { 11 | prop_assert!(ResourceTransitiveChecker::verify_module(&module).is_ok()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/struct_defs_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bytecode_verifier::RecursiveStructDefChecker; 5 | use move_binary_format::file_format::CompiledModule; 6 | use proptest::prelude::*; 7 | 8 | proptest! { 9 | #[test] 10 | fn valid_recursive_struct_defs(module in CompiledModule::valid_strategy(20)) { 11 | prop_assert!(RecursiveStructDefChecker::verify_module(&module).is_ok()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /mvm/build.rs: -------------------------------------------------------------------------------- 1 | use std::process::{Command, Stdio}; 2 | 3 | fn main() { 4 | #[cfg(feature = "assets")] 5 | { 6 | run("tests/assets", "bash", &["./build_assets.sh"]); 7 | } 8 | } 9 | 10 | pub fn run(path: &str, cmd: &str, args: &[&str]) { 11 | let status = Command::new(cmd) 12 | .current_dir(path) 13 | .args(args) 14 | .stdout(Stdio::piped()) 15 | .status() 16 | .unwrap(); 17 | if !status.success() { 18 | panic!("Failed to run {} {} {:?}", path, cmd, args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/ability_field_requirements_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bytecode_verifier::ability_field_requirements; 5 | use move_binary_format::file_format::CompiledModule; 6 | use proptest::prelude::*; 7 | 8 | proptest! { 9 | #[test] 10 | fn valid_ability_transitivity(module in CompiledModule::valid_strategy(20)) { 11 | prop_assert!(ability_field_requirements::verify_module(&module).is_ok()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /mvm/tests/assets/sources/EventProxy.move: -------------------------------------------------------------------------------- 1 | module Assets::EventProxy { 2 | use Std::Event; 3 | 4 | struct U64 has copy, key, store, drop { val: u64 } 5 | 6 | public fun emit_event(addr: &signer, val: u64) { 7 | let handle = Event::new_event_handle(addr); 8 | Event::emit_event(&mut handle, U64 { val }); 9 | Event::destroy_handle(handle); 10 | } 11 | 12 | public fun create_val(val: u64): U64 { 13 | U64 { val } 14 | } 15 | 16 | public(script) fun test_only() { 17 | abort 1 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /language/move-binary-format/serializer-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serializer-tests" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem serializer tests" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dev-dependencies] 13 | proptest = "1.0.0" 14 | proptest-derive = "0.3.0" 15 | move-binary-format = { path = "../", features = ["fuzzing"] } 16 | 17 | [features] 18 | fuzzing = ["move-binary-format/fuzzing"] 19 | -------------------------------------------------------------------------------- /common/nibble/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diem-nibble" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem diem-nibble" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | proptest = { version = "1.0.0", optional = true } 14 | serde = { version = "1.0.117", default-features = false, package = "alt_serde", features = ["derive", "alloc"] } 15 | 16 | [features] 17 | default = ["std"] 18 | fuzzing = ["proptest"] 19 | 20 | std = [ 21 | ] -------------------------------------------------------------------------------- /common/proptest-helpers/proptest-regressions/unit_tests/repeat_vec_tests.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc bed7b5b3625868c27a6c5c41149a5a33d499f9d8eb3c5c63345246135f4c4040 # shrinks to item_sizes = [], ok_queries = [Index(0)] 8 | cc 7b5ab398a2ae837e253aee9685848a8b3dc7402484173431621ff55cdda47e9f # shrinks to item_sizes = [], ops = [Get(Index(0))] 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build_wasm_no_std: 2 | cd mvm; cargo +nightly build --package mvm --target wasm32-unknown-unknown --no-default-features --features="sp_check" 3 | 4 | build_wasm_std: 5 | cd mvm; cargo +nightly build --package mvm --no-default-features --features="std,sp_check" 6 | 7 | clippy: 8 | cargo clippy 9 | 10 | tests: 11 | cargo test --all --tests --no-fail-fast -- --test-threads=4 --nocapture 12 | 13 | fmt: 14 | cargo fmt --all 15 | 16 | pre-compile: fmt clippy tests build_wasm_std build_wasm_no_std 17 | cargo build 18 | 19 | gas_bench: 20 | cargo test --release --test gas_bench gas_bench --features "bench" -- --nocapture -------------------------------------------------------------------------------- /crypto/crypto-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diem-crypto-derive" 3 | version = "0.0.1" 4 | authors = ["Diem Association "] 5 | description = "Diem custom derives for `diem-crypto`" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = ["crates-io"] 10 | edition = "2018" 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | syn = { version = "1.0.64", features = ["derive"] } 17 | quote = "1.0.9" 18 | proc-macro2 = "1.0.24" 19 | 20 | [dev-dependencies] 21 | anyhow = "1.0.38" 22 | 23 | [features] 24 | default = ["std"] 25 | std = [ ] -------------------------------------------------------------------------------- /language/bytecode-verifier/invalid-mutations/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "invalid-mutations" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Diem Association "] 6 | description = "Diem invalid mutations" 7 | repository = "https://github.com/diem/diem" 8 | homepage = "https://diem.com" 9 | license = "Apache-2.0" 10 | publish = false 11 | 12 | [dependencies] 13 | move-core-types = { path = "../../move-core/types" } 14 | move-binary-format = { path = "../../move-binary-format" } 15 | proptest = "1.0.0" 16 | diem-proptest-helpers = { path = "../../../common/proptest-helpers" } 17 | 18 | [features] 19 | default = [] 20 | -------------------------------------------------------------------------------- /crypto/crypto-derive/src/hasher.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /// Converts a camel-case string to snake-case 5 | pub fn camel_to_snake(text: &str) -> String { 6 | let mut out = String::with_capacity(text.len()); 7 | let mut first = true; 8 | text.chars().for_each(|c| { 9 | if !first && c.is_uppercase() { 10 | out.push('_'); 11 | out.extend(c.to_lowercase()); 12 | } else if first { 13 | first = false; 14 | out.extend(c.to_lowercase()); 15 | } else { 16 | out.push(c); 17 | } 18 | }); 19 | out 20 | } 21 | -------------------------------------------------------------------------------- /common/short-hex-str/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "short-hex-str" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem implementation for retries of operations" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | mirai-annotations = { path = "../../mirai-annotations" } 14 | serde = { version = "1.0.117", default-features = false, package = "alt_serde", features = ["derive"] } 15 | 16 | [dev-dependencies] 17 | proptest = "1.0.0" 18 | hex = "0.4.2" 19 | 20 | [features] 21 | default = ["std"] 22 | std = [ 23 | ] 24 | -------------------------------------------------------------------------------- /language/move-vm/types/src/unit_tests/identifier_prop_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::file_format::CompiledModule; 5 | use proptest::prelude::*; 6 | 7 | proptest! { 8 | #[test] 9 | fn identifier_serializer_roundtrip(module in CompiledModule::valid_strategy(20)) { 10 | let module_id = module.self_id(); 11 | let deserialized_module_id = { 12 | let serialized_key = bcs::to_bytes(&module_id).unwrap(); 13 | bcs::from_bytes(&serialized_key).expect("Deserialize should work") 14 | }; 15 | prop_assert_eq!(module_id, deserialized_module_id); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /language/move-core/types/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Core types for Move. 5 | 6 | #![cfg_attr(not(feature = "std"), no_std)] 7 | #![allow(clippy::unit_arg)] 8 | 9 | #[macro_use] 10 | extern crate alloc; 11 | 12 | pub mod abi; 13 | pub mod account_address; 14 | pub mod effects; 15 | pub mod errmap; 16 | pub mod gas_schedule; 17 | pub mod identifier; 18 | pub mod language_storage; 19 | pub mod move_resource; 20 | pub mod parser; 21 | #[cfg(any(test, feature = "fuzzing"))] 22 | pub mod proptest_types; 23 | pub mod resolver; 24 | pub mod transaction_argument; 25 | #[cfg(test)] 26 | mod unit_tests; 27 | pub mod value; 28 | pub mod vm_status; 29 | -------------------------------------------------------------------------------- /mvm/src/io/config.rs: -------------------------------------------------------------------------------- 1 | use crate::io::key::{AccessKey, KeyType}; 2 | use crate::io::traits::Storage; 3 | use alloc::vec::Vec; 4 | use diem_types::access_path::AccessPath; 5 | use diem_types::on_chain_config::ConfigStorage; 6 | 7 | pub struct ConfigStore<'a, S: Storage> { 8 | store: &'a S, 9 | } 10 | 11 | impl<'a, S: Storage> From<&'a S> for ConfigStore<'a, S> { 12 | fn from(store: &'a S) -> Self { 13 | ConfigStore { store } 14 | } 15 | } 16 | 17 | impl<'a, S: Storage> ConfigStorage for ConfigStore<'a, S> { 18 | fn fetch_config(&self, access_path: AccessPath) -> Option> { 19 | self.store 20 | .get(AccessKey::new(access_path, KeyType::Resource).as_ref()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /language/move-vm/test-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-vm-test-utils" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Move VM Test Utils" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | anyhow = "1.0.34" 16 | 17 | move-vm-runtime = { path = "../runtime", version = "0.1.0" } 18 | move-core-types = {path = "../../move-core/types", version = "0.1.0" } 19 | move-binary-format = { path = "../../move-binary-format", version = "0.1.0" } 20 | -------------------------------------------------------------------------------- /bcs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this project 2 | 3 | This project welcomes contributions. 4 | 5 | ## Contributor License Agreement (CLA) 6 | 7 | For pull request to be accepted by any Libra projects, a CLA must be [signed](https://libra.org/en-US/cla-sign). You will only need to do this once to work on any of Libra's open source projects. 8 | 9 | When submitting a pull request (PR), the `libra-github-bot` will check your submission for a valid CLA. If one is not found, then you will need to [submit](https://libra.org/en-US/cla-sign) an Individual CLA for yourself or a Corporate CLA for your company. 10 | 11 | ## Issues 12 | 13 | This project uses GitHub Issues to track bugs. Please include necessary information and instructions to reproduce your issue. 14 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bytecode-verifier-tests" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem bytecode verifier tests" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dev-dependencies] 13 | petgraph = "0.5.1" 14 | proptest = "1.0.0" 15 | 16 | bytecode-verifier = { path = "../" } 17 | invalid-mutations = { path = "../invalid-mutations" } 18 | move-core-types = { path = "../../move-core/types" } 19 | move-binary-format = { path = "../../move-binary-format", features = ["fuzzing"] } 20 | 21 | [features] 22 | fuzzing = ["move-binary-format/fuzzing"] 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "common/short-hex-str", 4 | "common/cell", 5 | "crypto/crypto", 6 | "crypto/crypto-derive", 7 | "language/borrow-graph", 8 | "language/bytecode-verifier", 9 | "language/bytecode-verifier/invalid-mutations", 10 | "language/bytecode-verifier/bytecode-verifier-tests", 11 | "language/move-core/types", 12 | "language/move-stdlib", 13 | "language/move-binary-format", 14 | "language/move-binary-format/serializer-tests", 15 | "language/move-vm/runtime", 16 | "language/move-vm/types", 17 | "language/move-vm/test-utils", 18 | "mvm", 19 | "bcs", 20 | "mirai-annotations", 21 | "common/nibble", 22 | "common/proptest-helpers", 23 | "common/fallible", 24 | "stdlib", 25 | "types" 26 | ] 27 | -------------------------------------------------------------------------------- /language/move-vm/runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | 6 | //! The core Move VM logic. 7 | //! 8 | //! It is a design goal for the Move VM to be independent of the Diem blockchain, so that 9 | //! other blockchains can use it as well. The VM isn't there yet, but hopefully will be there 10 | //! soon. 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | #[macro_use] 14 | extern crate mirai_annotations; 15 | #[macro_use] 16 | extern crate alloc; 17 | extern crate log; 18 | 19 | pub mod data_cache; 20 | mod interpreter; 21 | pub mod loader; 22 | pub mod logging; 23 | pub mod move_vm; 24 | pub mod native_functions; 25 | mod runtime; 26 | pub mod session; 27 | #[cfg(test)] 28 | mod unit_tests; 29 | -------------------------------------------------------------------------------- /crypto/crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | #![deny(missing_docs)] 6 | //! This feature gets turned on only if diem-crypto is compiled via MIRAI in a nightly build. 7 | #![cfg_attr(mirai, allow(incomplete_features), feature(const_generics))] 8 | #![cfg_attr(not(feature = "std"), no_std)] 9 | 10 | #[macro_use] 11 | extern crate alloc; 12 | 13 | #[cfg(test)] 14 | mod unit_tests; 15 | 16 | pub mod ed25519; 17 | pub mod hash; 18 | pub mod serde_name; 19 | #[cfg(test)] 20 | pub mod test_utils; 21 | pub mod traits; 22 | 23 | pub use self::traits::*; 24 | pub use hash::HashValue; 25 | 26 | ///Reexport once_cell and serde_name for use in CryptoHasher Derive implementation. 27 | #[doc(hidden)] 28 | pub use cell::{Lazy, OnceCell}; 29 | -------------------------------------------------------------------------------- /mvm/tests/assets/scripts/Transfer.move: -------------------------------------------------------------------------------- 1 | script { 2 | use PontemFramework::PontAccount; 3 | use PontemFramework::NOX::NOX; 4 | use Std::Signer; 5 | use Std::Errors; 6 | 7 | fun transfer(from: signer, to: signer, from_balance: u64, to_balance: u64, to_move: u64) { 8 | assert!(PontAccount::balance(Signer::address_of(&from)) == from_balance, Errors::custom(0)); 9 | assert!(PontAccount::balance(Signer::address_of(&to)) == to_balance, Errors::custom(1)); 10 | 11 | PontAccount::pay_from(&from, Signer::address_of(&to), to_move); 12 | 13 | assert!(PontAccount::balance(Signer::address_of(&from)) == from_balance - to_move, Errors::custom(2)); 14 | assert!(PontAccount::balance(Signer::address_of(&to)) == to_balance + to_move, Errors::custom(3)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /language/borrow-graph/src/paths.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::borrow::ToOwned; 5 | use alloc::vec::Vec; 6 | 7 | pub type PathSlice = [Lbl]; 8 | pub type Path = Vec; 9 | 10 | pub fn leq(lhs: &PathSlice, rhs: &PathSlice) -> bool { 11 | lhs.len() <= rhs.len() && lhs.iter().zip(rhs).all(|(l, r)| l == r) 12 | } 13 | 14 | pub fn factor(lhs: &PathSlice, mut rhs: Path) -> (Path, Path) { 15 | assert!(leq(lhs, &rhs)); 16 | let suffix = rhs.split_off(lhs.len()); 17 | (rhs, suffix) 18 | } 19 | 20 | pub fn append(lhs: &PathSlice, rhs: &PathSlice) -> Path { 21 | let mut path: Path = lhs.into(); 22 | path.append(&mut rhs.to_owned()); 23 | path 24 | } 25 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/duplication_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bytecode_verifier::DuplicationChecker; 5 | use move_binary_format::file_format::*; 6 | use proptest::prelude::*; 7 | 8 | #[test] 9 | fn duplicated_friend_decls() { 10 | let mut m = basic_test_module(); 11 | let handle = ModuleHandle { 12 | address: AddressIdentifierIndex::new(0), 13 | name: IdentifierIndex::new(0), 14 | }; 15 | m.friend_decls.push(handle.clone()); 16 | m.friend_decls.push(handle); 17 | DuplicationChecker::verify_module(&m).unwrap_err(); 18 | } 19 | 20 | proptest! { 21 | #[test] 22 | fn valid_duplication(module in CompiledModule::valid_strategy(20)) { 23 | prop_assert!(DuplicationChecker::verify_module(&module).is_ok()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bcs/benches/bcs_bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bcs::to_bytes; 5 | use criterion::{criterion_group, criterion_main, Criterion}; 6 | use std::collections::{BTreeMap, HashMap}; 7 | 8 | pub fn bcs_benchmark(c: &mut Criterion) { 9 | let mut btree_map = BTreeMap::new(); 10 | let mut hash_map = HashMap::new(); 11 | for i in 0u32..2000u32 { 12 | btree_map.insert(i, i); 13 | hash_map.insert(i, i); 14 | } 15 | c.bench_function("serialize btree map", |b| { 16 | b.iter(|| { 17 | to_bytes(&btree_map).unwrap(); 18 | }) 19 | }); 20 | c.bench_function("serialize hash map", |b| { 21 | b.iter(|| { 22 | to_bytes(&hash_map).unwrap(); 23 | }) 24 | }); 25 | } 26 | 27 | criterion_group!(benches, bcs_benchmark); 28 | criterion_main!(benches); 29 | -------------------------------------------------------------------------------- /common/fallible/src/copy_from_slice.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use core::fmt; 5 | 6 | /// A fallible wrapper around [`std::vec::Vec::copy_from_slice`] 7 | pub fn copy_slice_to_vec(slice: &[T], vec: &mut [T]) -> Result<(), CopySliceError> 8 | where 9 | T: Copy, 10 | { 11 | if slice.len() != vec.len() { 12 | return Err(CopySliceError); 13 | } 14 | 15 | vec.copy_from_slice(slice); 16 | 17 | Ok(()) 18 | } 19 | 20 | #[derive(Debug)] 21 | pub struct CopySliceError; 22 | 23 | impl fmt::Display for CopySliceError { 24 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 25 | write!( 26 | f, 27 | "can't copy source slice into destination slice: sizes don't match" 28 | ) 29 | } 30 | } 31 | 32 | #[cfg(feature = "std")] 33 | impl std::error::Error for CopySliceError {} 34 | -------------------------------------------------------------------------------- /language/move-vm/types/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![cfg_attr(not(feature = "std"), no_std)] 5 | #![forbid(unsafe_code)] 6 | 7 | #[macro_use] 8 | extern crate alloc; 9 | 10 | macro_rules! debug_write { 11 | ($($toks: tt)*) => { 12 | write!($($toks)*).map_err(|_| 13 | PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) 14 | .with_message("failed to write to buffer".to_string()) 15 | ) 16 | }; 17 | } 18 | 19 | macro_rules! debug_writeln { 20 | ($($toks: tt)*) => { 21 | writeln!($($toks)*).map_err(|_| 22 | PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) 23 | .with_message("failed to write to buffer".to_string()) 24 | ) 25 | }; 26 | } 27 | 28 | pub mod data_store; 29 | pub mod gas_schedule; 30 | pub mod loaded_data; 31 | pub mod natives; 32 | pub mod values; 33 | 34 | #[cfg(test)] 35 | mod unit_tests; 36 | -------------------------------------------------------------------------------- /language/move-vm/types/src/values/value_prop_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::values::{prop::layout_and_value_strategy, Value}; 5 | use move_core_types::value::MoveValue; 6 | use proptest::prelude::*; 7 | 8 | proptest! { 9 | #[test] 10 | fn serializer_round_trip((layout, value) in layout_and_value_strategy()) { 11 | let blob = value.simple_serialize(&layout).expect("must serialize"); 12 | let value_deserialized = Value::simple_deserialize(&blob, &layout).expect("must deserialize"); 13 | assert!(value.equals(&value_deserialized).unwrap()); 14 | 15 | let move_value = value.as_move_value(&layout); 16 | 17 | let blob2 = move_value.simple_serialize().expect("must serialize"); 18 | assert_eq!(blob, blob2); 19 | 20 | let move_value_deserialized = MoveValue::simple_deserialize(&blob2, &layout).expect("must deserialize."); 21 | assert_eq!(move_value, move_value_deserialized); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /types/src/on_chain_config/diem_version.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::on_chain_config::OnChainConfig; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | /// Defines the version of Diem Validator software. 8 | #[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord, Serialize)] 9 | pub struct DiemVersion { 10 | pub major: u64, 11 | } 12 | 13 | impl OnChainConfig for DiemVersion { 14 | const IDENTIFIER: &'static str = "DiemVersion"; 15 | } 16 | 17 | // NOTE: version number for release 1.2 Diem 18 | // Items gated by this version number include: 19 | // - the ScriptFunction payload type 20 | pub const DIEM_VERSION_2: DiemVersion = DiemVersion { major: 2 }; 21 | 22 | // NOTE: version number for release 1.3 of Diem 23 | // Items gated by this version number include: 24 | // - Multi-agent transactions 25 | pub const DIEM_VERSION_3: DiemVersion = DiemVersion { major: 3 }; 26 | 27 | // Maximum current known version 28 | pub const DIEM_MAX_KNOWN_VERSION: DiemVersion = DIEM_VERSION_3; 29 | -------------------------------------------------------------------------------- /types/src/account_config/constants/addresses.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_address::AccountAddress; 5 | 6 | pub use move_core_types::language_storage::CORE_CODE_ADDRESS; 7 | 8 | pub fn diem_root_address() -> AccountAddress { 9 | AccountAddress::from_hex_literal("0xA550C18") 10 | .expect("Parsing valid hex literal should always succeed") 11 | } 12 | 13 | pub fn validator_set_address() -> AccountAddress { 14 | crate::on_chain_config::config_address() 15 | } 16 | 17 | pub fn treasury_compliance_account_address() -> AccountAddress { 18 | AccountAddress::from_hex_literal("0xB1E55ED") 19 | .expect("Parsing valid hex literal should always succeed") 20 | } 21 | 22 | pub fn reserved_vm_address() -> AccountAddress { 23 | AccountAddress::new([0u8; AccountAddress::LENGTH]) 24 | } 25 | 26 | pub fn testnet_dd_account_address() -> AccountAddress { 27 | AccountAddress::from_hex_literal("0xDD") 28 | .expect("Parsing valid hex literal should always succeed") 29 | } 30 | -------------------------------------------------------------------------------- /types/src/account_config/constants/event.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_config::constants::CORE_CODE_ADDRESS; 5 | use alloc::borrow::ToOwned; 6 | use cell::Lazy; 7 | use move_core_types::{ 8 | ident_str, 9 | identifier::IdentStr, 10 | language_storage::{ModuleId, StructTag}, 11 | }; 12 | 13 | pub const EVENT_MODULE_IDENTIFIER: &IdentStr = ident_str!("Event"); 14 | pub static EVENT_MODULE: Lazy = 15 | Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, EVENT_MODULE_IDENTIFIER.to_owned())); 16 | pub const EVENT_HANDLE_STRUCT_IDENTIFIER: &IdentStr = ident_str!("EventHandle"); 17 | pub const EVENT_HANDLE_GENERATOR_STRUCT_IDENTIFIER: &IdentStr = ident_str!("EventHandleGenerator"); 18 | 19 | pub fn event_handle_generator_struct_tag() -> StructTag { 20 | StructTag { 21 | address: CORE_CODE_ADDRESS, 22 | module: EVENT_MODULE_IDENTIFIER.to_owned(), 23 | name: EVENT_HANDLE_GENERATOR_STRUCT_IDENTIFIER.to_owned(), 24 | type_params: vec![], 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /stdlib/build_std.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | function lockfile_waithold() 3 | { 4 | declare -ir time_beg=$(date '+%s') 5 | declare -ir time_max=7140 # 7140 s = 1 hour 59 min. 6 | 7 | while ! \ 8 | (set -o noclobber ; \ 9 | echo -e "DATE:$(date)\nUSER:$(whoami)\nPID:$$" > /tmp/global.lock \ 10 | ) 2>/dev/null 11 | do 12 | if [ $(($(date '+%s') - ${time_beg})) -gt ${time_max} ] ; then 13 | echo "Error: waited too long for lock file /tmp/global.lock" 1>&2 14 | return 1 15 | fi 16 | sleep 1 17 | done 18 | 19 | return 0 20 | } 21 | 22 | function lockfile_release() 23 | { 24 | rm -f /tmp/global.lock 25 | } 26 | 27 | lockfile_waithold 28 | rm -rf pont-stdlib 29 | git clone https://github.com/pontem-network/pont-stdlib.git 30 | cd pont-stdlib 31 | git reset --hard release-v1.0.0 32 | dove build -b 33 | cd .. 34 | 35 | rm -rf move-stdlib 36 | git clone https://github.com/pontem-network/move-stdlib.git 37 | cd move-stdlib 38 | git reset --hard release-v1.0.0 39 | dove build -b 40 | lockfile_release 41 | -------------------------------------------------------------------------------- /types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diem-types" 3 | version = "0.0.1" 4 | authors = ["Diem Association "] 5 | description = "Diem types" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = ["crates-io"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | anyhow = { version = "1.0.34", default-features = false } 14 | hex = { version = "0.4.2", default-features = false, features = ["alloc"] } 15 | serde = { version = "1", default-features = false, package = "alt_serde", features = ["derive", "alloc"] } 16 | cell = { path = "../common/cell", default-features = false } 17 | hashbrown = "0.9" 18 | bcs = { path = "../bcs", default-features = false } 19 | diem-crypto = { path = "../crypto/crypto", version = "0.0.1", default-features = false } 20 | diem-crypto-derive = { path = "../crypto/crypto-derive", version = "0.0.1", default-features = false } 21 | move-core-types = { path = "../language/move-core/types", default-features = false } 22 | 23 | [dev-dependencies] 24 | serde_json = { version = "1.0.61", package = "alt_serde_json" } 25 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/signer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_vm_runtime::native_functions::NativeContext; 8 | use move_vm_types::{ 9 | gas_schedule::NativeCostIndex, 10 | loaded_data::runtime_types::Type, 11 | natives::function::{native_gas, NativeResult}, 12 | pop_arg, 13 | values::{values_impl::SignerRef, Value}, 14 | }; 15 | use smallvec::smallvec; 16 | 17 | pub fn native_borrow_address( 18 | context: &mut NativeContext, 19 | _ty_args: Vec, 20 | mut arguments: VecDeque, 21 | ) -> PartialVMResult { 22 | debug_assert!(_ty_args.is_empty()); 23 | debug_assert!(arguments.len() == 1); 24 | 25 | let signer_reference = pop_arg!(arguments, SignerRef); 26 | let cost = native_gas(context.cost_table(), NativeCostIndex::SIGNER_BORROW, 1); 27 | 28 | Ok(NativeResult::ok( 29 | cost, 30 | smallvec![signer_reference.borrow_signer()?], 31 | )) 32 | } 33 | -------------------------------------------------------------------------------- /mvm/src/io/context.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use move_core_types::language_storage::StructTag; 3 | 4 | pub const TIMESTAMP_MODULE: &str = "PontTimestamp"; 5 | pub const CURRENT_TIME_MICROSECONDS: &str = "CurrentTimeMicroseconds"; 6 | 7 | pub const BLOCK_MODULE: &str = "PontBlock"; 8 | pub const BLOCK_METADATA: &str = "BlockMetadata"; 9 | 10 | #[derive(Debug)] 11 | pub struct ExecutionContext { 12 | pub timestamp: u64, 13 | pub block_height: u64, 14 | } 15 | 16 | impl ExecutionContext { 17 | pub fn new(timestamp: u64, block_height: u64) -> ExecutionContext { 18 | ExecutionContext { 19 | timestamp, 20 | block_height, 21 | } 22 | } 23 | 24 | pub fn resolve(&self, tag: &StructTag) -> Option> { 25 | if tag.module.as_str() == TIMESTAMP_MODULE && tag.name.as_str() == CURRENT_TIME_MICROSECONDS 26 | { 27 | bcs::to_bytes(&self.timestamp).ok() 28 | } else if tag.module.as_str() == BLOCK_MODULE && tag.name.as_str() == BLOCK_METADATA { 29 | bcs::to_bytes(&self.block_height).ok() 30 | } else { 31 | None 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/compilation/cross_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use diem_crypto::{ 5 | ed25519::{Ed25519PrivateKey, Ed25519PublicKey}, 6 | multi_ed25519::{MultiEd25519PrivateKey, MultiEd25519PublicKey}, 7 | test_utils::KeyPair, 8 | traits::*, 9 | }; 10 | use diem_crypto_derive::{CryptoHasher, BCSCryptoHash}; 11 | use rand::{prelude::ThreadRng, thread_rng}; 12 | use serde::{Deserialize, Serialize}; 13 | 14 | #[derive(CryptoHasher, BCSCryptoHash, Serialize, Deserialize)] 15 | struct TestTypedSemantics(String); 16 | 17 | fn main() { 18 | let mut csprng: ThreadRng = thread_rng(); 19 | let ed25519_keypair: KeyPair = 20 | KeyPair::generate(&mut csprng); 21 | 22 | let message = TestTypedSemantics(String::from("hello_world")); 23 | let signature = ed25519_keypair.private_key.sign(&message); 24 | 25 | let multi_ed25519_keypair: KeyPair = 26 | KeyPair::generate(&mut csprng); 27 | 28 | signature.verify(&message, &multi_ed25519_keypair.public_key); 29 | } 30 | -------------------------------------------------------------------------------- /mvm/tests/assets/build_assets.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function lockfile_waithold() 4 | { 5 | declare -ir time_beg=$(date '+%s') 6 | declare -ir time_max=7140 # 7140 s = 1 hour 59 min. 7 | 8 | while ! \ 9 | (set -o noclobber ; \ 10 | echo -e "DATE:$(date)\nUSER:$(whoami)\nPID:$$" > /tmp/global.lock \ 11 | ) 2>/dev/null 12 | do 13 | if [ $(($(date '+%s') - ${time_beg})) -gt ${time_max} ] ; then 14 | echo "Error: waited too long for lock file /tmp/global.lock" 1>&2 15 | return 1 16 | fi 17 | sleep 1 18 | done 19 | 20 | return 0 21 | } 22 | 23 | function lockfile_release() 24 | { 25 | rm -f /tmp/global.lock 26 | } 27 | 28 | lockfile_waithold 29 | 30 | set -e 31 | dove build 32 | dove tx "store_u64(13)" 33 | dove tx "tx_test<0x01::Pontem::T>(100)" 34 | dove build -b -o "valid_pack" --modules_exclude "ReflectTest" 35 | dove build -b -o "invalid_pack" --modules_exclude "Store" "ReflectTest" 36 | 37 | dove tx "rt_signers(rt)" 38 | dove tx "signers_tr_with_user(root)" 39 | dove tx "Assets::ScriptBook::test" 40 | dove tx "signer_order" 41 | 42 | lockfile_release 43 | 44 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/support/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::{ 5 | file_format::{ 6 | empty_module, Bytecode, CodeUnit, FunctionDefinition, FunctionHandle, IdentifierIndex, 7 | ModuleHandleIndex, SignatureIndex, 8 | }, 9 | CompiledModule, 10 | }; 11 | 12 | /// Create a dummy module to wrap the bytecode program in local@code 13 | pub fn dummy_procedure_module(code: Vec) -> CompiledModule { 14 | let mut module = empty_module(); 15 | let code_unit = CodeUnit { 16 | code, 17 | ..Default::default() 18 | }; 19 | let fun_def = FunctionDefinition { 20 | code: Some(code_unit), 21 | ..Default::default() 22 | }; 23 | 24 | let fun_handle = FunctionHandle { 25 | module: ModuleHandleIndex(0), 26 | name: IdentifierIndex(0), 27 | parameters: SignatureIndex(0), 28 | return_: SignatureIndex(0), 29 | type_parameters: vec![], 30 | }; 31 | 32 | module.function_handles.push(fun_handle); 33 | module.function_defs.push(fun_def); 34 | module 35 | } 36 | -------------------------------------------------------------------------------- /mvm/src/io/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::io::balance::CurrencyInfo; 2 | use alloc::vec::Vec; 3 | use move_core_types::account_address::AccountAddress; 4 | use move_core_types::language_storage::TypeTag; 5 | 6 | pub trait EventHandler { 7 | fn on_event(&self, guid: Vec, seq_num: u64, ty_tag: TypeTag, message: Vec); 8 | } 9 | 10 | pub trait Storage { 11 | /// Returns the data for `key` in the storage or `None` if the key can not be found. 12 | fn get(&self, key: &[u8]) -> Option>; 13 | /// Set `key` to `value` in the storage. 14 | fn insert(&self, key: &[u8], value: &[u8]); 15 | /// Clear the storage of the given `key` and its value. 16 | fn remove(&self, key: &[u8]); 17 | } 18 | 19 | pub type CurrencyAccessPath = [u8]; 20 | pub type Balance = u64; 21 | 22 | pub trait BalanceAccess { 23 | fn get_currency_info(&self, path: &CurrencyAccessPath) -> Option; 24 | fn get_balance(&self, address: &AccountAddress, path: &CurrencyAccessPath) -> Option; 25 | fn add(&self, address: &AccountAddress, path: &CurrencyAccessPath, amount: Balance); 26 | fn sub(&self, address: &AccountAddress, path: &CurrencyAccessPath, amount: Balance); 27 | } 28 | -------------------------------------------------------------------------------- /language/move-stdlib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-stdlib" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Diem Association "] 6 | description = "Diem stdlib" 7 | repository = "https://github.com/diem/diem" 8 | homepage = "https://diem.com" 9 | license = "Apache-2.0" 10 | publish = false 11 | 12 | [dependencies] 13 | move-vm-types = { path = "../move-vm/types", default-features = false } 14 | move-binary-format = { path = "../move-binary-format", default-features = false } 15 | move-core-types = { path = "../move-core/types", default-features = false } 16 | move-vm-runtime = { path = "../move-vm/runtime", default-features = false } 17 | diem-crypto = { path = "../../crypto/crypto", default-features = false } 18 | uint = { version = "0.9.1", default-features = false } 19 | smallvec = { version = "1.6.1", default-features = false } 20 | sha2 = { version = "0.9.3", default-features = false } 21 | sha3 = { version = "0.9.1", default-features = false } 22 | 23 | [features] 24 | default = ["std"] 25 | testing = [] 26 | std = [ 27 | "move-vm-types/std", 28 | "move-binary-format/std", 29 | "move-core-types/std", 30 | "move-vm-runtime/std", 31 | "diem-crypto/std", 32 | ] 33 | -------------------------------------------------------------------------------- /language/bytecode-verifier/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![forbid(unsafe_code)] 5 | 6 | //! Verifies bytecode sanity. 7 | 8 | #![cfg_attr(not(feature = "std"), no_std)] 9 | 10 | #[macro_use] 11 | extern crate alloc; 12 | 13 | // Bounds checks are implemented in the `vm` crate. 14 | pub mod ability_field_requirements; 15 | pub mod check_duplication; 16 | pub mod code_unit_verifier; 17 | pub mod constants; 18 | pub mod control_flow; 19 | pub mod cyclic_dependencies; 20 | pub mod dependencies; 21 | pub mod friends; 22 | pub mod instantiation_loops; 23 | pub mod instruction_consistency; 24 | pub mod script_signature; 25 | pub mod signature; 26 | pub mod struct_defs; 27 | pub mod verifier; 28 | 29 | pub use check_duplication::DuplicationChecker; 30 | pub use code_unit_verifier::CodeUnitVerifier; 31 | pub use instruction_consistency::InstructionConsistency; 32 | pub use signature::SignatureChecker; 33 | pub use struct_defs::RecursiveStructDefChecker; 34 | pub use verifier::{verify_module, verify_script}; 35 | 36 | mod absint; 37 | mod acquires_list_verifier; 38 | mod locals_safety; 39 | mod reference_safety; 40 | mod stack_usage_verifier; 41 | mod type_safety; 42 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/unit_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::errors::PartialVMResult; 5 | use move_core_types::gas_schedule::ONE_GAS_UNIT; 6 | use move_vm_runtime::native_functions::NativeContext; 7 | use move_vm_types::{ 8 | loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, 9 | }; 10 | use smallvec::smallvec; 11 | use std::collections::VecDeque; 12 | 13 | use move_core_types::account_address::AccountAddress; 14 | 15 | pub fn native_create_signers_for_testing( 16 | _context: &mut NativeContext, 17 | ty_args: Vec, 18 | mut args: VecDeque, 19 | ) -> PartialVMResult { 20 | debug_assert!(ty_args.is_empty()); 21 | debug_assert!(args.len() == 1); 22 | 23 | let num_signers = pop_arg!(args, u64); 24 | let signers = Value::vector_for_testing_only((0..num_signers).map(|i| { 25 | let mut buffer = [0; AccountAddress::LENGTH]; 26 | buffer[16..].copy_from_slice(&(i as u128).to_le_bytes()); 27 | Value::signer(AccountAddress::new(buffer)) 28 | })); 29 | 30 | Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![signers])) 31 | } 32 | -------------------------------------------------------------------------------- /bcs/Cargo.toml: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 | # 3 | # When uploading crates to the registry Cargo will automatically 4 | # "normalize" Cargo.toml files for maximal compatibility 5 | # with all versions of Cargo and also rewrite `path` dependencies 6 | # to registry (e.g., crates.io) dependencies 7 | # 8 | # If you believe there's an error in this file please file an 9 | # issue against the rust-lang/cargo repository. If you're 10 | # editing this file be aware that the upstream Cargo.toml 11 | # will likely look very different (and much more reasonable) 12 | 13 | [package] 14 | edition = "2018" 15 | name = "bcs" 16 | version = "0.1.3" 17 | authors = ["Diem "] 18 | description = "Binary Canonical Serialization (BCS)" 19 | homepage = "https://diem.com" 20 | readme = "README.md" 21 | license = "Apache-2.0" 22 | repository = "https://github.com/diem/bcs" 23 | 24 | [[bench]] 25 | name = "bcs_bench" 26 | harness = false 27 | 28 | [dependencies] 29 | serde = { version = "1.0.117", default-features = false, package = "alt_serde", features = ["derive"] } 30 | 31 | [dev-dependencies] 32 | criterion = "0.3.3" 33 | proptest = "1.0.0" 34 | proptest-derive = "0.2.0" 35 | 36 | [features] 37 | default = ["std"] 38 | 39 | std = [ 40 | ] -------------------------------------------------------------------------------- /language/move-core/types/src/move_resource.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{ 5 | identifier::{IdentStr, Identifier}, 6 | language_storage::{StructTag, TypeTag}, 7 | }; 8 | use alloc::borrow::ToOwned; 9 | use alloc::vec::Vec; 10 | use serde::de::DeserializeOwned; 11 | 12 | pub trait MoveStructType { 13 | const MODULE_NAME: &'static IdentStr; 14 | const STRUCT_NAME: &'static IdentStr; 15 | 16 | fn module_identifier() -> Identifier { 17 | Self::MODULE_NAME.to_owned() 18 | } 19 | 20 | fn struct_identifier() -> Identifier { 21 | Self::STRUCT_NAME.to_owned() 22 | } 23 | 24 | fn type_params() -> Vec { 25 | vec![] 26 | } 27 | 28 | fn struct_tag() -> StructTag { 29 | StructTag { 30 | address: crate::language_storage::CORE_CODE_ADDRESS, 31 | name: Self::struct_identifier(), 32 | module: Self::module_identifier(), 33 | type_params: Self::type_params(), 34 | } 35 | } 36 | } 37 | 38 | pub trait MoveResource: MoveStructType + DeserializeOwned { 39 | fn resource_path() -> Vec { 40 | Self::struct_tag().access_vector() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /common/nibble/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | #![cfg_attr(not(feature = "std"), no_std)] 4 | #![forbid(unsafe_code)] 5 | 6 | //! `Nibble` represents a four-bit unsigned integer. 7 | 8 | use core::fmt; 9 | #[cfg(feature = "fuzzing")] 10 | use proptest::prelude::*; 11 | use serde::{Deserialize, Serialize}; 12 | 13 | #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] 14 | pub struct Nibble(u8); 15 | 16 | impl From for Nibble { 17 | fn from(nibble: u8) -> Self { 18 | assert!(nibble < 16, "Nibble out of range: {}", nibble); 19 | Self(nibble) 20 | } 21 | } 22 | 23 | impl From for u8 { 24 | fn from(nibble: Nibble) -> Self { 25 | nibble.0 26 | } 27 | } 28 | 29 | impl fmt::LowerHex for Nibble { 30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 31 | write!(f, "{:x}", self.0) 32 | } 33 | } 34 | 35 | #[cfg(feature = "fuzzing")] 36 | impl Arbitrary for Nibble { 37 | type Parameters = (); 38 | type Strategy = BoxedStrategy; 39 | 40 | fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { 41 | (0..16u8).prop_map(Self::from).boxed() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /language/move-vm/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-vm-types" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Types for Move VM" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | mirai-annotations = { path = "../../../mirai-annotations", default-features = false } 14 | cell = { path = "../../../common/cell", default-features = false } 15 | proptest = { version = "1.0.0", optional = true } 16 | sha2 = { version = "0.9.2", default-features = false } 17 | serde = { version = "1", default-features = false, package = "alt_serde", features = ["derive", "alloc"] } 18 | smallvec = "1.7.0" 19 | hashbrown = "0.9" 20 | bcs = { path = "../../../bcs", default-features = false } 21 | move-core-types = { path = "../../move-core/types", default-features = false } 22 | move-binary-format = { path = "../../move-binary-format", default-features = false } 23 | 24 | [dev-dependencies] 25 | proptest = "1.0.0" 26 | 27 | [features] 28 | fuzzing = ["proptest", "move-binary-format/fuzzing"] 29 | default = ["std"] 30 | std = [ 31 | "sha2/std", 32 | "move-binary-format/std", 33 | "move-core-types/std", 34 | ] 35 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/multi_pass_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bytecode_verifier::{ 5 | ability_field_requirements, constants, instantiation_loops::InstantiationLoopChecker, 6 | DuplicationChecker, InstructionConsistency, RecursiveStructDefChecker, SignatureChecker, 7 | }; 8 | use move_binary_format::CompiledModule; 9 | use proptest::prelude::*; 10 | 11 | proptest! { 12 | #[test] 13 | fn check_verifier_passes(module in CompiledModule::valid_strategy(20)) { 14 | DuplicationChecker::verify_module(&module).expect("DuplicationChecker failure"); 15 | SignatureChecker::verify_module(&module).expect("SignatureChecker failure"); 16 | InstructionConsistency::verify_module(&module).expect("InstructionConsistency failure"); 17 | constants::verify_module(&module).expect("constants failure"); 18 | ability_field_requirements::verify_module(&module).expect("ability_field_requirements failure"); 19 | RecursiveStructDefChecker::verify_module(&module).expect("RecursiveStructDefChecker failure"); 20 | InstantiationLoopChecker::verify_module(&module).expect("InstantiationLoopChecker failure"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /mvm/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use diem_types::account_config::CORE_CODE_ADDRESS; 4 | use move_core_types::identifier::Identifier; 5 | use move_core_types::language_storage::ModuleId; 6 | use move_core_types::resolver::ModuleResolver; 7 | use mvm::genesis::init_storage; 8 | use mvm::io::state::State; 9 | use mvm::mvm::Mvm; 10 | 11 | use crate::common::mock::{BankMock, EventHandlerMock, StorageMock}; 12 | 13 | pub mod assets; 14 | pub mod mock; 15 | 16 | pub fn vm() -> ( 17 | Mvm, 18 | StorageMock, 19 | EventHandlerMock, 20 | BankMock, 21 | ) { 22 | let store = StorageMock::new(); 23 | let event = EventHandlerMock::default(); 24 | let bank = BankMock::default(); 25 | init_storage(store.clone(), Default::default()).unwrap(); 26 | 27 | let vm = Mvm::new(store.clone(), event.clone(), bank.clone()).unwrap(); 28 | (vm, store, event, bank) 29 | } 30 | 31 | pub fn contains_core_module(state: &State, name: &str) { 32 | if state 33 | .get_module(&ModuleId::new( 34 | CORE_CODE_ADDRESS, 35 | Identifier::new(name).unwrap(), 36 | )) 37 | .unwrap() 38 | .is_none() 39 | { 40 | panic!("Module {} not found", name); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /language/bytecode-verifier/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bytecode-verifier" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Diem bytecode verifier" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | hashbrown = "0.9" 14 | anyhow = {version ="1.0.34", default-features = false} 15 | mirai-annotations = { path = "../../mirai-annotations", default-features = false } 16 | petgraph = { git = "https://github.com/pontem-network/petgraph.git", package = "petgraph_core", rev = "b8e795dd9d7bb1143a7ac6bbe745e420e9caf500", default-features = false, features = ["graphmap", "stable_graph", "matrix_graph"]} 17 | 18 | borrow-graph = { path = "../borrow-graph", default-features = false } 19 | move-binary-format = { path = "../move-binary-format", version = "0.1.0", default-features = false } 20 | move-core-types = { path = "../move-core/types", default-features = false } 21 | 22 | [dev-dependencies] 23 | invalid-mutations = { path = "invalid-mutations", version = "0.1.0" } 24 | 25 | [features] 26 | default = ["std"] 27 | fuzzing = [] 28 | 29 | std = [ 30 | "anyhow/std", 31 | "move-core-types/std", 32 | "borrow-graph/std", 33 | "move-binary-format/std", 34 | ] 35 | -------------------------------------------------------------------------------- /types/src/on_chain_config/registered_currencies.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::on_chain_config::OnChainConfig; 5 | use alloc::vec::Vec; 6 | use anyhow::{anyhow, Result}; 7 | use core::fmt; 8 | use move_core_types::identifier::Identifier; 9 | use serde::{Deserialize, Serialize}; 10 | 11 | #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] 12 | pub struct RegisteredCurrencies { 13 | currency_codes: Vec, 14 | } 15 | 16 | impl fmt::Display for RegisteredCurrencies { 17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 18 | write!(f, "[")?; 19 | for currency_code in self.currency_codes().iter() { 20 | write!(f, "{} ", currency_code)?; 21 | } 22 | write!(f, "]") 23 | } 24 | } 25 | 26 | impl RegisteredCurrencies { 27 | pub fn currency_codes(&self) -> &[Identifier] { 28 | &self.currency_codes 29 | } 30 | 31 | pub fn from_bytes(bytes: &[u8]) -> Result { 32 | bcs::from_bytes(bytes) 33 | .map_err(|err| anyhow!("Failed to decode RegisteredCurrencies. {:?}", err)) 34 | } 35 | } 36 | 37 | impl OnChainConfig for RegisteredCurrencies { 38 | // registered currencies address 39 | const IDENTIFIER: &'static str = "RegisteredCurrencies"; 40 | } 41 | -------------------------------------------------------------------------------- /language/move-binary-format/src/unit_tests/binary_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::file_format_common::*; 5 | use proptest::prelude::*; 6 | 7 | #[test] 8 | fn binary_len() { 9 | let mut binary_data = BinaryData::new(); 10 | for _ in 0..100 { 11 | binary_data.push(1).unwrap(); 12 | } 13 | assert_eq!(binary_data.len(), 100); 14 | } 15 | 16 | proptest! { 17 | #[test] 18 | fn vec_to_binary(vec in any::>()) { 19 | let binary_data = BinaryData::from(vec.clone()); 20 | let vec2 = binary_data.into_inner(); 21 | assert_eq!(vec.len(), vec2.len()); 22 | } 23 | } 24 | 25 | proptest! { 26 | #[test] 27 | fn binary_push(item in any::()) { 28 | let mut binary_data = BinaryData::new(); 29 | binary_data.push(item).unwrap(); 30 | assert_eq!(binary_data.into_inner()[0], item); 31 | } 32 | } 33 | 34 | proptest! { 35 | #[test] 36 | fn binary_extend(vec in any::>()) { 37 | let mut binary_data = BinaryData::new(); 38 | binary_data.extend(&vec).unwrap(); 39 | assert_eq!(binary_data.len(), vec.len()); 40 | for (index, item) in vec.iter().enumerate() { 41 | assert_eq!(*item, binary_data.as_inner()[index]); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mvm/tests/assets/sources/Store.move: -------------------------------------------------------------------------------- 1 | module Assets::Store { 2 | struct U64 has copy, key, store, drop { val: u64 } 3 | 4 | struct U128 has copy, key, store, drop { val: u128 } 5 | 6 | struct Address has copy, key, store, drop { val: address } 7 | 8 | struct VectorU8 has copy, key, store, drop { val: vector } 9 | 10 | struct Res has store, key { val: R } 11 | 12 | public fun store_u64(account: &signer, val: u64) { 13 | let foo = U64 { val: val }; 14 | move_to(account, foo); 15 | } 16 | 17 | public fun load_u64(account: address): u64 acquires U64 { 18 | let val = move_from(account); 19 | return val.val 20 | } 21 | 22 | public fun store_u128(account: &signer, val: u128) { 23 | let foo = U128 { val: val }; 24 | move_to(account, foo); 25 | } 26 | 27 | public fun store_address(account: &signer, val: address) { 28 | let addr = Address { val: val }; 29 | move_to
(account, addr); 30 | } 31 | 32 | public fun store_vector_u8(account: &signer, val: vector) { 33 | let vec = VectorU8 { val: val }; 34 | move_to(account, vec); 35 | } 36 | 37 | public fun store_res(account: &signer, val: R) { 38 | let res = Res { val: val }; 39 | move_to>(account, res); 40 | } 41 | } -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/event.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_core_types::gas_schedule::GasAlgebra; 8 | use move_vm_runtime::native_functions::NativeContext; 9 | use move_vm_types::{ 10 | gas_schedule::NativeCostIndex, 11 | loaded_data::runtime_types::Type, 12 | natives::function::{native_gas, NativeResult}, 13 | pop_arg, 14 | values::Value, 15 | }; 16 | use smallvec::smallvec; 17 | 18 | pub fn write_to_event_store( 19 | context: &mut NativeContext, 20 | mut ty_args: Vec, 21 | mut arguments: VecDeque, 22 | ) -> PartialVMResult { 23 | debug_assert!(ty_args.len() == 1); 24 | debug_assert!(arguments.len() == 3); 25 | 26 | let ty = ty_args.pop().unwrap(); 27 | let msg = arguments.pop_back().unwrap(); 28 | let seq_num = pop_arg!(arguments, u64); 29 | let guid = pop_arg!(arguments, Vec); 30 | 31 | let cost = native_gas( 32 | context.cost_table(), 33 | NativeCostIndex::EMIT_EVENT, 34 | msg.size().get() as usize, 35 | ); 36 | 37 | if !context.save_event(guid, seq_num, ty, msg)? { 38 | return Ok(NativeResult::err(cost, 0)); 39 | } 40 | 41 | Ok(NativeResult::ok(cost, smallvec![])) 42 | } 43 | -------------------------------------------------------------------------------- /language/move-binary-format/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-binary-format" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Move Binary Format" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | hashbrown = "0.9" 14 | anyhow = { version = "1.0.38", default-features = false } 15 | cell = { path = "../../common/cell", default-features = false } 16 | mirai-annotations = { path = "../../mirai-annotations", default-features = false } 17 | proptest = { version = "1.0.0", optional = true } 18 | proptest-derive = { version = "0.3.0", optional = true } 19 | ref-cast = "1.0.6" 20 | variant_count = "1.1.0" 21 | move-core-types = { path = "../move-core/types", default-features = false } 22 | 23 | [dev-dependencies] 24 | proptest = "1.0.0" 25 | proptest-derive = "0.3.0" 26 | diem-proptest-helpers = { path = "../../common/proptest-helpers", version = "0.1.0" } 27 | move-core-types = { path = "../move-core/types", features = ["fuzzing"] } 28 | serde_json = { version = "1.0.61", package = "alt_serde_json", default-features = false } 29 | 30 | [features] 31 | default = ["std"] 32 | fuzzing = ["proptest", "proptest-derive", "move-core-types/fuzzing"] 33 | std = [ 34 | "anyhow/std", 35 | "move-core-types/std", 36 | "cell/std", 37 | ] 38 | 39 | -------------------------------------------------------------------------------- /language/move-binary-format/serializer-tests/tests/serializer_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::file_format::CompiledModule; 5 | use proptest::prelude::*; 6 | 7 | proptest! { 8 | #[test] 9 | fn serializer_roundtrip(module in CompiledModule::valid_strategy(20)) { 10 | let mut serialized = Vec::with_capacity(2048); 11 | module.serialize(&mut serialized).expect("serialization should work"); 12 | 13 | let deserialized_module = CompiledModule::deserialize(&serialized) 14 | .expect("deserialization should work"); 15 | prop_assert_eq!(module, deserialized_module); 16 | } 17 | } 18 | 19 | proptest! { 20 | // Generating arbitrary compiled modules is really slow, possibly because of 21 | // https://github.com/AltSysrq/proptest/issues/143. 22 | #![proptest_config(ProptestConfig::with_cases(16))] 23 | 24 | /// Make sure that garbage inputs don't crash the serializer and deserializer. 25 | #[test] 26 | fn garbage_inputs(module in any_with::(16)) { 27 | let mut serialized = Vec::with_capacity(65536); 28 | module.serialize(&mut serialized).expect("serialization should work"); 29 | 30 | let deserialized_module = CompiledModule::deserialize_no_check_bounds(&serialized) 31 | .expect("deserialization should work"); 32 | prop_assert_eq!(module, deserialized_module); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /mvm/src/io/key.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use diem_types::access_path::AccessPath; 3 | use move_core_types::account_address::AccountAddress; 4 | use move_core_types::language_storage::{ModuleId, StructTag}; 5 | 6 | pub struct AccessKey(Vec); 7 | 8 | pub enum KeyType { 9 | Resource, 10 | Module, 11 | } 12 | 13 | impl AccessKey { 14 | pub fn new(path: AccessPath, k_type: KeyType) -> AccessKey { 15 | match k_type { 16 | KeyType::Resource => { 17 | let mut key = Vec::with_capacity(AccountAddress::LENGTH + path.path.len()); 18 | key.extend_from_slice(path.address.as_ref()); 19 | key.extend_from_slice(path.path.as_ref()); 20 | AccessKey(key) 21 | } 22 | KeyType::Module => AccessKey(path.path), 23 | } 24 | } 25 | } 26 | 27 | impl From<(&AccountAddress, &StructTag)> for AccessKey { 28 | fn from((addr, tag): (&AccountAddress, &StructTag)) -> Self { 29 | let tag = tag.access_vector(); 30 | let mut key = Vec::with_capacity(AccountAddress::LENGTH + tag.len()); 31 | key.extend_from_slice(addr.as_ref()); 32 | key.extend_from_slice(&tag); 33 | AccessKey(key) 34 | } 35 | } 36 | 37 | impl From<&ModuleId> for AccessKey { 38 | fn from(id: &ModuleId) -> Self { 39 | AccessKey(id.access_vector()) 40 | } 41 | } 42 | 43 | impl AsRef<[u8]> for AccessKey { 44 | fn as_ref(&self) -> &[u8] { 45 | &self.0 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /language/move-vm/runtime/src/logging.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::errors::{PartialVMError, VMError}; 5 | use move_core_types::vm_status::{StatusCode, StatusType}; 6 | use tracing::error; 7 | // 8 | // Utility functions 9 | // 10 | 11 | pub fn expect_no_verification_errors(err: VMError) -> VMError { 12 | match err.status_type() { 13 | status_type @ StatusType::Deserialization | status_type @ StatusType::Verification => { 14 | let message = format!( 15 | "Unexpected verifier/deserialization error! This likely means there is code \ 16 | stored on chain that is unverifiable!\nError: {:?}", 17 | &err 18 | ); 19 | let (_old_status, _old_sub_status, _old_message, location, indices, offsets) = 20 | err.all_data(); 21 | let major_status = match status_type { 22 | StatusType::Deserialization => StatusCode::UNEXPECTED_DESERIALIZATION_ERROR, 23 | StatusType::Verification => StatusCode::UNEXPECTED_VERIFIER_ERROR, 24 | _ => unreachable!(), 25 | }; 26 | 27 | error!("[VM] {}", message); 28 | PartialVMError::new(major_status) 29 | .with_message(message) 30 | .at_indices(indices) 31 | .at_code_offsets(offsets) 32 | .finish(location) 33 | } 34 | _ => err, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/proptest-helpers/src/unit_tests/pick_idx_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{pick_slice_idxs, Index}; 5 | use proptest::{collection::vec, prelude::*}; 6 | use std::collections::HashSet; 7 | 8 | proptest! { 9 | /// All values returned from `pick_slice_idxs` are in bounds. 10 | #[test] 11 | fn bounds(total_len in 0..100usize, idxs in vec(any::(), 0..200usize)) { 12 | prop_assert!(pick_slice_idxs(total_len, &idxs).into_iter().all(|idx| idx < total_len)); 13 | } 14 | 15 | /// There's no duplication in the values returned from `pick_slice_idxs`. 16 | #[test] 17 | fn uniqueness(total_len in 0..100usize, idxs in vec(any::(), 0..200usize)) { 18 | let picked = pick_slice_idxs(total_len, &idxs); 19 | let picked_len = picked.len(); 20 | let picked_set: HashSet<_> = picked.into_iter().collect(); 21 | prop_assert_eq!(picked_set.len(), picked_len); 22 | prop_assert!(picked_len <= total_len); 23 | } 24 | 25 | /// The number of items returned is the same as the number requested or the total length, 26 | /// whichever's smaller. 27 | #[test] 28 | fn length(total_len in 0..100usize, idxs in vec(any::(), 0..200usize)) { 29 | let picked = pick_slice_idxs(total_len, &idxs); 30 | let picked_len = picked.len(); 31 | let expected_len = total_len.min(idxs.len()); 32 | prop_assert_eq!(expected_len, picked_len); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /language/move-vm/runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-vm-runtime" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Core Move execution logic" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | hashbrown = "0.9" 14 | mirai-annotations = { path = "../../../mirai-annotations", default-features = false } 15 | cell = { path = "../../../common/cell", version = "0.1.0", default-features = false } 16 | hex = { version = "0.4.2", default-features = false } 17 | anyhow = { version = "1.0.34", default-features = false } 18 | log = {version = "0.4", default-features = false } 19 | tracing = {version = "0.1.26", default-features = false } 20 | sha3 = {version = "0.9.1", default-features = false } 21 | 22 | bytecode-verifier = { path = "../../bytecode-verifier", default-features = false } 23 | diem-crypto = { path = "../../../crypto/crypto", default-features = false } 24 | move-core-types = { path = "../../move-core/types", default-features = false } 25 | move-vm-types = { path = "../types", default-features = false } 26 | move-binary-format = { path = "../../move-binary-format", default-features = false } 27 | 28 | [features] 29 | default = ["std"] 30 | 31 | std = [ 32 | "cell/std", 33 | "anyhow/std", 34 | "move-binary-format/std", 35 | "move-core-types/std", 36 | "move-vm-types/std", 37 | "bytecode-verifier/std", 38 | "diem-crypto/std", 39 | "log/std", 40 | ] 41 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/reflect.rs: -------------------------------------------------------------------------------- 1 | use alloc::collections::VecDeque; 2 | use alloc::vec; 3 | use alloc::vec::Vec; 4 | use move_binary_format::errors::PartialVMResult; 5 | use move_core_types::language_storage::TypeTag; 6 | use move_core_types::vm_status::sub_status::INVALID_TYPE_PARAM; 7 | use move_vm_runtime::native_functions::NativeContext; 8 | use move_vm_types::gas_schedule::NativeCostIndex; 9 | use move_vm_types::loaded_data::runtime_types::Type; 10 | use move_vm_types::natives::function::{native_gas, NativeResult}; 11 | use move_vm_types::values::Struct; 12 | use move_vm_types::values::Value; 13 | use smallvec::smallvec; 14 | 15 | pub fn type_info( 16 | context: &mut NativeContext, 17 | ty_args: Vec, 18 | arguments: VecDeque, 19 | ) -> PartialVMResult { 20 | debug_assert!(ty_args.len() == 1); 21 | debug_assert!(arguments.is_empty()); 22 | 23 | let cost = native_gas(context.cost_table(), NativeCostIndex::TYPE_INFO, 0); 24 | 25 | let type_tag = context.type_to_type_tag(&ty_args[0])?; 26 | if let TypeTag::Struct(struct_tag) = type_tag { 27 | Ok(NativeResult::ok( 28 | cost, 29 | smallvec![Value::struct_(Struct::pack(vec![ 30 | Value::address(struct_tag.address), 31 | Value::vector_u8(struct_tag.module.into_bytes()), 32 | Value::vector_u8(struct_tag.name.into_bytes()), 33 | ]))], 34 | )) 35 | } else { 36 | Ok(NativeResult::err(cost, INVALID_TYPE_PARAM)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /types/src/event.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_address::AccountAddress; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | /// A Rust representation of an Event Handle Resource. 8 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 9 | pub struct EventHandle { 10 | /// Total number of events emitted to this event stream. 11 | counter: u64, 12 | /// A globally unique ID for this event stream. 13 | guid: GUIDWrapper, 14 | } 15 | 16 | impl EventHandle { 17 | /// Constructs a new Event Handle 18 | pub fn new(guid: GUIDWrapper, counter: u64) -> Self { 19 | EventHandle { counter, guid } 20 | } 21 | 22 | /// Return the counter for the handle 23 | pub fn count(&self) -> u64 { 24 | self.counter 25 | } 26 | } 27 | 28 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 29 | pub struct GUIDWrapper { 30 | len_bytes: u8, 31 | guid: GUID, 32 | } 33 | 34 | /// A globally unique identifier derived from the sender's address and a counter 35 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 36 | pub struct GUID { 37 | id: ID, 38 | } 39 | 40 | /// A non-privileged identifier that can be freely created by anyone. Useful for looking up GUID's. 41 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 42 | struct ID { 43 | /// If creation_num is `i`, this is the `i+1`th GUID created by `addr` 44 | creation_num: u64, 45 | /// Address that created the GUID 46 | addr: AccountAddress, 47 | } 48 | -------------------------------------------------------------------------------- /common/proptest-helpers/src/unit_tests/growing_subset_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::GrowingSubset; 5 | use proptest::{collection::vec, prelude::*, sample::Index as PropIndex}; 6 | 7 | proptest! { 8 | #[test] 9 | fn max_len(inputs in vec((0..1000usize, 0..100_000usize), 1..5000)) { 10 | let len = inputs.len(); 11 | let max_idx = 1 + inputs.iter().map(|x| x.0).max().expect("inputs has length at least 1"); 12 | 13 | let mut growing_subset: GrowingSubset<_, _> = inputs.into_iter().collect(); 14 | assert_eq!(len, growing_subset.total_len()); 15 | growing_subset.advance_to(&max_idx); 16 | prop_assert_eq!(len, growing_subset.len()); 17 | } 18 | 19 | #[test] 20 | fn pick_valid( 21 | inputs in vec((0..1000usize, 0..100_000usize), 1..5000), 22 | // queries goes up to 1100 so that advance_to past the end is tested. 23 | mut queries in vec((0..1100usize, any::()), 0..500), 24 | ) { 25 | // Sort the queries so that indexes are advanced in order. 26 | queries.sort_by_key(|x| x.0); 27 | 28 | let mut growing_subset: GrowingSubset<_, _> = inputs.into_iter().collect(); 29 | for (to_idx, index) in queries { 30 | growing_subset.advance_to(&to_idx); 31 | if growing_subset.is_empty() { 32 | continue; 33 | } 34 | let (picked_idx, _) = growing_subset.pick_item(&index); 35 | prop_assert!(*picked_idx < to_idx); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/account.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_core_types::account_address::AccountAddress; 8 | use move_vm_runtime::native_functions::NativeContext; 9 | use move_vm_types::{ 10 | gas_schedule::NativeCostIndex, 11 | loaded_data::runtime_types::Type, 12 | natives::function::{native_gas, NativeResult}, 13 | pop_arg, 14 | values::Value, 15 | }; 16 | use smallvec::smallvec; 17 | 18 | pub fn native_create_signer( 19 | context: &mut NativeContext, 20 | ty_args: Vec, 21 | mut arguments: VecDeque, 22 | ) -> PartialVMResult { 23 | debug_assert!(ty_args.is_empty()); 24 | debug_assert!(arguments.len() == 1); 25 | 26 | let address = pop_arg!(arguments, AccountAddress); 27 | let cost = native_gas(context.cost_table(), NativeCostIndex::CREATE_SIGNER, 0); 28 | Ok(NativeResult::ok(cost, smallvec![Value::signer(address)])) 29 | } 30 | 31 | /// NOTE: this function will be deprecated after the Diem v3 release, but must 32 | /// remain for replaying old transactions 33 | pub fn native_destroy_signer( 34 | context: &mut NativeContext, 35 | ty_args: Vec, 36 | arguments: VecDeque, 37 | ) -> PartialVMResult { 38 | debug_assert!(ty_args.is_empty()); 39 | debug_assert!(arguments.len() == 1); 40 | 41 | let cost = native_gas(context.cost_table(), NativeCostIndex::DESTROY_SIGNER, 0); 42 | Ok(NativeResult::ok(cost, smallvec![])) 43 | } 44 | -------------------------------------------------------------------------------- /language/move-core/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "move-core-types" 3 | version = "0.1.0" 4 | authors = ["Diem Association "] 5 | description = "Core types for Move" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = false 10 | edition = "2018" 11 | 12 | [dependencies] 13 | anyhow = { version = "1.0.34", default-features = false } 14 | bcs = { path = "../../../bcs", default-features = false } 15 | hex = { version = "0.4.2", default-features = false, features = ["alloc"] } 16 | mirai-annotations = { path = "../../../mirai-annotations", default-features = false } 17 | cell = { path = "../../../common/cell", default-features = false } 18 | proptest = { version = "1.0.0", default-features = false, optional = true } 19 | proptest-derive = { version = "0.3.0", default-features = false, optional = true } 20 | rand = { version = "0.7.3", default-features = false, optional = true } 21 | ref-cast = "1.0.3" 22 | serde = { version = "1", default-features = false, package = "alt_serde", features = ["derive", "alloc"] } 23 | enum-iterator = "0.6.0" 24 | parity-scale-codec = { version = "2.3.0", default-features = false } 25 | parity-scale-codec-derive = { version = "2.3.0", default-features = false } 26 | 27 | [dev-dependencies] 28 | proptest = "1.0.0" 29 | proptest-derive = "0.3.0" 30 | regex = "1.4.2" 31 | serde_json = { version = "1.0.61", package = "alt_serde_json" } 32 | 33 | [features] 34 | default = ["std"] 35 | fuzzing = ["proptest", "proptest-derive"] 36 | std = [ 37 | "anyhow/std", 38 | "bcs/std", 39 | "parity-scale-codec/std", 40 | "rand/std" 41 | ] 42 | -------------------------------------------------------------------------------- /mvm/tests/genesis.rs: -------------------------------------------------------------------------------- 1 | use mvm::genesis::{init_storage, GenesisConfig}; 2 | 3 | use crate::common::contains_core_module; 4 | use crate::common::mock::StorageMock; 5 | use mvm::io::state::State; 6 | 7 | mod common; 8 | 9 | #[test] 10 | fn test_genesis_success() { 11 | let store = StorageMock::new(); 12 | init_storage(store.clone(), GenesisConfig::default()).unwrap(); 13 | let state = State::new(store); 14 | 15 | // Move Stdlib. 16 | contains_core_module(&state, "ASCII"); 17 | contains_core_module(&state, "BCS"); 18 | contains_core_module(&state, "BitVector"); 19 | contains_core_module(&state, "Capability"); 20 | contains_core_module(&state, "Debug"); 21 | contains_core_module(&state, "Errors"); 22 | contains_core_module(&state, "Event"); 23 | contains_core_module(&state, "FixedPoint32"); 24 | contains_core_module(&state, "GUID"); 25 | contains_core_module(&state, "Hash"); 26 | contains_core_module(&state, "Option"); 27 | contains_core_module(&state, "Reflect"); 28 | contains_core_module(&state, "Signer"); 29 | contains_core_module(&state, "Vector"); 30 | 31 | // Pontem Stdlib. 32 | contains_core_module(&state, "ChainId"); 33 | contains_core_module(&state, "CoreAddresses"); 34 | contains_core_module(&state, "Genesis"); 35 | contains_core_module(&state, "KSM"); 36 | contains_core_module(&state, "NativeToken"); 37 | contains_core_module(&state, "NOX"); 38 | contains_core_module(&state, "PontAccount"); 39 | contains_core_module(&state, "PontBlock"); 40 | contains_core_module(&state, "PontTimestamp"); 41 | contains_core_module(&state, "Signature"); 42 | contains_core_module(&state, "Token"); 43 | } 44 | -------------------------------------------------------------------------------- /language/move-binary-format/src/cursor.rs: -------------------------------------------------------------------------------- 1 | use core::cmp; 2 | 3 | use anyhow::{Error, Result}; 4 | 5 | pub struct Cursor 6 | where 7 | T: AsRef<[u8]>, 8 | { 9 | inner: T, 10 | pos: u64, 11 | } 12 | 13 | impl Cursor 14 | where 15 | T: AsRef<[u8]>, 16 | { 17 | pub fn new(inner: T) -> Cursor { 18 | Cursor { pos: 0, inner } 19 | } 20 | 21 | pub fn position(&self) -> u64 { 22 | self.pos 23 | } 24 | 25 | pub fn set_position(&mut self, pos: u64) { 26 | self.pos = pos; 27 | } 28 | 29 | pub fn read(&mut self, buf: &mut [u8]) -> Result { 30 | let source = self.fill_buf(); 31 | let amt = cmp::min(buf.len(), source.len()); 32 | 33 | if amt == 1 { 34 | buf[0] = source[0]; 35 | } else { 36 | buf[..amt].copy_from_slice(&source[..amt]); 37 | } 38 | 39 | self.pos += amt as u64; 40 | Ok(amt) 41 | } 42 | 43 | pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { 44 | let n = buf.len(); 45 | let source = self.fill_buf(); 46 | 47 | if buf.len() > source.len() { 48 | return Err(Error::msg("Unexpected Eof failed to fill whole buffer")); 49 | } 50 | 51 | if buf.len() == 1 { 52 | buf[0] = source[0]; 53 | } else { 54 | buf.copy_from_slice(&source[..n]); 55 | } 56 | 57 | self.pos += n as u64; 58 | Ok(()) 59 | } 60 | 61 | fn fill_buf(&mut self) -> &[u8] { 62 | let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); 63 | &self.inner.as_ref()[(amt as usize)..] 64 | } 65 | 66 | pub fn get_ref(&self) -> &T { 67 | &self.inner 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /language/move-binary-format/src/unit_tests/signature_token_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::cursor::Cursor; 5 | use crate::{ 6 | deserializer::load_signature_token_test_entry, 7 | file_format::{SignatureToken, StructHandleIndex}, 8 | file_format_common::{BinaryData, SIGNATURE_TOKEN_DEPTH_MAX}, 9 | serializer::{serialize_signature_token, serialize_signature_token_unchecked}, 10 | }; 11 | 12 | #[test] 13 | fn serialize_and_deserialize_nested_types_max() { 14 | let mut ty = SignatureToken::Struct(StructHandleIndex::new(0)); 15 | for _ in 1..SIGNATURE_TOKEN_DEPTH_MAX { 16 | ty = SignatureToken::Vector(Box::new(ty)); 17 | let mut binary = BinaryData::new(); 18 | serialize_signature_token(&mut binary, &ty).expect("serialization should succeed"); 19 | 20 | let cursor = Cursor::new(binary.as_inner()); 21 | load_signature_token_test_entry(cursor).expect("deserialization should succeed"); 22 | } 23 | } 24 | 25 | #[test] 26 | fn serialize_nested_types_too_deep() { 27 | let mut ty = SignatureToken::Struct(StructHandleIndex::new(0)); 28 | for _ in 1..SIGNATURE_TOKEN_DEPTH_MAX { 29 | ty = SignatureToken::Vector(Box::new(ty)); 30 | } 31 | 32 | for _ in 0..10 { 33 | ty = SignatureToken::Vector(Box::new(ty)); 34 | 35 | let mut binary = BinaryData::new(); 36 | serialize_signature_token(&mut binary, &ty).expect_err("serialization should fail"); 37 | 38 | let mut binary = BinaryData::new(); 39 | serialize_signature_token_unchecked(&mut binary, &ty) 40 | .expect("serialization (unchecked) should succeed"); 41 | 42 | let cursor = Cursor::new(binary.as_inner()); 43 | load_signature_token_test_entry(cursor).expect_err("deserialization should fail"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/negative_stack_size_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::support::dummy_procedure_module; 5 | use bytecode_verifier::CodeUnitVerifier; 6 | use move_binary_format::file_format::Bytecode; 7 | use move_core_types::vm_status::StatusCode; 8 | 9 | #[test] 10 | fn one_pop_no_push() { 11 | let module = dummy_procedure_module(vec![Bytecode::Pop, Bytecode::Ret]); 12 | let result = CodeUnitVerifier::verify_module(&module); 13 | assert_eq!( 14 | result.unwrap_err().major_status(), 15 | StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK 16 | ); 17 | } 18 | 19 | #[test] 20 | fn one_pop_one_push() { 21 | // Height: 0 + (-1 + 1) = 0 would have passed original usage verifier 22 | let module = dummy_procedure_module(vec![Bytecode::ReadRef, Bytecode::Ret]); 23 | let result = CodeUnitVerifier::verify_module(&module); 24 | assert_eq!( 25 | result.unwrap_err().major_status(), 26 | StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK 27 | ); 28 | } 29 | 30 | #[test] 31 | fn two_pop_one_push() { 32 | // Height: 0 + 1 + (-2 + 1) = 0 would have passed original usage verifier 33 | let module = dummy_procedure_module(vec![Bytecode::LdU64(0), Bytecode::Add, Bytecode::Ret]); 34 | let result = CodeUnitVerifier::verify_module(&module); 35 | assert_eq!( 36 | result.unwrap_err().major_status(), 37 | StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK 38 | ); 39 | } 40 | 41 | #[test] 42 | fn two_pop_no_push() { 43 | let module = dummy_procedure_module(vec![Bytecode::WriteRef, Bytecode::Ret]); 44 | let result = CodeUnitVerifier::verify_module(&module); 45 | assert_eq!( 46 | result.unwrap_err().major_status(), 47 | StatusCode::NEGATIVE_STACK_SIZE_WITHIN_BLOCK 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /mvm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #[macro_use] 4 | extern crate alloc; 5 | 6 | #[cfg(feature = "sp_check")] 7 | extern crate sp_io; 8 | #[cfg(feature = "sp_check")] 9 | #[allow(unused_imports)] 10 | use sp_io::EcdsaVerifyError; 11 | 12 | use crate::io::context::ExecutionContext; 13 | use crate::types::{Gas, ModuleTx, PublishPackageTx, ScriptTx, VmResult}; 14 | use alloc::vec::Vec; 15 | use anyhow::Error; 16 | use diem_types::account_address::AccountAddress; 17 | 18 | pub mod abi; 19 | pub mod error; 20 | pub mod gas_schedule; 21 | pub mod genesis; 22 | pub mod io; 23 | pub mod mvm; 24 | pub mod types; 25 | 26 | pub trait Vm { 27 | /// Publishes module to the chain. 28 | fn publish_module(&self, gas: Gas, module: ModuleTx, dry_run: bool) -> VmResult; 29 | 30 | /// Publishes package of modules to the chain. 31 | fn publish_module_package( 32 | &self, 33 | gas: Gas, 34 | package: PublishPackageTx, 35 | dry_run: bool, 36 | ) -> VmResult; 37 | 38 | /// Execute script. 39 | fn execute_script( 40 | &self, 41 | gas: Gas, 42 | context: ExecutionContext, 43 | tx: ScriptTx, 44 | dry_run: bool, 45 | ) -> VmResult; 46 | 47 | /// Clear vm cache. 48 | fn clear(&self); 49 | } 50 | 51 | pub trait StateAccess { 52 | /// Return module bytecode by its id. `module_id` is ModuleId encoded by bcs. 53 | fn get_module(&self, module_id: &[u8]) -> Result>, Error>; 54 | /// Return module abi bytecode by its id. `module_id` is ModuleId encoded by bcs. 55 | fn get_module_abi(&self, module_id: &[u8]) -> Result>, Error>; 56 | /// Return resource by its account address and struct tag. `tag` is StructTag encoded by bcs. 57 | fn get_resource(&self, address: &AccountAddress, tag: &[u8]) -> Result>, Error>; 58 | } 59 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/debug.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_core_types::gas_schedule::ONE_GAS_UNIT; 8 | use move_vm_runtime::native_functions::NativeContext; 9 | #[allow(unused_imports)] 10 | use move_vm_types::values::{values_impl::debug::print_reference, Reference}; 11 | #[allow(unused_imports)] 12 | use move_vm_types::{ 13 | loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, 14 | }; 15 | use smallvec::smallvec; 16 | 17 | #[allow(unused_mut)] 18 | #[allow(unused_variables)] 19 | pub fn native_print( 20 | context: &mut NativeContext, 21 | mut ty_args: Vec, 22 | mut args: VecDeque, 23 | ) -> PartialVMResult { 24 | debug_assert!(ty_args.len() == 1); 25 | debug_assert!(args.len() == 1); 26 | 27 | // No-op if the feature flag is not present. 28 | #[cfg(feature = "testing")] 29 | { 30 | let ty = ty_args.pop().unwrap(); 31 | let r = pop_arg!(args, Reference); 32 | 33 | let mut buf = String::new(); 34 | print_reference(&mut buf, &r)?; 35 | println!("[debug] {}", buf); 36 | } 37 | 38 | Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![])) 39 | } 40 | 41 | #[allow(unused_variables)] 42 | pub fn native_print_stack_trace( 43 | context: &mut NativeContext, 44 | ty_args: Vec, 45 | args: VecDeque, 46 | ) -> PartialVMResult { 47 | debug_assert!(ty_args.is_empty()); 48 | debug_assert!(args.is_empty()); 49 | 50 | #[cfg(feature = "testing")] 51 | { 52 | let mut s = String::new(); 53 | context.print_stack_trace(&mut s)?; 54 | println!("{}", s); 55 | } 56 | 57 | Ok(NativeResult::ok(ONE_GAS_UNIT, smallvec![])) 58 | } 59 | -------------------------------------------------------------------------------- /language/move-vm/types/src/data_store.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{ 5 | loaded_data::runtime_types::Type, 6 | values::{GlobalValue, Value}, 7 | }; 8 | use alloc::vec::Vec; 9 | use move_binary_format::errors::{PartialVMResult, VMResult}; 10 | use move_core_types::{account_address::AccountAddress, language_storage::ModuleId}; 11 | 12 | /// Provide an implementation for bytecodes related to data with a given data store. 13 | /// 14 | /// The `DataStore` is a generic concept that includes both data and events. 15 | /// A default implementation of the `DataStore` is `TransactionDataCache` which provides 16 | /// an in memory cache for a given transaction and the atomic transactional changes 17 | /// proper of a script execution (transaction). 18 | pub trait DataStore { 19 | // --- 20 | // StateStore operations 21 | // --- 22 | 23 | /// Try to load a resource from remote storage and create a corresponding GlobalValue 24 | /// that is owned by the data store. 25 | fn load_resource( 26 | &mut self, 27 | addr: AccountAddress, 28 | ty: &Type, 29 | ) -> PartialVMResult<&mut GlobalValue>; 30 | 31 | /// Get the serialized format of a `CompiledModule` given a `ModuleId`. 32 | fn load_module(&self, module_id: &ModuleId) -> VMResult>; 33 | 34 | /// Publish a module. 35 | fn publish_module(&mut self, module_id: &ModuleId, blob: Vec) -> VMResult<()>; 36 | 37 | /// Check if this module exists. 38 | fn exists_module(&self, module_id: &ModuleId) -> VMResult; 39 | 40 | // --- 41 | // EventStore operations 42 | // --- 43 | 44 | /// Emit an event to the EventStore 45 | fn emit_event( 46 | &mut self, 47 | guid: Vec, 48 | seq_num: u64, 49 | ty: Type, 50 | val: Value, 51 | ) -> PartialVMResult<()>; 52 | } 53 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_vm_runtime::native_functions::NativeContext; 8 | use move_vm_types::{ 9 | gas_schedule::NativeCostIndex, 10 | loaded_data::runtime_types::Type, 11 | natives::function::{native_gas, NativeResult}, 12 | pop_arg, 13 | values::Value, 14 | }; 15 | use sha2::{Digest, Sha256}; 16 | use sha3::Sha3_256; 17 | use smallvec::smallvec; 18 | 19 | pub fn native_sha2_256( 20 | context: &mut NativeContext, 21 | _ty_args: Vec, 22 | mut arguments: VecDeque, 23 | ) -> PartialVMResult { 24 | debug_assert!(_ty_args.is_empty()); 25 | debug_assert!(arguments.len() == 1); 26 | 27 | let hash_arg = pop_arg!(arguments, Vec); 28 | 29 | let cost = native_gas( 30 | context.cost_table(), 31 | NativeCostIndex::SHA2_256, 32 | hash_arg.len(), 33 | ); 34 | 35 | let hash_vec = Sha256::digest(hash_arg.as_slice()).to_vec(); 36 | Ok(NativeResult::ok( 37 | cost, 38 | smallvec![Value::vector_u8(hash_vec)], 39 | )) 40 | } 41 | 42 | pub fn native_sha3_256( 43 | context: &mut NativeContext, 44 | _ty_args: Vec, 45 | mut arguments: VecDeque, 46 | ) -> PartialVMResult { 47 | debug_assert!(_ty_args.is_empty()); 48 | debug_assert!(arguments.len() == 1); 49 | 50 | let hash_arg = pop_arg!(arguments, Vec); 51 | 52 | let cost = native_gas( 53 | context.cost_table(), 54 | NativeCostIndex::SHA3_256, 55 | hash_arg.len(), 56 | ); 57 | 58 | let hash_vec = Sha3_256::digest(hash_arg.as_slice()).to_vec(); 59 | Ok(NativeResult::ok( 60 | cost, 61 | smallvec![Value::vector_u8(hash_vec)], 62 | )) 63 | } 64 | -------------------------------------------------------------------------------- /common/proptest-helpers/src/value_generator.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use proptest::{ 5 | strategy::{Strategy, ValueTree}, 6 | test_runner::{Config, TestRng, TestRunner}, 7 | }; 8 | 9 | /// Context for generating single values out of strategies. 10 | /// 11 | /// Proptest is designed to be built around "value trees", which represent a spectrum from complex 12 | /// values to simpler ones. But in some contexts, like benchmarking or generating corpuses, one just 13 | /// wants a single value. This is a convenience struct for that. 14 | #[derive(Default)] 15 | pub struct ValueGenerator { 16 | runner: TestRunner, 17 | } 18 | 19 | impl ValueGenerator { 20 | /// Creates a new value generator with the default RNG. 21 | pub fn new() -> Self { 22 | Default::default() 23 | } 24 | 25 | /// Creates a new value generator with provided RNG 26 | pub fn new_with_rng(rng: TestRng) -> Self { 27 | Self { 28 | runner: TestRunner::new_with_rng(Config::default(), rng), 29 | } 30 | } 31 | 32 | /// Creates a new value generator with a deterministic RNG. 33 | /// 34 | /// This generator has a hardcoded seed, so its results are predictable across test runs. 35 | /// However, a new proptest version may change the seed. 36 | pub fn deterministic() -> Self { 37 | Self { 38 | runner: TestRunner::deterministic(), 39 | } 40 | } 41 | 42 | /// Generates a single value for this strategy. 43 | /// 44 | /// Panics if generating the new value fails. The only situation in which this can happen is if 45 | /// generating the value causes too many internal rejects. 46 | pub fn generate(&mut self, strategy: S) -> S::Value { 47 | strategy 48 | .new_tree(&mut self.runner) 49 | .expect("creating a new value should succeed") 50 | .current() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mvm/src/io/state.rs: -------------------------------------------------------------------------------- 1 | use crate::io::balance::MasterOfCoin; 2 | use crate::io::context::ExecutionContext; 3 | use crate::io::key::AccessKey; 4 | use crate::io::session::StateSession; 5 | use crate::io::traits::{BalanceAccess, Storage}; 6 | use alloc::vec::Vec; 7 | use anyhow::Error; 8 | use move_core_types::account_address::AccountAddress; 9 | use move_core_types::language_storage::{ModuleId, StructTag}; 10 | use move_core_types::resolver::{ModuleResolver, ResourceResolver}; 11 | 12 | pub struct State { 13 | store: S, 14 | } 15 | 16 | impl State { 17 | pub fn new(store: S) -> State { 18 | State { store } 19 | } 20 | 21 | pub fn state_session<'c, B: BalanceAccess>( 22 | &self, 23 | context: Option, 24 | master_of_coin: &'c MasterOfCoin, 25 | ) -> StateSession<'c, '_, State, B> { 26 | StateSession::new(self, context, master_of_coin.session(self)) 27 | } 28 | } 29 | 30 | impl ModuleResolver for State { 31 | type Error = Error; 32 | 33 | fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { 34 | Ok(self.store.get(AccessKey::from(module_id).as_ref())) 35 | } 36 | } 37 | 38 | impl ResourceResolver for State { 39 | type Error = Error; 40 | 41 | fn get_resource( 42 | &self, 43 | address: &AccountAddress, 44 | typ: &StructTag, 45 | ) -> Result>, Self::Error> { 46 | Ok(self.store.get(AccessKey::from((address, typ)).as_ref())) 47 | } 48 | } 49 | 50 | impl WriteEffects for State { 51 | fn delete(&self, key: AccessKey) { 52 | self.store.remove(key.as_ref()); 53 | } 54 | 55 | fn insert(&self, key: AccessKey, blob: Vec) { 56 | self.store.insert(key.as_ref(), &blob); 57 | } 58 | } 59 | 60 | pub trait WriteEffects { 61 | fn delete(&self, path: AccessKey); 62 | fn insert(&self, path: AccessKey, blob: Vec); 63 | } 64 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/bcs.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use move_binary_format::errors::PartialVMResult; 7 | use move_core_types::vm_status::sub_status::NFE_BCS_SERIALIZATION_FAILURE; 8 | use move_vm_runtime::native_functions::NativeContext; 9 | use move_vm_types::{ 10 | gas_schedule::NativeCostIndex, 11 | loaded_data::runtime_types::Type, 12 | natives::function::{native_gas, NativeResult}, 13 | pop_arg, 14 | values::{values_impl::Reference, Value}, 15 | }; 16 | use smallvec::smallvec; 17 | 18 | /// Rust implementation of Move's `native public fun to_bytes(&T): vector` 19 | pub fn native_to_bytes( 20 | context: &mut NativeContext, 21 | mut ty_args: Vec, 22 | mut args: VecDeque, 23 | ) -> PartialVMResult { 24 | debug_assert!(ty_args.len() == 1); 25 | debug_assert!(args.len() == 1); 26 | 27 | let ref_to_val = pop_arg!(args, Reference); 28 | 29 | let arg_type = ty_args.pop().unwrap(); 30 | // delegate to the BCS serialization for `Value` 31 | let serialized_value_opt = match context.type_to_type_layout(&arg_type)? { 32 | None => None, 33 | Some(layout) => ref_to_val.read_ref()?.simple_serialize(&layout), 34 | }; 35 | let serialized_value = match serialized_value_opt { 36 | None => { 37 | let cost = native_gas(context.cost_table(), NativeCostIndex::BCS_TO_BYTES, 1); 38 | return Ok(NativeResult::err(cost, NFE_BCS_SERIALIZATION_FAILURE)); 39 | } 40 | Some(serialized_value) => serialized_value, 41 | }; 42 | 43 | // cost is proportional to the size of the serialized value 44 | let cost = native_gas( 45 | context.cost_table(), 46 | NativeCostIndex::BCS_TO_BYTES, 47 | serialized_value.len(), 48 | ); 49 | 50 | Ok(NativeResult::ok( 51 | cost, 52 | smallvec![Value::vector_u8(serialized_value)], 53 | )) 54 | } 55 | -------------------------------------------------------------------------------- /types/src/on_chain_config/vm_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::on_chain_config::OnChainConfig; 5 | use alloc::vec::Vec; 6 | use anyhow::{anyhow, format_err, Result}; 7 | use move_core_types::gas_schedule::{CostTable, GasConstants}; 8 | use serde::{Deserialize, Serialize}; 9 | 10 | /// Defines all the on chain configuration data needed by VM. 11 | #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] 12 | pub struct VMConfig { 13 | pub gas_schedule: CostTable, 14 | } 15 | 16 | #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] 17 | struct CostTableInner { 18 | pub instruction_table: Vec, 19 | pub native_table: Vec, 20 | pub gas_constants: GasConstants, 21 | } 22 | 23 | #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] 24 | struct VMConfigInner { 25 | pub gas_schedule: CostTableInner, 26 | } 27 | 28 | impl CostTableInner { 29 | pub fn as_cost_table(&self) -> Result { 30 | let instruction_table = bcs::from_bytes(&self.instruction_table) 31 | .map_err(|err| anyhow!("Failed to decode bcs. {:?}", err))?; 32 | let native_table = bcs::from_bytes(&self.native_table) 33 | .map_err(|err| anyhow!("Failed to decode bcs. {:?}", err))?; 34 | Ok(CostTable { 35 | instruction_table, 36 | native_table, 37 | gas_constants: self.gas_constants.clone(), 38 | }) 39 | } 40 | } 41 | 42 | impl OnChainConfig for VMConfig { 43 | const IDENTIFIER: &'static str = "DiemVMConfig"; 44 | 45 | fn deserialize_into_config(bytes: &[u8]) -> Result { 46 | let raw_vm_config = bcs::from_bytes::(&bytes).map_err(|e| { 47 | format_err!( 48 | "Failed first round of deserialization for VMConfigInner: {}", 49 | e 50 | ) 51 | })?; 52 | let gas_schedule = raw_vm_config.gas_schedule.as_cost_table()?; 53 | Ok(VMConfig { gas_schedule }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /language/bytecode-verifier/src/friends.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! This module contains verification of usage of dependencies for modules 5 | use move_binary_format::{ 6 | access::ModuleAccess, 7 | errors::{Location, PartialVMError, PartialVMResult, VMResult}, 8 | file_format::CompiledModule, 9 | }; 10 | use move_core_types::vm_status::StatusCode; 11 | 12 | pub fn verify_module(module: &CompiledModule) -> VMResult<()> { 13 | verify_module_impl(module).map_err(|e| e.finish(Location::Module(module.self_id()))) 14 | } 15 | 16 | fn verify_module_impl(module: &CompiledModule) -> PartialVMResult<()> { 17 | // cannot make friends with the module itself 18 | let self_handle = module.self_handle(); 19 | if module.friend_decls().contains(self_handle) { 20 | return Err(PartialVMError::new( 21 | StatusCode::INVALID_FRIEND_DECL_WITH_SELF, 22 | )); 23 | } 24 | 25 | // cannot make friends with modules outside of the account address 26 | // 27 | // NOTE: this constraint is a policy decision rather than a technical requirement. The VM and 28 | // other bytecode verifier passes do not rely on the assumption that friend modules must be 29 | // declared within the same account address. 30 | // 31 | // However, lacking a definite use case of friending modules across account boundaries, and also 32 | // to minimize the associated changes on the module publishing flow, we temporarily enforce this 33 | // constraint and we may consider lifting this limitation in the future. 34 | let self_address = 35 | module.address_identifier_at(module.module_handle_at(module.self_handle_idx()).address); 36 | let has_external_friend = module 37 | .friend_decls() 38 | .iter() 39 | .any(|handle| module.address_identifier_at(handle.address) != self_address); 40 | if has_external_friend { 41 | return Err(PartialVMError::new( 42 | StatusCode::INVALID_FRIEND_DECL_WITH_MODULES_OUTSIDE_ACCOUNT_ADDRESS, 43 | )); 44 | } 45 | 46 | Ok(()) 47 | } 48 | -------------------------------------------------------------------------------- /mvm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mvm" 3 | version = "0.1.3" 4 | authors = [ 5 | "Alex Koz. ", 6 | "Dm. Yakushev ", 7 | ] 8 | edition = "2018" 9 | 10 | [dependencies] 11 | hashbrown = "0.9" 12 | anyhow = { version = "1.0.34", default-features = false } 13 | hex = { version = "0.4.2", default-features = false, features = ["alloc"] } 14 | serde = { version = "1", default-features = false, package = "alt_serde", features = ["derive", "alloc"] } 15 | parity-scale-codec = { version = "2", default-features = false } 16 | parity-scale-codec-derive = { version = "2", default-features = false } 17 | cell = { path = "../common/cell", default-features = false } 18 | move-vm-runtime = { path = "../language/move-vm/runtime", default-features = false } 19 | move-vm-types = { path = "../language/move-vm/types", default-features = false } 20 | move-core-types = { path = "../language/move-core/types", default-features = false } 21 | move-binary-format = { path = "../language/move-binary-format", default-features = false } 22 | diem-crypto = { path = "../crypto/crypto", default-features = false } 23 | bcs = { path = "../bcs", default-features = false } 24 | stdlib = { path = "../stdlib", default-features = false, optional = true } 25 | log = { version = "0.4.14", default-features = false } 26 | diem-types = { path = "../types", default-features = false } 27 | move-stdlib = { path = "../language/move-stdlib", default-features = false } 28 | 29 | [dependencies.sp-io] 30 | git = "https://github.com/paritytech/substrate" 31 | branch = "polkadot-v0.9.11" 32 | default-features = false 33 | optional = true 34 | 35 | [features] 36 | default = ["std", "assets", "move_stdlib", "sp_check"] 37 | assets = [] 38 | bench = [] 39 | move_stdlib = [ 40 | "stdlib" 41 | ] 42 | std = [ 43 | "anyhow/std", 44 | "move-binary-format/std", 45 | "move-core-types/std", 46 | "move-vm-types/std", 47 | "move-vm-runtime/std", 48 | "parity-scale-codec/std", 49 | "log/std", 50 | "cell/std", 51 | "sp-io/std" 52 | ] 53 | testing = [ 54 | "move-stdlib/testing" 55 | ] 56 | 57 | sp_check = [ 58 | "sp-io" 59 | ] 60 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/code_unit_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::support::dummy_procedure_module; 5 | use bytecode_verifier::CodeUnitVerifier; 6 | use move_binary_format::file_format::Bytecode; 7 | use move_core_types::vm_status::StatusCode; 8 | 9 | #[test] 10 | fn invalid_fallthrough_br_true() { 11 | let module = dummy_procedure_module(vec![Bytecode::LdFalse, Bytecode::BrTrue(1)]); 12 | let result = CodeUnitVerifier::verify_module(&module); 13 | assert_eq!( 14 | result.unwrap_err().major_status(), 15 | StatusCode::INVALID_FALL_THROUGH 16 | ); 17 | } 18 | 19 | #[test] 20 | fn invalid_fallthrough_br_false() { 21 | let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::BrFalse(1)]); 22 | let result = CodeUnitVerifier::verify_module(&module); 23 | assert_eq!( 24 | result.unwrap_err().major_status(), 25 | StatusCode::INVALID_FALL_THROUGH 26 | ); 27 | } 28 | 29 | // all non-branch instructions should trigger invalid fallthrough; just check one of them 30 | #[test] 31 | fn invalid_fallthrough_non_branch() { 32 | let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::Pop]); 33 | let result = CodeUnitVerifier::verify_module(&module); 34 | assert_eq!( 35 | result.unwrap_err().major_status(), 36 | StatusCode::INVALID_FALL_THROUGH 37 | ); 38 | } 39 | 40 | #[test] 41 | fn valid_fallthrough_branch() { 42 | let module = dummy_procedure_module(vec![Bytecode::Branch(0)]); 43 | let result = CodeUnitVerifier::verify_module(&module); 44 | assert!(result.is_ok()); 45 | } 46 | 47 | #[test] 48 | fn valid_fallthrough_ret() { 49 | let module = dummy_procedure_module(vec![Bytecode::Ret]); 50 | let result = CodeUnitVerifier::verify_module(&module); 51 | assert!(result.is_ok()); 52 | } 53 | 54 | #[test] 55 | fn valid_fallthrough_abort() { 56 | let module = dummy_procedure_module(vec![Bytecode::LdU64(7), Bytecode::Abort]); 57 | let result = CodeUnitVerifier::verify_module(&module); 58 | assert!(result.is_ok()); 59 | } 60 | -------------------------------------------------------------------------------- /types/src/on_chain_config/vm_publishing_option.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::on_chain_config::OnChainConfig; 5 | use alloc::vec::Vec; 6 | use anyhow::{format_err, Result}; 7 | use diem_crypto::HashValue; 8 | use serde::{Deserialize, Serialize}; 9 | 10 | /// Defines and holds the publishing policies for the VM. There are three possible configurations: 11 | /// 1. No module publishing, only allowlisted scripts are allowed. 12 | /// 2. No module publishing, custom scripts are allowed. 13 | /// 3. Both module publishing and custom scripts are allowed. 14 | /// We represent these as an enum instead of a struct since allowlisting and module/script 15 | /// publishing are mutually exclusive options. 16 | #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] 17 | pub struct VMPublishingOption { 18 | pub script_allow_list: Vec, 19 | pub is_open_module: bool, 20 | } 21 | 22 | impl VMPublishingOption { 23 | pub fn locked(allowlist: Vec) -> Self { 24 | Self { 25 | script_allow_list: allowlist, 26 | is_open_module: false, 27 | } 28 | } 29 | 30 | pub fn custom_scripts() -> Self { 31 | Self { 32 | script_allow_list: vec![], 33 | is_open_module: false, 34 | } 35 | } 36 | 37 | pub fn open() -> Self { 38 | Self { 39 | script_allow_list: vec![], 40 | is_open_module: true, 41 | } 42 | } 43 | 44 | pub fn is_open_module(&self) -> bool { 45 | self.is_open_module 46 | } 47 | 48 | pub fn is_open_script(&self) -> bool { 49 | self.script_allow_list.is_empty() 50 | } 51 | } 52 | 53 | impl OnChainConfig for VMPublishingOption { 54 | const IDENTIFIER: &'static str = "DiemTransactionPublishingOption"; 55 | 56 | fn deserialize_into_config(bytes: &[u8]) -> Result { 57 | bcs::from_bytes(&bytes).map_err(|e| { 58 | format_err!( 59 | "Failed first round of deserialization for VMPublishingOptionInner: {}", 60 | e 61 | ) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /language/move-binary-format/src/constant.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::file_format::{Constant, SignatureToken}; 5 | use alloc::boxed::Box; 6 | use move_core_types::value::{MoveTypeLayout, MoveValue}; 7 | 8 | fn sig_to_ty(sig: &SignatureToken) -> Option { 9 | match sig { 10 | SignatureToken::Signer => Some(MoveTypeLayout::Signer), 11 | SignatureToken::Address => Some(MoveTypeLayout::Address), 12 | SignatureToken::Bool => Some(MoveTypeLayout::Bool), 13 | SignatureToken::U8 => Some(MoveTypeLayout::U8), 14 | SignatureToken::U64 => Some(MoveTypeLayout::U64), 15 | SignatureToken::U128 => Some(MoveTypeLayout::U128), 16 | SignatureToken::Vector(v) => Some(MoveTypeLayout::Vector(Box::new(sig_to_ty(v.as_ref())?))), 17 | SignatureToken::Reference(_) 18 | | SignatureToken::MutableReference(_) 19 | | SignatureToken::Struct(_) 20 | | SignatureToken::TypeParameter(_) 21 | | SignatureToken::StructInstantiation(_, _) => None, 22 | } 23 | } 24 | 25 | fn ty_to_sig(ty: &MoveTypeLayout) -> Option { 26 | match ty { 27 | MoveTypeLayout::Address => Some(SignatureToken::Address), 28 | MoveTypeLayout::Signer => Some(SignatureToken::Signer), 29 | MoveTypeLayout::U8 => Some(SignatureToken::U8), 30 | MoveTypeLayout::U64 => Some(SignatureToken::U64), 31 | MoveTypeLayout::U128 => Some(SignatureToken::U128), 32 | MoveTypeLayout::Vector(v) => Some(SignatureToken::Vector(Box::new(ty_to_sig(v.as_ref())?))), 33 | MoveTypeLayout::Struct(_) => None, 34 | MoveTypeLayout::Bool => Some(SignatureToken::Bool), 35 | } 36 | } 37 | 38 | impl Constant { 39 | pub fn serialize_constant(ty: &MoveTypeLayout, v: &MoveValue) -> Option { 40 | Some(Self { 41 | type_: ty_to_sig(ty)?, 42 | data: v.simple_serialize()?, 43 | }) 44 | } 45 | 46 | pub fn deserialize_constant(&self) -> Option { 47 | let ty = sig_to_ty(&self.type_)?; 48 | MoveValue::simple_deserialize(&self.data, &ty).ok() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /language/move-core/types/src/proptest_types.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{ 5 | account_address::AccountAddress, 6 | identifier::Identifier, 7 | language_storage::{StructTag, TypeTag}, 8 | transaction_argument::TransactionArgument, 9 | }; 10 | use proptest::{collection::vec, prelude::*}; 11 | impl Arbitrary for TypeTag { 12 | type Parameters = (); 13 | type Strategy = BoxedStrategy; 14 | 15 | fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { 16 | use TypeTag::*; 17 | let leaf = prop_oneof![ 18 | Just(Bool), 19 | Just(U8), 20 | Just(U64), 21 | Just(U128), 22 | Just(Address), 23 | Just(Vector(Box::new(Bool))), 24 | ]; 25 | leaf.prop_recursive( 26 | 8, // levels deep 27 | 16, // max size 28 | 4, // max number of items per collection 29 | |inner| { 30 | ( 31 | any::(), 32 | any::(), 33 | any::(), 34 | vec(inner, 0..4), 35 | ) 36 | .prop_map(|(address, module, name, type_params)| { 37 | Struct(StructTag { 38 | address, 39 | module, 40 | name, 41 | type_params, 42 | }) 43 | }) 44 | }, 45 | ) 46 | .boxed() 47 | } 48 | } 49 | 50 | impl Arbitrary for TransactionArgument { 51 | type Parameters = (); 52 | fn arbitrary_with(_args: ()) -> Self::Strategy { 53 | prop_oneof![ 54 | any::().prop_map(TransactionArgument::Bool), 55 | any::().prop_map(TransactionArgument::U64), 56 | any::().prop_map(TransactionArgument::Address), 57 | vec(any::(), 0..10).prop_map(TransactionArgument::U8Vector), 58 | ] 59 | .boxed() 60 | } 61 | 62 | type Strategy = BoxedStrategy; 63 | } 64 | -------------------------------------------------------------------------------- /language/move-vm/runtime/src/move_vm.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{native_functions::NativeFunction, runtime::VMRuntime, session::Session}; 5 | use move_binary_format::errors::{Location, VMResult}; 6 | use move_core_types::{ 7 | account_address::AccountAddress, identifier::Identifier, resolver::MoveResolver, 8 | }; 9 | 10 | pub struct MoveVM { 11 | pub runtime: VMRuntime, 12 | } 13 | 14 | impl MoveVM { 15 | pub fn new(natives: I) -> VMResult 16 | where 17 | I: IntoIterator, 18 | { 19 | Ok(Self { 20 | runtime: VMRuntime::new(natives).map_err(|err| err.finish(Location::Undefined))?, 21 | }) 22 | } 23 | 24 | /// Create a new Session backed by the given storage. 25 | /// 26 | /// Right now it is the caller's responsibility to ensure cache coherence of the Move VM Loader 27 | /// - When a module gets published in a Move VM Session, and then gets used by another 28 | /// transaction, it will be loaded into the code cache and stay there even if the resulted 29 | /// effects do not get commited back to the storage when the Session ends. 30 | /// - As a result, if one wants to have multiple sessions at a time, one needs to make sure 31 | /// none of them will try to publish a module. In other words, if there is a module publishing 32 | /// Session it must be the only Session existing. 33 | /// - In general, a new Move VM needs to be created whenever the storage gets modified by an 34 | /// outer envrionment, or otherwise the states may be out of sync. There are a few exceptional 35 | /// cases where this may not be necessary, with the most notable one being the common module 36 | /// publishing flow: you can keep using the same Move VM if you publish some modules in a Session 37 | /// and apply the effects to the storage when the Session ends. 38 | pub fn new_session<'r, S: MoveResolver>(&self, remote: &'r S) -> Session<'r, '_, S> { 39 | self.runtime.new_session(remote) 40 | } 41 | 42 | /// Clears vm state. 43 | pub fn clear(&self) { 44 | self.runtime.clear(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /language/bytecode-verifier/src/ability_field_requirements.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! This module implements a checker for verifying that all of the struct's fields satisfy the 5 | //! abilities required by the struct's abilities 6 | use alloc::vec::Vec; 7 | use move_binary_format::{ 8 | access::ModuleAccess, 9 | binary_views::BinaryIndexedView, 10 | errors::{verification_error, Location, PartialVMResult, VMResult}, 11 | file_format::{AbilitySet, CompiledModule, StructFieldInformation, TableIndex}, 12 | IndexKind, 13 | }; 14 | use move_core_types::vm_status::StatusCode; 15 | 16 | pub fn verify_module(module: &CompiledModule) -> VMResult<()> { 17 | verify_module_impl(module).map_err(|e| e.finish(Location::Module(module.self_id()))) 18 | } 19 | 20 | fn verify_module_impl(module: &CompiledModule) -> PartialVMResult<()> { 21 | let view = BinaryIndexedView::Module(module); 22 | for (idx, struct_def) in module.struct_defs().iter().enumerate() { 23 | let sh = module.struct_handle_at(struct_def.struct_handle); 24 | let fields = match &struct_def.field_information { 25 | StructFieldInformation::Native => continue, 26 | StructFieldInformation::Declared(fields) => fields, 27 | }; 28 | let required_abilities = sh 29 | .abilities 30 | .into_iter() 31 | .map(|a| a.requires()) 32 | .fold(AbilitySet::EMPTY, |acc, required| acc | required); 33 | // Assume type parameters have all abilities, as the struct's abilities will be dependent on 34 | // them 35 | let type_parameter_abilities = sh 36 | .type_parameters 37 | .iter() 38 | .map(|_| AbilitySet::ALL) 39 | .collect::>(); 40 | for field in fields { 41 | let field_abilities = view.abilities(&field.signature.0, &type_parameter_abilities)?; 42 | if !required_abilities.is_subset(field_abilities) { 43 | return Err(verification_error( 44 | StatusCode::FIELD_MISSING_TYPE_ABILITY, 45 | IndexKind::StructDefinition, 46 | idx as TableIndex, 47 | )); 48 | } 49 | } 50 | } 51 | Ok(()) 52 | } 53 | -------------------------------------------------------------------------------- /language/bytecode-verifier/src/constants.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! This module implements a checker for verifying that 5 | //! - a constant's type only refers to primitive types 6 | //! - a constant's data serializes correctly for that type 7 | use move_binary_format::{ 8 | access::ModuleAccess, 9 | errors::{verification_error, Location, PartialVMResult, VMResult}, 10 | file_format::{CompiledModule, CompiledScript, Constant, SignatureToken, TableIndex}, 11 | IndexKind, 12 | }; 13 | use move_core_types::vm_status::StatusCode; 14 | 15 | pub fn verify_module(module: &CompiledModule) -> VMResult<()> { 16 | verify_module_impl(module).map_err(|e| e.finish(Location::Module(module.self_id()))) 17 | } 18 | 19 | fn verify_module_impl(module: &CompiledModule) -> PartialVMResult<()> { 20 | for (idx, constant) in module.constant_pool().iter().enumerate() { 21 | verify_constant(idx, constant)? 22 | } 23 | Ok(()) 24 | } 25 | 26 | pub fn verify_script(module: &CompiledScript) -> VMResult<()> { 27 | verify_script_impl(module).map_err(|e| e.finish(Location::Script)) 28 | } 29 | 30 | fn verify_script_impl(script: &CompiledScript) -> PartialVMResult<()> { 31 | for (idx, constant) in script.constant_pool.iter().enumerate() { 32 | verify_constant(idx, constant)? 33 | } 34 | Ok(()) 35 | } 36 | 37 | fn verify_constant(idx: usize, constant: &Constant) -> PartialVMResult<()> { 38 | verify_constant_type(idx, &constant.type_)?; 39 | verify_constant_data(idx, constant) 40 | } 41 | 42 | fn verify_constant_type(idx: usize, type_: &SignatureToken) -> PartialVMResult<()> { 43 | if type_.is_valid_for_constant() { 44 | Ok(()) 45 | } else { 46 | Err(verification_error( 47 | StatusCode::INVALID_CONSTANT_TYPE, 48 | IndexKind::ConstantPool, 49 | idx as TableIndex, 50 | )) 51 | } 52 | } 53 | 54 | fn verify_constant_data(idx: usize, constant: &Constant) -> PartialVMResult<()> { 55 | match constant.deserialize_constant() { 56 | Some(_) => Ok(()), 57 | None => Err(verification_error( 58 | StatusCode::MALFORMED_CONSTANT_DATA, 59 | IndexKind::ConstantPool, 60 | idx as TableIndex, 61 | )), 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /crypto/crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diem-crypto" 3 | version = "0.0.1" 4 | authors = ["Diem Association "] 5 | description = "Diem diem-crypto" 6 | repository = "https://github.com/diem/diem" 7 | homepage = "https://diem.com" 8 | license = "Apache-2.0" 9 | publish = ["crates-io"] 10 | edition = "2018" 11 | 12 | [dependencies] 13 | anyhow = { version = "1.0.38", default-features = false } 14 | bytes = { version = "1.0.1", default-features = false } 15 | serde = { version = "1.0.117", default-features = false, package = "alt_serde", features = ["derive"] } 16 | static_assertions = "1.1.0" 17 | mirai-annotations = { path = "../../mirai-annotations", default-features = false } 18 | diem-nibble = { path = "../../common/nibble", default-features = false, version = "0.1.0" } 19 | hex = { version = "0.4.2", default-features = false, features = ["alloc"] } 20 | cell = { path = "../../common/cell", version = "0.1.0", default-features = false } 21 | tiny-keccak = { version = "2.0.2", features = ["sha3"] } 22 | rand = { version = "0.7.3", default-features = false, optional = true } 23 | rand_core = { version = "0.5.1", default-features = false, optional = true } 24 | serde_bytes = { version = "0.11.5", default-features = false, optional = true } 25 | bcs = { path = "../../bcs", default-features = false } 26 | proptest = { version = "1.0.0", optional = true } 27 | proptest-derive = { version = "0.2.0", optional = true } 28 | diem-crypto-derive = { path = "../crypto-derive", default-features = false, optional = true } 29 | ed25519-dalek = { version = "1.0.0-pre.4", features = ["u64_backend", "alloc"], default-features = false } 30 | 31 | [dev-dependencies] 32 | bitvec = "0.19.4" 33 | byteorder = "=1.4.3" 34 | proptest = "1.0.0" 35 | proptest-derive = "0.3.0" 36 | ripemd160 = "0.9.1" 37 | criterion = "0.3.4" 38 | sha3 = "0.9.1" 39 | serde_json = "1.0.60" 40 | trybuild = "1.0.35" 41 | 42 | [features] 43 | default = ["std"] 44 | fuzzing = ["proptest", "proptest-derive", "cloneable-private-keys"] 45 | assert-private-keys-not-cloneable = [] 46 | cloneable-private-keys = [] 47 | 48 | std = [ 49 | "anyhow/std", 50 | "bytes/std", 51 | "diem-nibble/std", 52 | "hex/std", 53 | "bcs/std", 54 | "rand/std", 55 | "rand_core/std", 56 | "serde_bytes/std", 57 | "diem-crypto-derive/std", 58 | "cell/std", 59 | ] 60 | -------------------------------------------------------------------------------- /mvm/src/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct SubStatus { 3 | pub category: Category, 4 | pub reason: u64, 5 | } 6 | 7 | impl SubStatus { 8 | pub fn new(code: u64) -> SubStatus { 9 | let category = code as u8; 10 | let reason = code >> 8; 11 | 12 | let category = match category { 13 | 1 => Category::INVALID_STATE, 14 | 2 => Category::REQUIRES_ADDRESS, 15 | 3 => Category::REQUIRES_ROLE, 16 | 4 => Category::REQUIRES_CAPABILITY, 17 | 5 => Category::NOT_PUBLISHED, 18 | 6 => Category::ALREADY_PUBLISHED, 19 | 7 => Category::INVALID_ARGUMENT, 20 | 8 => Category::LIMIT_EXCEEDED, 21 | 10 => Category::INTERNAL, 22 | _ => Category::CUSTOM, 23 | }; 24 | 25 | SubStatus { category, reason } 26 | } 27 | } 28 | 29 | #[allow(non_camel_case_types)] 30 | #[derive(Debug)] 31 | pub enum Category { 32 | /// The system is in a state where the performed operation is not allowed. Example: call to a function only allowed 33 | /// in genesis. 34 | INVALID_STATE, 35 | /// The signer of a transaction does not have the expected address for this operation. Example: a call to a function 36 | /// which publishes a resource under a particular address. 37 | REQUIRES_ADDRESS, 38 | /// The signer of a transaction does not have the expected role for this operation. Example: a call to a function 39 | /// which requires the signer to have the role of treasury compliance. 40 | REQUIRES_ROLE, 41 | /// The signer of a transaction does not have a required capability. 42 | REQUIRES_CAPABILITY, 43 | /// A resource is required but not published. Example: access to non-existing AccountLimits resource. 44 | NOT_PUBLISHED, 45 | /// Attempting to publish a resource that is already published. Example: calling an initialization function 46 | /// twice. 47 | ALREADY_PUBLISHED, 48 | /// An argument provided to an operation is invalid. Example: a signing key has the wrong format. 49 | INVALID_ARGUMENT, 50 | /// A limit on an amount, e.g. a currency, is exceeded. Example: withdrawal of money after account limits window 51 | /// is exhausted. 52 | LIMIT_EXCEEDED, 53 | /// An internal error (bug) has occurred. 54 | INTERNAL, 55 | /// A custom error category for extension points. 56 | CUSTOM, 57 | } 58 | -------------------------------------------------------------------------------- /crypto/crypto/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: crypto 3 | title: Crypto 4 | custom_edit_url: https://github.com/diem/diem/edit/main/crypto/crypto/README.md 5 | --- 6 | 7 | The crypto component hosts all the implementations of cryptographic primitives we use in Diem: hashing, signing, and key derivation/generation. The parts of the library using traits.rs contains the crypto API enforcing type safety, verifiable random functions, EdDSA & MultiEdDSA signatures. 8 | 9 | ## Overview 10 | 11 | Diem makes use of several cryptographic algorithms: 12 | 13 | * SHA-3 as the main hash function. It is standardized in [FIPS 202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf). It is based on the [tiny_keccak](https://docs.rs/tiny-keccak/1.4.2/tiny_keccak/) library. 14 | * HKDF: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) based on [RFC 5869](https://tools.ietf.org/html/rfc5869). It is used to generate keys from a salt (optional), seed, and application-info (optional). 15 | * traits.rs introduces new abstractions for the crypto API. 16 | * Ed25519 performs signatures using the new API design based on [ed25519-dalek](https://docs.rs/ed25519-dalek/1.0.0-pre.1/ed25519_dalek/) library with additional security checks (e.g. for malleability). 17 | * X25519 to perform key exchanges. It is used to secure communications between validators via the [Noise Protocol Framework](http://www.noiseprotocol.org/noise.html). It is based on the x25519-dalek library. 18 | 19 | ## How is this module organized? 20 | ``` 21 | crypto/src 22 | ├── hash.rs # Hash function (SHA-3) 23 | ├── hkdf.rs # HKDF implementation (HMAC-based Extract-and-Expand Key Derivation Function based on RFC 5869) 24 | ├── macros/ # Derivations for SilentDebug and SilentDisplay 25 | ├── utils.rs # Serialization utility functions 26 | ├── lib.rs 27 | ├── ed25519.rs # Ed25519 implementation of the signing/verification API in traits.rs 28 | ├── multi_ed25519.rs # MultiEd25519 implementation of the signing/verification API in traits.rs 29 | ├── x25519.rs # X25519 wrapper 30 | ├── test_utils.rs 31 | ├── traits.rs # New API design and the necessary abstractions 32 | └── unit_tests/ # Tests 33 | ``` 34 | 35 | Note: This crate historically had support for BLS12381, ECVRF, and SlIP-0010, though were removed due to lack of use. The last git revision before there removal is 00301524. 36 | -------------------------------------------------------------------------------- /language/bytecode-verifier/invalid-mutations/src/helpers.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::btree_set::BTreeSet; 5 | use core::ops::Index as OpsIndex; 6 | use proptest::sample::Index as PropIndex; 7 | /// Given a maximum value `max` and a list of [`Index`](proptest::sample::Index) instances, picks 8 | /// integers in the range `[0, max)` uniformly randomly and without duplication. 9 | /// 10 | /// If `indexes_len` is greater than `max`, all indexes will be returned. 11 | /// 12 | /// This function implements [Robert Floyd's F2 13 | /// algorithm](https://blog.acolyer.org/2018/01/30/a-sample-of-brilliance/) for sampling without 14 | /// replacement. 15 | pub(crate) fn pick_idxs(max: usize, indexes: &T, indexes_len: usize) -> Vec 16 | where 17 | T: OpsIndex + ?Sized, 18 | P: AsRef, 19 | { 20 | // See https://blog.acolyer.org/2018/01/30/a-sample-of-brilliance/ (the F2 algorithm) 21 | // for a longer explanation. This is a variant that works with zero-indexing. 22 | let mut selected = BTreeSet::new(); 23 | let to_select = indexes_len.min(max); 24 | for (iter_idx, choice) in ((max - to_select)..max).enumerate() { 25 | // "RandInt(1, J)" in the original algorithm means a number between 1 26 | // and choice, both inclusive. `PropIndex::index` picks a number between 0 and 27 | // whatever's passed in, with the latter exclusive. Pass in "+1" to ensure the same 28 | // range of values is picked from. (This also ensures that if choice is 0 then `index` 29 | // doesn't panic. 30 | let idx = indexes[iter_idx].as_ref().index(choice + 1); 31 | if !selected.insert(idx) { 32 | selected.insert(choice); 33 | } 34 | } 35 | selected.into_iter().collect() 36 | } 37 | 38 | /// Given a maximum value `max` and a slice of [`Index`](proptest::sample::Index) instances, picks 39 | /// integers in the range `[0, max)` uniformly randomly and without duplication. 40 | /// 41 | /// If the number of `Index` instances is greater than `max`, all indexes will be returned. 42 | /// 43 | /// This function implements [Robert Floyd's F2 44 | /// algorithm](https://blog.acolyer.org/2018/01/30/a-sample-of-brilliance/) for sampling without 45 | /// replacement. 46 | #[inline] 47 | pub(crate) fn pick_slice_idxs(max: usize, indexes: &[impl AsRef]) -> Vec { 48 | pick_idxs(max, indexes, indexes.len()) 49 | } 50 | -------------------------------------------------------------------------------- /language/move-binary-format/serializer-tests/tests/serializer_tests.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 3d00be1cbcb9f344e7bce080015d7a755f6e69acd37dbde62e449732af226fe4 # shrinks to module = CompiledModule: { module_handles: [ ModuleHandle { address: AddressPoolIndex(0), name: IdentifierIndex(0) },] struct_handles: [ StructHandle { module: ModuleHandleIndex(0), name: IdentifierIndex(0), is_resource: false }, StructHandle { module: ModuleHandleIndex(0), name: IdentifierIndex(0), is_resource: false },] function_handles: [ FunctionHandle { module: ModuleHandleIndex(0), name: IdentifierIndex(0), signature: FunctionSignatureIndex(0) }, FunctionHandle { module: ModuleHandleIndex(0), name: IdentifierIndex(0), signature: FunctionSignatureIndex(1) },] struct_defs: [ StructDefinition { struct_handle: 1, field_count: 0, fields: 0 },] field_defs: [] function_defs: [ FunctionDefinition { function: 1, flags: 0x0, code: CodeUnit { max_stack_size: 0, locals: 0 code: [] } },] type_signatures: [ TypeSignature(Unit), TypeSignature(Unit),] function_signatures: [ FunctionSignature { return_type: Unit, arg_types: [] }, FunctionSignature { return_type: Unit, arg_types: [] },] locals_signatures: [ LocalsSignature([]),] string_pool: [ "",] address_pool: [ Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),] } 8 | cc 7b1bb969b87bfcdbb0f635eb46212f8437d21bcd1ba754de84d66bb552e6aec2 # shrinks to module = CompiledModule { module_handles: [], struct_handles: [], function_handles: [], type_signatures: [], function_signatures: [], locals_signatures: [], string_pool: [], byte_array_pool: [], address_pool: [0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000], struct_defs: [], field_defs: [], function_defs: [] } 9 | cc 4118fc247fb7d48382876de931d47a8999a6e42658bbecc93afff9245ade141b # shrinks to module = CompiledModule { module_handles: [], struct_handles: [], function_handles: [], type_signatures: [], function_signatures: [], locals_signatures: [], string_pool: [], byte_array_pool: [], address_pool: [], struct_defs: [], field_defs: [FieldDefinition { struct_: StructHandleIndex(0), name: IdentifierIndex(0), signature: TypeSignatureIndex(0) }], function_defs: [] } 10 | -------------------------------------------------------------------------------- /language/move-binary-format/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: vm 3 | title: Virtual Machine 4 | custom_edit_url: https://github.com/libra/libra/edit/master/language/vm/README.md 5 | --- 6 | 7 | 8 | The MoveVM executes transactions expressed in the Move bytecode. There are 9 | two main crates: the core VM and the VM runtime. The VM core contains the low-level 10 | data type for the VM - mostly the file format and abstraction over it. A gas 11 | metering logical abstraction is also defined there. 12 | 13 | ## Overview 14 | 15 | The MoveVM is a stack machine with a static type system. The MoveVM honors 16 | the specification of the Move language through a mix of file format, 17 | verification (for reference [bytcode verifier README](https://github.com/libra/libra/blob/master/language/bytecode-verifier/README.md)) 18 | and runtime constraints. The structure of the file format allows the 19 | definition of modules, types (resources and unrestricted types), and 20 | functions. Code is expressed via bytecode instructions, which may have 21 | references to external functions and types. The file format also imposes 22 | certain invariants of the language such as opaque types and private fields. 23 | From the file format definition it should be clear that modules define a 24 | scope/namespace for functions and types. Types are opaque given all fields 25 | are private, and types carry no functions or methods. 26 | 27 | ## Implementation Details 28 | 29 | The MoveVM core crate provides the definition of the file format and all 30 | utilities related to the file format: 31 | * A simple Rust abstraction over the file format 32 | (`libra/language/vm/src/file_format.rs`) and the bytecodes. These Rust 33 | structures are widely used in the code base. 34 | * Serialization and deserialization of the file format. These define the 35 | on-chain binary representation of the code. 36 | * Some pretty printing functionalities. 37 | * A proptest infrastructure for the file format. 38 | 39 | The `CompiledModule` and `CompiledScript` definitions in 40 | `libra/language/vm/src/file_format.rs` are the top-level structs for a Move 41 | *Module* or *Transaction Script*, respectively. These structs provide a 42 | simple abstraction over the file format. Additionally, a set of 43 | [*Views*](https://github.com/libra/libra/blob/master/language/vm/src/views.rs) are defined to easily navigate and inspect 44 | `CompiledModule`s and `CompiledScript`s. 45 | 46 | ## Folder Structure 47 | 48 | ``` 49 | . 50 | ├── src # VM core files 51 | ├── tests # Proptests 52 | └── vm-runtime # Interpreter and runtime data types (see README in that folder) 53 | ``` 54 | -------------------------------------------------------------------------------- /types/src/account_config/constants/coins.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_config::constants::{from_currency_code_string, CORE_CODE_ADDRESS}; 5 | use alloc::borrow::ToOwned; 6 | use alloc::string::{String, ToString}; 7 | use cell::Lazy; 8 | use move_core_types::{ 9 | ident_str, 10 | identifier::IdentStr, 11 | language_storage::{ModuleId, StructTag, TypeTag}, 12 | }; 13 | 14 | pub const XDX_NAME: &str = "XDX"; 15 | pub const XDX_IDENTIFIER: &IdentStr = ident_str!(XDX_NAME); 16 | pub const XUS_NAME: &str = "XUS"; 17 | pub const XUS_IDENTIFIER: &IdentStr = ident_str!(XUS_NAME); 18 | 19 | pub fn xus_tag() -> TypeTag { 20 | TypeTag::Struct(StructTag { 21 | address: CORE_CODE_ADDRESS, 22 | module: from_currency_code_string(XUS_NAME).unwrap(), 23 | name: from_currency_code_string(XUS_NAME).unwrap(), 24 | type_params: vec![], 25 | }) 26 | } 27 | 28 | pub static XDX_MODULE: Lazy = 29 | Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, XDX_IDENTIFIER.to_owned())); 30 | 31 | pub fn xdx_type_tag() -> TypeTag { 32 | TypeTag::Struct(StructTag { 33 | address: CORE_CODE_ADDRESS, 34 | module: from_currency_code_string(XDX_NAME).unwrap(), 35 | name: from_currency_code_string(XDX_NAME).unwrap(), 36 | type_params: vec![], 37 | }) 38 | } 39 | 40 | /// Return `Some(struct_name)` if `t` is a `StructTag` representing one of the current Diem coin 41 | /// types (XDX, XUS), `None` otherwise. 42 | pub fn coin_name(t: &TypeTag) -> Option { 43 | match t { 44 | TypeTag::Struct(StructTag { 45 | address, 46 | module, 47 | name, 48 | .. 49 | }) if *address == CORE_CODE_ADDRESS && module == name => { 50 | let name_str = name.to_string(); 51 | if name_str == XDX_NAME || name_str == XUS_NAME { 52 | Some(name_str) 53 | } else { 54 | None 55 | } 56 | } 57 | _ => None, 58 | } 59 | } 60 | 61 | #[test] 62 | fn coin_names() { 63 | assert!(coin_name(&xus_tag()).unwrap() == XUS_NAME); 64 | assert!(coin_name(&xdx_type_tag()).unwrap() == XDX_NAME); 65 | assert!(coin_name(&TypeTag::U64) == None); 66 | 67 | let bad_name = ident_str!("NotACoin").to_owned(); 68 | let bad_coin = TypeTag::Struct(StructTag { 69 | address: CORE_CODE_ADDRESS, 70 | module: bad_name.clone(), 71 | name: bad_name, 72 | type_params: vec![], 73 | }); 74 | assert!(coin_name(&bad_coin) == None); 75 | } 76 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/signature.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::collections::VecDeque; 5 | use alloc::vec::Vec; 6 | use core::convert::TryFrom; 7 | use diem_crypto::{ed25519, traits::*}; 8 | use move_binary_format::errors::PartialVMResult; 9 | use move_vm_runtime::native_functions::NativeContext; 10 | use move_vm_types::{ 11 | gas_schedule::NativeCostIndex, 12 | loaded_data::runtime_types::Type, 13 | natives::function::{native_gas, NativeResult}, 14 | pop_arg, 15 | values::Value, 16 | }; 17 | use smallvec::smallvec; 18 | 19 | pub fn native_ed25519_publickey_validation( 20 | context: &mut NativeContext, 21 | _ty_args: Vec, 22 | mut arguments: VecDeque, 23 | ) -> PartialVMResult { 24 | debug_assert!(_ty_args.is_empty()); 25 | debug_assert!(arguments.len() == 1); 26 | 27 | let key_bytes = pop_arg!(arguments, Vec); 28 | 29 | let cost = native_gas( 30 | context.cost_table(), 31 | NativeCostIndex::ED25519_VALIDATE_KEY, 32 | key_bytes.len(), 33 | ); 34 | 35 | // This deserialization performs point-on-curve and small subgroup checks 36 | let valid = ed25519::Ed25519PublicKey::try_from(&key_bytes[..]).is_ok(); 37 | Ok(NativeResult::ok(cost, smallvec![Value::bool(valid)])) 38 | } 39 | 40 | pub fn native_ed25519_signature_verification( 41 | context: &mut NativeContext, 42 | _ty_args: Vec, 43 | mut arguments: VecDeque, 44 | ) -> PartialVMResult { 45 | debug_assert!(_ty_args.is_empty()); 46 | debug_assert!(arguments.len() == 3); 47 | 48 | let msg = pop_arg!(arguments, Vec); 49 | let pubkey = pop_arg!(arguments, Vec); 50 | let signature = pop_arg!(arguments, Vec); 51 | 52 | let cost = native_gas( 53 | context.cost_table(), 54 | NativeCostIndex::ED25519_VERIFY, 55 | msg.len(), 56 | ); 57 | 58 | let sig = match ed25519::Ed25519Signature::try_from(signature.as_slice()) { 59 | Ok(sig) => sig, 60 | Err(_) => { 61 | return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])); 62 | } 63 | }; 64 | let pk = match ed25519::Ed25519PublicKey::try_from(pubkey.as_slice()) { 65 | Ok(pk) => pk, 66 | Err(_) => { 67 | return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])); 68 | } 69 | }; 70 | 71 | let verify_result = sig.verify_arbitrary_msg(msg.as_slice(), &pk).is_ok(); 72 | Ok(NativeResult::ok( 73 | cost, 74 | smallvec![Value::bool(verify_result)], 75 | )) 76 | } 77 | -------------------------------------------------------------------------------- /language/move-binary-format/src/proptest_types/constants.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::file_format::{Constant, SignatureToken}; 5 | use move_core_types::account_address::AccountAddress; 6 | use proptest::{ 7 | arbitrary::any, 8 | collection::{btree_set, vec, SizeRange}, 9 | strategy::Strategy, 10 | }; 11 | 12 | // A `ConstantPoolGen` gives you back a `Strategy` that makes a constant pool with 13 | // `Address` and `Vector` only. 14 | // TODO: make it more general and plug in a constant API 15 | #[derive(Clone, Debug)] 16 | pub struct ConstantPoolGen { 17 | addresses: Vec, 18 | byte_arrays: Vec>, 19 | } 20 | 21 | impl ConstantPoolGen { 22 | // Return a `Strategy` that builds a ConstantPool with a number of `addresse`s and 23 | // `vector` respectively driven by `address_count` and `byte_array_count` 24 | pub fn strategy( 25 | address_count: impl Into, 26 | byte_array_count: impl Into, 27 | ) -> impl Strategy { 28 | // get unique sets of addresses and vector (empty vector allowed) 29 | ( 30 | btree_set(any::(), address_count), 31 | btree_set(vec(any::(), 0..=20), byte_array_count), 32 | ) 33 | .prop_map(|(addresses, byte_arrays)| Self { 34 | addresses: addresses.into_iter().collect(), 35 | byte_arrays: byte_arrays.into_iter().collect(), 36 | }) 37 | } 38 | 39 | // Return the `ConstantPool` 40 | pub fn constant_pool(self) -> Vec { 41 | let mut constants = vec![]; 42 | for address in self.addresses { 43 | constants.push(Constant { 44 | type_: SignatureToken::Address, 45 | data: address.to_vec(), 46 | }); 47 | } 48 | for mut byte_array in self.byte_arrays { 49 | // TODO: below is a trick to make serialization easy (size being one byte) 50 | // This can hopefully help soon in defining an API for constants 51 | // As a restriction is a non issue as we don't have input over big numbers (>100) 52 | if byte_array.len() > 127 { 53 | continue; 54 | } 55 | byte_array.push(byte_array.len() as u8); 56 | byte_array.reverse(); 57 | constants.push(Constant { 58 | type_: SignatureToken::Vector(Box::new(SignatureToken::U8)), 59 | data: byte_array, 60 | }); 61 | } 62 | constants 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /bcs/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::string::String; 5 | use alloc::string::ToString; 6 | use core::fmt; 7 | use serde::{de, ser}; 8 | 9 | pub type Result = core::result::Result; 10 | 11 | #[derive(Clone, Debug, PartialEq)] 12 | pub enum Error { 13 | Eof, 14 | Io(String), 15 | ExceededMaxLen(usize), 16 | ExceededContainerDepthLimit(&'static str), 17 | ExpectedBoolean, 18 | ExpectedMapKey, 19 | ExpectedMapValue, 20 | NonCanonicalMap, 21 | ExpectedOption, 22 | Custom(String), 23 | MissingLen, 24 | NotSupported(&'static str), 25 | RemainingInput, 26 | Utf8, 27 | NonCanonicalUleb128Encoding, 28 | IntegerOverflowDuringUleb128Decoding, 29 | } 30 | 31 | #[cfg(feature = "std")] 32 | impl std::error::Error for Error {} 33 | 34 | impl fmt::Display for Error { 35 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 36 | match self { 37 | Error::Eof => write!(f, "unexpected end of input"), 38 | Error::Io(v) => write!(f, "I/O error: {0}", v), 39 | Error::ExceededMaxLen(v) => write!(f, "exceeded max sequence length: {0}", v), 40 | Error::ExceededContainerDepthLimit(v) => { 41 | write!(f, "exceeded max container depth while entering: {0}", v) 42 | } 43 | Error::ExpectedBoolean => write!(f, "expected boolean"), 44 | Error::ExpectedMapKey => write!(f, "expected map key"), 45 | Error::ExpectedMapValue => write!(f, "expected map value"), 46 | Error::NonCanonicalMap => write!( 47 | f, 48 | "keys of serialized maps must be unique and in increasing order" 49 | ), 50 | Error::ExpectedOption => write!(f, "expected option type"), 51 | Error::Custom(err) => write!(f, "{0}", err), 52 | Error::MissingLen => write!(f, "sequence missing length"), 53 | Error::NotSupported(v) => write!(f, "{0}", v), 54 | Error::RemainingInput => write!(f, "remaining input"), 55 | Error::Utf8 => write!(f, "malformed utf8"), 56 | Error::NonCanonicalUleb128Encoding => { 57 | write!(f, "ULEB128 encoding was not minimal in size") 58 | } 59 | Error::IntegerOverflowDuringUleb128Decoding => { 60 | write!(f, "ULEB128-encoded integer did not fit in the target size") 61 | } 62 | } 63 | } 64 | } 65 | 66 | impl ser::Error for Error { 67 | fn custom(msg: T) -> Self { 68 | Error::Custom(msg.to_string()) 69 | } 70 | } 71 | 72 | impl de::Error for Error { 73 | fn custom(msg: T) -> Self { 74 | Error::Custom(msg.to_string()) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /language/move-core/types/src/resolver.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{ 5 | account_address::AccountAddress, 6 | language_storage::{ModuleId, StructTag}, 7 | }; 8 | use alloc::vec::Vec; 9 | use core::fmt::Debug; 10 | 11 | /// Traits for resolving Move modules and resources from persistent storage 12 | 13 | /// A persistent storage backend that can resolve modules by address + name. 14 | /// Storage backends should return 15 | /// - Ok(Some(..)) if the data exists 16 | /// - Ok(None) if the data does not exist 17 | /// - Err(..) only when something really wrong happens, for example 18 | /// - invariants are broken and observable from the storage side 19 | /// (this is not currently possible as ModuleId and StructTag 20 | /// are always structurally valid) 21 | /// - storage encounters internal error 22 | pub trait ModuleResolver { 23 | type Error: Debug; 24 | 25 | fn get_module(&self, id: &ModuleId) -> Result>, Self::Error>; 26 | } 27 | 28 | /// A persistent storage backend that can resolve resources by address + type 29 | /// Storage backends should return 30 | /// - Ok(Some(..)) if the data exists 31 | /// - Ok(None) if the data does not exist 32 | /// - Err(..) only when something really wrong happens, for example 33 | /// - invariants are broken and observable from the storage side 34 | /// (this is not currently possible as ModuleId and StructTag 35 | /// are always structurally valid) 36 | /// - storage encounters internal error 37 | pub trait ResourceResolver { 38 | type Error: Debug; 39 | 40 | fn get_resource( 41 | &self, 42 | address: &AccountAddress, 43 | typ: &StructTag, 44 | ) -> Result>, Self::Error>; 45 | } 46 | 47 | /// A persistent storage implementation that can resolve both resources and modules 48 | pub trait MoveResolver: 49 | ModuleResolver + ResourceResolver 50 | { 51 | type Err: Debug; 52 | } 53 | 54 | impl + ResourceResolver + ?Sized> MoveResolver 55 | for T 56 | { 57 | type Err = E; 58 | } 59 | 60 | impl ResourceResolver for &T { 61 | type Error = T::Error; 62 | 63 | fn get_resource( 64 | &self, 65 | address: &AccountAddress, 66 | tag: &StructTag, 67 | ) -> Result>, Self::Error> { 68 | (**self).get_resource(address, tag) 69 | } 70 | } 71 | 72 | impl ModuleResolver for &T { 73 | type Error = T::Error; 74 | fn get_module(&self, module_id: &ModuleId) -> Result>, Self::Error> { 75 | (**self).get_module(module_id) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - release-* 8 | 9 | env: 10 | RUST_BACKTRACE: full 11 | CARGO_INCREMENTAL: 0 12 | RUSTUP_MAX_RETRIES: 10 13 | CARGO_NET_RETRY: 10 14 | 15 | jobs: 16 | test: 17 | name: Tests 18 | runs-on: ${{ matrix.os }} 19 | 20 | defaults: 21 | run: 22 | shell: bash 23 | 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | rust: 28 | - stable 29 | dove: 30 | - 1.5.5 31 | os: 32 | - macos-latest 33 | - ubuntu-latest 34 | 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v2 38 | 39 | - name: Rust Toolchain 40 | uses: actions-rs/toolchain@v1 41 | with: 42 | toolchain: ${{ matrix.rust }} 43 | profile: minimal 44 | override: true 45 | components: rustfmt, clippy 46 | 47 | - name: Code-style 48 | run: cargo fmt -- --check 49 | 50 | - name: Dove executable 51 | uses: pontem-network/get-dove@main 52 | with: 53 | prerelease: true 54 | version: ${{ matrix.dove }} 55 | token: ${{ secrets.GITHUB_TOKEN }} 56 | 57 | - name: Tests 58 | run: cargo test --all --tests --no-fail-fast -- --test-threads=4 --nocapture 59 | 60 | - name: Clippy 61 | uses: actions-rs/clippy-check@v1 62 | with: 63 | token: ${{ secrets.GITHUB_TOKEN }} 64 | args: --all --no-deps 65 | 66 | build: 67 | name: Build 68 | runs-on: ${{ matrix.os }} 69 | defaults: 70 | run: 71 | shell: bash 72 | 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | rust: 77 | - nightly-2021-04-24 78 | dove: 79 | - 1.5.5 80 | os: 81 | - macos-latest 82 | - ubuntu-latest 83 | 84 | steps: 85 | - name: Checkout 86 | uses: actions/checkout@v2 87 | 88 | - name: Rust Toolchain 89 | uses: actions-rs/toolchain@v1 90 | with: 91 | toolchain: ${{ matrix.rust }} 92 | profile: minimal 93 | override: true 94 | target: wasm32-unknown-unknown 95 | 96 | - name: Dove executable 97 | uses: pontem-network/get-dove@main 98 | with: 99 | prerelease: true 100 | version: ${{ matrix.dove }} 101 | token: ${{ secrets.GITHUB_TOKEN }} 102 | 103 | - name: Build WASM -std 104 | run: | 105 | cd mvm 106 | cargo build --package mvm --target wasm32-unknown-unknown --no-default-features --features="sp_check" 107 | 108 | - name: Build with +std 109 | run: | 110 | cd mvm 111 | cargo build --package mvm --no-default-features --features="std,sp_check" 112 | -------------------------------------------------------------------------------- /types/src/resources/currency_info.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::{ 5 | access_path::AccessPath, 6 | account_config::constants::{ 7 | diem_root_address, type_tag_for_currency_code, CORE_CODE_ADDRESS, DIEM_MODULE_IDENTIFIER, 8 | }, 9 | event::EventHandle, 10 | }; 11 | use anyhow::anyhow; 12 | use anyhow::Result; 13 | use move_core_types::{ 14 | ident_str, 15 | identifier::{IdentStr, Identifier}, 16 | language_storage::{ResourceKey, StructTag}, 17 | move_resource::{MoveResource, MoveStructType}, 18 | }; 19 | use serde::{Deserialize, Serialize}; 20 | 21 | /// Struct that represents a CurrencyInfo resource 22 | #[derive(Debug, Serialize, Deserialize, Clone)] 23 | pub struct CurrencyInfoResource { 24 | pub total_value: u128, 25 | decimals: u8, 26 | currency_code: Identifier, 27 | mint_events: EventHandle, 28 | burn_events: EventHandle, 29 | } 30 | 31 | impl MoveStructType for CurrencyInfoResource { 32 | const MODULE_NAME: &'static IdentStr = DIEM_MODULE_IDENTIFIER; 33 | const STRUCT_NAME: &'static IdentStr = ident_str!("TokenInfo"); 34 | } 35 | 36 | impl MoveResource for CurrencyInfoResource {} 37 | 38 | impl CurrencyInfoResource { 39 | pub fn new( 40 | total_value: u128, 41 | decimals: u8, 42 | currency_code: Identifier, 43 | mint_events: EventHandle, 44 | burn_events: EventHandle, 45 | ) -> Self { 46 | Self { 47 | total_value, 48 | decimals, 49 | currency_code, 50 | mint_events, 51 | burn_events, 52 | } 53 | } 54 | 55 | pub fn currency_code(&self) -> &IdentStr { 56 | &self.currency_code 57 | } 58 | 59 | pub fn decimals(&self) -> u8 { 60 | self.decimals 61 | } 62 | 63 | pub fn total_value(&self) -> u128 { 64 | self.total_value 65 | } 66 | 67 | pub fn struct_tag_for(currency_code: Identifier) -> StructTag { 68 | StructTag { 69 | address: CORE_CODE_ADDRESS, 70 | module: CurrencyInfoResource::module_identifier(), 71 | name: CurrencyInfoResource::struct_identifier(), 72 | type_params: vec![type_tag_for_currency_code(currency_code)], 73 | } 74 | } 75 | 76 | pub fn resource_path_for(currency_code: Identifier) -> AccessPath { 77 | let resource_key = ResourceKey::new( 78 | diem_root_address(), 79 | CurrencyInfoResource::struct_tag_for(currency_code), 80 | ); 81 | AccessPath::resource_access_path(resource_key) 82 | } 83 | 84 | pub fn try_from_bytes(bytes: &[u8]) -> Result { 85 | bcs::from_bytes(bytes).map_err(|err| anyhow!("Failed to decode bcs. {:?}", err)) 86 | } 87 | 88 | pub fn mint_events(&self) -> &EventHandle { 89 | &self.mint_events 90 | } 91 | 92 | pub fn burn_events(&self) -> &EventHandle { 93 | &self.burn_events 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /language/bytecode-verifier/bytecode-verifier-tests/src/unit_tests/control_flow_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::support::dummy_procedure_module; 5 | use bytecode_verifier::control_flow; 6 | use move_binary_format::{ 7 | access::ModuleAccess, 8 | errors::PartialVMResult, 9 | file_format::{Bytecode, CompiledModule, FunctionDefinitionIndex, TableIndex}, 10 | }; 11 | use move_core_types::vm_status::StatusCode; 12 | 13 | fn verify_module(module: &CompiledModule) -> PartialVMResult<()> { 14 | for (idx, function_definition) in module 15 | .function_defs() 16 | .iter() 17 | .enumerate() 18 | .filter(|(_, def)| !def.is_native()) 19 | { 20 | control_flow::verify( 21 | Some(FunctionDefinitionIndex(idx as TableIndex)), 22 | function_definition 23 | .code 24 | .as_ref() 25 | .expect("unexpected native function"), 26 | )? 27 | } 28 | Ok(()) 29 | } 30 | 31 | //************************************************************************************************** 32 | // Simple cases - Copied from code unit verifier 33 | //************************************************************************************************** 34 | 35 | #[test] 36 | fn invalid_fallthrough_br_true() { 37 | let module = dummy_procedure_module(vec![Bytecode::LdFalse, Bytecode::BrTrue(1)]); 38 | let result = verify_module(&module); 39 | assert_eq!( 40 | result.unwrap_err().major_status(), 41 | StatusCode::INVALID_FALL_THROUGH 42 | ); 43 | } 44 | 45 | #[test] 46 | fn invalid_fallthrough_br_false() { 47 | let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::BrFalse(1)]); 48 | let result = verify_module(&module); 49 | assert_eq!( 50 | result.unwrap_err().major_status(), 51 | StatusCode::INVALID_FALL_THROUGH 52 | ); 53 | } 54 | 55 | // all non-branch instructions should trigger invalid fallthrough; just check one of them 56 | #[test] 57 | fn invalid_fallthrough_non_branch() { 58 | let module = dummy_procedure_module(vec![Bytecode::LdTrue, Bytecode::Pop]); 59 | let result = verify_module(&module); 60 | assert_eq!( 61 | result.unwrap_err().major_status(), 62 | StatusCode::INVALID_FALL_THROUGH 63 | ); 64 | } 65 | 66 | #[test] 67 | fn valid_fallthrough_branch() { 68 | let module = dummy_procedure_module(vec![Bytecode::Branch(0)]); 69 | let result = verify_module(&module); 70 | assert!(result.is_ok()); 71 | } 72 | 73 | #[test] 74 | fn valid_fallthrough_ret() { 75 | let module = dummy_procedure_module(vec![Bytecode::Ret]); 76 | let result = verify_module(&module); 77 | assert!(result.is_ok()); 78 | } 79 | 80 | #[test] 81 | fn valid_fallthrough_abort() { 82 | let module = dummy_procedure_module(vec![Bytecode::LdU64(7), Bytecode::Abort]); 83 | let result = verify_module(&module); 84 | assert!(result.is_ok()); 85 | } 86 | -------------------------------------------------------------------------------- /types/src/account_config/constants/diem.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_config::constants::CORE_CODE_ADDRESS; 5 | use alloc::borrow::ToOwned; 6 | use anyhow::{bail, ensure, Result}; 7 | use cell::Lazy; 8 | use move_core_types::{ 9 | identifier::{IdentStr, Identifier}, 10 | language_storage::{ModuleId, StructTag, TypeTag}, 11 | }; 12 | 13 | pub use move_core_types::vm_status::known_locations::{DIEM_MODULE, DIEM_MODULE_IDENTIFIER}; 14 | 15 | const COIN_MODULE_IDENTIFIER: &IdentStr = DIEM_MODULE_IDENTIFIER; 16 | pub static COIN_MODULE: Lazy = 17 | Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, COIN_MODULE_IDENTIFIER.to_owned())); 18 | 19 | // TODO: This imposes a few implied restrictions: 20 | // 1) The currency module must be published under the core code address. 21 | // 2) The module name must be the same as the gas specifier. 22 | // 3) The struct name must be the same as the module name 23 | // We need to consider whether we want to switch to a more or fully qualified name. 24 | pub fn type_tag_for_currency_code(currency_code: Identifier) -> TypeTag { 25 | TypeTag::Struct(StructTag { 26 | address: CORE_CODE_ADDRESS, 27 | module: currency_code.clone(), 28 | name: currency_code, 29 | type_params: vec![], 30 | }) 31 | } 32 | 33 | pub fn currency_code_from_type_tag(type_tag: TypeTag) -> Result { 34 | let struct_tag = match type_tag { 35 | TypeTag::Struct(struct_tag) => struct_tag, 36 | _ => bail!( 37 | "expected a type for a currency struct, received: {:?}", 38 | type_tag 39 | ), 40 | }; 41 | 42 | ensure!( 43 | struct_tag.address == CORE_CODE_ADDRESS 44 | && struct_tag.module == struct_tag.name 45 | && struct_tag.type_params.is_empty(), 46 | "not a valid currency struct tag: {:?}", 47 | struct_tag, 48 | ); 49 | 50 | let currency_code = struct_tag.name; 51 | 52 | ensure!( 53 | allowed_currency_code_string(currency_code.as_str()), 54 | "currency code can only contain uppercase alphanumeric characters: '{}'", 55 | currency_code, 56 | ); 57 | 58 | Ok(currency_code) 59 | } 60 | 61 | /// In addition to the constraints for valid Move identifiers, currency codes 62 | /// should consist entirely of uppercase alphanumeric characters (e.g., no underscores). 63 | pub fn allowed_currency_code_string(possible_currency_code_string: &str) -> bool { 64 | possible_currency_code_string 65 | .chars() 66 | .all(|chr| matches!(chr, 'A'..='Z' | '0'..='9')) 67 | && Identifier::is_valid(possible_currency_code_string) 68 | } 69 | 70 | pub fn from_currency_code_string(currency_code_string: &str) -> Result { 71 | if !allowed_currency_code_string(currency_code_string) { 72 | bail!("Invalid currency code '{}'", currency_code_string) 73 | } 74 | Identifier::new(currency_code_string) 75 | } 76 | -------------------------------------------------------------------------------- /language/bytecode-verifier/src/verifier.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! This module contains the public APIs supported by the bytecode verifier. 5 | use crate::{ 6 | ability_field_requirements, check_duplication::DuplicationChecker, 7 | code_unit_verifier::CodeUnitVerifier, constants, friends, 8 | instantiation_loops::InstantiationLoopChecker, instruction_consistency::InstructionConsistency, 9 | script_signature, signature::SignatureChecker, struct_defs::RecursiveStructDefChecker, 10 | }; 11 | use move_binary_format::{ 12 | check_bounds::BoundsChecker, 13 | errors::{Location, VMResult}, 14 | file_format::{CompiledModule, CompiledScript}, 15 | }; 16 | 17 | /// Helper for a "canonical" verification of a module. 18 | /// 19 | /// Clients that rely on verification should call the proper passes 20 | /// internally rather than using this function. 21 | /// 22 | /// This function is intended to provide a verification path for clients 23 | /// that do not require full control over verification. It is advised to 24 | /// call this umbrella function instead of each individual checkers to 25 | /// minimize the code locations that need to be updated should a new checker 26 | /// is introduced. 27 | pub fn verify_module(module: &CompiledModule) -> VMResult<()> { 28 | BoundsChecker::verify_module(module).map_err(|e| { 29 | // We can't point the error at the module, because if bounds-checking 30 | // failed, we cannot safely index into module's handle to itself. 31 | e.finish(Location::Undefined) 32 | })?; 33 | DuplicationChecker::verify_module(module)?; 34 | SignatureChecker::verify_module(module)?; 35 | InstructionConsistency::verify_module(module)?; 36 | constants::verify_module(module)?; 37 | friends::verify_module(module)?; 38 | ability_field_requirements::verify_module(module)?; 39 | RecursiveStructDefChecker::verify_module(module)?; 40 | InstantiationLoopChecker::verify_module(module)?; 41 | CodeUnitVerifier::verify_module(module) 42 | } 43 | 44 | /// Helper for a "canonical" verification of a script. 45 | /// 46 | /// Clients that rely on verification should call the proper passes 47 | /// internally rather than using this function. 48 | /// 49 | /// This function is intended to provide a verification path for clients 50 | /// that do not require full control over verification. It is advised to 51 | /// call this umbrella function instead of each individual checkers to 52 | /// minimize the code locations that need to be updated should a new checker 53 | /// is introduced. 54 | pub fn verify_script(script: &CompiledScript) -> VMResult<()> { 55 | BoundsChecker::verify_script(script).map_err(|e| e.finish(Location::Script))?; 56 | DuplicationChecker::verify_script(script)?; 57 | SignatureChecker::verify_script(script)?; 58 | InstructionConsistency::verify_script(script)?; 59 | constants::verify_script(script)?; 60 | CodeUnitVerifier::verify_script(script)?; 61 | script_signature::verify_script(script) 62 | } 63 | -------------------------------------------------------------------------------- /mvm/src/io/session.rs: -------------------------------------------------------------------------------- 1 | use crate::io::balance::{BalanceOp, MasterOfCoinSession}; 2 | use crate::io::context::ExecutionContext; 3 | use crate::io::traits::BalanceAccess; 4 | use alloc::vec::Vec; 5 | use anyhow::Error; 6 | use diem_types::account_config; 7 | use move_binary_format::errors::VMResult; 8 | use move_core_types::account_address::AccountAddress; 9 | use move_core_types::effects::{ChangeSet, Event}; 10 | use move_core_types::language_storage::{ModuleId, StructTag, CORE_CODE_ADDRESS}; 11 | use move_core_types::resolver::{ModuleResolver, ResourceResolver}; 12 | 13 | pub struct StateSession< 14 | 'b, 15 | 'r, 16 | R: ModuleResolver + ResourceResolver, 17 | B: BalanceAccess, 18 | > { 19 | remote: &'r R, 20 | context: Option, 21 | coin_session: MasterOfCoinSession<'b, 'r, B, R>, 22 | } 23 | 24 | impl< 25 | 'b, 26 | 'r, 27 | R: ModuleResolver + ResourceResolver, 28 | B: BalanceAccess, 29 | > StateSession<'b, 'r, R, B> 30 | { 31 | pub(crate) fn new( 32 | remote: &'r R, 33 | context: Option, 34 | coin_session: MasterOfCoinSession<'b, 'r, B, R>, 35 | ) -> StateSession<'b, 'r, R, B> { 36 | StateSession { 37 | remote, 38 | context, 39 | coin_session, 40 | } 41 | } 42 | 43 | pub fn finish( 44 | self, 45 | (mut changes, events): (ChangeSet, Vec), 46 | ) -> VMResult<(ChangeSet, Vec, Vec)> { 47 | let balance_op = self.coin_session.finish(&mut changes)?; 48 | Ok((changes, events, balance_op)) 49 | } 50 | } 51 | 52 | impl< 53 | 'b, 54 | 'r, 55 | R: ModuleResolver + ResourceResolver, 56 | B: BalanceAccess, 57 | > ModuleResolver for StateSession<'b, 'r, R, B> 58 | { 59 | type Error = Error; 60 | 61 | fn get_module(&self, id: &ModuleId) -> Result>, Self::Error> { 62 | self.remote.get_module(id) 63 | } 64 | } 65 | 66 | impl< 67 | 'b, 68 | 'r, 69 | R: ModuleResolver + ResourceResolver, 70 | B: BalanceAccess, 71 | > ResourceResolver for StateSession<'b, 'r, R, B> 72 | { 73 | type Error = Error; 74 | 75 | fn get_resource( 76 | &self, 77 | address: &AccountAddress, 78 | tag: &StructTag, 79 | ) -> Result>, Self::Error> { 80 | if tag.address == CORE_CODE_ADDRESS { 81 | if address == &account_config::diem_root_address() { 82 | if let Some(ctx) = &self.context { 83 | if let Some(blob) = ctx.resolve(tag) { 84 | return Ok(Some(blob)); 85 | } 86 | } 87 | } 88 | if let Some(blob) = self.coin_session.resolve(address, tag)? { 89 | return Ok(Some(blob)); 90 | } 91 | } 92 | self.remote.get_resource(address, tag) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /language/move-stdlib/src/natives/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | pub mod account; 5 | pub mod bcs; 6 | pub mod event; 7 | pub mod hash; 8 | pub mod reflect; 9 | pub mod signature; 10 | pub mod signer; 11 | pub mod u256; 12 | pub mod vector; 13 | 14 | #[cfg(feature = "testing")] 15 | pub mod unit_test; 16 | 17 | pub mod debug; 18 | 19 | use move_core_types::{account_address::AccountAddress, identifier::Identifier}; 20 | use move_vm_runtime::native_functions::{NativeFunction, NativeFunctionTable}; 21 | 22 | pub fn all_natives(move_std_addr: AccountAddress) -> NativeFunctionTable { 23 | const NATIVES: &[(&str, &str, NativeFunction)] = &[ 24 | ("BCS", "to_bytes", bcs::native_to_bytes), 25 | ("Event", "write_to_event_store", event::write_to_event_store), 26 | ("Hash", "sha2_256", hash::native_sha2_256), 27 | ("Hash", "sha3_256", hash::native_sha3_256), 28 | ("Signer", "borrow_address", signer::native_borrow_address), 29 | ("Vector", "length", vector::native_length), 30 | ("Vector", "empty", vector::native_empty), 31 | ("Vector", "borrow", vector::native_borrow), 32 | ("Vector", "borrow_mut", vector::native_borrow), 33 | ("Vector", "push_back", vector::native_push_back), 34 | ("Vector", "pop_back", vector::native_pop), 35 | ("Vector", "destroy_empty", vector::native_destroy_empty), 36 | ("Vector", "swap", vector::native_swap), 37 | ("Debug", "print", debug::native_print), 38 | ( 39 | "Debug", 40 | "print_stack_trace", 41 | debug::native_print_stack_trace, 42 | ), 43 | #[cfg(feature = "testing")] 44 | ( 45 | "UnitTest", 46 | "create_signers_for_testing", 47 | unit_test::native_create_signers_for_testing, 48 | ), 49 | ("U256", "from_u8", u256::from_u8), 50 | ("U256", "from_u64", u256::from_u64), 51 | ("U256", "from_u128", u256::from_u128), 52 | ("U256", "as_u8", u256::as_u8), 53 | ("U256", "as_u64", u256::as_u64), 54 | ("U256", "as_u128", u256::as_u128), 55 | ("U256", "add", u256::add), 56 | ("U256", "sub", u256::sub), 57 | ("U256", "mul", u256::mul), 58 | ("U256", "div", u256::div), 59 | ( 60 | "PontAccount", 61 | "create_signer", 62 | account::native_create_signer, 63 | ), 64 | ( 65 | "PontAccount", 66 | "destroy_signer", 67 | account::native_destroy_signer, 68 | ), 69 | ( 70 | "Signature", 71 | "ed25519_validate_pubkey", 72 | signature::native_ed25519_publickey_validation, 73 | ), 74 | ( 75 | "Signature", 76 | "ed25519_verify", 77 | signature::native_ed25519_signature_verification, 78 | ), 79 | ("Reflect", "type_info", reflect::type_info), 80 | ]; 81 | NATIVES 82 | .iter() 83 | .cloned() 84 | .map(|(module_name, func_name, func)| { 85 | ( 86 | move_std_addr, 87 | Identifier::new(module_name).unwrap(), 88 | Identifier::new(func_name).unwrap(), 89 | func, 90 | ) 91 | }) 92 | .collect() 93 | } 94 | -------------------------------------------------------------------------------- /crypto/crypto/src/unit_tests/cryptohasher.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Test file for the procedural macros CryptoHasher and BCSCryptoHash. 5 | 6 | use crate as diem_crypto; 7 | use crate::{ 8 | hash::{CryptoHash, CryptoHasher, DIEM_HASH_PREFIX}, 9 | HashValue, 10 | }; 11 | use diem_crypto_derive::{BCSCryptoHash, CryptoHasher}; 12 | use serde::{Deserialize, Serialize}; 13 | use tiny_keccak::{Hasher, Sha3}; 14 | 15 | // The expected use case. 16 | #[derive(Serialize, Deserialize, CryptoHasher, BCSCryptoHash)] 17 | pub struct Foo { 18 | a: u64, 19 | b: u32, 20 | } 21 | 22 | // Used for testing the seed in FooHasher. 23 | pub struct Bar {} 24 | 25 | // Complex example with generics and serde-rename. 26 | #[derive(Serialize, Deserialize, CryptoHasher, BCSCryptoHash)] 27 | #[serde(rename = "Foo")] 28 | pub struct Baz { 29 | a: T, 30 | b: u32, 31 | } 32 | 33 | impl CryptoHash for Bar { 34 | type Hasher = FooHasher; 35 | 36 | fn hash(&self) -> HashValue { 37 | let state = Self::Hasher::default(); 38 | state.finish() 39 | } 40 | } 41 | 42 | #[test] 43 | fn test_cryptohasher_name() { 44 | let mut salt = DIEM_HASH_PREFIX.to_vec(); 45 | salt.extend_from_slice(b"Foo"); 46 | 47 | let value = Bar {}; 48 | let expected = { 49 | let mut digest = Sha3::v256(); 50 | digest.update(HashValue::sha3_256_of(&salt[..]).as_ref()); 51 | let mut hasher_bytes = [0u8; 32]; 52 | digest.finalize(&mut hasher_bytes); 53 | hasher_bytes 54 | }; 55 | let actual = CryptoHash::hash(&value); 56 | assert_eq!(&expected, actual.as_ref()); 57 | } 58 | 59 | #[test] 60 | fn test_bcs_cryptohash() { 61 | let mut salt = DIEM_HASH_PREFIX.to_vec(); 62 | salt.extend_from_slice(b"Foo"); 63 | 64 | let value = Foo { a: 5, b: 1025 }; 65 | let expected = { 66 | let mut digest = Sha3::v256(); 67 | digest.update(HashValue::sha3_256_of(&salt[..]).as_ref()); 68 | digest.update(&bcs::to_bytes(&value).unwrap()); 69 | let mut hasher_bytes = [0u8; 32]; 70 | digest.finalize(&mut hasher_bytes); 71 | hasher_bytes 72 | }; 73 | let actual = CryptoHash::hash(&value); 74 | assert_eq!(&expected, actual.as_ref()); 75 | } 76 | 77 | #[test] 78 | fn test_bcs_cryptohash_with_generics() { 79 | let value = Baz { a: 5u64, b: 1025 }; 80 | let expected = CryptoHash::hash(&Foo { a: 5, b: 1025 }); 81 | let actual = CryptoHash::hash(&value); 82 | assert_eq!(expected, actual); 83 | } 84 | 85 | fn prefixed_sha3(input: &[u8]) -> [u8; 32] { 86 | let mut sha3 = ::tiny_keccak::Sha3::v256(); 87 | let salt: Vec = [DIEM_HASH_PREFIX, input].concat(); 88 | sha3.update(&salt); 89 | let mut output = [0u8; 32]; 90 | sha3.finalize(&mut output); 91 | output 92 | } 93 | 94 | #[test] 95 | fn test_cryptohasher_salt_access() { 96 | // the salt for this simple struct is expected to be its name 97 | assert_eq!(FooHasher::seed(), &prefixed_sha3(b"Foo")); 98 | assert_eq!(::Hasher::seed(), &prefixed_sha3(b"Foo")); 99 | assert_eq!( 100 | as CryptoHash>::Hasher::seed(), 101 | &prefixed_sha3(b"Foo") 102 | ); 103 | assert_eq!( 104 | as CryptoHash>::Hasher::seed(), 105 | &prefixed_sha3(b"Foo") 106 | ); 107 | assert_eq!(::Hasher::seed(), &prefixed_sha3(b"Foo")); 108 | } 109 | -------------------------------------------------------------------------------- /mvm/tests/gas_bench.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | #[cfg(feature = "bench")] 4 | mod bench { 5 | use crate::common::assets::{ 6 | empty_loop, math_loop, read_write_loop, store_module, vector_loop, 7 | }; 8 | use crate::common::mock::Utils; 9 | use crate::common::mock::{BankMock, EventHandlerMock, StorageMock}; 10 | use crate::common::vm; 11 | use move_core_types::vm_status::StatusCode; 12 | use mvm::io::context::ExecutionContext; 13 | use mvm::mvm::Mvm; 14 | use mvm::types::{Gas, ScriptTx}; 15 | use mvm::Vm; 16 | use std::fmt::{Display, Formatter}; 17 | use std::time::Instant; 18 | 19 | #[test] 20 | fn gas_bench() { 21 | let (vm, _, _, _) = vm(); 22 | vm.pub_mod(store_module()); 23 | 24 | let mut avg = Avg::default(); 25 | find_gas_per_seconds(&vm, &mut avg, empty_loop, "empty_loop"); 26 | find_gas_per_seconds(&vm, &mut avg, math_loop, "math_loop"); 27 | find_gas_per_seconds(&vm, &mut avg, read_write_loop, "read_write_loop"); 28 | find_gas_per_seconds(&vm, &mut avg, vector_loop, "vector_loop"); 29 | 30 | println!("Gas avg: {}", avg); 31 | } 32 | 33 | fn find_gas_per_seconds( 34 | vm: &Mvm, 35 | avg: &mut Avg, 36 | script_supplier: S, 37 | name: &str, 38 | ) where 39 | S: Fn(u64) -> ScriptTx, 40 | { 41 | for _ in 0..10 { 42 | let gas = calc_gas_per_seconds(vm, &script_supplier); 43 | println!("Check script {}: gas: {}", name, gas); 44 | avg.add(gas); 45 | } 46 | } 47 | 48 | fn calc_gas_per_seconds( 49 | vm: &Mvm, 50 | script_supplier: &S, 51 | ) -> u64 52 | where 53 | S: Fn(u64) -> ScriptTx, 54 | { 55 | let mut total_time = 0; 56 | let mut total_gas = 0; 57 | while total_time < 10_000 { 58 | let script = script_supplier(10_000); 59 | let gas = Gas::new(18446744073709550, 1).unwrap(); 60 | let context = ExecutionContext::new(100, 100); 61 | let now = Instant::now(); 62 | let res = vm.execute_script(gas, context, script, false); 63 | let elapsed = now.elapsed().as_millis(); 64 | if res.status_code != StatusCode::EXECUTED { 65 | panic!("Transaction failed: {:?}", res); 66 | } 67 | total_time += elapsed; 68 | total_gas += res.gas_used; 69 | } 70 | 71 | total_gas / (total_time as u64 / 1000) 72 | } 73 | 74 | #[derive(Debug)] 75 | struct Results { 76 | time: u128, 77 | gas: u64, 78 | iter: u64, 79 | } 80 | 81 | #[derive(Default)] 82 | struct Avg { 83 | vec: Vec, 84 | } 85 | 86 | impl Avg { 87 | pub fn add(&mut self, val: u64) { 88 | self.vec.push(val) 89 | } 90 | } 91 | 92 | impl Display for Avg { 93 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 94 | let avg = (self.vec.iter().sum::() as f64) / self.vec.len() as f64; 95 | 96 | let sum: f64 = self 97 | .vec 98 | .iter() 99 | .map(|val| *val as f64) 100 | .map(|val| (val - avg).powf(2.0)) 101 | .sum(); 102 | 103 | write!(f, "{} ± {}", avg, (sum / avg.powf(2.0)).sqrt()) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /language/bytecode-verifier/invalid-mutations/src/signature.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use move_binary_format::file_format::{ 5 | CompiledModule, Signature, SignatureToken, StructFieldInformation, TypeSignature, 6 | }; 7 | use proptest::sample::Index as PropIndex; 8 | 9 | pub struct SignatureRefMutation<'a> { 10 | module: &'a mut CompiledModule, 11 | mutations: Vec<(PropIndex, PropIndex)>, 12 | } 13 | 14 | impl<'a> SignatureRefMutation<'a> { 15 | pub fn new(module: &'a mut CompiledModule, mutations: Vec<(PropIndex, PropIndex)>) -> Self { 16 | Self { module, mutations } 17 | } 18 | 19 | pub fn apply(self) -> bool { 20 | if self.module.signatures.is_empty() { 21 | return false; 22 | } 23 | let module = self.module; 24 | let mut mutations = false; 25 | for (s_idx, t_idx) in self.mutations { 26 | let sig_idx = s_idx.index(module.signatures.len()); 27 | let sig = &module.signatures[sig_idx]; 28 | if sig.is_empty() { 29 | continue; 30 | } 31 | let token_idx = t_idx.index(sig.len()); 32 | let new_sig = mutate_sig(sig, token_idx); 33 | module.signatures[sig_idx] = new_sig; 34 | mutations = true; 35 | } 36 | mutations 37 | } 38 | } 39 | 40 | /// Context for applying a list of `FieldRefMutation` instances. 41 | pub struct FieldRefMutation<'a> { 42 | module: &'a mut CompiledModule, 43 | mutations: Vec<(PropIndex, PropIndex)>, 44 | } 45 | 46 | impl<'a> FieldRefMutation<'a> { 47 | pub fn new(module: &'a mut CompiledModule, mutations: Vec<(PropIndex, PropIndex)>) -> Self { 48 | Self { module, mutations } 49 | } 50 | 51 | #[inline] 52 | pub fn apply(self) -> bool { 53 | if self.module.struct_defs.is_empty() { 54 | return false; 55 | } 56 | let module = self.module; 57 | let mut mutations = false; 58 | for (s_idx, f_idx) in self.mutations { 59 | let struct_idx = s_idx.index(module.struct_defs.len()); 60 | let struct_def = &mut module.struct_defs[struct_idx]; 61 | if let StructFieldInformation::Declared(fields) = &mut struct_def.field_information { 62 | if fields.is_empty() { 63 | continue; 64 | } 65 | let field_idx = f_idx.index(fields.len()); 66 | let field_def = &mut fields[field_idx]; 67 | let new_ty = mutate_field(&field_def.signature.0); 68 | fields[field_idx].signature = TypeSignature(new_ty); 69 | mutations = true; 70 | } 71 | } 72 | mutations 73 | } 74 | } 75 | 76 | fn mutate_sig(sig: &Signature, token_idx: usize) -> Signature { 77 | use SignatureToken::*; 78 | 79 | Signature( 80 | sig.0 81 | .iter() 82 | .enumerate() 83 | .map(|(idx, token)| { 84 | if idx == token_idx { 85 | match &token { 86 | Reference(_) | MutableReference(_) => Reference(Box::new(token.clone())), 87 | _ => Reference(Box::new(Reference(Box::new(token.clone())))), 88 | } 89 | } else { 90 | token.clone() 91 | } 92 | }) 93 | .collect(), 94 | ) 95 | } 96 | 97 | fn mutate_field(token: &SignatureToken) -> SignatureToken { 98 | SignatureToken::Reference(Box::new(token.clone())) 99 | } 100 | -------------------------------------------------------------------------------- /language/move-vm/types/src/loaded_data/runtime_types.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use alloc::boxed::Box; 5 | use alloc::vec::Vec; 6 | use move_binary_format::{ 7 | errors::{PartialVMError, PartialVMResult}, 8 | file_format::{AbilitySet, StructDefinitionIndex, StructTypeParameter}, 9 | }; 10 | use move_core_types::{identifier::Identifier, language_storage::ModuleId, vm_status::StatusCode}; 11 | 12 | pub const TYPE_DEPTH_MAX: usize = 256; 13 | 14 | #[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] 15 | pub struct StructType { 16 | pub fields: Vec, 17 | pub abilities: AbilitySet, 18 | pub type_parameters: Vec, 19 | pub name: Identifier, 20 | pub module: ModuleId, 21 | pub struct_def: StructDefinitionIndex, 22 | } 23 | 24 | impl StructType { 25 | pub fn type_param_constraints(&self) -> impl ExactSizeIterator { 26 | self.type_parameters.iter().map(|param| ¶m.constraints) 27 | } 28 | } 29 | 30 | #[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] 31 | pub enum Type { 32 | Bool, 33 | U8, 34 | U64, 35 | U128, 36 | Address, 37 | Signer, 38 | Vector(Box), 39 | Struct(usize), 40 | StructInstantiation(usize, Vec), 41 | Reference(Box), 42 | MutableReference(Box), 43 | TyParam(usize), 44 | } 45 | 46 | impl Type { 47 | fn clone_impl(&self, depth: usize) -> PartialVMResult { 48 | self.apply_subst(|idx, _| Ok(Type::TyParam(idx)), depth) 49 | } 50 | 51 | fn apply_subst(&self, subst: F, depth: usize) -> PartialVMResult 52 | where 53 | F: Fn(usize, usize) -> PartialVMResult + Copy, 54 | { 55 | if depth > TYPE_DEPTH_MAX { 56 | return Err(PartialVMError::new(StatusCode::VM_MAX_TYPE_DEPTH_REACHED)); 57 | } 58 | let res = match self { 59 | Type::TyParam(idx) => subst(*idx, depth)?, 60 | Type::Bool => Type::Bool, 61 | Type::U8 => Type::U8, 62 | Type::U64 => Type::U64, 63 | Type::U128 => Type::U128, 64 | Type::Address => Type::Address, 65 | Type::Signer => Type::Signer, 66 | Type::Vector(ty) => Type::Vector(Box::new(ty.apply_subst(subst, depth + 1)?)), 67 | Type::Reference(ty) => Type::Reference(Box::new(ty.apply_subst(subst, depth + 1)?)), 68 | Type::MutableReference(ty) => { 69 | Type::MutableReference(Box::new(ty.apply_subst(subst, depth + 1)?)) 70 | } 71 | Type::Struct(def_idx) => Type::Struct(*def_idx), 72 | Type::StructInstantiation(def_idx, instantiation) => { 73 | let mut inst = vec![]; 74 | for ty in instantiation { 75 | inst.push(ty.apply_subst(subst, depth + 1)?) 76 | } 77 | Type::StructInstantiation(*def_idx, inst) 78 | } 79 | }; 80 | Ok(res) 81 | } 82 | 83 | pub fn subst(&self, ty_args: &[Type]) -> PartialVMResult { 84 | self.apply_subst( 85 | |idx, depth| match ty_args.get(idx) { 86 | Some(ty) => ty.clone_impl(depth), 87 | None => Err( 88 | PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) 89 | .with_message(format!( 90 | "type substitution failed: index out of bounds -- len {} got {}", 91 | ty_args.len(), 92 | idx 93 | )), 94 | ), 95 | }, 96 | 1, 97 | ) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /common/cell/src/lazy.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | 3 | #[cfg(feature = "std")] 4 | use core::ops::DerefMut; 5 | 6 | use crate::once_cell::OnceCell; 7 | use core::cell::Cell; 8 | use core::fmt; 9 | 10 | #[cfg(feature = "std")] 11 | use std::panic::RefUnwindSafe; 12 | 13 | /// A value which is initialized on the first access. 14 | /// 15 | /// This type is thread-safe and can be used in statics. 16 | /// 17 | /// # Example 18 | /// 19 | /// ``` 20 | /// use std::collections::HashMap; 21 | /// 22 | /// use once_cell::sync::Lazy; 23 | /// 24 | /// static HASHMAP: Lazy> = Lazy::new(|| { 25 | /// println!("initializing"); 26 | /// let mut m = HashMap::new(); 27 | /// m.insert(13, "Spica".to_string()); 28 | /// m.insert(74, "Hoyten".to_string()); 29 | /// m 30 | /// }); 31 | /// 32 | /// fn main() { 33 | /// println!("ready"); 34 | /// std::thread::spawn(|| { 35 | /// println!("{:?}", HASHMAP.get(&13)); 36 | /// }).join().unwrap(); 37 | /// println!("{:?}", HASHMAP.get(&74)); 38 | /// 39 | /// // Prints: 40 | /// // ready 41 | /// // initializing 42 | /// // Some("Spica") 43 | /// // Some("Hoyten") 44 | /// } 45 | /// ``` 46 | pub struct Lazy T> { 47 | cell: OnceCell, 48 | init: Cell>, 49 | } 50 | 51 | impl fmt::Debug for Lazy { 52 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 53 | f.debug_struct("Lazy") 54 | .field("cell", &self.cell) 55 | .field("init", &"..") 56 | .finish() 57 | } 58 | } 59 | 60 | // We never create a `&F` from a `&Lazy` so it is fine 61 | // to not impl `Sync` for `F` 62 | // we do create a `&mut Option` in `force`, but this is 63 | // properly synchronized, so it only happens once 64 | // so it also does not contribute to this impl. 65 | unsafe impl Sync for Lazy where OnceCell: Sync {} 66 | // auto-derived `Send` impl is OK. 67 | 68 | #[cfg(feature = "std")] 69 | impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} 70 | 71 | impl Lazy { 72 | /// Creates a new lazy value with the given initializing 73 | /// function. 74 | pub const fn new(f: F) -> Lazy { 75 | Lazy { 76 | cell: OnceCell::new(), 77 | init: Cell::new(Some(f)), 78 | } 79 | } 80 | } 81 | 82 | impl T> Lazy { 83 | /// Forces the evaluation of this lazy value and 84 | /// returns a reference to the result. This is equivalent 85 | /// to the `Deref` impl, but is explicit. 86 | /// 87 | /// # Example 88 | /// ``` 89 | /// use once_cell::sync::Lazy; 90 | /// 91 | /// let lazy = Lazy::new(|| 92); 92 | /// 93 | /// assert_eq!(Lazy::force(&lazy), &92); 94 | /// assert_eq!(&*lazy, &92); 95 | /// ``` 96 | pub fn force(this: &Lazy) -> &T { 97 | this.cell.get_or_init(|| match this.init.take() { 98 | Some(f) => f(), 99 | None => panic!("Lazy instance has previously been poisoned"), 100 | }) 101 | } 102 | } 103 | 104 | impl T> Deref for Lazy { 105 | type Target = T; 106 | fn deref(&self) -> &T { 107 | Lazy::force(self) 108 | } 109 | } 110 | 111 | #[cfg(feature = "std")] 112 | impl T> DerefMut for Lazy { 113 | fn deref_mut(&mut self) -> &mut T { 114 | Lazy::force(self); 115 | self.cell.get_mut().unwrap_or_else(|| unreachable!()) 116 | } 117 | } 118 | 119 | impl Default for Lazy { 120 | /// Creates a new lazy value using `Default` as the initializing function. 121 | fn default() -> Lazy { 122 | Lazy::new(T::default) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /language/move-core/types/src/unit_tests/address_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::account_address::AccountAddress; 5 | use diem_crypto::{hash::CryptoHash, HashValue}; 6 | use hex::FromHex; 7 | use proptest::prelude::*; 8 | use std::{ 9 | convert::{AsRef, TryFrom}, 10 | str::FromStr, 11 | }; 12 | 13 | #[test] 14 | fn test_address_bytes() { 15 | let hex = Vec::from_hex("ca843279e3427144cead5e4d5999a3d0ca843279e3427144cead5e4d5999a3d0") 16 | .expect("You must provide a valid Hex format"); 17 | 18 | assert_eq!( 19 | hex.len(), 20 | AccountAddress::LENGTH as usize, 21 | "Address {:?} is not {}-bytes long. Addresses must be {} bytes", 22 | hex, 23 | AccountAddress::LENGTH, 24 | AccountAddress::LENGTH, 25 | ); 26 | let address = AccountAddress::try_from(&hex[..]).unwrap_or_else(|_| { 27 | panic!( 28 | "The address {:?} is of invalid length. Addresses must be 32-bytes long", 29 | &hex 30 | ) 31 | }); 32 | 33 | assert_eq!(address.as_ref().to_vec(), hex); 34 | } 35 | 36 | #[test] 37 | fn test_address() { 38 | let hex = Vec::from_hex("ca843279e3427144cead5e4d5999a3d0ca843279e3427144cead5e4d5999a3d0") 39 | .expect("You must provide a valid Hex format"); 40 | 41 | assert_eq!( 42 | hex.len(), 43 | AccountAddress::LENGTH as usize, 44 | "Address {:?} is not {}-bytes long. Addresses must be {} bytes", 45 | hex, 46 | AccountAddress::LENGTH, 47 | AccountAddress::LENGTH, 48 | ); 49 | 50 | let address: AccountAddress = AccountAddress::try_from(&hex[..]).unwrap_or_else(|_| { 51 | panic!( 52 | "The address {:?} is of invalid length. Addresses must be 32-bytes long", 53 | &hex 54 | ) 55 | }); 56 | 57 | let hash_vec = 58 | &Vec::from_hex("81fdf1b3fe04abd62ada9adc8852fab3d1b145b875c259f017e697ea2f4da249") 59 | .expect("You must provide a valid Hex format"); 60 | 61 | let mut hash = [0u8; 32]; 62 | let bytes = &hash_vec[..32]; 63 | hash.copy_from_slice(&bytes); 64 | 65 | assert_eq!(address.hash(), HashValue::new(hash)); 66 | assert_eq!(address.as_ref().to_vec(), hex); 67 | } 68 | 69 | #[test] 70 | fn test_ref() { 71 | let address = AccountAddress::new([1u8; AccountAddress::LENGTH]); 72 | let _: &[u8] = address.as_ref(); 73 | } 74 | 75 | #[test] 76 | fn test_address_from_proto_invalid_length() { 77 | let bytes = vec![1; 123]; 78 | assert!(AccountAddress::try_from(&bytes[..]).is_err()); 79 | } 80 | 81 | #[test] 82 | fn test_deserialize_from_json_value() { 83 | let address = AccountAddress::random(); 84 | let json_value = serde_json::to_value(address).expect("serde_json::to_value fail."); 85 | let address2: AccountAddress = 86 | serde_json::from_value(json_value).expect("serde_json::from_value fail."); 87 | assert_eq!(address, address2) 88 | } 89 | 90 | #[test] 91 | fn test_address_from_empty_string() { 92 | assert!(AccountAddress::try_from("".to_string()).is_err()); 93 | assert!(AccountAddress::from_str("").is_err()); 94 | } 95 | 96 | proptest! { 97 | #[test] 98 | fn test_address_string_roundtrip(addr in any::()) { 99 | let s = String::from(&addr); 100 | let addr2 = AccountAddress::try_from(s).expect("roundtrip to string should work"); 101 | prop_assert_eq!(addr, addr2); 102 | } 103 | 104 | #[test] 105 | fn test_address_protobuf_roundtrip(addr in any::()) { 106 | let bytes = addr.to_vec(); 107 | prop_assert_eq!(bytes.clone(), addr.as_ref()); 108 | let addr2 = AccountAddress::try_from(&bytes[..]).unwrap(); 109 | prop_assert_eq!(addr, addr2); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /language/move-core/types/src/errmap.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::language_storage::ModuleId; 5 | use alloc::collections::BTreeMap; 6 | use alloc::string::String; 7 | use anyhow::{bail, Result}; 8 | use serde::{Deserialize, Serialize}; 9 | #[cfg(feature = "std")] 10 | use std::{ 11 | fs::File, 12 | io::{Read, Write}, 13 | path::Path, 14 | }; 15 | 16 | #[derive(Debug, Clone, Serialize, Deserialize)] 17 | pub struct ErrorDescription { 18 | /// The constant name of error e.g., ECANT_PAY_DEPOSIT 19 | pub code_name: String, 20 | /// The code description. This is generated from the doc comments on the constant. 21 | pub code_description: String, 22 | } 23 | 24 | #[derive(Debug, Clone, Serialize, Deserialize)] 25 | pub struct ErrorContext { 26 | /// The error category e.g., INVALID_ARGUMENT 27 | pub category: ErrorDescription, 28 | /// The error reason e.g., ECANT_PAY_DEPOSIT 29 | pub reason: ErrorDescription, 30 | } 31 | 32 | #[derive(Debug, Clone, Serialize, Deserialize)] 33 | pub struct ErrorMapping { 34 | /// The set of error categories and their descriptions 35 | pub error_categories: BTreeMap, 36 | /// The set of modules, and the module-specific errors 37 | pub module_error_maps: BTreeMap>, 38 | } 39 | 40 | impl Default for ErrorMapping { 41 | fn default() -> Self { 42 | Self { 43 | error_categories: BTreeMap::new(), 44 | module_error_maps: BTreeMap::new(), 45 | } 46 | } 47 | } 48 | 49 | impl ErrorMapping { 50 | pub fn add_error_category( 51 | &mut self, 52 | category_id: u64, 53 | description: ErrorDescription, 54 | ) -> Result<()> { 55 | if let Some(previous_entry) = self.error_categories.insert(category_id, description) { 56 | bail!(format!( 57 | "Entry for category {} already taken by: {:#?}", 58 | category_id, previous_entry 59 | )) 60 | } 61 | Ok(()) 62 | } 63 | 64 | pub fn add_module_error( 65 | &mut self, 66 | module_id: ModuleId, 67 | abort_code: u64, 68 | description: ErrorDescription, 69 | ) -> Result<()> { 70 | let module_error_map = self.module_error_maps.entry(module_id.clone()).or_default(); 71 | if let Some(previous_entry) = module_error_map.insert(abort_code, description) { 72 | bail!(format!( 73 | "Duplicate entry for abort code {} found in {}, previous entry: {:#?}", 74 | abort_code, module_id, previous_entry 75 | )) 76 | } 77 | Ok(()) 78 | } 79 | 80 | #[cfg(feature = "std")] 81 | pub fn from_file>(path: P) -> Self { 82 | let mut bytes = Vec::new(); 83 | File::open(path).unwrap().read_to_end(&mut bytes).unwrap(); 84 | bcs::from_bytes(&bytes).unwrap() 85 | } 86 | 87 | #[cfg(feature = "std")] 88 | pub fn to_file>(&self, path: P) { 89 | let bytes = bcs::to_bytes(self).unwrap(); 90 | let mut file = File::create(path).unwrap(); 91 | file.write_all(&bytes).unwrap(); 92 | } 93 | 94 | pub fn get_explanation(&self, module: &ModuleId, output_code: u64) -> Option { 95 | let category = output_code & 0xFFu64; 96 | let reason_code = output_code >> 8; 97 | self.error_categories.get(&category).and_then(|category| { 98 | self.module_error_maps.get(module).and_then(|module_map| { 99 | module_map.get(&reason_code).map(|reason| ErrorContext { 100 | category: category.clone(), 101 | reason: reason.clone(), 102 | }) 103 | }) 104 | }) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /language/move-vm/types/src/values/value_tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) The Diem Core Contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use crate::values::*; 5 | use move_binary_format::errors::*; 6 | 7 | #[test] 8 | fn locals() -> PartialVMResult<()> { 9 | const LEN: usize = 4; 10 | let mut locals = Locals::new(LEN); 11 | for i in 0..LEN { 12 | assert!(locals.copy_loc(i).is_err()); 13 | assert!(locals.move_loc(i).is_err()); 14 | assert!(locals.borrow_loc(i).is_err()); 15 | } 16 | locals.store_loc(1, Value::u64(42))?; 17 | 18 | assert!(locals.copy_loc(1)?.equals(&Value::u64(42))?); 19 | let r = locals.borrow_loc(1)?.value_as::()?; 20 | assert!(r.read_ref()?.equals(&Value::u64(42))?); 21 | assert!(locals.move_loc(1)?.equals(&Value::u64(42))?); 22 | 23 | assert!(locals.copy_loc(1).is_err()); 24 | assert!(locals.move_loc(1).is_err()); 25 | assert!(locals.borrow_loc(1).is_err()); 26 | 27 | assert!(locals.copy_loc(LEN + 1).is_err()); 28 | assert!(locals.move_loc(LEN + 1).is_err()); 29 | assert!(locals.borrow_loc(LEN + 1).is_err()); 30 | 31 | Ok(()) 32 | } 33 | 34 | #[test] 35 | fn struct_pack_and_unpack() -> PartialVMResult<()> { 36 | let vals = vec![Value::u8(10), Value::u64(20), Value::u128(30)]; 37 | let s = Struct::pack(vec![Value::u8(10), Value::u64(20), Value::u128(30)]); 38 | let unpacked: Vec<_> = s.unpack()?.collect(); 39 | 40 | assert!(vals.len() == unpacked.len()); 41 | for (v1, v2) in vals.iter().zip(unpacked.iter()) { 42 | assert!(v1.equals(v2)?); 43 | } 44 | 45 | Ok(()) 46 | } 47 | 48 | #[test] 49 | fn struct_borrow_field() -> PartialVMResult<()> { 50 | let mut locals = Locals::new(1); 51 | locals.store_loc( 52 | 0, 53 | Value::struct_(Struct::pack(vec![Value::u8(10), Value::bool(false)])), 54 | )?; 55 | let r: StructRef = locals.borrow_loc(0)?.value_as()?; 56 | 57 | { 58 | let f: Reference = r.borrow_field(1)?.value_as()?; 59 | assert!(f.read_ref()?.equals(&Value::bool(false))?); 60 | } 61 | 62 | { 63 | let f: Reference = r.borrow_field(1)?.value_as()?; 64 | f.write_ref(Value::bool(true))?; 65 | } 66 | 67 | { 68 | let f: Reference = r.borrow_field(1)?.value_as()?; 69 | assert!(f.read_ref()?.equals(&Value::bool(true))?); 70 | } 71 | 72 | Ok(()) 73 | } 74 | 75 | #[test] 76 | fn struct_borrow_nested() -> PartialVMResult<()> { 77 | let mut locals = Locals::new(1); 78 | 79 | fn inner(x: u64) -> Value { 80 | Value::struct_(Struct::pack(vec![Value::u64(x)])) 81 | } 82 | fn outer(x: u64) -> Value { 83 | Value::struct_(Struct::pack(vec![Value::u8(10), inner(x)])) 84 | } 85 | 86 | locals.store_loc(0, outer(20))?; 87 | let r1: StructRef = locals.borrow_loc(0)?.value_as()?; 88 | let r2: StructRef = r1.borrow_field(1)?.value_as()?; 89 | 90 | { 91 | let r3: Reference = r2.borrow_field(0)?.value_as()?; 92 | assert!(r3.read_ref()?.equals(&Value::u64(20))?); 93 | } 94 | 95 | { 96 | let r3: Reference = r2.borrow_field(0)?.value_as()?; 97 | r3.write_ref(Value::u64(30))?; 98 | } 99 | 100 | { 101 | let r3: Reference = r2.borrow_field(0)?.value_as()?; 102 | assert!(r3.read_ref()?.equals(&Value::u64(30))?); 103 | } 104 | 105 | assert!(r2.read_ref()?.equals(&inner(30))?); 106 | assert!(r1.read_ref()?.equals(&outer(30))?); 107 | 108 | Ok(()) 109 | } 110 | 111 | #[test] 112 | fn global_value_non_struct() -> PartialVMResult<()> { 113 | assert!(GlobalValue::cached(Value::u64(100)).is_err()); 114 | assert!(GlobalValue::cached(Value::bool(false)).is_err()); 115 | 116 | let mut locals = Locals::new(1); 117 | locals.store_loc(0, Value::u8(0))?; 118 | let r = locals.borrow_loc(0)?; 119 | assert!(GlobalValue::cached(r).is_err()); 120 | 121 | Ok(()) 122 | } 123 | --------------------------------------------------------------------------------