从0到1简易区块链开发手册V0.2-创建钱包

1.概念

创建钱包其实就是创建比特币地址,在比特币世界中,没有账户概念,不需要也不会在任何地方存储个人数据(比如姓名,×××件号码等)。但是,我们总要有某种途径识别出你是交易输出的所有者(也就是说,你拥有在这些输出上锁定的币),这就是比特币地址(address)需要完成的使命。

关于钱包这个概念,我个人觉得imtoken在用户引导那部分写得很清楚,此处将链接给到大家,有兴趣的可以去看看

https://www.cnblogs.com/fangbei/p/imToken-clearance.html

我们来看一下一个真实的比特币账户,1FSzfZ27CVTkfNw6TWxnHPaRLRCgpWvbFC ,比特币地址是完全公开的,如果你想要给某个人发送币,只需要知道他的地址就可以了。但是,地址(尽管地址也是独一无二的)并不是用来证明你是一个“钱包”所有者的信物。实际上,所谓的地址,只不过是将公钥表示成人类可读的形式而已,因为原生的公钥人类很难阅读。在比特币中,你的身份(identity)就是一对(或者多对)保存在你的电脑(或者你能够获取到的地方)上的公钥(public key)和私钥(private key)。比特币基于一些加密算法的组合来创建这些密钥,并且保证了在这个世界上没有其他人能够取走你的币,除非拿到你的密钥。

关于如何创建一个钱包以及钱包集合,通过下图进行简单展示

                        图 创建钱包与钱包集合

                            图 创建钱包wallet

                            图 创建钱包集合

2. 定义钱包结构体

type Wallet struct {
    //1.私钥
    PrivateKey ecdsa.PrivateKey
    //2.公钥
    PublickKey []byte //原始公钥
}

定义钱包Wallet的属性为私钥:PrivateKey,类型为系统内置的结构体对象ecdsa.PrivateKey,公钥:PublickKey,类型为字节数组

3. 生成钱包地址

                        图   从私钥到生成钱包地址的过程图      
3.1 通过椭圆曲线算法产生密钥对
func newKeyPair() (ecdsa.PrivateKey, []byte) {
    //椭圆加密
    curve := elliptic.P256() //根据椭圆加密算法,得到一个椭圆曲线值
    //生成私钥
    privateKey, err := ecdsa.GenerateKey(curve, rand.Reader) //*Private
    if err != nil {
        log.Panic(err)
    }

    //通过私钥生成原始公钥
    publicKey := append(privateKey.PublicKey.X.Bytes(), privateKey.PublicKey.Y.Bytes()...)
    return *privateKey, publicKey
}

椭圆曲线加密:(ECC:ellipse curve Cryptography),非对称加密

  • 根据椭圆曲线算法,产生随机私钥
  • 根据私钥,产生公钥
3.2 创建钱包对象
func NewWallet() *Wallet {
    privateKey, publicKey := newKeyPair()
    return &Wallet{privateKey, publicKey}
}

通过newKeyPair函数将返回的私钥与公钥生成钱包对象Wallet

3.3 定义常量值
const version = byte(0x00)
const addressCheckSumLen = 4
  • version: 版本前缀,比特币中固定为0
  • addressCheckSumLen: 用于获取校验码的长度变量,取添加版本+数据进行两次SHA256之后的前4个字节
3.5 根据公钥获取地址

                            图 从**公钥**到生成钱包地址的过程图
func PubKeyHash(publickKey []byte) []byte {
    //1.sha256
    hasher := sha256.New()
    hasher.Write(publickKey)
    hash1 := hasher.Sum(nil)

    //2.ripemd160
    hasher2 := ripemd160.New()
    hasher2.Write(hash1)
    hash2 := hasher2.Sum(nil)

    //3.返回公钥哈希
    return hash2
}

通过公钥生成公钥哈希的步骤已完成。

func GetAddressByPubKeyHash(pubKeyHash []byte) []byte {
    //添加版本号:
    versioned_payload := append([]byte{version}, pubKeyHash...)

    //根据versioned_payload-->两次sha256,取前4位,得到checkSum
    checkSumBytes := CheckSum(versioned_payload)

    //拼接全部数据
    full_payload := append(versioned_payload, checkSumBytes...)

    //Base58编码
    address := Base58Encode(full_payload)
    return address
}

相关函数如下

  • 生成校验码
func CheckSum(payload [] byte) []byte {
    firstHash := sha256.Sum256(payload)
    secondHash := sha256.Sum256(firstHash[:])
    return secondHash[:addressCheckSumLen]
}

通过两次sha256哈希得到校验码,返回校验码前四位

  • 字节数组转Base58加密

    var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
    func Base58Encode(input []byte)[]byte{
    var result [] byte
    x := big.NewInt(0).SetBytes(input)
    
    base :=big.NewInt(int64(len(b58Alphabet)))
    zero:=big.NewInt(0)
    mod:= &big.Int{}
    for x.Cmp(zero) !=0{
        x.DivMod(x,base,mod)
        result = append(result,b58Alphabet[mod.Int64()])
    }
    ReverseBytes(result)
    for b:=range input{
        if b == 0x00{
            result = append([]byte{b58Alphabet[0]},result...)
        }else {
            break
        }
    }
    
    return result
    
    }

以上功能函数定义好之后,定义Wallet的方法GetAddress返回钱包address

func (w *Wallet) GetAddress() []byte {
    pubKeyHash := PubKeyHash(w.PublickKey)
    address := GetAddressByPubKeyHash(pubKeyHash)
    return address
}

至此,我们已经能够生成一个比特币地址了,可以通过https://www.blockchain.com/explorer进行钱包地址查看余额。

4.定义钱包集合结构体

type Wallets struct {
    WalletMap map[string]*Wallet
}

定义钱包集合结构体Wallets,属性为WalletMap,类型为Wallet集合

5.创建钱包集合

func (ws *Wallets) CreateNewWallets() {
    wallet := NewWallet()
    var address []byte
    address = wallet.GetAddress()
    fmt.Printf("创建的钱包地址:%s\n", address)
    ws.WalletMap[string(address)] = wallet
    //将钱包集合存入到本地文件中
    ws.SaveFile()
}
  • 创建一个钱包对象
  • 通过GetAddress获取钱包对象的地址
  • 将钱包地址作为钱包集合的key,钱包对象作为value存储至钱包集合中
  • 通过SaveFile将钱包集合存入到本地文件中
5.1 定义常量存储钱包数据
const walletsFile = "Wallets.dat" //存储钱包数据的本地文件名
5.2 本地化存储钱包对象
func (ws *Wallets) SaveFile() {
    //1.将ws对象的数据--->byte[]
    var buf bytes.Buffer
    //序列化的过程中:被序列化的对象中包含了接口,那么该接口需要注册
    gob.Register(elliptic.P256()) //Curve
    encoder := gob.NewEncoder(&buf)
    err := encoder.Encode(ws)
    if err != nil {
        log.Panic(err)
    }
    wsBytes := buf.Bytes()

    //2.将数据存储到文件中
    err = ioutil.WriteFile(walletsFile, wsBytes, 0644)
    if err != nil {
        log.Panic(err)
    }
}

6.获取钱包集合

此处我们提供一个函数,用户获取钱包集合

  • 读取本地的钱包文件,如果文件存在,直接获取
  • 如果文件不存在,创建并返回一个空的钱包对象
func GetWallets()  *Wallets {
    //钱包文件不存在
    if _, err := os.Stat(walletsFile); os.IsNotExist(err) {
        fmt.Println("区块链钱包不存在")
        //创建钱包集合
        wallets := &Wallets{}
        wallets.WalletMap = make(map[string]*Wallet)
        return wallets
    }

    //钱包文件存在
    //读取本地的钱包文件中的数据
    wsBytes, err := ioutil.ReadFile(walletsFile)
    if err != nil {
        log.Panic(err)
    }
    gob.Register(elliptic.P256()) //Curve
    //将数据反序列化变成钱包集合对象
    var wallets Wallets
    reader := bytes.NewReader(wsBytes)
    decoder := gob.NewDecoder(reader)
    err = decoder.Decode(&wallets)
    if err != nil {
        log.Panic(err)
    }
    return  &wallets
}

7.命令行中调用

7.1 创建钱包

回到上一章节(二.实现命令行功能-2.1创建钱包)的命令行功能

func (cli *CLI) GetAddressLists() {
    fmt.Println("钱包地址列表为:")
        //获取钱包的集合,遍历,依次输出
    _, wallets := GetWallets() //获取钱包集合对象
    for address, _ := range wallets.WalletMap {
        fmt.Printf("\t%s\n", address)
    }
}

此时进行编译运行

$ go build -o mybtc main.go
$ ./mybtc createwallet //创建第一个钱包
$ ./mybtc createwallet //创建第二个钱包
$ ./mybtc createwallet //创建第三个钱包

返回的结果:

创建的钱包地址:14A1b3Lp3hL5B7vZvT2UWk1W78m2Kh8MUB
创建的钱包地址:1G3SkYAJdWy5pd1hFpcciUoJi8zy8PdV11
创建的钱包地址:1AA2fyYdXCQMwLMu5NBvq7Fb9UiHqg2cQV
7.2 获取钱包地址

回到上一章节(二.实现命令行功能-2.2 获取钱包地址)的命令行功能

func (cli *CLI) GetAddressLists() {
    fmt.Println("钱包地址列表为:")
    //获取钱包的集合,遍历,依次输出
    wallets := GetWallets()
    for address, _ := range wallets.WalletMap {

        fmt.Printf("\t%s\n", address)
    }
}
$ ./mybtc getaddresslists

返回的结果

钱包地址列表为:
        1AA2fyYdXCQMwLMu5NBvq7Fb9UiHqg2cQV
        14A1b3Lp3hL5B7vZvT2UWk1W78m2Kh8MUB
        1G3SkYAJdWy5pd1hFpcciUoJi8zy8PdV11

上面我们提到生成的比特币地址可以通过https://www.blockchain.com/explorer进行钱包地址查看余额,现在我们来进行简单的查看验证,查看该地址:1AA2fyYdXCQMwLMu5NBvq7Fb9UiHqg2cQV

                            图  通过搜索框进行地址搜索

                            图  钱包地址详情

如果修改钱包地址的某个字符,如将随后的V改为X

1AA2fyYdXCQMwLMu5NBvq7Fb9UiHqg2cQV === > 1AA2fyYdXCQMwLMu5NBvq7Fb9UiHqg2cQX

原文地址:http://blog.51cto.com/clovemfong/2161923

时间: 2024-07-31 04:16:47

从0到1简易区块链开发手册V0.2-创建钱包的相关文章

从0到1简易区块链开发手册V0.3-数据持久化与创世区块

1.BoltDB简介 Bolt是一个纯粹Key/Value模型的程序.该项目的目标是为不需要完整数据库服务器(如Postgres或MySQL)的项目提供一个简单,快速,可靠的数据库. BoltDB只需要将其链接到你的应用程序代码中即可使用BoltDB提供的API来高效的存取数据.而且BoltDB支持完全可序列化的ACID事务,让应用程序可以更简单的处理复杂操作. 其源码地址为:https://github.com/boltdb/bolt 2.BoltDB特性 BoltDB设计源于LMDB,具有以

从0到1简易区块链开发手册V0.4-实现转账交易的思路分析

六.转账交易 创世区块创建完毕之后,按照我们的正常思路,是继续创建新的区块,并加入至区块链中,没错,这确实是学习路线,但是我们首先来了解一个区块是如何生成的,转账交易 ===>打包交易 ===>工作量证明 ===>生成区块 在上文,我们提到了钱包地址这个概念,我们一般可以简单将钱包地址理解为一个银行账户,那么交易也就可以理解为是地址与地址之间的转账过程. 因为这部分内容非常重要,设置可以说交易就是比特币原理的核心,所以,为了保证大家对概念有充分的了解,本章节的理论描述部分此处摘录liuc

从0到1简易区块链开发手册V0.6-实现打印区块

八. 打印区块 以上的转账交易中,我们共计创建了四个区块,其中一个区块为创世区块,另外三个区块都是对我们的交易进行打包后产生的新区块,本文将介绍如何将区块信息打印出来. 1.命令行代码 func (cli *CLI) PrintChains() { //cli.BlockChain.PrintChains() bc := GetBlockChainObject() //bc{Tip,DB} if bc == nil { fmt.Println("没有BlockChain,无法打印任何数据..&q

从0到1简易区块链开发手册V0.5-实现余额查询

七. 查询余额 其实这个章节的一些知识点在转账交易那一章节均有所涉及,所以,查询余额这个功能相对而言比较简单,只要熟悉了UTXO模型,加上对交易流程的了解之后,对查询余额基本上已经有了思路. 1.命令行代码 func (cli *CLI) GetBalance(address string) { bc := GetBlockChainObject() if bc == nil { fmt.Println("没有BlockChain,无法查询..") os.Exit(1) } defer

从Go语言编码角度解释实现简易区块链

区块链技术 人们可以用许多不同的方式解释区块链技术,其中通过加密货币来看区块链一直是主流.大多数人接触区块链技术都是从比特币谈起,但比特币仅仅是众多加密货币的一种. 到底什么是区块链技术? 从金融学相关角度来看,区块链是一种存储数据的方式,去中心化的数据库,应用到比特币也就是去中心化账本: 从密码学角度来看,区块链是一种传递价值的协议: 从计算机科学的角度来看,区块链只是一种数据结构: 不同于我们平时接触的手机电脑,先有系统,然后才会在系统里开发各种APP应用.09年第一枚比特币诞生,15年也就

区块链开发技术路线的思考(二)

在前一篇文章里讨论了基于 Ethereum 和 Hyperledger 开发区块链项目的优缺点.我的结论是明显的,两者志向远大,假以时日或许会一飞冲天,但现阶段的成熟度都还不够.如果你有心现在投入区块链的开发,那么我的建议是,基于 Bitcoin 自建链,同时关注甚至参与 Ethereum 或 Hyperledger 核心项目,帮它们夯实地基. Bitcoin 无疑是最成熟.质量最佳.讨论最深入的区块链项目,如果按照关注度来算市场份额的话,在区块链领域,Bitcoin 可能三分天下有其二.它目前

区块链开发(五)区块链ICO:互联网进化的驱动力

区块链开发(五)区块链ICO:互联网进化的驱动力 李赫 2016年10月8日 由于区块链不可篡改的特性,在众多区块链组织和公司的共同努力下,互联网将逐步从中心化的信任进化到由算法.数据为核心的去中心化信任.随着中心化的信任中介被逐渐削弱和替代,互联网的运作方式将被以区块链为代表的系统所改变.因此,区块链不仅是一种技术,更是一个关于互联网进化的故事,尽管这个故事还有些遥远,但它已经有了萌芽和初步的发展. 区块链ICO,正是符合去中心化趋势,通过全球众筹,可以将沉淀在全球的小额资金充分利用起来,形成

区块链开发:以太坊网络

区块链开发:以太坊网络 一.geth Geth 又名Go Ethereum. 是以太坊协议的三种实现之一,由Go语言开发,完全开源的项目.Geth 可以被安装在很多操作系统上,包括Windows.Linux.Mac的OSX.Android或者IOS系统 Geth官网:https://geth.ethereum.org/ Geth的Github地址:https://github.com/ethereum/go-ethereum Ubuntu安装geth客户端: 官方教程:https://githu

区块链3.0才能真正推动区块链时代大步向前!

第一代区块链的典型产物就是比特币及其山寨币.因为是第一代产品,区块链1.0的价值仅仅体现在数字币发行与交易上. 第二代区块链的代表是以太坊.同区块链1.0相比,区块链2.0的最大特性就是它引入了智能合约和可编程底层,这使得人们可以基于其架构开发各种用途的区块链引用,至于项目代币则是其的推广激励手段之一.区块链3.0则在区块链2.0的基础上更进一步,它具有更好的性能,其应用范围也更加广泛,诸如物联网.金融.人工智能等都可以是它大展身手的舞台.有人甚至预测,区块链3.0会真正推动区块链技术在现实中的