9.9 KiB
原文路径:https://github.com/cosmos/cosmos-sdk/blob/master/docs/basics/accounts.md
账户系统
必备阅读 {hide}
- 一个SDK程序的剖析 {prereq}
账户定义
在Cosmos SDK中,一个账户是指定的一个公私钥对.公钥可以用于派生出Addresses
,Addresses
可以在程序里面的各个模块间区分不同的用户.Addresses
同样可以和消息进行关联用于确定发消息的账户.私钥一般用于生成签名来证明一个消息是被一个Addresses
(和私钥关联的Addresses
)所发送.
Cosmos SDK使用一套称之为 BIP32的标准来生成公私钥.这个标准定义了怎么去创建一个HD钱包(钱包就是一批账户的集合).每一个账户的核心,都有一个种子,每一个种子都有一个12或24个字的助记符.使用这个助记符,使用一种单向的加密方法可以派生出任意数量的私钥.公钥可以通过私钥推导出来.当然,助记符是最敏感的信息,因为可以不停通过助记符来重新生成私钥.
Account 0 Account 1 Account 2
+------------------+ +------------------+ +------------------+
| | | | | |
| Address 0 | | Address 1 | | Address 2 |
| ^ | | ^ | | ^ |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| + | | + | | + |
| Public key 0 | | Public key 1 | | Public key 2 |
| ^ | | ^ | | ^ |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| + | | + | | + |
| Private key 0 | | Private key 1 | | Private key 2 |
| ^ | | ^ | | ^ |
+------------------+ +------------------+ +------------------+
| | |
| | |
| | |
+--------------------------------------------------------------------+
|
|
+---------+---------+
| |
| Master PrivKey |
| |
+-------------------+
|
|
+---------+---------+
| |
| Mnemonic (Seed) |
| |
+-------------------+
在Cosmos SDK中,账户可以在Keybase
中作为一个对象来储存和管理.
Keybase
Keybase
是储存和管理账户的对象,在Cosmos SDK中,Keybase
要实现以下接口
+++ 7d7821b9af/crypto/keys/types.go (L13-L86)
在Cosmos SDK中,Keybase
接口的默认实现对象是dbKeybase
.
+++ 7d7821b9af/crypto/keys/keybase.go
dbKeybase
上面对Keybase
接口中方法实现的笔记:
Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error)
对message
字节进行签名.需要做一些准备工作将message
编码成 [] byte类型,可以参考auth
模块message
准备的例子.注意,SDK上面没有实现签名的验证,签名验证被推迟到anteHandler
中进行 +++7d7821b9af/x/auth/types/txbuilder.go (L176-L209)
CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error)
创建一个新的助记符并打印在日志里,但是并不保存在磁盘上CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error)
基于bip44 path
创建一个新的账户并将其保存在磁盘上.注意私钥在保存前用密码加密,永远不会储存未加密的私钥.在这个方法的上下文中,account
和address
参数指的是BIP44派生路径的段(例如0
,1
,2
, ...)用于从助记符派生出私钥和公钥(注意:给相同的助记符和account
将派生出相同的私钥,给相同的account
和address
也会派生出相同的公钥和Address
).最后注意CreateAccount
方法使用在Tendermint library中的secp256k1
派生出公私钥和Address
.总之,这个方法是用来创建用户的钥匙和地址的,并不是共识秘钥,参见Addresses
获取更多信息
dbKeybase
的实现是最基本的,并没有根据需求提供锁定功能.锁定功能指如果一个dbKeybase
实例被创建,底层的db
就被锁定意味着除了实例化它的程序其他程序无法访问它.这就是SDK程序使用另外一套Keybase
接口的实现lazyKeybase
的原因
+++ 7d7821b9af/crypto/keys/lazy_keybase.go
lazyKeybase
是dbKeybase
的一个简单包装,它仅在要执行操作时锁定数据库,并在之后立即将其解锁。使用lazyKeybase
命令行界面可以在 rest server运行时创建新的账户,它也可以同时传递多个CLI命令
地址和公钥
Addresses
和PubKey
在程序里面都是标识一个参与者的公共信息.Cosmos SDK默认提供3中类型的Addresses
和PubKey
- 基于用户的
Addresses
和PubKey
,用于指定用户(例如message
的发送者).它们通过 **secp256k1
**曲线推导出来 - 基于验证节点的
Addresses
和PubKey
用于指定验证者的操作员,它们通过 **secp256k1
**曲线推导出来 - 基于共识节点的
Addresses
和PubKey
用于指定参与共识的验证着节点,它们通过 **ed25519
**曲线推导出来
Address bech32 Prefix | Pubkey bech32 Prefix | Curve | Address byte length | Pubkey byte length | |
---|---|---|---|---|---|
Accounts | cosmos | cosmospub | secp256k1 |
20 |
33 |
Validator Operator | cosmosvaloper | cosmosvaloperpub | secp256k1 |
20 |
33 |
Consensus Nodes | cosmosvalcons | cosmosvalconspub | ed25519 |
20 |
32 |
公钥
在Cosmos SDK里面PubKey
遵循在 tendermint的crypto
包中定义的Pubkey
接口
+++ bc572217c0/crypto/crypto.go (L22-L27)
对于secp256k1
类型的秘钥,具体的实现可以在这里找到.对于ed25519
类型的密钥,具体实现可以在这里找到.
请注意,在Cosmos SDK中,Pubkeys
并非以其原始格式进行操作。它使用Amino
和bech32
进行2次编码.在SDK里面,Pubkeys
首先调用Bytes()
方法在原始的 Pubkey
中(这里面提供amino编码),然后使用bech32
的ConvertAndEncode
方法
+++ 7d7821b9af/types/address.go (L579-L729)
地址
在Cosmos SDK默认提送3种类型的地址
AccAddress
用于账户ValAddress
用于验证者操作员ConsAddress
用于验证着节点
这些地址类型都是一种长度为20的十六进制编码的[]byte
数组的别名,这里有一种标准方法从Pubkey pub
中获取到地址aa
.
aa := sdk.AccAddress(pub.Address().Bytes())
这些地址实现了 Address
接口
+++ 7d7821b9af/types/address.go (L71-L80)
值得注意的是,Marhsal()
和Bytes()
方法都返回相同的[]byte
类型的地址,根据protobuff的兼容性要求我们需要前者.同样,String()
也被用来返回bech32
编码类型的地址,这个应该是用户看到的最终编码形式.下面是一个例子:
+++ 7d7821b9af/types/address.go (L229-L243)
接下来 {hide}
学习gas and fees {hide}