Aptos

2025年09月09日更新 4 人订阅
原价: ¥ 2.2 限时优惠
专栏简介 Aptos 开发实战:从环境搭建到第一个 Hello World Aptos 开发指南:在 JetBrains 编辑器中配置运行、编译、测试与发布部署,实现更高效开发 Aptos 区块链智能合约入门:使用 Move 实现消息存储与检索 Aptos Move 语言中的变量管理与内存所有权机制详解 Aptos Move 编程语言中的四大基础类型解析:UINT、STRING、BOOL 与 ADDRESS 深入解读 APTOS-MOVE 中的 Vector 向量核心特性与操作 深入理解APTOS-MOVE中的函数修饰符:核心概念与应用 深入解读 Aptos Move 的 Struct 特性与四大能力 Aptos Move 控制流解析:IF、WHILE与LOOP的深入解读 Aptos Move 模块的特性与实操指南:模块引用与作用域管理 Aptos Move 模块的发布与交互:完整指南 深入理解 Aptos Move 中的 Object 创建与管理 深入探索 Aptos Move:Object 配置与实操指南 使用 Aptos Move 实现随机数生成:从 AIP-41 到实战操作 Aptos Move 实践指南:构建并部署同质化代币水龙头 (FA Faucet) Aptos Move NFT 项目实操指南:从开发到部署全流程解析 Aptos Move 开发入门:从环境搭建到合约部署全流程实录 Aptos Move 入门:从零到一的合约开发与测试实战 Move 语言核心:布尔逻辑与地址类型的实战精解 深入 Aptos Move:从public到friend,函数可见性详解 Aptos Move 编程:for、while 与 loop 循环的实战详解 Aptos Move 安全编程:abort 与 assert! 错误处理实战 Aptos Move 实战:基础运算与比较逻辑的实现与测试 Aptos Move 性能优化:位运算与移位操作实战 Aptos Move 实战:as 关键字与整数类型转换技巧 Aptos Move DeFi 实战:从零构建流动性池兑换逻辑 Aptos Move 实战:用 signer 实现合约所有权与访问控制 Aptos Move 核心安全:& 与 &mut 引用机制详解 Aptos Move 实战:全面掌握 SimpleMap 的增删改查 Aptos Move 入门:掌握链上资源(Resource)的增删改查 Aptos Move 深度实践:用嵌套数据结构构建链上金银储备系统 Aptos Move 实操:如何用 Tables 构建一个链上房产管理系统

Aptos Move 实操:如何用 Tables 构建一个链上房产管理系统

AptosMove实操:如何用Tables构建一个链上房产管理系统Aptos独特的数据存储模型为其生态应用提供了坚实基础,而Table功能正是其中高效管理链上数据的关键。本文将通过一个完整的链上房产管理系统,深入探讨如何在AptosMove中利用Table实现去中心化应用的

Aptos Move 实操:如何用 Tables 构建一个链上房产管理系统

Aptos 独特的数据存储模型为其生态应用提供了坚实基础,而 Table 功能正是其中高效管理链上数据的关键。本文将通过一个完整的链上房产管理系统,深入探讨如何在 Aptos Move 中利用 Table 实现去中心化应用的增、查、改、删核心功能。

实操

Aptos Move Tables

示例一

module net2dev_addr::tables_demo {
    use aptos_framework::table::{Self, Table};
    use std::signer;
    use std::string::String;

    struct Property has store, copy, drop {
        baths: u16,
        beds: u16,
        sqm: u16,
        phy_address: String,
        price: u64,
        available: bool
    }

    struct PropList has key {
        info: Table<u64, Property>,
        prop_id: u64
    }

    fun register_seller(account: &signer) {
        let init_property = PropList { info: table::new(), prop_id: 0 };
        move_to(account, init_property);
    }

    fun list_property(account: &signer, prop_info: Property) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr) == true, 101);
        let prop_list = borrow_global_mut<PropList>(account_addr);
        let new_id = prop_list.prop_id + 1;
        prop_list.info.upsert(new_id, prop_info);
        prop_list.prop_id = new_id;
    }

    fun read_property(
        account: &signer, prop_id: u64
    ): (u16, u16, u16, String, u64, bool) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr) == true, 101);
        let prop_list = borrow_global<PropList>(account_addr);
        let info = prop_list.info.borrow(prop_id);
        (info.baths, info.beds, info.sqm, info.phy_address, info.price, info.available)
    }

    #[test_only]
    use std::debug::print;

    #[test_only]
    use std::string::utf8;

    #[test(seller1 = @0x123, seller2 = @0x124)]
    fun test_function(seller1: signer, seller2: signer) acquires PropList {
        register_seller(&seller1);
        let prop_info = Property {
            baths: 2,
            beds: 3,
            sqm: 110,
            phy_address: utf8(b"Santa Marta, Colombia"),
            price: 120000,
            available: true
        };
        list_property(&seller1, prop_info);
        let (_, _, _, location, price, available) = read_property(&seller1, 1);
        assert!(location == utf8(b"Santa Marta, Colombia"));
        assert!(price == 120000);
        assert!(available);
        print(&location);
        print(&price);
        print(&available);

        register_seller(&seller2);
        let prop_info = Property {
            baths: 2,
            beds: 2,
            sqm: 150,
            phy_address: utf8(b"Dubai, UAE"),
            price: 350000,
            available: true
        };
        list_property(&seller2, prop_info);
        let (baths, beds, sqm, location, price, available) = read_property(&seller2, 1);
        assert!(baths == 2);
        assert!(beds == 2);
        assert!(sqm == 150);
        assert!(location == utf8(b"Dubai, UAE"));
        assert!(price == 350000);
        assert!(available);
        print(&baths);
        print(&beds);
        print(&sqm);
        print(&location);
        print(&price);
        print(&available);
    }
}

这段代码是一个 Aptos Move 智能合约,它的作用是让房产卖家能在区块链上登记和管理房产信息。你可以把它理解为一个简单的链上房产列表应用

它主要做了三件事:

  1. 注册卖家: 任何想卖房的人都可以调用 register_seller 函数,在自己的账户下创建一个“房产清单” ( PropList )。
  2. 发布房产: 卖家可以调用 list_property 函数,将一套房子的详细信息(比如几卧几卫、面积、价格等)登记到自己的清单里,每套房产都会得到一个独一无二的 ID。
  3. 查询房产: 任何人都可以调用 read_property 函数,通过房产 ID 查看房子的具体信息。

代码中用到的 Table 就像一个高效的数据库,它能安全地存储多套房产信息。这确保了每套房产数据都只属于对应的卖家,并且这些信息都公开透明、不可篡改。

测试

➜ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING my-dapp
Running Move unit tests
[debug] "Santa Marta, Colombia"
[debug] 120000
[debug] true
[debug] 2
[debug] 2
[debug] 150
[debug] "Dubai, UAE"
[debug] 350000
[debug] true
[ PASS    ] 0x48daaa7d16f1a59929ece03157b8f3e4625bc0a201988ac6fea9b38f50db5ef3::tables_demo::test_function
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
  "Result": "Success"
}

这段测试结果表明,你的 Aptos Move 智能合约代码在所有单元测试中运行正常,没有发现任何问题

具体来说:

  • Running Move unit tests: 启动单元测试。
  • [debug] 输出: 打印出你代码中用于调试的变量值,比如 "Santa Marta, Colombia", 120000, true 等,这些都是你 test_function 中设置和读取的房产信息,说明数据读写都正确无误。
  • [ PASS ] ...tables_demo::test_function: 表示你编写的 test_function 这个测试用例通过了
  • Test result: OK. Total tests: 1; passed: 1; failed: 0: 总结测试结果,显示总共运行了1个测试,1个通过,0个失败。这代表你的代码在测试覆盖范围内是可靠的
  • { "Result": "Success" }: 最终结果为成功。

示例二

module net2dev_addr::tables_demo {
    use aptos_framework::table::{Self, Table};
    use std::signer;
    use std::string::String;
    use std::option::Option;

    /// PropertyList 资源
    const E_RESOURCE_NOT_FOUND: u64 = 101; // PropList资源不存在
    /// 房产ID不存在
    const E_PROPERTY_NOT_FOUND: u64 = 102; // 房产ID不存在

    struct Property has store, copy, drop {
        baths: u16,
        beds: u16,
        sqm: u16,
        phy_address: String,
        price: u64,
        available: bool
    }

    struct PropList has key {
        info: Table<u64, Property>,
        prop_id: u64
    }

    fun register_seller(account: &signer) {
        let init_property = PropList { info: table::new(), prop_id: 0 };
        move_to(account, init_property);
    }

    fun list_property(account: &signer, prop_info: Property) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr) == true, 101);
        let prop_list = borrow_global_mut<PropList>(account_addr);
        let new_id = prop_list.prop_id + 1;
        prop_list.info.upsert(new_id, prop_info);
        prop_list.prop_id = new_id;
    }

    fun read_property(
        account: &signer, prop_id: u64
    ): (u16, u16, u16, String, u64, bool) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr) == true, 101);
        let prop_list = borrow_global<PropList>(account_addr);
        let info = prop_list.info.borrow(prop_id);
        (info.baths, info.beds, info.sqm, info.phy_address, info.price, info.available)
    }

    fun update_property(
        account: &signer,
        prop_id: u64,
        baths: Option<u16>,
        beds: Option<u16>,
        sqm: Option<u16>,
        phy_address: Option<String>,
        price: Option<u64>,
        available: Option<bool>
    ) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr), E_RESOURCE_NOT_FOUND);
        let prop_list = borrow_global_mut<PropList>(account_addr);
        assert!(prop_list.info.contains(prop_id), E_PROPERTY_NOT_FOUND);
        let info = prop_list.info.borrow_mut(prop_id);

        if (baths.is_some()) {
            info.baths = baths.destroy_some()
        };

        if (beds.is_some()) {
            info.beds = beds.destroy_some()
        };

        if (sqm.is_some()) {
            info.sqm = sqm.destroy_some()
        };

        if (phy_address.is_some()) {
            info.phy_address = phy_address.destroy_some()
        };

        if (price.is_some()) {
            info.price = price.destroy_some()
        };

        if (available.is_some()) {
            info.available = available.destroy_some()
        };
    }

    fun delete_property(account: &signer, prop_id: u64) acquires PropList {
        let account_addr = signer::address_of(account);
        assert!(exists<PropList>(account_addr), E_RESOURCE_NOT_FOUND);
        let prop_list = borrow_global_mut<PropList>(account_addr);
        assert!(prop_list.info.contains(prop_id), E_PROPERTY_NOT_FOUND);
        prop_list.info.remove(prop_id);
    }

    #[test_only]
    use std::debug::print;

    #[test_only]
    use std::string::utf8;
    use std::option;

    #[test(seller1 = @0x123, seller2 = @0x124)]
    fun test_function(seller1: signer, seller2: signer) acquires PropList {
        // Test list_property and read_property for seller1
        register_seller(&seller1);
        let prop_info_s1 = Property {
            baths: 2,
            beds: 3,
            sqm: 110,
            phy_address: utf8(b"Santa Marta, Colombia"),
            price: 120000,
            available: true
        };
        list_property(&seller1, prop_info_s1);
        let (baths, beds, sqm, location, price, available) = read_property(&seller1, 1);
        assert!(baths == 2);
        assert!(beds == 3);
        assert!(sqm == 110);
        assert!(location == utf8(b"Santa Marta, Colombia"));
        assert!(price == 120000);
        assert!(available);
        print(&location);
        print(&price);
        print(&available);

        register_seller(&seller2);
        let prop_info = Property {
            baths: 2,
            beds: 2,
            sqm: 150,
            phy_address: utf8(b"Dubai, UAE"),
            price: 350000,
            available: true
        };
        list_property(&seller2, prop_info);
        let (baths, beds, sqm, location, price, available) = read_property(&seller2, 1);
        assert!(baths == 2);
        assert!(beds == 2);
        assert!(sqm == 150);
        assert!(location == utf8(b"Dubai, UAE"));
        assert!(price == 350000);
        assert!(available);
        print(&baths);
        print(&beds);
        print(&sqm);
        print(&location);
        print(&price);
        print(&available);

        // Test update_property for seller1
        update_property(
            &seller1,
            1,
            option::some(3),
            option::some(4),
            option::none(),
            option::none(),
            option::some(150000),
            option::some(false)
        );
        let (
            baths_updated,
            beds_updated,
            sqm_updated,
            location_updated,
            price_updated,
            available_updated
        ) = read_property(&seller1, 1);
        assert!(baths_updated == 3);
        assert!(beds_updated == 4);
        assert!(sqm_updated == 110); // Should remain unchanged
        assert!(location_updated == utf8(b"Santa Marta, Colombia")); // Should remain unchanged
        assert!(price_updated == 150000);
        assert!(available_updated == false);
        print(&baths_updated);
        print(&beds_updated);
        print(&price_updated);
        print(&available_updated);

        // Test delete_property for seller1
        delete_property(&seller1, 1);
        let prop_list = borrow_global<PropList>(signer::address_of(&seller1));
        assert!(prop_list.info.contains(1) == false, 102); // The property should no longer exist

    }
}

这段 Aptos Move 代码是一个链上房产管理系统的精简版。它利用 Aptos 的核心特性 Table (表),为每位房产卖家提供了一个私有的、可扩展的、类似数据库的房产清单。

这使得房产信息(如面积、卧室数、价格等)可以直接存储在区块链上,确保了数据的公开透明不可篡改。买家可以随时调用函数来查询房产信息,而只有卖家本人才能发布、更新和删除自己名下的房产,从而实现了安全、去中心化的房产信息管理。

测试

➜ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING my-dapp
Running Move unit tests
[debug] "Santa Marta, Colombia"
[debug] 120000
[debug] true
[debug] 2
[debug] 2
[debug] 150
[debug] "Dubai, UAE"
[debug] 350000
[debug] true
[debug] 3
[debug] 4
[debug] 150000
[debug] false
[ PASS    ] 0x48daaa7d16f1a59929ece03157b8f3e4625bc0a201988ac6fea9b38f50db5ef3::tables_demo::test_function
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
  "Result": "Success"
}

这段测试结果表明,你的 Aptos Move 智能合约代码在所有单元测试中运行正常,没有发现任何问题

具体来说,[debug] 输出显示了房产数据的创建和更新都完全符合预期。最初登记的房产信息(如“Santa Marta, Colombia”和120000的价格)被正确读取,随后更新后的信息(如3个浴室、4个卧室和150000的新价格)也被成功验证。

最终的Test result: OK. Total tests: 1; passed: 1; failed: 0则明确告诉你:你编写的唯一一个测试用例完全通过了,这意味着你智能合约的核心功能——从房产登记、信息读取、更新到删除——都运行得非常可靠。

总结

通过这个完整的链上房产管理系统示例,我们全面展示了 Aptos Move 中 Table 的核心应用。从基础的资源定义,到核心的增、查、改、删函数实现,我们不仅掌握了 Table 的实操方法,更理解了其在链上数据管理中的重要性。实践证明,Table 是构建高效、安全且可扩展的去中心化应用的关键。希望本文能为你打开 Aptos Move 开发的大门,激发你创造更多有趣的链上应用。

参考

点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论