From 82ab11722abdfdc5b68b200aa36b06ffa9a564e9 Mon Sep 17 00:00:00 2001 From: Feliciss <10203-feliciss@users.noreply.0xacab.org> Date: Tue, 21 May 2024 12:02:26 +0900 Subject: [PATCH] [gh-1622] remove resource account in account.move. --- examples/steal_split/sources/steal_split.move | 95 +++++++++++++- frameworks/moveos-stdlib/doc/account.md | 94 +------------- frameworks/moveos-stdlib/sources/account.move | 122 ++---------------- frameworks/rooch-framework/doc/account.md | 27 +--- .../rooch-framework/sources/account.move | 25 +--- 5 files changed, 116 insertions(+), 247 deletions(-) diff --git a/examples/steal_split/sources/steal_split.move b/examples/steal_split/sources/steal_split.move index 9a56130bbb..fe37981e2a 100644 --- a/examples/steal_split/sources/steal_split.move +++ b/examples/steal_split/sources/steal_split.move @@ -40,10 +40,16 @@ module rooch_examples::rooch_examples { const ErrorBothPlayersDoNotHaveDecisionsSubmitted: u64 = 7; const ErrorPlayerHasDecisionSubmitted: u64 = 8; + // TODO: remove resource account address struct ResouceAccountAddress has key { addr: address } + // TODO: Account holder holds an account of the resource + struct AccountHolder { + account: Object, + } + struct State has key { next_game_id: u128, games: SimpleMap, @@ -107,9 +113,96 @@ module rooch_examples::rooch_examples { event_creation_timestamp_in_seconds: u64 } + /// ----------TODO---------- /// + /// Scheme identifier used when hashing an account's address together with a seed to derive the address (not the + /// authentication key) of a resource account. This is an abuse of the notion of a scheme identifier which, for now, + /// serves to domain separate hashes used to derive resource account addresses from hashes used to derive + /// authentication keys. Without such separation, an adversary could create (and get a signer for) a resource account + /// whose address matches an existing address of a MultiEd25519 wallet. + const SCHEME_DERIVE_RESOURCE_ACCOUNT: u8 = 255; + + /// A resource account is used to manage resources independent of an account managed by a user. + /// In Rooch a resource account is created based upon the sha3 256 of the source's address and additional seed data. + /// A resource account can only be created once + public fun create_resource_account(source: &signer): (signer, SignerCapability) { + let source_addr = signer::address_of(source); + let seed = account::generate_seed_bytes(&source_addr); + let resource_addr = create_resource_address(&source_addr, seed); + assert!(!is_resource_account(resource_addr), ErrorAccountIsAlreadyResourceAccount); + let resource_signer = if (exists_at(resource_addr)) { + let object_id = account_object_id(resource_addr); + let obj = object::borrow_object(object_id); + let account = object::borrow(obj); + assert!(account.sequence_number == 0, ErrorResourceAccountAlreadyUsed); + create_signer(resource_addr) + } else { + create_account_unchecked(resource_addr) + }; + + move_resource_to(&resource_signer,ResourceAccount {}); + + let signer_cap = SignerCapability { addr: resource_addr }; + + account_authentication::init_authentication_keys(&resource_signer); + account_coin_store::init_account_coin_stores(&resource_signer); + (resource_signer, signer_cap) + } + + public fun is_resource_account(addr: address): bool { + exists_resource(addr) + } + + /// This is a helper function to compute resource addresses. Computation of the address + /// involves the use of a cryptographic hash operation and should be use thoughtfully. + fun create_resource_address(source: &address, seed: vector): address { + let bytes = bcs::to_bytes(source); + vector::append(&mut bytes, seed); + vector::push_back(&mut bytes, SCHEME_DERIVE_RESOURCE_ACCOUNT); + bcs::to_address(hash::sha3_256(bytes)) + } + + #[test] + fun test_create_resource_account() { + let alice_addr = @123456; + let alice = create_account_for_testing(alice_addr); + let (resource_account, resource_account_cap) = create_resource_account(&alice); + let signer_cap_addr = get_signer_capability_address(&resource_account_cap); + move_resource_to( + &resource_account, + CapResponsbility { + cap: resource_account_cap + } + ); + + let resource_addr = signer::address_of(&resource_account); + std::debug::print(&100100); + std::debug::print(&resource_addr); + assert!(resource_addr != signer::address_of(&alice), 106); + assert!(resource_addr == signer_cap_addr, 107); + } + + //TODO figure out why this test should failed + #[test(sender=@0x42, resource_account=@0xbb6e573f7feb9d8474ac20813fc086cc3100b8b7d49c246b0f4aee8ea19eaef4)] + #[expected_failure(abort_code = ErrorResourceAccountAlreadyUsed, location = Self)] + fun test_failure_create_resource_account_wrong_sequence_number(sender: address, resource_account: address){ + { + create_account_for_testing(resource_account); + increment_sequence_number_internal(resource_account); + }; + let sender_signer = create_account_for_testing(sender); + let (signer, cap) = create_resource_account(&sender_signer); + move_resource_to( + &signer, + CapResponsbility { + cap + } + ); + } + /// ----------TODO---------- /// + fun init(account: &signer) { // let source_addr = signer::address_of(account); - let (signer, cap) = account_entry::create_resource_account(account); + let (signer, cap) = create_resource_account(account); let resource_address = signer::address_of(&signer); account::move_resource_to(account, ResouceAccountAddress { diff --git a/frameworks/moveos-stdlib/doc/account.md b/frameworks/moveos-stdlib/doc/account.md index d0e1657f60..c2d6b1054d 100644 --- a/frameworks/moveos-stdlib/doc/account.md +++ b/frameworks/moveos-stdlib/doc/account.md @@ -6,7 +6,6 @@ - [Resource `Account`](#0x2_account_Account) -- [Resource `ResourceAccount`](#0x2_account_ResourceAccount) - [Struct `SignerCapability`](#0x2_account_SignerCapability) - [Constants](#@Constants_0) - [Function `create_account_by_system`](#0x2_account_create_account_by_system) @@ -14,11 +13,9 @@ - [Function `sequence_number`](#0x2_account_sequence_number) - [Function `increment_sequence_number_for_system`](#0x2_account_increment_sequence_number_for_system) - [Function `signer_address`](#0x2_account_signer_address) -- [Function `is_resource_account`](#0x2_account_is_resource_account) - [Function `exists_at`](#0x2_account_exists_at) - [Function `create_signer_for_system`](#0x2_account_create_signer_for_system) - [Function `create_signer`](#0x2_account_create_signer) -- [Function `create_resource_account`](#0x2_account_create_resource_account) - [Function `create_signer_with_capability`](#0x2_account_create_signer_with_capability) - [Function `get_signer_capability_address`](#0x2_account_get_signer_capability_address) - [Function `account_object_id`](#0x2_account_account_object_id) @@ -62,18 +59,6 @@ It is also used to store the account's resources - - -## Resource `ResourceAccount` - -ResourceAccount can only be stored under address, not in other structs. - - -
struct ResourceAccount has key
-
- - - ## Struct `SignerCapability` @@ -120,32 +105,12 @@ Account already exists - - -Resource Account can't derive resource account - - -
const ErrorAccountIsAlreadyResourceAccount: u64 = 6;
-
- - - - - -Account does not exists - - -
const ErrorAccountNotExists: u64 = 2;
-
- - - Cannot create account because address is reserved -
const ErrorAddressReserved: u64 = 4;
+
const ErrorAddressReserved: u64 = 3;
 
@@ -155,17 +120,7 @@ Cannot create account because address is reserved Address to create is not a valid reserved address -
const ErrorNotValidSystemReservedAddress: u64 = 7;
-
- - - - - -An attempt to create a resource account on an account that has a committed transaction - - -
const ErrorResourceAccountAlreadyUsed: u64 = 5;
+
const ErrorNotValidSystemReservedAddress: u64 = 4;
 
@@ -175,7 +130,7 @@ An attempt to create a resource account on an account that has a committed trans The resource with the given type already exists -
const ErrorResourceAlreadyExists: u64 = 8;
+
const ErrorResourceAlreadyExists: u64 = 5;
 
@@ -185,7 +140,7 @@ The resource with the given type already exists The resource with the given type not exists -
const ErrorResourceNotExists: u64 = 9;
+
const ErrorResourceNotExists: u64 = 6;
 
@@ -195,21 +150,7 @@ The resource with the given type not exists Sequence number exceeds the maximum value for a u64 -
const ErrorSequenceNumberTooBig: u64 = 3;
-
- - - - - -Scheme identifier used when hashing an account's address together with a seed to derive the address (not the -authentication key) of a resource account. This is an abuse of the notion of a scheme identifier which, for now, -serves to domain separate hashes used to derive resource account addresses from hashes used to derive -authentication keys. Without such separation, an adversary could create (and get a signer for) a resource account -whose address matches an existing address of a MultiEd25519 wallet. - - -
const SCHEME_DERIVE_RESOURCE_ACCOUNT: u8 = 255;
+
const ErrorSequenceNumberTooBig: u64 = 2;
 
@@ -283,17 +224,6 @@ Return the current sequence number at addr - - -## Function `is_resource_account` - - - -
public fun is_resource_account(addr: address): bool
-
- - - ## Function `exists_at` @@ -327,20 +257,6 @@ Return the current sequence number at addr - - -## Function `create_resource_account` - -A resource account is used to manage resources independent of an account managed by a user. -In Rooch a resource account is created based upon the sha3 256 of the source's address and additional seed data. -A resource account can only be created once - - -
public fun create_resource_account(source: &signer): (signer, account::SignerCapability)
-
- - - ## Function `create_signer_with_capability` diff --git a/frameworks/moveos-stdlib/sources/account.move b/frameworks/moveos-stdlib/sources/account.move index addfd311ea..d3cbc6afe1 100644 --- a/frameworks/moveos-stdlib/sources/account.move +++ b/frameworks/moveos-stdlib/sources/account.move @@ -16,8 +16,6 @@ module moveos_std::account { sequence_number: u64, } - /// ResourceAccount can only be stored under address, not in other structs. - struct ResourceAccount has key {} /// SignerCapability can only be stored in other structs, not under address. /// So that the capability is always controlled by contracts, not by some EOA. struct SignerCapability has store { addr: address } @@ -27,33 +25,18 @@ module moveos_std::account { // cannot be dummy key, or empty key const CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER:vector = x"0000000000000000000000000000000000000000000000000000000000000001"; - /// Scheme identifier used when hashing an account's address together with a seed to derive the address (not the - /// authentication key) of a resource account. This is an abuse of the notion of a scheme identifier which, for now, - /// serves to domain separate hashes used to derive resource account addresses from hashes used to derive - /// authentication keys. Without such separation, an adversary could create (and get a signer for) a resource account - /// whose address matches an existing address of a MultiEd25519 wallet. - const SCHEME_DERIVE_RESOURCE_ACCOUNT: u8 = 255; - /// Account already exists const ErrorAccountAlreadyExists: u64 = 1; - /// Account does not exists - const ErrorAccountNotExists: u64 = 2; /// Sequence number exceeds the maximum value for a u64 - const ErrorSequenceNumberTooBig: u64 = 3; + const ErrorSequenceNumberTooBig: u64 = 2; /// Cannot create account because address is reserved - const ErrorAddressReserved: u64 = 4; - /// An attempt to create a resource account on an account that has a committed transaction - const ErrorResourceAccountAlreadyUsed: u64 = 5; - /// Resource Account can't derive resource account - const ErrorAccountIsAlreadyResourceAccount: u64 = 6; + const ErrorAddressReserved: u64 = 3; /// Address to create is not a valid reserved address - const ErrorNotValidSystemReservedAddress: u64 = 7; - - + const ErrorNotValidSystemReservedAddress: u64 = 4; /// The resource with the given type already exists - const ErrorResourceAlreadyExists: u64 = 8; + const ErrorResourceAlreadyExists: u64 = 5; /// The resource with the given type not exists - const ErrorResourceNotExists: u64 = 9; + const ErrorResourceNotExists: u64 = 6; /// Publishes a new `Account` resource under `new_address` via system. A signer representing `new_address` @@ -99,6 +82,15 @@ module moveos_std::account { (signer, signer_cap) } + /// This is a helper function to generate seed for resource address + fun generate_seed_bytes(addr: &address): vector { + let sequence_number = Self::sequence_number(*addr); + + let seed_bytes = bcs::to_bytes(addr); + vector::append(&mut seed_bytes, bcs::to_bytes(&sequence_number)); + + hash::sha3_256(seed_bytes) + } /// Return the current sequence number at `addr` public fun sequence_number(addr: address): u64 { @@ -140,10 +132,6 @@ module moveos_std::account { cap.addr } - public fun is_resource_account(addr: address): bool { - exists_resource(addr) - } - public fun exists_at(addr: address): bool { exist_account_object(addr) } @@ -155,49 +143,6 @@ module moveos_std::account { native public(friend) fun create_signer(addr: address): signer; - /// A resource account is used to manage resources independent of an account managed by a user. - /// In Rooch a resource account is created based upon the sha3 256 of the source's address and additional seed data. - /// A resource account can only be created once - public fun create_resource_account(source: &signer): (signer, SignerCapability) { - let source_addr = signer::address_of(source); - let seed = generate_seed_bytes(&source_addr); - let resource_addr = create_resource_address(&source_addr, seed); - assert!(!is_resource_account(resource_addr), ErrorAccountIsAlreadyResourceAccount); - let resource_signer = if (exists_at(resource_addr)) { - let object_id = account_object_id(resource_addr); - let obj = object::borrow_object(object_id); - let account = object::borrow(obj); - assert!(account.sequence_number == 0, ErrorResourceAccountAlreadyUsed); - create_signer(resource_addr) - } else { - create_account_unchecked(resource_addr) - }; - - move_resource_to(&resource_signer,ResourceAccount {}); - - let signer_cap = SignerCapability { addr: resource_addr }; - (resource_signer, signer_cap) - } - - - /// This is a helper function to generate seed for resource address - fun generate_seed_bytes(addr: &address): vector { - let sequence_number = Self::sequence_number(*addr); - - let seed_bytes = bcs::to_bytes(addr); - vector::append(&mut seed_bytes, bcs::to_bytes(&sequence_number)); - - hash::sha3_256(seed_bytes) - } - - /// This is a helper function to compute resource addresses. Computation of the address - /// involves the use of a cryptographic hash operation and should be use thoughtfully. - fun create_resource_address(source: &address, seed: vector): address { - let bytes = bcs::to_bytes(source); - vector::append(&mut bytes, seed); - vector::push_back(&mut bytes, SCHEME_DERIVE_RESOURCE_ACCOUNT); - bcs::to_address(hash::sha3_256(bytes)) - } public fun create_signer_with_capability(capability: &SignerCapability): signer { let addr = &capability.addr; @@ -341,7 +286,6 @@ module moveos_std::account { let alice = create_account_for_testing(alice_addr); let alice_addr_actual = signer::address_of(&alice); let sequence_number = sequence_number(alice_addr); - //std::debug::print(&sequence_number); assert!(alice_addr_actual == alice_addr, 103); assert!(sequence_number >= 0, 104); } @@ -351,44 +295,6 @@ module moveos_std::account { cap: SignerCapability } - #[test] - fun test_create_resource_account() { - let alice_addr = @123456; - let alice = create_account_for_testing(alice_addr); - let (resource_account, resource_account_cap) = create_resource_account(&alice); - let signer_cap_addr = get_signer_capability_address(&resource_account_cap); - move_resource_to( - &resource_account, - CapResponsbility { - cap: resource_account_cap - } - ); - - let resource_addr = signer::address_of(&resource_account); - std::debug::print(&100100); - std::debug::print(&resource_addr); - assert!(resource_addr != signer::address_of(&alice), 106); - assert!(resource_addr == signer_cap_addr, 107); - } - - //TODO figure out why this test should failed - #[test(sender=@0x42, resource_account=@0xbb6e573f7feb9d8474ac20813fc086cc3100b8b7d49c246b0f4aee8ea19eaef4)] - #[expected_failure(abort_code = ErrorResourceAccountAlreadyUsed, location = Self)] - fun test_failure_create_resource_account_wrong_sequence_number(sender: address, resource_account: address){ - { - create_account_for_testing(resource_account); - increment_sequence_number_internal(resource_account); - }; - let sender_signer = create_account_for_testing(sender); - let (signer, cap) = create_resource_account(&sender_signer); - move_resource_to( - &signer, - CapResponsbility { - cap - } - ); - } - #[test_only] fun drop_account_object(self: Object) { let obj = object::drop_unchecked(self); diff --git a/frameworks/rooch-framework/doc/account.md b/frameworks/rooch-framework/doc/account.md index 4dba30a236..2071a19ca7 100644 --- a/frameworks/rooch-framework/doc/account.md +++ b/frameworks/rooch-framework/doc/account.md @@ -9,7 +9,6 @@ - [Constants](#@Constants_0) - [Function `create_account`](#0x3_account_create_account) - [Function `create_account_internal`](#0x3_account_create_account_internal) -- [Function `create_resource_account`](#0x3_account_create_resource_account)
use 0x2::account;
@@ -38,22 +37,12 @@ Just using to get Account module signer
 ## Constants
 
 
-
-
-Account already exists
-
-
-
const ErrorAccountAlreadyExists: u64 = 1;
-
- - - Cannot create account because address is reserved -
const ErrorAddressReserved: u64 = 2;
+
const ErrorAddressReserved: u64 = 1;
 
@@ -80,17 +69,3 @@ is returned. This way, the caller of this function can publish additional resour
public(friend) fun create_account_internal(new_address: address): signer
 
- - - - - -## Function `create_resource_account` - -A resource account is used to manage resources independent of an account managed by a user. -In Rooch a resource account is created based upon the sha3 256 of the source's address and additional seed data. -A resource account can only be created once - - -
public fun create_resource_account(source: &signer): (signer, account::SignerCapability)
-
diff --git a/frameworks/rooch-framework/sources/account.move b/frameworks/rooch-framework/sources/account.move index ea2e2b2a6a..50cf7b4661 100644 --- a/frameworks/rooch-framework/sources/account.move +++ b/frameworks/rooch-framework/sources/account.move @@ -2,11 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 module rooch_framework::account { - use moveos_std::account::SignerCapability; + use moveos_std::account; use rooch_framework::account_coin_store; use rooch_framework::account_authentication; use moveos_std::signer::module_signer; - use moveos_std::account; use moveos_std::core_addresses; friend rooch_framework::genesis; @@ -16,10 +15,8 @@ module rooch_framework::account { /// Just using to get Account module signer struct AccountPlaceholder {} - /// Account already exists - const ErrorAccountAlreadyExists: u64 = 1; /// Cannot create account because address is reserved - const ErrorAddressReserved: u64 = 2; + const ErrorAddressReserved: u64 = 1; /// Publishes a new `Account` resource under `new_address`. A signer representing `new_address` /// is returned. This way, the caller of this function can publish additional resources under @@ -38,29 +35,11 @@ module rooch_framework::account { new_account } - - /// A resource account is used to manage resources independent of an account managed by a user. - /// In Rooch a resource account is created based upon the sha3 256 of the source's address and additional seed data. - /// A resource account can only be created once - public fun create_resource_account(source: &signer): (signer, SignerCapability) { - let (resource_signer, signer_cap) = account::create_resource_account(source); - - account_authentication::init_authentication_keys(&resource_signer); - account_coin_store::init_account_coin_stores(&resource_signer); - (resource_signer, signer_cap) - } - #[test_only] public fun create_account_for_testing(new_address: address): signer { create_account_internal(new_address) } - #[test_only] - struct Test has key{ - addr: address, - version: u64 - } - #[test(sender=@0x0)] #[expected_failure(abort_code = ErrorAddressReserved, location = Self)] fun test_failure_entry_account_creation_reserved(sender: address){