diff --git a/Cargo.lock b/Cargo.lock index adfc6b8021bc6..bb9652f475855 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,15 +101,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aho-corasick" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" -dependencies = [ - "memchr", -] - [[package]] name = "aliasable" version = "0.1.3" @@ -4466,6 +4457,16 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + [[package]] name = "bumpalo" version = "3.11.0" @@ -5017,7 +5018,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e4b6aa369f41f5faa04bb80c9b1f4216ea81646ed6124d76ba5c49a7aafd9cd" dependencies = [ "cookie", - "idna 0.2.3", + "idna", "log", "publicsuffix", "serde 1.0.149", @@ -6152,10 +6153,11 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ + "matches", "percent-encoding", ] @@ -6167,9 +6169,9 @@ checksum = "85dcb89d2b10c5f6133de2efd8c11959ce9dbb46a2f7a4cab208c4eeda6ce1ab" [[package]] name = "fs_extra" -version = "1.3.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "funty" @@ -6484,7 +6486,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ - "aho-corasick 0.7.18", + "aho-corasick", "bstr", "fnv", "log", @@ -6806,9 +6808,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "httpmock" -version = "0.6.7" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b56b6265f15908780cbee987912c1e98dbca675361f748291605a8a3a1df09" +checksum = "c159c4fc205e6c1a9b325cb7ec135d13b5f47188ce175dabb76ec847f331d9bd" dependencies = [ "assert-json-diff", "async-object-pool", @@ -6938,16 +6940,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "ignore" version = "0.4.18" @@ -7468,7 +7460,7 @@ dependencies = [ "petgraph 0.6.2", "pico-args", "regex", - "regex-syntax 0.6.27", + "regex-syntax", "string_cache", "term", "tiny-keccak", @@ -7638,12 +7630,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "libm" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" - [[package]] name = "libnghttp2-sys" version = "0.1.7+1.45.0" @@ -9006,9 +8992,9 @@ dependencies = [ [[package]] name = "multer" -version = "2.1.0" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +checksum = "a30ba6d97eb198c5e8a35d67d5779d6680cca35652a60ee90fc23dc431d4fde8" dependencies = [ "bytes", "encoding_rs", @@ -9023,6 +9009,24 @@ dependencies = [ "version_check", ] +[[package]] +name = "multipart" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" +dependencies = [ + "buf_redux", + "httparse", + "log", + "mime", + "mime_guess", + "quick-error 1.2.3", + "rand 0.8.5", + "safemem", + "tempfile", + "twoway", +] + [[package]] name = "named-lock" version = "0.2.0" @@ -9257,7 +9261,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -9612,9 +9615,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" @@ -10178,22 +10181,22 @@ dependencies = [ [[package]] name = "proptest" -version = "1.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" dependencies = [ "bit-set", "bitflags 1.3.2", "byteorder", "lazy_static 1.4.0", "num-traits 0.2.15", + "quick-error 2.0.1", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.6.27", + "regex-syntax", "rusty-fork", "tempfile", - "unarray", ] [[package]] @@ -10268,7 +10271,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aeeedb0b429dc462f30ad27ef3de97058b060016f47790c066757be38ef792b4" dependencies = [ - "idna 0.2.3", + "idna", "psl-types", ] @@ -10303,6 +10306,12 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.22.0" @@ -10595,13 +10604,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-syntax", ] [[package]] @@ -10610,7 +10619,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax 0.6.27", + "regex-syntax", ] [[package]] @@ -10619,12 +10628,6 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" - [[package]] name = "remove_dir_all" version = "0.5.3" @@ -10956,7 +10959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", - "quick-error", + "quick-error 1.2.3", "tempfile", "wait-timeout", ] @@ -10967,6 +10970,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "same-file" version = "1.0.6" @@ -11322,17 +11331,6 @@ dependencies = [ "digest 0.10.5", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.5", -] - [[package]] name = "sha1_smol" version = "1.0.0" @@ -12132,9 +12130,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.26.0" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ "autocfg", "bytes", @@ -12148,7 +12146,7 @@ dependencies = [ "socket2", "tokio-macros", "tracing", - "windows-sys 0.45.0", + "winapi 0.3.9", ] [[package]] @@ -12241,9 +12239,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log", @@ -12597,9 +12595,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" dependencies = [ "base64 0.13.0", "byteorder", @@ -12608,12 +12606,21 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha1", + "sha-1", "thiserror", "url", "utf-8", ] +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -12666,12 +12673,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - [[package]] name = "uncased" version = "0.9.7" @@ -12742,9 +12743,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" @@ -12763,9 +12764,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" dependencies = [ "tinyvec", ] @@ -12835,12 +12836,13 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna", + "matches", "percent-encoding", "serde 1.0.149", ] @@ -12965,9 +12967,9 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69" +checksum = "ed7b8be92646fc3d18b06147664ebc5f48d222686cb11a8755e561a735aacc6d" dependencies = [ "bytes", "futures-channel", @@ -12978,10 +12980,10 @@ dependencies = [ "log", "mime", "mime_guess", - "multer", + "multipart", "percent-encoding", "pin-project", - "rustls-pemfile 1.0.1", + "rustls-pemfile 0.2.1", "scoped-tls", "serde 1.0.149", "serde_json", diff --git a/aptos-move/aptos-gas/src/aptos_framework.rs b/aptos-move/aptos-gas/src/aptos_framework.rs index 478eef0ec8908..550f4e490d1ef 100644 --- a/aptos-move/aptos-gas/src/aptos_framework.rs +++ b/aptos-move/aptos-gas/src/aptos_framework.rs @@ -163,7 +163,10 @@ crate::natives::define_gas_parameters_for_natives!(GasParameters, "aptos_framewo [.util.from_bytes.base, "util.from_bytes.base", 300 * MUL], [.util.from_bytes.per_byte, "util.from_bytes.per_byte", 5 * MUL], + [.transaction_context.get_txn_hash.base, { 10.. => "transaction_context.get_txn_hash.base" }, 200 * MUL], [.transaction_context.get_script_hash.base, "transaction_context.get_script_hash.base", 200 * MUL], + // Based on SHA3-256's cost + [.transaction_context.generate_unique_address.base, { 10.. => "transaction_context.generate_unique_address.base" }, 4000 * MUL], [.code.request_publish.base, "code.request_publish.base", 500 * MUL], [.code.request_publish.per_byte, "code.request_publish.per_byte", 2 * MUL], diff --git a/aptos-move/aptos-gas/src/gas_meter.rs b/aptos-move/aptos-gas/src/gas_meter.rs index 93438c868456d..f49754cf551b5 100644 --- a/aptos-move/aptos-gas/src/gas_meter.rs +++ b/aptos-move/aptos-gas/src/gas_meter.rs @@ -34,6 +34,7 @@ use std::collections::BTreeMap; // Change log: // - V10 +// - Added generate_unique_address and get_txn_hash native functions // - Storage gas charges (excluding "storage fees") stop respecting the storage gas curves // - V9 // - Accurate tracking of the cost of loading resource groups diff --git a/aptos-move/aptos-vm/src/move_vm_ext/vm.rs b/aptos-move/aptos-vm/src/move_vm_ext/vm.rs index c4e6df56eeabd..56e263b05544b 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/vm.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/vm.rs @@ -113,7 +113,11 @@ impl MoveVmExt { _ => vec![], }; - extensions.add(NativeTransactionContext::new(script_hash, self.chain_id)); + extensions.add(NativeTransactionContext::new( + txn_hash.to_vec(), + script_hash, + self.chain_id, + )); extensions.add(NativeCodeContext::default()); extensions.add(NativeStateStorageContext::new(remote)); diff --git a/aptos-move/aptos-vm/src/natives.rs b/aptos-move/aptos-vm/src/natives.rs index eb4dfef998e23..4ee79f9a027dc 100644 --- a/aptos-move/aptos-vm/src/natives.rs +++ b/aptos-move/aptos-vm/src/natives.rs @@ -91,7 +91,11 @@ pub fn configure_for_unit_test() { #[cfg(feature = "testing")] fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) { exts.add(NativeCodeContext::default()); - exts.add(NativeTransactionContext::new(vec![1], ChainId::test().id())); // We use the testing environment chain ID here + exts.add(NativeTransactionContext::new( + vec![1], + vec![1], + ChainId::test().id(), + )); // We use the testing environment chain ID here exts.add(NativeAggregatorContext::new( [0; 32], &*DUMMY_RESOLVER, diff --git a/aptos-move/framework/aptos-framework/doc/object.md b/aptos-move/framework/aptos-framework/doc/object.md index 99ceda65c242d..ec9e34f94b1bd 100644 --- a/aptos-move/framework/aptos-framework/doc/object.md +++ b/aptos-move/framework/aptos-framework/doc/object.md @@ -42,6 +42,7 @@ make it so that a reference to a global object can be returned from a function. - [Function `convert`](#0x1_object_convert) - [Function `create_named_object`](#0x1_object_create_named_object) - [Function `create_user_derived_object`](#0x1_object_create_user_derived_object) +- [Function `create_object`](#0x1_object_create_object) - [Function `create_object_from_account`](#0x1_object_create_object_from_account) - [Function `create_object_from_object`](#0x1_object_create_object_from_object) - [Function `create_object_from_guid`](#0x1_object_create_object_from_guid) @@ -87,6 +88,7 @@ make it so that a reference to a global object can be returned from a function. use 0x1::guid; use 0x1::hash; use 0x1::signer; +use 0x1::transaction_context; use 0x1::vector; @@ -227,8 +229,7 @@ This is a one time ability given to the creator to configure the object as neces can_delete: bool
- Set to true so long as deleting the object is possible. For example, the object was - created via create_object_from_guid. + True if the object can be deleted. Named objects are not deletable.
@@ -427,6 +428,16 @@ Emitted whenever the object's owner field is changed. ## Constants + + +generate_unique_address uses this for domain separation within its native implementation + + +
const DERIVE_AUID_ADDRESS_SCHEME: u8 = 251;
+
+ + + The object does not allow for deletion @@ -828,16 +839,51 @@ Derivde objects, similar to named objects, cannot be deleted. + + + + +## Function `create_object` + +Create a new object by generating a random unique address based on transaction hash. +The unique address is computed sha3_256([transaction hash | auid counter | 0xFB]). +The created object is deletable as we can guarantee the same unique address can +never be regenerated with future txs. + + +
public fun create_object(owner_address: address): object::ConstructorRef
+
+ + + +
+Implementation + + +
public fun create_object(owner_address: address): ConstructorRef {
+    let unique_address = transaction_context::generate_auid_address();
+    create_object_internal(owner_address, unique_address, true)
+}
+
+ + +
## Function `create_object_from_account` +Use create_object instead. Create a new object from a GUID generated by an account. +As the GUID creation internally increments a counter, two transactions that executes +create_object_from_account function for the same creator run sequentially. +Therefore, using create_object method for creating objects is preferrable as it +doesn't have the same bottlenecks. -
public fun create_object_from_account(creator: &signer): object::ConstructorRef
+
#[deprecated]
+public fun create_object_from_account(creator: &signer): object::ConstructorRef
 
@@ -860,10 +906,16 @@ Create a new object from a GUID generated by an account. ## Function `create_object_from_object` +Use create_object instead. Create a new object from a GUID generated by an object. +As the GUID creation internally increments a counter, two transactions that executes +create_object_from_object function for the same creator run sequentially. +Therefore, using create_object method for creating objects is preferrable as it +doesn't have the same bottlenecks. -
public fun create_object_from_object(creator: &signer): object::ConstructorRef
+
#[deprecated]
+public fun create_object_from_object(creator: &signer): object::ConstructorRef
 
diff --git a/aptos-move/framework/aptos-framework/doc/staking_config.md b/aptos-move/framework/aptos-framework/doc/staking_config.md index 92e77e132bfdf..d0f21450963a2 100644 --- a/aptos-move/framework/aptos-framework/doc/staking_config.md +++ b/aptos-move/framework/aptos-framework/doc/staking_config.md @@ -1191,7 +1191,8 @@ StakingRewardsConfig does not exist under the aptos_framework before creating it -
aborts_if !exists<StakingRewardsConfig>(@aptos_framework);
+
pragma verify_duration_estimate = 120;
+aborts_if !exists<StakingRewardsConfig>(@aptos_framework);
 aborts_if !features::spec_periodical_reward_rate_decrease_enabled();
 include StakingRewardsConfigRequirement;
 
diff --git a/aptos-move/framework/aptos-framework/doc/transaction_context.md b/aptos-move/framework/aptos-framework/doc/transaction_context.md index 981c01a44b618..791e456e810d3 100644 --- a/aptos-move/framework/aptos-framework/doc/transaction_context.md +++ b/aptos-move/framework/aptos-framework/doc/transaction_context.md @@ -5,15 +5,178 @@ +- [Struct `AUID`](#0x1_transaction_context_AUID) +- [Constants](#@Constants_0) +- [Function `get_txn_hash`](#0x1_transaction_context_get_txn_hash) +- [Function `get_transaction_hash`](#0x1_transaction_context_get_transaction_hash) +- [Function `generate_unique_address`](#0x1_transaction_context_generate_unique_address) +- [Function `generate_auid_address`](#0x1_transaction_context_generate_auid_address) - [Function `get_script_hash`](#0x1_transaction_context_get_script_hash) -- [Specification](#@Specification_0) - - [Function `get_script_hash`](#@Specification_0_get_script_hash) +- [Function `generate_auid`](#0x1_transaction_context_generate_auid) +- [Function `auid_address`](#0x1_transaction_context_auid_address) +- [Specification](#@Specification_1) + - [Function `get_txn_hash`](#@Specification_1_get_txn_hash) + - [Function `generate_unique_address`](#@Specification_1_generate_unique_address) + - [Function `get_script_hash`](#@Specification_1_get_script_hash) -
+
use 0x1::features;
+
+ + + + + +## Struct `AUID` + +A wrapper denoting aptos unique identifer (AUID) +for storing an address + + +
struct AUID has drop, store
+
+ + + +
+Fields + + +
+
+unique_address: address +
+
+ +
+
+ + +
+ + + +## Constants + + + + +AUID feature is not supported. + + +
const EAUID_NOT_SUPPORTED: u64 = 1;
+
+ + + + + +## Function `get_txn_hash` + +Return the transaction hash of the current transaction. + + +
fun get_txn_hash(): vector<u8>
+
+ + + +
+Implementation + + +
native fun get_txn_hash(): vector<u8>;
+
+ + + +
+ + + +## Function `get_transaction_hash` + +Return the transaction hash of the current transaction. +Internally calls the private function get_txn_hash. +This function is created for to feature gate the get_txn_hash function. + + +
public fun get_transaction_hash(): vector<u8>
+
+ + + +
+Implementation + + +
public fun get_transaction_hash(): vector<u8> {
+    assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+    get_txn_hash()
+}
+
+ + + +
+ + + +## Function `generate_unique_address` + +Return a universally unique identifier (of type address) generated +by hashing the transaction hash of this transaction and a sequence number +specific to this transaction. This function can be called any +number of times inside a single transaction. Each such call increments +the sequence number and generates a new unique address. +Uses Scheme in types/src/transaction/authenticator.rs for domain separation +from other ways of generating unique addresses. + + +
fun generate_unique_address(): address
+
+ + + +
+Implementation + + +
native fun generate_unique_address(): address;
+
+ + + +
+ + + +## Function `generate_auid_address` +Return a aptos unique identifier. Internally calls +the private function generate_unique_address. This function is +created for to feature gate the generate_unique_address function. +
public fun generate_auid_address(): address
+
+ + + +
+Implementation + + +
public fun generate_auid_address(): address {
+    assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+    generate_unique_address()
+}
+
+ + + +
+ ## Function `get_script_hash` @@ -37,12 +200,108 @@ Return the script hash of the current entry function. - + + +## Function `generate_auid` + +This method runs generate_unique_address native function and returns +the generated unique address wrapped in the AUID class. + + +
public fun generate_auid(): transaction_context::AUID
+
+ + + +
+Implementation + + +
public fun generate_auid(): AUID {
+    assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+    return AUID {
+        unique_address: generate_unique_address()
+    }
+}
+
+ + + +
+ + + +## Function `auid_address` + + + +
public fun auid_address(auid: &transaction_context::AUID): address
+
+ + + +
+Implementation + + +
public fun auid_address(auid: &AUID): address {
+    auid.unique_address
+}
+
+ + + +
+ + ## Specification - + + + + +
fun spec_get_txn_hash(): vector<u8>;
+
+ + + + + +### Function `get_txn_hash` + + +
fun get_txn_hash(): vector<u8>
+
+ + + + +
pragma opaque;
+aborts_if false;
+ensures result == spec_get_txn_hash();
+
+ + + + + +### Function `generate_unique_address` + + +
fun generate_unique_address(): address
+
+ + + + +
pragma opaque;
+
+ + + + ### Function `get_script_hash` diff --git a/aptos-move/framework/aptos-framework/doc/transaction_validation.md b/aptos-move/framework/aptos-framework/doc/transaction_validation.md index 44896c2d6c0ac..c9eb48546eebc 100644 --- a/aptos-move/framework/aptos-framework/doc/transaction_validation.md +++ b/aptos-move/framework/aptos-framework/doc/transaction_validation.md @@ -698,7 +698,8 @@ Aborts if length of public key hashed vector not equal the number of singers. -
let gas_payer = if (txn_sequence_number < GAS_PAYER_FLAG_BIT) {
+
pragma verify_duration_estimate = 120;
+let gas_payer = if (txn_sequence_number < GAS_PAYER_FLAG_BIT) {
     signer::address_of(sender)
 } else {
     secondary_signer_addresses[len(secondary_signer_addresses) - 1]
diff --git a/aptos-move/framework/aptos-framework/sources/configs/staking_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/staking_config.spec.move
index f87769d4a89a9..1de8d344a2670 100644
--- a/aptos-move/framework/aptos-framework/sources/configs/staking_config.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/configs/staking_config.spec.move
@@ -83,6 +83,7 @@ spec aptos_framework::staking_config {
     }
 
     spec calculate_and_save_latest_epoch_rewards_rate(): FixedPoint64 {
+        pragma verify_duration_estimate = 120;
         aborts_if !exists(@aptos_framework);
         aborts_if !features::spec_periodical_reward_rate_decrease_enabled();
         include StakingRewardsConfigRequirement;
diff --git a/aptos-move/framework/aptos-framework/sources/object.move b/aptos-move/framework/aptos-framework/sources/object.move
index 2594feeafcc42..e8473d1ced55b 100644
--- a/aptos-move/framework/aptos-framework/sources/object.move
+++ b/aptos-move/framework/aptos-framework/sources/object.move
@@ -22,6 +22,7 @@ module aptos_framework::object {
     use std::vector;
 
     use aptos_framework::account;
+    use aptos_framework::transaction_context;
     use aptos_framework::create_signer::create_signer;
     use aptos_framework::event;
     use aptos_framework::from_bcs;
@@ -51,6 +52,9 @@ module aptos_framework::object {
     /// nesting, but any checks such as transfer will only be evaluated this deep.
     const MAXIMUM_OBJECT_NESTING: u8 = 8;
 
+    /// generate_unique_address uses this for domain separation within its native implementation
+    const DERIVE_AUID_ADDRESS_SCHEME: u8 = 0xFB;
+
     /// Scheme identifier used to generate an object's address `obj_addr` as derived from another object.
     /// The object's address is generated as:
     /// ```
@@ -108,8 +112,7 @@ module aptos_framework::object {
     /// This is a one time ability given to the creator to configure the object as necessary
     struct ConstructorRef has drop {
         self: address,
-        /// Set to true so long as deleting the object is possible. For example, the object was
-        /// created via create_object_from_guid.
+        /// True if the object can be deleted. Named objects are not deletable.
         can_delete: bool,
     }
 
@@ -210,13 +213,34 @@ module aptos_framework::object {
         create_object_internal(creator_address, obj_addr, false)
     }
 
+    /// Create a new object by generating a random unique address based on transaction hash.
+    /// The unique address is computed sha3_256([transaction hash | auid counter | 0xFB]).
+    /// The created object is deletable as we can guarantee the same unique address can
+    /// never be regenerated with future txs.
+    public fun create_object(owner_address: address): ConstructorRef {
+        let unique_address = transaction_context::generate_auid_address();
+        create_object_internal(owner_address, unique_address, true)
+    }
+
+    #[deprecated]
+    /// Use `create_object` instead.
     /// Create a new object from a GUID generated by an account.
+    /// As the GUID creation internally increments a counter, two transactions that executes
+    /// `create_object_from_account` function for the same creator run sequentially.
+    /// Therefore, using `create_object` method for creating objects is preferrable as it
+    /// doesn't have the same bottlenecks.
     public fun create_object_from_account(creator: &signer): ConstructorRef {
         let guid = account::create_guid(creator);
         create_object_from_guid(signer::address_of(creator), guid)
     }
 
+    #[deprecated]
+    /// Use `create_object` instead.
     /// Create a new object from a GUID generated by an object.
+    /// As the GUID creation internally increments a counter, two transactions that executes
+    /// `create_object_from_object` function for the same creator run sequentially.
+    /// Therefore, using `create_object` method for creating objects is preferrable as it
+    /// doesn't have the same bottlenecks.
     public fun create_object_from_object(creator: &signer): ConstructorRef acquires ObjectCore {
         let guid = create_guid(creator);
         create_object_from_guid(signer::address_of(creator), guid)
@@ -650,4 +674,25 @@ module aptos_framework::object {
         assert!(owner(hero) == @0x456, 0);
         transfer_with_ref(linear_transfer_ref_bad, @0x789);
     }
+
+    #[test(fx = @std)]
+    fun test_correct_auid(fx: signer) {
+        use std::features;
+        let feature = features::get_auids();
+        features::change_feature_flags(&fx, vector[feature], vector[]);
+
+        let auid1 = aptos_framework::transaction_context::generate_auid_address();
+        let bytes = aptos_framework::transaction_context::get_transaction_hash();
+        std::vector::push_back(&mut bytes, 1);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, 0);
+        std::vector::push_back(&mut bytes, DERIVE_AUID_ADDRESS_SCHEME);
+        let auid2 = aptos_framework::from_bcs::to_address(std::hash::sha3_256(bytes));
+        assert!(auid1 == auid2, 0);
+    }
 }
diff --git a/aptos-move/framework/aptos-framework/sources/transaction_context.move b/aptos-move/framework/aptos-framework/sources/transaction_context.move
index 45a371148cae0..b515ed1e1f2fd 100644
--- a/aptos-move/framework/aptos-framework/sources/transaction_context.move
+++ b/aptos-move/framework/aptos-framework/sources/transaction_context.move
@@ -1,4 +1,83 @@
 module aptos_framework::transaction_context {
+
+    use std::features;
+
+    /// AUID feature is not supported.
+    const EAUID_NOT_SUPPORTED: u64 = 1;
+
+    /// A wrapper denoting aptos unique identifer (AUID)
+    /// for storing an address
+    struct AUID has drop, store {
+        unique_address: address
+    }
+
+    /// Return the transaction hash of the current transaction.
+    native fun get_txn_hash(): vector;
+
+    /// Return the transaction hash of the current transaction.
+    /// Internally calls the private function `get_txn_hash`.
+    /// This function is created for to feature gate the `get_txn_hash` function.
+    public fun get_transaction_hash(): vector {
+        assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+        get_txn_hash()
+    }
+
+    /// Return a universally unique identifier (of type address) generated
+    /// by hashing the transaction hash of this transaction and a sequence number
+    /// specific to this transaction. This function can be called any
+    /// number of times inside a single transaction. Each such call increments
+    /// the sequence number and generates a new unique address.
+    /// Uses Scheme in types/src/transaction/authenticator.rs for domain separation
+    /// from other ways of generating unique addresses.
+    native fun generate_unique_address(): address;
+
+    /// Return a aptos unique identifier. Internally calls
+    /// the private function `generate_unique_address`. This function is
+    /// created for to feature gate the `generate_unique_address` function.
+    public fun generate_auid_address(): address {
+        assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+        generate_unique_address()
+    }
+
     /// Return the script hash of the current entry function.
     public native fun get_script_hash(): vector;
+
+    /// This method runs `generate_unique_address` native function and returns
+    /// the generated unique address wrapped in the AUID class.
+    public fun generate_auid(): AUID {
+        assert!(features::auids_enabled(), EAUID_NOT_SUPPORTED);
+        return AUID {
+            unique_address: generate_unique_address()
+        }
+    }
+
+    public fun auid_address(auid: &AUID): address {
+        auid.unique_address
+    }
+
+    #[test(fx = @std)]
+    fun test_auid_uniquess(fx: signer) {
+        use std::features;
+        use std::vector;
+
+        let feature = features::get_auids();
+        features::change_feature_flags(&fx, vector[feature], vector[]);
+
+        let auids: vector
= vector
[]; + let i: u64 = 0; + let count: u64 = 50; + while (i < count) { + i = i + 1; + vector::push_back(&mut auids, generate_auid_address()); + }; + i = 0; + while (i < count - 1) { + let j: u64 = i + 1; + while (j < count) { + assert!(*vector::borrow(&auids, i) != *vector::borrow(&auids, j), 0); + j = j + 1; + }; + i = i + 1; + }; + } } diff --git a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move index 0b1c59ee1a897..5d520bf261e59 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move @@ -4,6 +4,14 @@ spec aptos_framework::transaction_context { aborts_if false; ensures result == spec_get_script_hash(); } - spec fun spec_get_script_hash(): vector; + spec get_txn_hash(): vector { + pragma opaque; + aborts_if false; + ensures result == spec_get_txn_hash(); + } + spec fun spec_get_txn_hash(): vector; + spec generate_unique_address(): address { + pragma opaque; + } } diff --git a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move index b997af5fad0f4..a125f1d344b12 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move @@ -110,6 +110,7 @@ spec aptos_framework::transaction_validation { txn_expiration_time: u64, chain_id: u8, ) { + pragma verify_duration_estimate = 120; let gas_payer = if (txn_sequence_number < GAS_PAYER_FLAG_BIT) { signer::address_of(sender) } else { diff --git a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md index 54c8cc83e58fc..8414f43ddfb13 100644 --- a/aptos-move/framework/aptos-token-objects/doc/aptos_token.md +++ b/aptos-move/framework/aptos-token-objects/doc/aptos_token.md @@ -58,6 +58,7 @@ The key features are:
use 0x1::error;
+use 0x1::features;
 use 0x1::object;
 use 0x1::option;
 use 0x1::signer;
@@ -471,14 +472,25 @@ With an existing collection, directly mint a soul bound token into the recipient
     property_types: vector<String>,
     property_values: vector<vector<u8>>,
 ): ConstructorRef acquires AptosCollection {
-    let constructor_ref = token::create_from_account(
-        creator,
-        collection,
-        description,
-        name,
-        option::none(),
-        uri,
-    );
+    let constructor_ref = if (features::auids_enabled()) {
+        token::create(
+            creator,
+            collection,
+            description,
+            name,
+            option::none(),
+            uri,
+        )
+    } else {
+        token::create_from_account(
+            creator,
+            collection,
+            description,
+            name,
+            option::none(),
+            uri,
+        )
+    };
 
     let object_signer = object::generate_signer(&constructor_ref);
 
diff --git a/aptos-move/framework/aptos-token-objects/doc/token.md b/aptos-move/framework/aptos-token-objects/doc/token.md
index 0b23237681a04..391ae97000cbd 100644
--- a/aptos-move/framework/aptos-token-objects/doc/token.md
+++ b/aptos-move/framework/aptos-token-objects/doc/token.md
@@ -16,6 +16,7 @@ token are:
 -  [Struct `MutationEvent`](#0x4_token_MutationEvent)
 -  [Constants](#@Constants_0)
 -  [Function `create_common`](#0x4_token_create_common)
+-  [Function `create`](#0x4_token_create)
 -  [Function `create_named_token`](#0x4_token_create_named_token)
 -  [Function `create_from_account`](#0x4_token_create_from_account)
 -  [Function `create_token_address`](#0x4_token_create_token_address)
@@ -361,6 +362,42 @@ The token name is over the maximum length
 
 
 
+
+
+
+
+## Function `create`
+
+Creates a new token object with a unique address and returns the ConstructorRef
+for additional specialization.
+
+
+
public fun create(creator: &signer, collection_name: string::String, description: string::String, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
+
+ + + +
+Implementation + + +
public fun create(
+    creator: &signer,
+    collection_name: String,
+    description: String,
+    name: String,
+    royalty: Option<Royalty>,
+    uri: String,
+): ConstructorRef {
+    let creator_address = signer::address_of(creator);
+    let constructor_ref = object::create_object(creator_address);
+    create_common(&constructor_ref, creator_address, collection_name, description, name, royalty, uri);
+    constructor_ref
+}
+
+ + +
@@ -409,7 +446,8 @@ Creates a new token object from an account GUID and returns the ConstructorRef f additional specialization. -
public fun create_from_account(creator: &signer, collection_name: string::String, description: string::String, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
+
#[deprecated]
+public fun create_from_account(creator: &signer, collection_name: string::String, description: string::String, name: string::String, royalty: option::Option<royalty::Royalty>, uri: string::String): object::ConstructorRef
 
diff --git a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move index 17c77fa3fe3b4..f20cd7b600025 100644 --- a/aptos-move/framework/aptos-token-objects/sources/aptos_token.move +++ b/aptos-move/framework/aptos-token-objects/sources/aptos_token.move @@ -8,6 +8,7 @@ /// * Metadata property type module aptos_token_objects::aptos_token { use std::error; + use std::features; use std::option::{Self, Option}; use std::string::String; use std::signer; @@ -199,14 +200,25 @@ module aptos_token_objects::aptos_token { property_types: vector, property_values: vector>, ): ConstructorRef acquires AptosCollection { - let constructor_ref = token::create_from_account( - creator, - collection, - description, - name, - option::none(), - uri, - ); + let constructor_ref = if (features::auids_enabled()) { + token::create( + creator, + collection, + description, + name, + option::none(), + uri, + ) + } else { + token::create_from_account( + creator, + collection, + description, + name, + option::none(), + uri, + ) + }; let object_signer = object::generate_signer(&constructor_ref); diff --git a/aptos-move/framework/aptos-token-objects/sources/token.move b/aptos-move/framework/aptos-token-objects/sources/token.move index 2867bc18c2822..06e9bdfe529f4 100644 --- a/aptos-move/framework/aptos-token-objects/sources/token.move +++ b/aptos-move/framework/aptos-token-objects/sources/token.move @@ -106,6 +106,22 @@ module aptos_token_objects::token { }; } + /// Creates a new token object with a unique address and returns the ConstructorRef + /// for additional specialization. + public fun create( + creator: &signer, + collection_name: String, + description: String, + name: String, + royalty: Option, + uri: String, + ): ConstructorRef { + let creator_address = signer::address_of(creator); + let constructor_ref = object::create_object(creator_address); + create_common(&constructor_ref, creator_address, collection_name, description, name, royalty, uri); + constructor_ref + } + /// Creates a new token object from a token name and returns the ConstructorRef for /// additional specialization. public fun create_named_token( @@ -124,6 +140,7 @@ module aptos_token_objects::token { constructor_ref } + #[deprecated] /// Creates a new token object from an account GUID and returns the ConstructorRef for /// additional specialization. public fun create_from_account( @@ -514,7 +531,7 @@ module aptos_token_objects::token { } #[test(creator = @0x123)] - fun test_burn_and_delete(creator: &signer) acquires Token { + fun test_create_from_account_burn_and_delete(creator: &signer) acquires Token { use aptos_framework::account; let collection_name = string::utf8(b"collection name"); @@ -538,6 +555,35 @@ module aptos_token_objects::token { assert!(!object::is_object(token_addr), 2); } + #[test(creator = @0x123,fx = @std)] + fun test_create_burn_and_delete(creator: &signer, fx: signer) acquires Token { + use aptos_framework::account; + use std::features; + + let feature = features::get_auids(); + features::change_feature_flags(&fx, vector[feature], vector[]); + + let collection_name = string::utf8(b"collection name"); + let token_name = string::utf8(b"token name"); + + create_collection_helper(creator, collection_name, 1); + account::create_account_for_test(signer::address_of(creator)); + let constructor_ref = create( + creator, + collection_name, + string::utf8(b"token description"), + token_name, + option::none(), + string::utf8(b"token uri"), + ); + let burn_ref = generate_burn_ref(&constructor_ref); + let token_addr = object::address_from_constructor_ref(&constructor_ref); + assert!(exists(token_addr), 0); + burn(burn_ref); + assert!(!exists(token_addr), 1); + assert!(!object::is_object(token_addr), 2); + } + #[test_only] fun create_collection_helper(creator: &signer, collection_name: String, max_supply: u64) { collection::create_fixed_collection( diff --git a/aptos-move/framework/move-stdlib/doc/features.md b/aptos-move/framework/move-stdlib/doc/features.md index d1c4ce9535541..a237205951252 100644 --- a/aptos-move/framework/move-stdlib/doc/features.md +++ b/aptos-move/framework/move-stdlib/doc/features.md @@ -62,6 +62,8 @@ return true. - [Function `get_delegation_pool_partial_governance_voting`](#0x1_features_get_delegation_pool_partial_governance_voting) - [Function `delegation_pool_partial_governance_voting_enabled`](#0x1_features_delegation_pool_partial_governance_voting_enabled) - [Function `gas_payer_enabled`](#0x1_features_gas_payer_enabled) +- [Function `get_auids`](#0x1_features_get_auids) +- [Function `auids_enabled`](#0x1_features_auids_enabled) - [Function `change_feature_flags`](#0x1_features_change_feature_flags) - [Function `is_enabled`](#0x1_features_is_enabled) - [Function `set`](#0x1_features_set) @@ -127,6 +129,17 @@ Lifetime: transient + + +Whether enable MOVE functions to call create_auid method to create AUIDs. +Lifetime: transient + + +
const APTOS_UNIQUE_IDENTIFIERS: u64 = 23;
+
+ + + Whether the new BLAKE2B-256 hash function native is enabled. @@ -1067,6 +1080,52 @@ Lifetime: transient + + + + +## Function `get_auids` + + + +
public fun get_auids(): u64
+
+ + + +
+Implementation + + +
public fun get_auids(): u64 { APTOS_UNIQUE_IDENTIFIERS }
+
+ + + +
+ + + +## Function `auids_enabled` + + + +
public fun auids_enabled(): bool
+
+ + + +
+Implementation + + +
public fun auids_enabled(): bool acquires Features {
+    is_enabled(APTOS_UNIQUE_IDENTIFIERS)
+}
+
+ + +
diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.move b/aptos-move/framework/move-stdlib/sources/configs/features.move index 1e96cfb53cd21..9f64c9ee8be45 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.move @@ -201,6 +201,14 @@ module std::features { is_enabled(GAS_PAYER_ENABLED) } + /// Whether enable MOVE functions to call create_auid method to create AUIDs. + /// Lifetime: transient + const APTOS_UNIQUE_IDENTIFIERS: u64 = 23; + public fun get_auids(): u64 { APTOS_UNIQUE_IDENTIFIERS } + public fun auids_enabled(): bool acquires Features { + is_enabled(APTOS_UNIQUE_IDENTIFIERS) + } + // ============================================================================================ // Feature Flag Implementation diff --git a/aptos-move/framework/src/natives/mod.rs b/aptos-move/framework/src/natives/mod.rs index 2089364b927ca..177b1c0416870 100644 --- a/aptos-move/framework/src/natives/mod.rs +++ b/aptos-move/framework/src/natives/mod.rs @@ -226,7 +226,11 @@ impl GasParameters { }, }, transaction_context: transaction_context::GasParameters { + get_txn_hash: transaction_context::GetTxnHashGasParameters { base: 0.into() }, get_script_hash: transaction_context::GetScriptHashGasParameters { base: 0.into() }, + generate_unique_address: transaction_context::GenerateUniqueAddressGasParameters { + base: 0.into(), + }, }, code: code::GasParameters { request_publish: code::RequestPublishGasParameters { diff --git a/aptos-move/framework/src/natives/transaction_context.rs b/aptos-move/framework/src/natives/transaction_context.rs index ca6f2d970e727..44afefa15e33d 100644 --- a/aptos-move/framework/src/natives/transaction_context.rs +++ b/aptos-move/framework/src/natives/transaction_context.rs @@ -2,9 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::natives::helpers::{make_safe_native, SafeNativeContext, SafeNativeResult}; -use aptos_types::on_chain_config::{Features, TimedFeatures}; +use aptos_types::{ + on_chain_config::{Features, TimedFeatures}, + transaction::authenticator::{AuthenticationKey, AuthenticationKeyPreimage}, +}; use better_any::{Tid, TidAble}; -use move_core_types::gas_algebra::InternalGas; +use move_core_types::{account_address::AccountAddress, gas_algebra::InternalGas}; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; use smallvec::{smallvec, SmallVec}; @@ -15,6 +18,9 @@ use std::{collections::VecDeque, fmt::Debug, sync::Arc}; /// natives of this extension. #[derive(Tid)] pub struct NativeTransactionContext { + txn_hash: Vec, + /// This is the number of AUIDs (Aptos unique identifiers) issued during the execution of this transaction + auid_counter: u64, script_hash: Vec, chain_id: u8, } @@ -22,8 +28,10 @@ pub struct NativeTransactionContext { impl NativeTransactionContext { /// Create a new instance of a native transaction context. This must be passed in via an /// extension into VM session functions. - pub fn new(script_hash: Vec, chain_id: u8) -> Self { + pub fn new(txn_hash: Vec, script_hash: Vec, chain_id: u8) -> Self { Self { + txn_hash, + auid_counter: 0, script_hash, chain_id, } @@ -34,6 +42,68 @@ impl NativeTransactionContext { } } +/*************************************************************************************************** + * native fun get_txn_hash + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Clone, Debug)] +pub struct GetTxnHashGasParameters { + pub base: InternalGas, +} + +fn native_get_txn_hash( + gas_params: &GetTxnHashGasParameters, + context: &mut SafeNativeContext, + mut _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(gas_params.base)?; + + let transaction_context = context.extensions().get::(); + + Ok(smallvec![Value::vector_u8( + transaction_context.txn_hash.clone() + )]) +} + +/*************************************************************************************************** + * native fun generate_unique_address + * + * gas cost: base_cost + * + **************************************************************************************************/ +#[derive(Clone, Debug)] +pub struct GenerateUniqueAddressGasParameters { + pub base: InternalGas, +} + +fn native_generate_unique_address( + gas_params: &GenerateUniqueAddressGasParameters, + context: &mut SafeNativeContext, + mut _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(gas_params.base)?; + + let mut transaction_context = context + .extensions_mut() + .get_mut::(); + transaction_context.auid_counter += 1; + + let hash_vec = AuthenticationKey::from_preimage(&AuthenticationKeyPreimage::auid( + transaction_context.txn_hash.clone(), + transaction_context.auid_counter, + )); + Ok(smallvec![Value::address(AccountAddress::new( + hash_vec + .to_vec() + .try_into() + .expect("Unable to convert hash vector into [u8]") + ))]) +} + /*************************************************************************************************** * native fun get_script_hash * @@ -66,7 +136,9 @@ fn native_get_script_hash( **************************************************************************************************/ #[derive(Debug, Clone)] pub struct GasParameters { + pub get_txn_hash: GetTxnHashGasParameters, pub get_script_hash: GetScriptHashGasParameters, + pub generate_unique_address: GenerateUniqueAddressGasParameters, } pub fn make_all( @@ -74,15 +146,35 @@ pub fn make_all( timed_features: TimedFeatures, features: Arc, ) -> impl Iterator { - let natives = [( - "get_script_hash", - make_safe_native( - gas_params.get_script_hash, - timed_features, - features, - native_get_script_hash, + let natives = [ + ( + "get_script_hash", + make_safe_native( + gas_params.get_script_hash, + timed_features.clone(), + features.clone(), + native_get_script_hash, + ), + ), + ( + "generate_unique_address", + make_safe_native( + gas_params.generate_unique_address, + timed_features.clone(), + features.clone(), + native_generate_unique_address, + ), + ), + ( + "get_txn_hash", + make_safe_native( + gas_params.get_txn_hash, + timed_features, + features, + native_get_txn_hash, + ), ), - )]; + ]; crate::natives::helpers::make_module_natives(natives) } diff --git a/types/src/transaction/authenticator.rs b/types/src/transaction/authenticator.rs index b65343501eeb7..82203a9fe1ded 100644 --- a/types/src/transaction/authenticator.rs +++ b/types/src/transaction/authenticator.rs @@ -246,6 +246,7 @@ pub enum Scheme { /// resources accounts. This application serves to domain separate hashes. Without such /// separation, an adversary could create (and get a signer for) a these accounts /// when a their address matches matches an existing address of a MultiEd25519 wallet. + DeriveAuid = 251, DeriveObjectAddressFromObject = 252, DeriveObjectAddressFromGuid = 253, DeriveObjectAddressFromSeed = 254, @@ -257,6 +258,7 @@ impl fmt::Display for Scheme { let display = match self { Scheme::Ed25519 => "Ed25519", Scheme::MultiEd25519 => "MultiEd25519", + Scheme::DeriveAuid => "DeriveAuid", Scheme::DeriveObjectAddressFromObject => "DeriveObjectAddressFromObject", Scheme::DeriveObjectAddressFromGuid => "DeriveObjectAddressFromGuid", Scheme::DeriveObjectAddressFromSeed => "DeriveObjectAddressFromSeed", @@ -461,6 +463,15 @@ impl AuthenticationKeyPreimage { Self::new(public_key.to_bytes(), Scheme::MultiEd25519) } + /// Construct a preimage from a transaction-derived AUID as (txn_hash || auid_scheme_id) + pub fn auid(txn_hash: Vec, auid_counter: u64) -> AuthenticationKeyPreimage { + let mut hash_arg = Vec::new(); + hash_arg.extend(txn_hash); + hash_arg.extend(auid_counter.to_le_bytes().to_vec()); + hash_arg.push(Scheme::DeriveAuid as u8); + Self(hash_arg) + } + /// Construct a vector from this authentication key pub fn into_vec(self) -> Vec { self.0