区块链实验六 : 钱包和地址

实验报告06orz

      • 实验目的及要求
      • 实验基本原理
      • 实验实施环境
      • 实验概述
      • 实验内容
        • 学习第六章 区块链钱包交易
        • 实现区块链钱包交易的代码编写
          • 项目目录截图
          • 原型代码
          • Terminal运行结果截图

实验目的及要求

了解编程语言的基本逻辑,理解编程语言运行机理。熟悉区块链的原理。能正确使用编程语言搭建区块和区块链,并进行钱包的实现。

实验基本原理

通过课堂理论教学准备,动手使用实验软件平台,完成慕课实验项目的要求。

实验实施环境

Goland & GoSDK

实验概述

编写区块链基本原型,加入钱包的算法。

实验内容

学习第六章 区块链钱包交易

imooc学习地址↓
6-1数字货币地址及身份识别
6-2数据钱包创建交易过程及代码实现
学习总结:
数字货币的地址及身份标识

  • 某种途径可以识别出你是交易输出的所有者,称之为身份
  • 在比特币中,你的身份(indentity)就是一对(或者多对)公钥(public key)和私钥(private key)
  • 所谓的地址,只不过是讲公钥表示成人类可读的形式

公钥算法和数字签名

  • 公钥加密(public-key cryptography)算法使用的是成对ide密钥:公钥和私钥
  • 公钥并不是敏感性息,可以告诉其他人。但是,私钥绝对不能告诉其他人:所有所有者(owner)才能知道私钥,能够识别,鉴定和证明所有者身份的就是私钥。

实现区块链钱包交易的代码编写

项目目录截图

区块链实验六 : 钱包和地址_第1张图片

原型代码

(因为代码量过多,这里只放部分)
wallet.go

package core

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"log"

	"golang.org/x/crypto/ripemd160"
)

const version = byte(0x00)
const addressChecksumLen = 4

// Wallet stores private and public keys
type Wallet struct {
     
	PrivateKey ecdsa.PrivateKey
	PublicKey  []byte
}

// NewWallet creates and returns a Wallet
func NewWallet() *Wallet {
     
	private, public := newKeyPair()
	wallet := Wallet{
     private, public}

	return &wallet
}

// GetAddress returns wallet address
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
}

// HashPubKey hashes public key
func HashPubKey(pubKey []byte) []byte {
     
	publicSHA256 := sha256.Sum256(pubKey)

	RIPEMD160Hasher := ripemd160.New()
	_, err := RIPEMD160Hasher.Write(publicSHA256[:])
	if err != nil {
     
		log.Panic(err)
	}
	publicRIPEMD160 := RIPEMD160Hasher.Sum(nil)

	return publicRIPEMD160
}

// ValidateAddress check if address if valid
func ValidateAddress(address string) bool {
     
	pubKeyHash := Base58Decode([]byte(address))
	actualChecksum := pubKeyHash[len(pubKeyHash)-addressChecksumLen:]
	version := pubKeyHash[0]
	pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-addressChecksumLen]
	targetChecksum := checksum(append([]byte{
     version}, pubKeyHash...))

	return bytes.Compare(actualChecksum, targetChecksum) == 0
}

// Checksum generates a checksum for a public key
func checksum(payload []byte) []byte {
     
	firstSHA := sha256.Sum256(payload)
	secondSHA := sha256.Sum256(firstSHA[:])

	return secondSHA[:addressChecksumLen]
}

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
}

wallets.go

package core

import (
	"bytes"
	"crypto/elliptic"
	"encoding/gob"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

const walletFile = "wallet_%s.dat"

// Wallets stores a collection of wallets
type Wallets struct {
     
	Wallets map[string]*Wallet
}

// NewWallets creates Wallets and fills it from a file if it exists
func NewWallets(nodeID string) (*Wallets, error) {
     
	wallets := Wallets{
     }
	wallets.Wallets = make(map[string]*Wallet)

	err := wallets.LoadFromFile(nodeID)

	return &wallets, err
}

// CreateWallet adds a Wallet to Wallets
func (ws *Wallets) CreateWallet() string {
     
	wallet := NewWallet()
	address := fmt.Sprintf("%s", wallet.GetAddress())

	ws.Wallets[address] = wallet

	return address
}

// GetAddresses returns an array of addresses stored in the wallet file
func (ws *Wallets) GetAddresses() []string {
     
	var addresses []string

	for address := range ws.Wallets {
     
		addresses = append(addresses, address)
	}

	return addresses
}

// GetWallet returns a Wallet by its address
func (ws Wallets) GetWallet(address string) Wallet {
     
	return *ws.Wallets[address]
}

// LoadFromFile loads wallets from the file
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)
	if err != nil {
     
		log.Panic(err)
	}

	var wallets Wallets
	gob.Register(elliptic.P256())
	decoder := gob.NewDecoder(bytes.NewReader(fileContent))
	err = decoder.Decode(&wallets)
	if err != nil {
     
		log.Panic(err)
	}

	ws.Wallets = wallets.Wallets

	return nil
}

// SaveToFile saves wallets to a file
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)
	}
}

Terminal运行结果截图

区块链实验六 : 钱包和地址_第2张图片
区块链实验六 : 钱包和地址_第3张图片

你可能感兴趣的:(区块链,区块链,比特币,go)