BIP: 44 Layer: Applications Title: Multi-Account Hierarchy for Deterministic Wallets Author: Marek Palatinus <slush@satoshilabs.com> Pavol Rusnak <stick@satoshilabs.com> Comments-Summary: Mixed review (one person) Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0044 Status: Proposed Type: Standards Track Created: 2014-04-24
Abstract
This BIP defines a logical hierarchy for deterministic wallets based on an algorithm described in BIP-0032 (BIP32 from now on) and purpose scheme described in BIP-0043 (BIP43 from now on).
这个BIP定义了一个基于BIP-0032和BIP-0043中描述的目的方案的逻辑层次结构。
This BIP is a particular application of BIP43.
这个BIP就是BIP43的一个特殊应用
Motivation
The hierarchy proposed in this paper is quite comprehensive. It allows the handling of multiple coins, multiple accounts, external and internal chains per account and millions of addresses per chain.
本文提出的层次结构比较全面。它允许处理多个硬币、多个帐户、每个帐户的外部和内部链以及每个链的数百万个地址。
Path levels
We define the following 5 levels in BIP32 path:
定义BIP32路径中的5个层次
m / purpose' / coin_type' / account' / change / address_index
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
路径中的撇号表示使用了经过硬化(hardern)处理的BIP32派生。
每个层次都有一个特殊的含义,在下面的章节中描述。
Purpose
Purpose is a constant set to 44' (or 0x8000002C) following the BIP43 recommendation. It indicates that the subtree of this node is used according to this specification.
根据BIP43建议将Purpose常量设置为44'(或0x8000002C),表示该节点的子树是根据本规范使用的。
Hardened derivation is used at this level.
硬化的派生在这个级别上使用。(所以右上角有'标记)
⚠️BIP-43 提出使用第一个强化子索引作为特殊的标识符表示 树状结构的“purpose”。基于 BIP-43,HD 钱包应该使用且只用第一层级的树的分支,而且有索引号码去识别结构并且有命名空间来定义剩余的树的目的地。举个 例子,HD 钱包只使用分支 m/i’/是 为了表明那个被索引号“i”定义的特殊为目地。
所以Purpose常量设置为44'是为了表示该钱包遵循的是 BIP-44 的 HD 钱包依据
Coin type-表示你存储的数字货币的类型
比如:index 0 表示的是比特币
index | hexa | symbol | coin |
---|---|---|---|
0 | 0x80000000 | BTC | Bitcoin |
One master node (seed) can be used for unlimited number of independent cryptocoins such as Bitcoin, Litecoin or Namecoin. However, sharing the same space for various cryptocoins has some disadvantages.
一个主节点(seed)可以用于无限数量的独立加密货币,如比特币、Litecoin或Namecoin。然而,为不同的加密币共享相同的空间有一些缺点。
This level creates a separate subtree for every cryptocoin, avoiding reusing addresses across cryptocoins and improving privacy issues.
这个级别为每个加密币创建一个单独的子树,避免在加密币之间重用地址,并改善了隐私问题。
Coin type is a constant, set for each cryptocoin. Cryptocoin developers may ask for registering unused number for their project.
硬币类型是一个常量,为每个加密硬币设置。加密币开发人员可能会要求为他们的项目注册未使用的号码。
The list of already allocated coin types is in the chapter "Registered coin types" below.
已分配硬币类型的列表在下面“注册硬币类型”一章中。
Hardened derivation is used at this level.
硬化的派生在这个级别上使用。(所以右上角有'标记)
Account-一类coin下能够有多个账户,就相当于你的人民币会存在多张银行卡中
This level splits the key space into independent user identities, so the wallet never mixes the coins across different accounts.
这个级别将密钥空间分割为独立的用户身份,因此钱包不会将硬币混合到不同的账户中。
Users can use these accounts to organize the funds in the same fashion as bank accounts; for donation purposes (where all addresses are considered public), for saving purposes, for common expenses etc.
用户可以使用这些账户以与银行账户相同的方式组织资金;捐款用途(所有地址均属公开地址)、储蓄用途、一般开支等。
Accounts are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation.
以顺序递增的方式从索引0开始编号。这个数字在BIP32派生中用作子索引。
Hardened derivation is used at this level.
硬化的派生在这个级别上使用。(所以右上角有'标记)
Software should prevent a creation of an account if a previous account does not have a transaction history (meaning none of its addresses have been used before).
如果以前的帐户没有交易历史记录(这意味着以前没有使用过它的地址),软件应该防止创建帐户。
Software needs to discover all used accounts after importing the seed from an external source. Such an algorithm is described in "Account discovery" chapter.
软件需要在从外部源导入种子之后发现所有使用过的帐户。在“帐户发现”一章中描述了这种算法。
Change-表明为外部链0或内部链1
Constant 0 is used for external chain and constant 1 for internal chain (also known as change addresses). External chain is used for addresses that are meant to be visible outside of the wallet (e.g. for receiving payments). Internal chain is used for addresses which are not meant to be visible outside of the wallet and is used for return transaction change.
常量0用于外部链,常量1用于内部链(也称为更改地址)。外部链用于在钱包外部可见的地址(例如用于接收付款)。内部链用于不在钱包外部可见的地址,用于返回交易更改。
Public derivation is used at this level.
在这个级别使用Public派生。
Index
Addresses are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation.
Public derivation is used at this level.
地址以顺序递增的方式从索引0开始编号。这个数字在BIP32派生中用作子索引。
在这个级别使用Public派生。
⚠️该级的作用是:
被HD钱包衍生的真正可用的地址是第四层级的子级,就是第五层级的树的“address_index”。
比如,第三个层级的主账户如M/44'/0'/1'收到比特币真正支付的地址是 M/44'/0'/0'/0/2
Account discovery
When the master seed is imported from an external source the software should start to discover the accounts in the following manner:
当主seed从外部源导入时,软件应该开始以以下方式发现帐户:
- derive the first account's node (index = 0)导出第一个帐户的节点
- derive the external chain node of this account 导出该帐户的外部链节点
- scan addresses of the external chain; respect the gap limit described below 扫描外链地址(只有外链地址外部可见);遵守下面描述的gap = 20的限制
- if no transactions are found on the external chain, stop discovery 如果在外部链上没有发现交易,则停止发现
- if there are some transactions, increase the account index and go to step 1如果有一些交易,增加帐户索引并转到第1步(直到发现所有的账户)
This algorithm is successful because software should disallow creation of new accounts if previous one has no transaction history, as described in chapter "Account" above.
这个算法是成功的,因为软件应该不允许创建新帐户,如果之前的帐户没有交易历史记录,如上面的“Account”一章所述。
Please note that the algorithm works with the transaction history, not account balances, so you can have an account with 0 total coins and the algorithm will still continue with discovery.
请注意,该算法是根据交易历史而不是账户余额来工作的,因此您可以拥有一个总共只有0枚硬币的账户,并且该算法仍将继续使用discovery。
Address gap limit
Address gap limit is currently set to 20. If the software hits 20 unused addresses in a row, it expects there are no used addresses beyond this point and stops searching the address chain. We scan just the external chains, because internal chains receive only coins that come from the associated external chains.
地址gap限制目前设置为20。如果软件连续访问了20个未使用的地址,它就会认为在此之后的也是没有使用过的地址,并停止搜索地址链。我们只扫描外部链,因为内部链只接收来自相关外部链的硬币。
Wallet software should warn when the user is trying to exceed the gap limit on an external chain by generating a new address.
当用户试图通过生成一个新地址来超过外部链的间隙限制时,钱包软件应该发出警告。
Registered coin types
These are the default registered coin types for usage in level 2 of BIP44 described in chapter "Coin type" above.
All these constants are used as hardened derivation.
以上是BIP44第2级使用的默认注册硬币类型,见上文“硬币类型”一章。
所有这些常数都用作强化派生。
index | hexa | coin |
---|---|---|
0 | 0x80000000 | Bitcoin |
1 | 0x80000001 | Bitcoin Testnet |
This BIP is not a central directory for the registered coin types, please visit SatoshiLabs that maintains the full list:
这个BIP不是注册硬币类型的中心目录,请访问SatoshiLabs,它维护完整的列表:
SLIP-0044 : Registered coin types for BIP-0044
To register a new coin type, an existing wallet that implements the standard is required and a pull request to the above file should be created.
要注册新的投币类型,需要一个实现该标准的现有钱包,并创建对上述文件的pull request。
Examples
coin | account | chain | address | path | subscriptions |
---|---|---|---|---|---|
Bitcoin | first | external | first | m / 44' / 0' / 0' / 0 / 0 | 第一个用于接收比特币支付的主账户的公钥 |
Bitcoin | first | external | second | m / 44' / 0' / 0' / 0 / 1 | |
Bitcoin | first | change | first | m / 44' / 0' / 0' / 1 / 0 | |
Bitcoin | first | change | second | m / 44' / 0' / 0' / 1 / 1 | |
Bitcoin | second | external | first | m / 44' / 0' / 1' / 0 / 0 | |
Bitcoin | second | external | second | m / 44' / 0' / 1' / 0 / 1 | |
Bitcoin | second | change | first | m / 44' / 0' / 1' / 1 / 0 | |
Bitcoin | second | change | second | m / 44' / 0' / 1' / 1 / 1 | |
Bitcoin Testnet | first | external | first | m / 44' / 1' / 0' / 0 / 0 | |
Bitcoin Testnet | first | external | second | m / 44' / 1' / 0' / 0 / 1 | |
Bitcoin Testnet | first | change | first | m / 44' / 1' / 0' / 1 / 0 | |
Bitcoin Testnet | first | change | second | m / 44' / 1' / 0' / 1 / 1 | |
Bitcoin Testnet | second | external | first | m / 44' / 1' / 1' / 0 / 0 | |
Bitcoin Testnet | second | external | second | m / 44' / 1' / 1' / 0 / 1 | |
Bitcoin Testnet | second | change | first | m / 44' / 1' / 1' / 1 / 0 | |
Bitcoin Testnet | second | change | second | m / 44' / 1' / 1' / 1 / 1 |
实例:
npm install ethereum-bip44 bitcore-lib --save
Create a new wallet:
var bitcore = require('bitcore-lib'); var EthereumBip44 = require('ethereum-bip44'); // create a new master private key var key = bitcore.HDPrivateKey(); // create the hd wallet var wallet = new EthereumBip44(key); // output the first address console.log(wallet.getAddress(0)); //0x6f22a64f04956935202008e5c48f6a8549c9b687 // output the second address console.log(wallet.getAddress(1)); //0x7641ef062d0123361d52a6a2b37eec4721093b75
node incex.js运行出错:
userdeMBP:test-hd-wallet user$ node index.js /Users/user/test-hd-wallet/node_modules/ethereum-bip44/node_modules/bitcore-lib/index.js:12 throw new Error(message); ^ Error: More than one instance of bitcore-lib found. Please make sure to require bitcore-lib and check that submodules do not also include their own bitcore-lib dependency.
将/Users/user/test-hd-wallet/node_modules/ethereum-bip44/node_modules下的bitcore-lib库删掉即可
查看wallet中的xprivkey为'xprv9s21ZrQH143K2fGrRNUdtYfVwgMF2AHtC4FfcFdVXyvXj2qZ373UUp1eDsT86YVpJ1PEzBzWdUjWkept79WaFpbXM6H3N7dXrHswUwPYNbW'
所以也可以用下面的方法:
Initialize from an existing private seed:
// create the hd wallet var wallet = EthereumBip44.fromPrivateSeed('xprv9s21ZrQH143K2fGrRNUdtYfVwgMF2AHtC4FfcFdVXyvXj2qZ373UUp1eDsT86YVpJ1PEzBzWdUjWkept79WaFpbXM6H3N7dXrHswUwPYNbW'); // output the first address console.log(wallet.getAddress(0)); // output the second address console.log(wallet.getAddress(1));
得到的结果是相同的
Initialize it from a public seed, for example on hot wallets that don't hold private keys:
var key = new bitcore.HDPrivateKey(); var derivedPubKey = key.derive("m/44'/60'/0'/0").hdPublicKey; // create the hd wallet var wallet = EthereumBip44.fromPublicSeed(derivedPubKey.toString()); // output the first address console.log(wallet.getAddress(0)); //0x3e7d28a1b8b73a04e8559a77d5422a04e1f0719e // output the second address console.log(wallet.getAddress(1)); //0x48635b1e9ad7e3d622310dc2dddeaa7b32597118