当前位置 博文首页 > GO语言创建钱包并遍历钱包(wallet)的实现代码

    GO语言创建钱包并遍历钱包(wallet)的实现代码

    作者:辜智强 -buaa 时间:2021-05-29 17:51

    基本知识

    公钥加密算法使用的是成对的密钥:公钥和私钥,公钥可以公开,私钥不能被公开。比特币钱包实际上是一个密钥对,当你安装 一个钱包应用,或者是使用一个比特币客户端来生成一个新地址是,他就会为你生成一个密钥对。

    代码实现

    func (cli *CLI) createWallet(nodeID string) {     //创建钱包的主函数
        wallets, _ := NewWallets(nodeID)   
        address := wallets.CreateWallet()
        wallets.SaveToFile(nodeID)
    
        fmt.Printf("Your new address: %s\n", address)
    }

    我们慢慢的分析这个程序,其中的NewWallets()函数如下,在这里先是定义了一个钱包集合,我们利用wallets结构体存储多个钱包,将他们保存到文件中或者从文件中进行加载,每个钱包都保存了一堆公钥和私钥。创建出了一个空的钱包集合后,便开始加载以前的钱包集合文件

    func NewWallets(nodeID string) (*Wallets, error) {
        wallets := Wallets{}
        wallets.Wallets = make(map[string]*Wallet)
        err := wallets.LoadFromFile(nodeID)
        return &wallets, err
    }
    
    type Wallets struct {
        Wallets map[string]*Wallet
    }
    type Wallet struct {
        PrivateKey ecdsa.PrivateKey
        PublicKey  []byte
    }
    func (ws *Wallets) LoadFromFile(nodeID string) error {
        walletFile := fmt.Sprintf(walletFile, nodeID)    
        if _, err := os.Stat(walletFile); os.IsNotExist(err) {   //判断文件是否存在
            return err
        }
    
        fileContent, err := ioutil.ReadFile(walletFile)
        // ReadFile 读取文件中的所有数据,返回读取的数据和遇到的错误。
        //如果读取成功,则 err 返回 nil,而不是 EOF
    func ReadFile(filename string) ([]byte, error)
        if err != nil {
            log.Panic(err)
        }
    
        var wallets Wallets
        gob.Register(elliptic.P256())
        //gob是Golang包自带的一个数据结构序列化的编码/解码工具。
        decoder := gob.NewDecoder(bytes.NewReader(fileContent))
        err = decoder.Decode(&wallets)//这里应该是一个解码的过程
        if err != nil {
            log.Panic(err)
        }
        ws.Wallets = wallets.Wallets
        return nil
    }

    再来看一看wallets.CreateWallet()方法,其中的NewWallet()如下, NewWallet()函数创建了一个钱包,我们可以根据公钥打印出相应的钱包对应的地址,然后将钱包存储到钱包集合结构体中

    unc (ws *Wallets) CreateWallet() string {
        wallet := NewWallet()
        address := fmt.Sprintf("%s", wallet.GetAddress())
        ws.Wallets[address] = wallet  //存储到钱包集合中
        return address
    }
    func NewWallet() *Wallet {
        private, public := newKeyPair()   //得到公钥和私钥
        wallet := Wallet{private, public}  //存储到钱包结构体
        return &wallet
    }
    func newKeyPair() (ecdsa.PrivateKey, []byte) {
        curve := elliptic.P256()
        private, err := ecdsa.GenerateKey(curve, rand.Reader)
        if err != nil {
            log.Panic(err)
        }
        pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...)
        return *private, pubKey
    }
    
    //由公钥得到地址,具体方法见我的博客用 [“go语言实现比特币地址校验”](https://blog.csdn.net/m0_37719047/article/details/81945896) 
    func (w Wallet) GetAddress() []byte {     
        pubKeyHash := HashPubKey(w.PublicKey)  
        versionedPayload := append([]byte{version}, pubKeyHash...)
        checksum := checksum(versionedPayload)
        fullPayload := append(versionedPayload, checksum...)
        address := Base58Encode(fullPayload)
        return address
    }

    最后将创建好的钱包更新到存储钱包集合的文件中去

    func (ws Wallets) SaveToFile(nodeID string) {
        var content bytes.Buffer     //开辟一个内存空间
        walletFile := fmt.Sprintf(walletFile, nodeID)
        gob.Register(elliptic.P256())
        encoder := gob.NewEncoder(&content)    //序列化结构体
        err := encoder.Encode(ws)
        if err != nil {
            log.Panic(err)
        }
        err = ioutil.WriteFile(walletFile, content.Bytes(), 0644)    //将序列化的数据写入到文件中去
        if err != nil {
            log.Panic(err)
        }
    }

    如果我们需要打印钱包集合中所有钱包对应的地址,我们可以利用以下的函数进行遍历。

    func (cli *CLI) listAddresses(nodeID string) {
        wallets, err := NewWallets(nodeID)   //加载现有的钱包集合
        if err != nil {
            log.Panic(err)
        }
        addresses := wallets.GetAddresses()
        for _, address := range addresses {
            fmt.Println(address)
        }
    }
    func (ws *Wallets) GetAddresses() []string {
        var addresses []string
        for address := range ws.Wallets {
            addresses = append(addresses, address)
        }
        return addresses
    }

    通过以上的代码,我们便完成了钱包,实现了 创建钱包和遍历钱包的功能

    参考

    https://jeiwan.cc/

    js
    下一篇:没有了