You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建身份识别合约:如何高效校验重复邮箱、电话及合约地址?

Hey there! Great question—tackling duplicate prevention in identity-focused Solidity contracts while keeping gas costs and storage bloat in check is a super common challenge. Let’s break down some better alternatives to your current approach, along with why they work:

1. Ditch Individual Person Contracts (Centralize Data in One Registry)

Your original setup deploys a new Person contract for every user, which is extremely gas-heavy—each contract deployment costs significant ETH, plus you end up with scattered storage across dozens/hundreds of contracts. Instead, store all user data in a single registry contract using structs and arrays, with lightweight mappings to enforce uniqueness.

Here’s a refined example:

contract PersonRegistry {
    struct Person {
        uint dateCreated;
        string name;
        string email;
        string phone;
        address owner;
    }

    // Track uniqueness: hash of email/phone → index of person in the array
    mapping(bytes32 => uint) private emailToIndex;
    mapping(bytes32 => uint) private phoneToIndex;
    mapping(address => uint) private ownerToIndex; // Prevent duplicate addresses

    Person[] private registeredPeople;

    function register(string calldata _name, string calldata _email, string calldata _phone) external {
        bytes32 emailHash = keccak256(abi.encodePacked(_email));
        bytes32 phoneHash = keccak256(abi.encodePacked(_phone));

        // Validate no duplicates exist
        require(emailToIndex[emailHash] == 0, "Email already registered");
        require(phoneToIndex[phoneHash] == 0, "Phone already registered");
        require(ownerToIndex[msg.sender] == 0, "Address already linked to a person");

        // Add new person to the array
        uint newIndex = registeredPeople.length;
        registeredPeople.push(Person({
            dateCreated: block.timestamp,
            name: _name,
            email: _email,
            phone: _phone,
            owner: msg.sender
        }));

        // Update mappings (use +1 to avoid confusion with default 0 value)
        emailToIndex[emailHash] = newIndex + 1;
        phoneToIndex[phoneHash] = newIndex + 1;
        ownerToIndex[msg.sender] = newIndex + 1;
    }

    // Getter for retrieving a person by email
    function getPersonByEmail(string calldata _email) external view returns (Person memory) {
        bytes32 emailHash = keccak256(abi.encodePacked(_email));
        uint index = emailToIndex[emailHash] - 1;
        require(index < registeredPeople.length, "Person not found");
        return registeredPeople[index];
    }

    // Add similar getters for phone/owner address
}

Why this works:

  • Way lower gas: No more deploying a contract per user—only one deployment, and storing data in an array is cheaper than managing multiple contract storages.
  • Leaner mappings: Instead of storing full contract addresses (20 bytes), we store array indices (effectively pointers), and the mappings only track uniqueness, not full data.
  • Easier management: All user data lives in one place, making it simpler to add features like updates or deletions later.
2. Optimize Storage with Hashed Values (Cut Down on String Costs)

If you don’t need to retrieve the raw email/phone from the contract (or can offload that to off-chain storage), store hashes of email/phone instead of the full strings. Dynamic string types are more expensive to store than fixed-size bytes32 values.

Modify the struct like this:

struct Person {
    uint dateCreated;
    string name;
    bytes32 emailHash;
    bytes32 phoneHash;
    address owner;
}

Then, when registering, you’d compute the hash upfront (either on-chain or off-chain) and store that. This cuts down on storage gas costs significantly, especially for longer emails/phone numbers.

3. Merkle Tree for Bulk Registrations (If You’re Handling Large Batches)

If you’re planning to register many users at once, a Merkle Tree can drastically reduce on-chain storage. You’d precompute a tree of all unique email/phone hashes, store only the root hash in the contract, and let users submit a proof to verify their eligibility during registration.

This is great for gas efficiency in bulk scenarios, but it’s overkill for individual, one-off registrations since it requires off-chain proof generation.

Key Takeaways

Your initial mapping idea isn’t bad, but the real gas bloat comes from deploying individual Person contracts. Centralizing data in a single registry is the most practical, cost-effective solution for most identity verification use cases. Combine that with hashed values for email/phone, and you’ll keep both gas costs and storage size under control.

内容的提问来源于stack exchange,提问作者HLeite

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:15:49