From 91f4a33cabc4918269b2e20fabc839b7318cb496 Mon Sep 17 00:00:00 2001 From: Igor Date: Fri, 6 Dec 2024 16:02:30 -0800 Subject: [PATCH] external unique state and verified external value --- .../doc/external_unique_state.md | 342 +++++++++++++ .../doc/verified_external_value.md | 462 ++++++++++++++++++ .../external/external_unique_state.move | 84 ++++ .../external/verified_external_value.move | 118 +++++ .../aptos-framework/sources/util.move | 1 + 5 files changed, 1007 insertions(+) create mode 100644 aptos-move/framework/aptos-framework/doc/external_unique_state.md create mode 100644 aptos-move/framework/aptos-framework/doc/verified_external_value.md create mode 100644 aptos-move/framework/aptos-framework/sources/external/external_unique_state.move create mode 100644 aptos-move/framework/aptos-framework/sources/external/verified_external_value.move diff --git a/aptos-move/framework/aptos-framework/doc/external_unique_state.md b/aptos-move/framework/aptos-framework/doc/external_unique_state.md new file mode 100644 index 0000000000000..2e144bdf65671 --- /dev/null +++ b/aptos-move/framework/aptos-framework/doc/external_unique_state.md @@ -0,0 +1,342 @@ + + + +# Module `0x1::external_unique_state` + +Onchain resource containing a set of ExternalValues. +Set is without duplicates - i.e. same value cannot be stored twice. + +Replaces move_to / borrow_global_mut / move_from +with move_to_external_storage / borrow_mut / move_from_external_storage + +Provides equivalent access restrictions as move_to / borrow_global_mut / move_from +byte instructions have (which are that only declaring module can call them), +via each type having a corresponding witness that needs to be provided. +(if the module doesn't give out the witness) + + +- [Resource `ExternalUniqueState`](#0x1_external_unique_state_ExternalUniqueState) +- [Struct `MutableHandle`](#0x1_external_unique_state_MutableHandle) +- [Constants](#@Constants_0) +- [Function `enable_external_storage_for_type`](#0x1_external_unique_state_enable_external_storage_for_type) +- [Function `move_to_external_storage`](#0x1_external_unique_state_move_to_external_storage) +- [Function `get_copy`](#0x1_external_unique_state_get_copy) +- [Function `move_from_external_storage`](#0x1_external_unique_state_move_from_external_storage) +- [Function `borrow_mut`](#0x1_external_unique_state_borrow_mut) +- [Function `handle_get_mut_value`](#0x1_external_unique_state_handle_get_mut_value) +- [Function `handle_store`](#0x1_external_unique_state_handle_store) + + +
use 0x1::error;
+use 0x1::signer;
+use 0x1::verified_external_value;
+
+ + + + + +## Resource `ExternalUniqueState` + +Resource containing all ExternalValues of a given type. +It also keeps a witness, which is required to be provided in order to access values of this type. + + +
struct ExternalUniqueState<T: drop, store, V: store> has key
+
+ + + +
+Fields + + +
+
+witness: V +
+
+ +
+
+values: verified_external_value::ExternalValuesSet<T> +
+
+ +
+
+ + +
+ + + +## Struct `MutableHandle` + +A handle containing the value, which can be mutated, and then stored back. + + +
struct MutableHandle<T: drop, store>
+
+ + + +
+Fields + + +
+
+typed_value: T +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ETYPE_MISMATCH: u64 = 4;
+
+ + + + + + + +
const EHASH_DOESNT_MATCH: u64 = 1;
+
+ + + + + +compressed_id already exists + + +
const ECOMPRESSED_ID_ALREADY_PRESENT: u64 = 2;
+
+ + + + + + + +
const ECORE_COMPRESSION_ALREADY_REGISTERED: u64 = 3;
+
+ + + + + + + +
const EWITNESS_MISMATCH: u64 = 4;
+
+ + + + + +## Function `enable_external_storage_for_type` + +Registers a particular type to be able to be stored in external state, with access guarded by the provided witness. + + +
public(friend) fun enable_external_storage_for_type<T: drop, store, V: store>(framework_signer: &signer, witness: V)
+
+ + + +
+Implementation + + +
public(friend) fun enable_external_storage_for_type<T: drop + store, V: store>(framework_signer: &signer, witness: V) {
+    let compressed_state = ExternalUniqueState<T, V> {
+        witness: witness,
+        values: verified_external_value::new_set()
+    };
+    assert!(!exists<ExternalUniqueState<T, V>>(signer::address_of(framework_signer)), error::invalid_argument(ECORE_COMPRESSION_ALREADY_REGISTERED));
+    move_to(framework_signer, compressed_state);
+}
+
+ + + +
+ + + +## Function `move_to_external_storage` + + + +
public fun move_to_external_storage<T: drop, store, V: store>(value: T, witness: &V): u256
+
+ + + +
+Implementation + + +
public fun move_to_external_storage<T: drop + store, V: store>(value: T, witness: &V): u256 acquires ExternalUniqueState {
+    let external_state = borrow_global_mut<ExternalUniqueState<T, V>>(@aptos_framework);
+    assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH));
+
+    let external_value = verified_external_value::move_to_external_storage(value);
+    let hash = external_value.get_hash();
+    external_state.values.add(external_value);
+    hash
+}
+
+ + + +
+ + + +## Function `get_copy` + + + +
public fun get_copy<T: copy, drop, store, V: store>(external_bytes: vector<u8>, witness: &V): T
+
+ + + +
+Implementation + + +
public fun get_copy<T: store + drop + copy, V: store>(external_bytes: vector<u8>, witness: &V): T acquires ExternalUniqueState {
+    let external_state = borrow_global<ExternalUniqueState<T, V>>(@aptos_framework);
+    assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH));
+    external_state.values.get_copy(verified_external_value::bytes_to_hash(external_bytes)).into_value(external_bytes)
+}
+
+ + + +
+ + + +## Function `move_from_external_storage` + + + +
public fun move_from_external_storage<T: drop, store, V: store>(external_bytes: vector<u8>, witness: &V): T
+
+ + + +
+Implementation + + +
public fun move_from_external_storage<T: drop + store, V: store>(external_bytes: vector<u8>, witness: &V): T acquires ExternalUniqueState {
+    let external_state = borrow_global_mut<ExternalUniqueState<T, V>>(@aptos_framework);
+    assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH));
+    external_state.values.remove(verified_external_value::bytes_to_hash(external_bytes)).into_value(external_bytes)
+}
+
+ + + +
+ + + +## Function `borrow_mut` + + + +
public(friend) fun borrow_mut<T: drop, store, V: store>(external_bytes: vector<u8>, witness: &V): external_unique_state::MutableHandle<T>
+
+ + + +
+Implementation + + +
public(friend) fun borrow_mut<T: drop + store, V: store>(external_bytes: vector<u8>, witness: &V): MutableHandle<T> acquires ExternalUniqueState {
+    let typed_value = move_from_external_storage<T, V>(external_bytes, witness);
+    MutableHandle {
+        typed_value,
+    }
+}
+
+ + + +
+ + + +## Function `handle_get_mut_value` + + + +
public(friend) fun handle_get_mut_value<T: drop, store>(self: &mut external_unique_state::MutableHandle<T>): &mut T
+
+ + + +
+Implementation + + +
public(friend) fun handle_get_mut_value<T: drop + store>(self: &mut MutableHandle<T>): &mut T {
+    &mut self.typed_value
+}
+
+ + + +
+ + + +## Function `handle_store` + + + +
public(friend) fun handle_store<T: drop, store, V: store>(self: external_unique_state::MutableHandle<T>, witness: &V): u256
+
+ + + +
+Implementation + + +
public(friend) fun handle_store<T: drop + store, V: store>(self: MutableHandle<T>, witness: &V): u256 acquires ExternalUniqueState {
+    let MutableHandle {
+        typed_value,
+    } = self;
+    move_to_external_storage(typed_value, witness)
+}
+
+ + + +
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/verified_external_value.md b/aptos-move/framework/aptos-framework/doc/verified_external_value.md new file mode 100644 index 0000000000000..5d4f91e065704 --- /dev/null +++ b/aptos-move/framework/aptos-framework/doc/verified_external_value.md @@ -0,0 +1,462 @@ + + + +# Module `0x1::verified_external_value` + +Module for ability to take move values, and store them externally +(and save on the cost difference between onchain and offchain state), +with ability to safely retrieve them later: to safely transorm them back +to move value, by providing the externally stored bytes. + +We do so by keeping the hash of the value in the onchain state, used to verify validity +of external bytes, guaranteeing validity of deserialized value. + + +- [Struct `ExternalValue`](#0x1_verified_external_value_ExternalValue) +- [Struct `Dummy`](#0x1_verified_external_value_Dummy) +- [Struct `ExternalValuesSet`](#0x1_verified_external_value_ExternalValuesSet) +- [Struct `MovedToExternalStorage`](#0x1_verified_external_value_MovedToExternalStorage) +- [Constants](#@Constants_0) +- [Function `move_to_external_storage`](#0x1_verified_external_value_move_to_external_storage) +- [Function `get_hash`](#0x1_verified_external_value_get_hash) +- [Function `into_value`](#0x1_verified_external_value_into_value) +- [Function `get_value_copy`](#0x1_verified_external_value_get_value_copy) +- [Function `new_set`](#0x1_verified_external_value_new_set) +- [Function `contains`](#0x1_verified_external_value_contains) +- [Function `add`](#0x1_verified_external_value_add) +- [Function `remove`](#0x1_verified_external_value_remove) +- [Function `get_copy`](#0x1_verified_external_value_get_copy) +- [Function `bytes_to_hash`](#0x1_verified_external_value_bytes_to_hash) + + +
use 0x1::bcs;
+use 0x1::big_ordered_map;
+use 0x1::error;
+use 0x1::event;
+use 0x1::from_bcs;
+use 0x1::hash;
+use 0x1::util;
+
+ + + + + +## Struct `ExternalValue` + +Externally storing any move value, while keeping the hash inside ExternalValue. + +Currently we require value to have drop - as value dissapears from chain + + +
struct ExternalValue<T: drop, store> has drop, store
+
+ + + +
+Fields + + +
+
+hash: u256 +
+
+ +
+
+ + +
+ + + +## Struct `Dummy` + + + +
struct Dummy has drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Struct `ExternalValuesSet` + +Set of ExternalValues, where only their hashes are stored onchain. +Set is without duplicates - i.e. same value cannot be stored twice. + + +
struct ExternalValuesSet<T: drop, store> has store
+
+ + + +
+Fields + + +
+
+hashes: big_ordered_map::BigOrderedMap<u256, verified_external_value::Dummy> +
+
+ +
+
+ + +
+ + + +## Struct `MovedToExternalStorage` + + + +
#[event]
+struct MovedToExternalStorage<T: drop, store> has drop, store
+
+ + + +
+Fields + + +
+
+hash: u256 +
+
+ +
+
+bytes: vector<u8> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EHASH_DOESNT_EXIST: u64 = 1;
+
+ + + + + + + +
const EHASH_DOESNT_MATCH: u64 = 1;
+
+ + + + + +## Function `move_to_external_storage` + +Takes a value, emits it as an event, and creates ExternalValue representing it +(which stores it's hash inside) + + +
public fun move_to_external_storage<T: drop, store>(value: T): verified_external_value::ExternalValue<T>
+
+ + + +
+Implementation + + +
public fun move_to_external_storage<T: drop + store>(value: T): ExternalValue<T> {
+    let bytes = bcs::to_bytes(&value);
+    let hash = bytes_to_hash(bytes);
+
+    event::emit(MovedToExternalStorage<T> {
+        hash,
+        bytes,
+    });
+    ExternalValue {
+        hash,
+    }
+}
+
+ + + +
+ + + +## Function `get_hash` + +Retrieves the hash of the value ExternalValue represents. + + +
public fun get_hash<T: drop, store>(self: &verified_external_value::ExternalValue<T>): u256
+
+ + + +
+Implementation + + +
public fun get_hash<T: drop + store>(self: &ExternalValue<T>): u256 {
+    self.hash
+}
+
+ + + +
+ + + +## Function `into_value` + +Converts ExternalValue into it's original move representation, by providing it's bytes. + + +
public fun into_value<T: drop, store>(self: verified_external_value::ExternalValue<T>, external_bytes: vector<u8>): T
+
+ + + +
+Implementation + + +
public fun into_value<T: drop + store>(self: ExternalValue<T>, external_bytes: vector<u8>): T {
+    let ExternalValue { hash } = self;
+    let data_hash = bytes_to_hash(external_bytes);
+    assert!(data_hash == hash, error::invalid_argument(EHASH_DOESNT_MATCH));
+
+    // maybe emit consumed event, so indexer can remove storing it?
+
+    util::from_bytes<T>(external_bytes)
+}
+
+ + + +
+ + + +## Function `get_value_copy` + +For a type that has copy, return original move representation of ExternalValue, without consuming it. + + +
public fun get_value_copy<T: copy, drop, store>(self: &verified_external_value::ExternalValue<T>, external_bytes: vector<u8>): T
+
+ + + +
+Implementation + + +
public fun get_value_copy<T: drop + store + copy>(self: &ExternalValue<T>, external_bytes: vector<u8>): T {
+    let data_hash = bytes_to_hash(external_bytes);
+    assert!(data_hash == self.hash, error::invalid_argument(EHASH_DOESNT_MATCH));
+    util::from_bytes<T>(external_bytes)
+}
+
+ + + +
+ + + +## Function `new_set` + +Creates new ExternalValuesSet + + +
public fun new_set<T: drop, store>(): verified_external_value::ExternalValuesSet<T>
+
+ + + +
+Implementation + + +
public fun new_set<T: drop + store>(): ExternalValuesSet<T> {
+    ExternalValuesSet { hashes: big_ordered_map::new() }
+}
+
+ + + +
+ + + +## Function `contains` + +Checks whether ExternalValuesSet contains ExternalValue with corresponding hash. + + +
public fun contains<T: drop, store>(self: &verified_external_value::ExternalValuesSet<T>, hash: u256): bool
+
+ + + +
+Implementation + + +
public fun contains<T: drop + store>(self: &ExternalValuesSet<T>, hash: u256): bool {
+    self.hashes.contains(&hash)
+}
+
+ + + +
+ + + +## Function `add` + +Adds ExternalValue to ExternalValuesSet +Abort if value already exists. + + +
public fun add<T: drop, store>(self: &mut verified_external_value::ExternalValuesSet<T>, value: verified_external_value::ExternalValue<T>)
+
+ + + +
+Implementation + + +
public fun add<T: drop + store>(self: &mut ExternalValuesSet<T>, value: ExternalValue<T>) {
+    let ExternalValue { hash } = value;
+    self.hashes.add(hash, Dummy {});
+}
+
+ + + +
+ + + +## Function `remove` + +Removes and returns ExternalValue with given hash from ExternalValuesSet. +Aborts if there is no entry for hash. + + +
public fun remove<T: drop, store>(self: &mut verified_external_value::ExternalValuesSet<T>, hash: u256): verified_external_value::ExternalValue<T>
+
+ + + +
+Implementation + + +
public fun remove<T: drop + store>(self: &mut ExternalValuesSet<T>, hash: u256): ExternalValue<T> {
+    self.hashes.remove(&hash);
+    ExternalValue { hash }
+}
+
+ + + +
+ + + +## Function `get_copy` + +For a type that has copy, returns ExternalValue with the given hash. +Aborts if there is no entry for hash. + + +
public fun get_copy<T: copy, drop, store>(self: &verified_external_value::ExternalValuesSet<T>, hash: u256): verified_external_value::ExternalValue<T>
+
+ + + +
+Implementation + + +
public fun get_copy<T: drop + store + copy>(self: &ExternalValuesSet<T>, hash: u256): ExternalValue<T> {
+    assert!(self.hashes.contains(&hash), error::invalid_argument(EHASH_DOESNT_EXIST));
+    ExternalValue { hash }
+}
+
+ + + +
+ + + +## Function `bytes_to_hash` + +Computes a hash of a given bytes. +Value is first serialized using bcs::to_bytes, and then the hash is computed using this function. + + +
public fun bytes_to_hash(external_bytes: vector<u8>): u256
+
+ + + +
+Implementation + + +
public fun bytes_to_hash(external_bytes: vector<u8>): u256 {
+    from_bcs::to_u256(hash::sha3_256(external_bytes))
+}
+
+ + + +
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/sources/external/external_unique_state.move b/aptos-move/framework/aptos-framework/sources/external/external_unique_state.move new file mode 100644 index 0000000000000..ad5314d3a9bbd --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/external/external_unique_state.move @@ -0,0 +1,84 @@ +/// Onchain resource containing a set of ExternalValues. +/// Set is without duplicates - i.e. same value cannot be stored twice. +/// +/// Replaces `move_to` / `borrow_global_mut` / `move_from` +/// with `move_to_external_storage` / `borrow_mut` / `move_from_external_storage` +/// +/// Provides equivalent access restrictions as `move_to` / `borrow_global_mut` / `move_from` +/// byte instructions have (which are that only declaring module can call them), +/// via each type having a corresponding witness that needs to be provided. +/// (if the module doesn't give out the witness) +module aptos_framework::external_unique_state { + use std::error; + use std::signer; + use aptos_framework::verified_external_value::{Self, ExternalValuesSet}; + + const EHASH_DOESNT_MATCH: u64 = 1; + /// compressed_id already exists + const ECOMPRESSED_ID_ALREADY_PRESENT: u64 = 2; + const ECORE_COMPRESSION_ALREADY_REGISTERED: u64 = 3; + const ETYPE_MISMATCH: u64 = 4; + const EWITNESS_MISMATCH: u64 = 4; + + /// Resource containing all ExternalValues of a given type. + /// It also keeps a witness, which is required to be provided in order to access values of this type. + struct ExternalUniqueState has key { + witness: V, + values: ExternalValuesSet, + } + + /// A handle containing the value, which can be mutated, and then stored back. + struct MutableHandle { + typed_value: T, + } + + /// Registers a particular type to be able to be stored in external state, with access guarded by the provided witness. + public(friend) fun enable_external_storage_for_type(framework_signer: &signer, witness: V) { + let compressed_state = ExternalUniqueState { + witness: witness, + values: verified_external_value::new_set() + }; + assert!(!exists>(signer::address_of(framework_signer)), error::invalid_argument(ECORE_COMPRESSION_ALREADY_REGISTERED)); + move_to(framework_signer, compressed_state); + } + + public fun move_to_external_storage(value: T, witness: &V): u256 acquires ExternalUniqueState { + let external_state = borrow_global_mut>(@aptos_framework); + assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH)); + + let external_value = verified_external_value::move_to_external_storage(value); + let hash = external_value.get_hash(); + external_state.values.add(external_value); + hash + } + + public fun get_copy(external_bytes: vector, witness: &V): T acquires ExternalUniqueState { + let external_state = borrow_global>(@aptos_framework); + assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH)); + external_state.values.get_copy(verified_external_value::bytes_to_hash(external_bytes)).into_value(external_bytes) + } + + public fun move_from_external_storage(external_bytes: vector, witness: &V): T acquires ExternalUniqueState { + let external_state = borrow_global_mut>(@aptos_framework); + assert!(witness == &external_state.witness, error::invalid_argument(EWITNESS_MISMATCH)); + external_state.values.remove(verified_external_value::bytes_to_hash(external_bytes)).into_value(external_bytes) + } + + public(friend) fun borrow_mut(external_bytes: vector, witness: &V): MutableHandle acquires ExternalUniqueState { + let typed_value = move_from_external_storage(external_bytes, witness); + MutableHandle { + typed_value, + } + } + + public(friend) fun handle_get_mut_value(self: &mut MutableHandle): &mut T { + &mut self.typed_value + } + + public(friend) fun handle_store(self: MutableHandle, witness: &V): u256 acquires ExternalUniqueState { + let MutableHandle { + typed_value, + } = self; + move_to_external_storage(typed_value, witness) + } +} diff --git a/aptos-move/framework/aptos-framework/sources/external/verified_external_value.move b/aptos-move/framework/aptos-framework/sources/external/verified_external_value.move new file mode 100644 index 0000000000000..4b799dec08743 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/external/verified_external_value.move @@ -0,0 +1,118 @@ +/// Module for ability to take move values, and store them externally +/// (and save on the cost difference between onchain and offchain state), +/// with ability to safely retrieve them later: to safely transorm them back +/// to move value, by providing the externally stored bytes. +/// +/// We do so by keeping the hash of the value in the onchain state, used to verify validity +/// of external bytes, guaranteeing validity of deserialized value. +module aptos_framework::verified_external_value { + const EHASH_DOESNT_MATCH: u64 = 1; + const EHASH_DOESNT_EXIST: u64 = 1; + + // TODO replace with BigOrderedMap + use std::bcs; + use std::error; + use std::hash; + use aptos_std::from_bcs; + use aptos_std::big_ordered_map::{Self, BigOrderedMap}; + use aptos_framework::event; + use aptos_framework::util; + + /// Externally storing any move value, while keeping the hash inside ExternalValue. + /// + /// Currently we require value to have drop - as value dissapears from chain + struct ExternalValue has drop, store { + hash: u256, + } + + struct Dummy has drop, store { } + + /// Set of `ExternalValue`s, where only their hashes are stored onchain. + /// Set is without duplicates - i.e. same value cannot be stored twice. + struct ExternalValuesSet has store { + hashes: BigOrderedMap, + } + + #[event] + struct MovedToExternalStorage has drop, store { + hash: u256, + // bytes needed to be passed back, in order to extract value. + bytes: vector, + } + + /// Takes a value, emits it as an event, and creates ExternalValue representing it + /// (which stores it's hash inside) + public fun move_to_external_storage(value: T): ExternalValue { + let bytes = bcs::to_bytes(&value); + let hash = bytes_to_hash(bytes); + + event::emit(MovedToExternalStorage { + hash, + bytes, + }); + ExternalValue { + hash, + } + } + + /// Retrieves the hash of the value ExternalValue represents. + public fun get_hash(self: &ExternalValue): u256 { + self.hash + } + + /// Converts `ExternalValue` into it's original move representation, by providing it's bytes. + public fun into_value(self: ExternalValue, external_bytes: vector): T { + let ExternalValue { hash } = self; + let data_hash = bytes_to_hash(external_bytes); + assert!(data_hash == hash, error::invalid_argument(EHASH_DOESNT_MATCH)); + + // maybe emit consumed event, so indexer can remove storing it? + + util::from_bytes(external_bytes) + } + + + /// For a type that has `copy`, return original move representation of `ExternalValue`, without consuming it. + public fun get_value_copy(self: &ExternalValue, external_bytes: vector): T { + let data_hash = bytes_to_hash(external_bytes); + assert!(data_hash == self.hash, error::invalid_argument(EHASH_DOESNT_MATCH)); + util::from_bytes(external_bytes) + } + + /// Creates new `ExternalValuesSet` + public fun new_set(): ExternalValuesSet { + ExternalValuesSet { hashes: big_ordered_map::new() } + } + + /// Checks whether `ExternalValuesSet` contains `ExternalValue` with corresponding hash. + public fun contains(self: &ExternalValuesSet, hash: u256): bool { + self.hashes.contains(&hash) + } + + /// Adds `ExternalValue` to `ExternalValuesSet` + /// Abort if `value` already exists. + public fun add(self: &mut ExternalValuesSet, value: ExternalValue) { + let ExternalValue { hash } = value; + self.hashes.add(hash, Dummy {}); + } + + /// Removes and returns `ExternalValue` with given `hash` from `ExternalValuesSet`. + /// Aborts if there is no entry for `hash`. + public fun remove(self: &mut ExternalValuesSet, hash: u256): ExternalValue { + self.hashes.remove(&hash); + ExternalValue { hash } + } + + /// For a type that has `copy`, returns `ExternalValue` with the given hash. + /// Aborts if there is no entry for `hash`. + public fun get_copy(self: &ExternalValuesSet, hash: u256): ExternalValue { + assert!(self.hashes.contains(&hash), error::invalid_argument(EHASH_DOESNT_EXIST)); + ExternalValue { hash } + } + + /// Computes a hash of a given bytes. + /// Value is first serialized using `bcs::to_bytes`, and then the hash is computed using this function. + public fun bytes_to_hash(external_bytes: vector): u256 { + from_bcs::to_u256(hash::sha3_256(external_bytes)) + } +} diff --git a/aptos-move/framework/aptos-framework/sources/util.move b/aptos-move/framework/aptos-framework/sources/util.move index c4888b06641be..36769463b6f9b 100644 --- a/aptos-move/framework/aptos-framework/sources/util.move +++ b/aptos-move/framework/aptos-framework/sources/util.move @@ -3,6 +3,7 @@ module aptos_framework::util { friend aptos_framework::any_map; friend aptos_framework::code; friend aptos_framework::gas_schedule; + friend aptos_framework::verified_external_value; /// Native function to deserialize a type T. ///