{"content":{"title":"Web3专题(二) 2种钱包之非确定性钱包（keystore管理私钥）","body":"以太坊上有 2 种钱包：\r\n\r\n1. 非确定性钱包，也叫随机钱包，每个账户通过独立的随机数生成器创建，使用`keystore`管理账户，**没有助记词**。\r\n\r\n2. 分层确定性钱包，也叫**HD Wallet**，每个账户通过固定的种子(seed)派生，使用`助记词`管理所有账户。\r\n\r\n本文讲解`非确定性钱包`，因为比较简单，下面会直接给出代码实现。下一篇文章会详细讲解`分层确定性钱包`，这个已经成为了行业标准，我会重磅介绍，并对比两种钱包的适用场景。\r\n\r\n### 概念\r\n\r\n随机数生成器：如[Web3专题(一) 助记词和生成私钥、公钥、地址的基本原理](https://learnblockchain.cn/article/7051)所说，私钥是 256 位随机数字，需要使用安全的随机源生成，并经过一系列算法生成公钥、地址。\r\n\r\nkeystore：是一种文件格式，称为存储机制，主要目的是提供一种安全的方式来保管私钥，需要用户提供密码来解锁私钥。\r\n\r\n通常，用 keystore 文件加密私钥等信息，来保护`非确定性钱包`。\r\n\r\n### 使用 Go 语言开发一个非确定性钱包\r\n\r\n1. 需要引入的包\r\n\r\n```go\r\nimport (\r\n\t\"github.com/ethereum/go-ethereum/accounts/keystore\"\r\n\t\"github.com/ethereum/go-ethereum/common\"\r\n\t\"github.com/ethereum/go-ethereum/crypto\"\r\n)\r\n```\r\n\r\n2. 创建 keystore 对象，所有的私钥都由这个 keystore 对象管理。在这里，我们指定`./keystore`文件夹保存账户。\r\n\r\n> **特别提醒**：\r\n> `NewKeyStore` 方法只会加载目录，并监控目录的变化，不会创建账户，创建账户在下面第 3 步。\r\n> `NewKeyStore` 方法内部会自动扫描`./keystore`文件夹，并加载这个文件夹下的所有账户到 keystore 对象\r\n\r\n```go\r\n// 第一个参数：./keystore 指定账户所在的文件夹\r\nks := keystore.NewKeyStore(\"./keystore\", keystore.StandardScryptN, keystore.StandardScryptP)\r\n```\r\n\r\n3. 创建一个新账户\r\n\r\n> `NewAccount` 会利用你指定的密码在`./keystore` 目录下创建一个 json 文件，这个文件包含了加密过的私钥、公钥、地址等。\r\n> 每执行一次 `NewAccount` 都会创建一个新账户。因此，如果只需要加载已有账户，则不需要执行这个方法。\r\n> 所有的 json 文件都会存放在`./keystore` 文件夹。\r\n\r\n```go\r\nacc, err := ks.NewAccount(\"your password\")\r\nif err != nil {\r\n    panic(err)\r\n}\r\n```\r\n\r\n4. 获取已创建的账户，会从./keystore 文件夹内拿到所有账户\r\n\r\n> `ks`对象是第2步创建的，会自动扫描`./keystore 文件夹`，拿到所有账户。\r\n\r\n```go\r\nfor _, acc := range ks.Accounts() {\r\n    fmt.Println(\"账户地址：\", acc.Address.String())\r\n}\r\n```\r\n\r\n5. 如果希望签名交易的话，可以使用钱包\r\n\r\n```go\r\nfor _, wallet := range ks.Wallets() {\r\n    // 这里每个钱包获得的第一个account和上面第4步的账户是一一对应的\r\n    _, _ = wallet.SignTx(wallet.Accounts()[0], nil, nil)\r\n    _, _ = wallet.SignData(wallet.Accounts()[0], \"\", nil)\r\n}\r\n```\r\n\r\n6. 如果希望导出私钥，则需要密码才可以。`PASSWORD`是上面第3步创建新账户设置的密码。\r\n\r\n```go\r\n// 先把账户的 json 文件导出为[]byte\r\nkjson, err := ks.Export(ks.Accounts()[0], PASSWORD, PASSWORD)\r\nif err != nil {\r\n    panic(err.Error())\r\n}\r\n\r\n// 通过kjson+密码可以解密私钥\r\nkey, err := keystore.DecryptKey(kjson, PASSWORD)\r\nif err != nil {\r\n    panic(err.Error())\r\n}\r\n\r\nprivateKey := key.PrivateKey\r\nfmt.Println(common.BytesToHash(crypto.FromECDSA(privateKey)).String())\r\n```\r\n\r\n至此，我们已经学会了如何使用 Go 语言创建`非确定性钱包`。"},"author":{"user":"https://learnblockchain.cn/people/2540","address":"0x2b624faC1616D08684Cf1d21793c2f39CC1895a0"},"history":"bafkreidkbubgyx5x2aichtov7dest3gcmvisymxfdbitradnov5vvc3doa","timestamp":1702529678,"version":1}