利用go語言建立錢包並遍歷錢包(wallet)
阿新 • • 發佈:2019-02-12
基本知識
公鑰加密演算法使用的是成對的金鑰:公鑰和私鑰,公鑰可以公開,私鑰不能被公開。比特幣錢包實際上是一個金鑰對,當你安裝 一個錢包應用,或者是使用一個比特幣客戶端來生成一個新地址是,他就會為你生成一個金鑰對。
程式碼實現
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
}
通過以上的程式碼,我們便完成了錢包,實現了 建立錢包和遍歷錢包的功能