Using Substrate’s account abstraction, developers can build a more scalable and secure wallet solution.
Original title: “How to use Substrate to make a hot wallet that can safely support millions of addresses? 》
Written by: Joe Petrowski
Translation: PolkaWorld Community
The Substrate and FRAME systems used for runtime development define a set of powerful primitive functions for building blockchain infrastructure. Using the two together creates a novel method for solving existing problems. This article will describe a practical application in which the functions of Substrate are used to implement a multi-address hot wallet.
Hot wallets usually mean keeping spending keys on online devices so that transactions can be easily created and broadcast, but the risks are usually higher. This article will explore some of Substrate’s account abstractions-multi-signature accounts, proxy accounts and derivative accounts-how we can build a hot wallet that can safely support millions of addresses.
If you need to hold tokens for multiple user accounts, but want to provide each customer with their own deposit address, then such a wallet will be very useful. The simple solution is to generate a new deposit address for each customer by generating a new key pair. But processing all these key pairs quickly is not easy. What if you have thousands of users? Using Substrate’s account abstraction, we can build a more scalable and secure solution.
Source and account ID
Before starting to build a hot wallet, we need to lay the foundation for it to be used. When users interact with the blockchain, they are calling certain functions. The collection of these “dispatchable” functions forms the interface of the blockchain.
Since the schedulable function is called from the outside, the blockchain may first care about who actually called the function. First, a function needs to check whether the caller is authorized to execute the function. Second, the chain may need to know exactly who called the function to update some information about the caller. If the caller is an account, the chain may need to update the balance of the account, for example to deduct transaction fees.
You might be thinking, “What does that mean if the caller is an account?” The functions in Substrate do not come from the account itself, but from the origins. For example, Polkadot’s governance system has a series of special sources that have privileges, such as allocating treasury funds or revoking Slash. If you use Substrate to design your own blockchain, you can create your own custom source. However, one thing to remember in this article is that accounts are just a variation of the source of Substrate. You can imagine that Substrate tells the dispatchable function, “The source of this dispatch is an account.”
Now that we have achieved the first leap of abstraction, we need a way to tell which account the source of the function refers to. If you have used any blockchain, you may be accustomed to using an account ID as the public key corresponding to the private key. This is no problem, this can also be used in Substrate. In this sense, an account is identified by a public key and authorized by the corresponding private key.
Substrate supports more abstractions. The account ID can be any 32-byte number. [1] It can be the public key corresponding to the private key, but it is not required. It only requires some kind of authorization method. Just like in it, there must be some unique way to generate this account identification number so that Substrate can complete the sentence at the beginning of the above: “The source of this schedule is the account identified by this number.” [2]
Hash function
Hash functions have always appeared in the blockchain. The blocks are actually linked together by their hash value. But we will use the properties of the hash function to achieve two other purposes: generating account ID and identifying function calls.
The hash function accepts some arbitrary size input and maps it to a fixed size output (for example, 32 bytes). However, it not only maps data to any 32-byte number, but should deterministically map unique data to a unique number. As it happens, 32 bytes can capture astronomical items. [3]
For example, we can get some information about the chain, such as “polkadot-treasury”, and use a hash function to convert it into an account ID (32 bytes). Alternatively, we can obtain information about certain transactions, such as “transfer 10 units to account 123…” and believe that the hash is the only image of that information.
Multi-signature account
With these, we can start building the first part of a hot wallet: multisig accounts. Due to the overall bulkiness, a multi-signature account may not look like a part of a popular wallet, but this account will serve as a security basis for the remaining components, and the bulkiness just mentioned will not hinder daily use.
Some blockchains use cryptographic multi-signatures, where multiple key holders sign a single transaction off-chain before submitting the transaction on-chain. The multi-signature system that comes with Substrate’s FRAME works in another way: it generates account IDs based on the individual accounts that make up the multi-signature and the necessary thresholds required for distribution from the generated accounts. Substrate adds a special multi-signature prefix to all this information and hashes it to obtain a 32-byte output, which will be used as the multi-signature account ID. Please note that this account ID does not have a private key associated with it.
In order to authorize the transaction from the new account ID, the members of the multi-signature use the function call they wish to make on the multi-signature account to submit the transaction on the chain. However, it is not efficient for everyone to submit a function call; it can be large, and block space is scarce (and therefore expensive). The hash function comes in handy again: only one account needs to submit the actual function call; others only submit the hash. They only need to say: “We agree to use this hash to call the function through a multi-signature account” without resubmitting the function.
This multi-signature itself is too clumsy to be used as a hot wallet because it requires multiple key holders to submit transactions to make it work. But it is highly secure, it can be used as a basic account, and we can turn it into a hot wallet without sacrificing its security.
Proxy account
The proxy account allows the multi-signature address to delegate spending authority to another account, which will be used as a hot wallet while still maintaining the security of the multi-signature. We will set up a one-time delayed agent to manage expenses, and another (or more) instant agent to manage the security of this multi-signature account.
The proxy account grants the privileges of one account to another account to make function calls on behalf of the account. These privileges can be specific, such as “only transactions related to mortgages”, or broad, such as “all transactions that do not involve the transfer of funds”, or even complete privileges such as “any transaction”.
To create an agent, you only need to make one transaction from the account to be agent, and specify which other account is the agent and its privileges. After the agency relationship is in place, the proxy account can conduct transactions for the proxy account, essentially telling the chain: “I am the agent of the account, I have these privileges, and I want to represent the proxy account.” The logic of the chain will verify that the agent does have Correct privileges and use the source of the proxy account to dispatch the function.
Adding a time delay adds a layer of security. Imagine a time delay of 600 blocks (one hour in Polkadot). The proxy account will still submit the transaction, saying that it is a proxy with certain privileges, but will only announce the hash value of the function call it wants to make. The owner of the proxy account can request the actual function call and review it. If the owner disagrees, they can reject the function call by submitting another transaction before the delay time expires. After the time delay, the agent can submit the actual function call corresponding to the announcement, which is then scheduled by Substrate. [4]
For our use case, the multi-signature key holder will make a transaction to set another account as a delayed agent with full privileges, including balance transfers, for example. Perhaps this proxy account will exist on an online server that can automatically conduct transactions. Whenever a transaction is made, it must first announce the hash, and then send the actual function call to other account holders (for simplicity, we treat this other account holder as a multi-signature member), and they can Verify that the function call is not malicious. If it is malicious, a multi-signature transaction can be conducted in time to reject the call, and out of prudent consideration, it is determined that the proxy account has been stolen and deleted.
This configuration does work, but we can still make it more convenient to use. Using only one agent, we may need a long time delay, because it may be difficult to coordinate enough multi-signature key holders to conduct rejection transactions in a short time. But an account can have multiple proxy accounts with different privileges. To solve this problem, set each multi-signature key holder as an agent with non-transfer privileges, especially the privilege to reject notifications from delayed agents.
Let us briefly introduce this configuration. In the center, we have a multi-signature account. The account does not have a private key, but there are two ways to control it: use a delayed proxy account or collect enough member account signers. Each member of the multi-signature also has the ability to reject transactions from the fully-privileged agent, but if no other members join the multi-signature transaction, the balance transfer cannot be performed.
It is a full-featured hot wallet by itself, just delete the proxy and set a new hot wallet to change the hotkey (a proxy account with full privileges) without changing its address (a multi-signature account). But our initial problem statement required thousands of users to use a unique deposit address. So far, we have only one user.
Derivative account
So far, we have used multiple methods to access a multi-signature account. Now, we will use one account to access many accounts.
Each account in Substrate has a derivative account tree that can be accessed. In order to obtain the account ID, Substrate naturally uses the hash algorithm. By hashing the account ID of the calling account with the required index and derived prefix, Substrate creates a new account ID. For example, the sender provides a function call and an index, saying: “I want to dispatch this function from a derived account with this index.”
You may have guessed what will happen later. The wallet owner can assign an index to each user and provide a derived account ID as the user’s deposit address. In order to access the funds, the proxy address will issue a transaction to transfer the funds from the derived address of the multi-signature account.
Specifically, the index is limited to 16 bits or 65,536 derived accounts, but it can also be nested. In other words, each derivative account can have its own set of 65,536 derivative accounts, and so on. The second level of the tree will have more than 4 billion accounts.
Full picture
Finally, let us use this knowledge. Imagine that the user with index 11 pays you and you have some “saving accounts” to deposit funds. The entire transaction looks like: “I am the agent of a multi-signature account. I want to transfer funds from a multi-signature derivative account (index 11) to a savings account.”
Assuming everything is normal for the regulator, the delay time will expire and the agent can broadcast the complete transaction. If the multi-signature members think that the hot key needs to be changed, they can simply generate a new key and delete the old key as a proxy without affecting the multi-signature or any of its derived addresses.
The above figure shows a schematic diagram of the wallet we have set up: Multi-signature (MS) is controlled by a set of n keys (denoted as k), and the time delay agent (H) is set as a hot key. It can derive almost unlimited addresses (sets of d) from multisignatures.
We can even further optimize this workflow. Substrate also provides functions to send a batch of function calls. If users regularly deposit and withdraw funds in their derivative accounts, you can send them all in one batch of transfers.
Substrate’s on-chain account abstraction provides a powerful way to manage accounts. By reducing the number of actual keys required and accessing accounts according to formal rules rather than private keys, you can operate thousands of accounts without having to deal with the limitation of storing an equal number of signature keys. This article only focuses on an example of building a hot wallet, but all abstractions are isolated and can be composed of more advanced applications.
Comment
1. It does not have to be 32 bytes. You can build runtime as you want, but I don’t want this article to go beyond the necessary scope.
2. A quick explanation of the word “unique”. Strictly speaking, my meaning here is stricter than the definition in the ordinary dictionary. An account is unique, not that it can only have one representation, but that all representations (or a series of representations) can be proved to be equal. There may be an unlimited number of methods to generate a specific number (account), but as long as all of these methods actually generate the same account, then the account can be considered unique. Explaining the mathematics in detail will be complicated enough to make your head big, but we will generate account IDs and pass them between functions. The key here is no matter how many functions we have string together (concatenated) to reach an account ID, which acts as the same account ID in terms of acting as a dispatch source.
3. If you are interested, 32 bytes can hold up to 1.15×10^77. The distance to the edge of the observable universe is 45.7 billion light-years, which is 4.32×10^23 kilometers or 4.32×10^29 mm. If we think of it as a flat optical disc, its area is 5.87×10^59 square millimeters. We still differ by 10^18 or billion squares. Therefore, the chance of two different hash inputs having the same output is like both items falling on the same square millimeter in the observable universe, then decomposing it into a grid of 1 billion times 1 billion, and then again All fell on the same square. These squares are 1 picometer (picometer) wide. For reference, the diameter of a helium atom is 62 picometers.
4. In fact, as long as the agent issues a notification, any account can submit the call, but for pragmatism, it is assumed that our hot wallet only uses the same account for notification and submission.
Source link: www.parity.io





