1. 首页 > 产业新闻 > 节能环保

从零开始学习比特币开发:生成地址

如果有人想发送比特给你,或者你从别人那里买几个比特币,就要把地址给对方,对方才能把币打到你指定的地址上。那么,讲解才能拥有一个地址呢,下面的我们就来讲讲这个问题。

比特币核心提供了很多 RPC 来供客户端调用,其中一个就是我们这里要讲的 生成一个新的地址,通过这个 RPC ,我们就可以生成一个新的地址,有了这个地址,别人就可以给我们转账了。

RPC 可以接收两个参数,第一个地址的标签,第二个是地址的类型。如果没有提供标签,那么默认的标签就是空,地址的类型当前支持:legacy、p2sh-segwit、bech32,默认类型由 参数指定,当前为 p2sh-segwit。

如果我们想看下这个 RPC 的帮助文档,可以执行如下的命令:

就会显示帮助信息

这个 RPC 对应的方法实现位于 文件,方法名称就是 RPC 名称,下面的我们来看这个方法。

  • 根据请求参数获得对应的钱包。

    方法内部实现如下:

    • 调用 方法,从请求对象中取得钱包的名字,如果用户指定了钱包名字,那么把钱包名字保存在参数 上,并返回真,否则返回假。
    • 如果可以获得用户指定的钱包名称,则调用 方法,从钱包集合 中取得指定的钱包,然后返回钱包。
    • 如果用户没有指定钱包或指定的钱包不存在,那么调用 方法,返回钱包集合 。如果钱包集合中只有一个钱包,或者在用户指定了帮助的情况下,至少有一个上面这些的钱包,那么返回第一个钱包,即默认的钱包。默认钱包在系统启动时候创建的。
  • 下面的,要确保钱包可用。如果钱包不可用,则直接 对象。
  • 如果指定了 参数或请求参数数量多于2个,则显示钱包的帮助信息。
  • 检查钱包是否设置了禁止私钥,即钱包是只读的 。如果是,则抛出异常。
  • 如果指定了标签,则调用 方法,检查标签,确保其不是 。如果是,则抛出异常。
  • 如果指定了地址类型,则调用 方法,检查地址类型,确保其是 、、 之一,如果不指定则默认是 ,并把地址类型保存在 变量中。
  • 如果钱包没有被锁定,则调用 方法填充密钥池。

    填充密钥这个方法,我们前面已经讲过,这里只简单友们下,不做详细分析。因为在衍生子钥的过程中,、 已经完全填充完了,所以导致 、 两个变量都为 0,从而不会重新再次衍生子密钥,所以实际上本方法在这里基本没有执行,而直接返回真。

  • 调用钱包的 方法,从密钥池中生成一个公钥。如果不能生成,则抛出异常。

    方法,我们在下面的详细讲解,此处略过。

  • 调用钱包对象的 方法,对公钥的脚本进行处理。方法内部执行如下:如果公钥是压缩的,并且地址类型是 ,或者 ,那么:
    • 调用 方法,生成 对象。
    • 调用 方法,获取对应的脚本。

      方法内部调用 ,以访问者模式来根据不同的 id,获取其对应的脚本对象。

      对象继承自 对象,实现了访问者模式,并通过重载 操作符来定义不同类型的 id。

      • 如果目标参数类型是 ,则调用脚本对象的 方法,清除脚本内容。
      • 如果目标参数类型是 ,则:首先调用脚本对象的 方法,清除脚本内容;然后,初始化脚本 。
      • 如果目标参数类型是 ,则:首先调用脚本对象的 方法,清除脚本内容;然后,初始化脚本 。
      • 如果目标参数类型是 ,则:首先调用脚本对象的 方法,清除脚本内容;然后,初始化脚本 。
      • 如果目标参数类型是 ,则:首先调用脚本对象的 方法,清除脚本内容;然后,初始化脚本 。
      • 如果目标参数类型是 ,则:首先调用脚本对象的 方法,清除脚本内容;然后,初始化脚本 。
    • 调用 方法,保存脚本对象。 方法,首先调用 方法,把脚本保存到 key store 的 集合中;然后,调用数据库访问对象的 方法,以 为键把脚本保存到数据库中。
  • 调用 方法,获取目的地 对象。 是一个具有特定目标的交易输出脚本模板。定义如下:,可能是几种类型之一:
    • CNoDestination没有目的地设置
    • CKeyIDP2PKH 目的
    • CScriptIDP2SH 目的
    • WitnessV0ScriptHashP2WSH 目的
    • WitnessV0KeyHashP2WPKH 目的
    • WitnessUnknown未知目的 P2W?

    方法,使用 表达式来根据不同的地址类型,生成不同的目的 。

    • 如果地址类型是 ,则直接返回公钥的 。内部把公钥的数据通过 SHA256 和 RIPEMD160 双重哈希之后,构造一个 对象。
    • 如果地址类型是 ,或 ,则处理如下:
      • 如果公钥不是压缩的,处理方法 。
      • 否则,生成 对象,然后调用 方法,获取对应的脚本,最后根据不同的地址类型生成的目的。

        对于默认的、不传地址类型的情况,就会返回 类型的 ,这个返回值在下面的两步中都会用到。

  • 调用钱包对象的 方法,来保存公钥地址。

    方法执行如下:

    • 从 集合中,取得对应的目的数据。
    • 根据集合中是否有对应的数据设置变量是否为更新。
    • 把标签保存为地址对应的 的 属性。
    • 如果参数 不空,则更新地址对应的 的 属性。
    • 调用数据库访问对象的 方法,保存参数 到数据库中。
    • 调用数据库访问对象的 方法,保存地址到数据库中。

      为用户提供的标签。 方法,我们在下一步讲解。

  • 调用 方法,解码目的地址,并返回其结果。 方法同样采用了访问者模式 。 类继承了 ,实现了访问者模式,通过重载 操作符来定义不同类型的 id

    。与前面相对应,这个方法会处理 、、、、 这几种不同情况。对于我们的默认情况来说,目的地址类型为 ,下面的我们就看下这种情况的处理,其他情况可自行阅读。
    • 调用当前网络参数的 方法,返回脚本前缀。

      对于主网络前缀是 5,测试网络是 196,回归测试网络是 196。

    • 把当前 20 个字节的数据加在前缀后面形成 21 个字节的字符串。
    • 调用 方法,编码成 Base58Check 格式,并返回其值。

      下面的,我们来看下 这个方法的处理。它的内部执行流程如下:用 21 个字节的字符串生成一个向量,同时调用 方法,生成一个 32 字节长的哈希字符串;然后把其最前面的 4个字节作为校验各加在 21 个字节的向量尾部,从而生成一个长度为 25个字节的字符串;最后,调用 方法,进行 Base58 编码。

      在 这个方法中,使用了双重 SHA256 哈希算法。 这个方法,读者可以自行阅读,这里不再展开。

  • 本方法从密钥池中生成一个公钥。第一个参数为公钥的引用,第二个参数 ,默认为假。

    内部逻辑如下:

  • 如果钱包禁止私钥,则返回假。
  • 调用 方法,从密钥池中取出一个密钥并获取其公钥。如果不成功,则生成数据库访问对象,然后调用 方法,生成一个公钥。

    这个方法,在创建钱包过程中,我们已经重点分析,这里不浪费口舌,我们重点看下 方法。这个方法的执行流程如下:

    • 生成一个公钥,并设置为密钥池的 属性。
    • 如果钱包没有被锁,则填充密钥池。

      这个方法,我们也讲过,这里直接略过。

    • 如果钱包启用了 HD,并且可以支持 HD 分割,并且参数 为真,则设置变量 为真。在调用本方法时,这个参数没有指定,而默认为假,所以变量 设置假。
    • 根据集合 是否为空,设置变量 的值。因为这里 集合为空,所以变量 为真。
    • 根据变量 、 确定从哪个集合中获取密钥池对象。根据上面分析,我们最终会从 集合中取数据。
    • 如果要数据的集合为为空,则返回假。
    • 生成数据库访问对象。
    • 从 取得其第一个元素,并从集合中删除它。
    • 从数据库取得索引对应的密钥池。如果失败,则抛出异常。
    • 从密钥池中取得公钥对应的 ID,并且检测其是否在 、或 集合之一,如果不在,则抛出异常。我们在创建钱包过程时候讲过,生成的私钥根据是否加密会保存在这两个集合之一。
    • 如果变量 为真,并且密钥池的 属性不等于变量 ,那么抛出异常。
    • 如果密钥池中保存的公钥是无效的,那么抛出异常。
    • 从 集合中消除对应的索引。
    • 返回真。
  • 调用
  • 从密钥池中取出对应的公钥。
  • 由于本人水平所限,文中错误在所难免,欢迎您踊跃指出错误,在下感激不尽。我的微信联系方式:joepeak。

    本文采摘于网络,不代表本站立场,转载联系作者并注明出处:http://www.fjxmta.com/chanye/jieneng/45415.html

    联系我们

    在线咨询:点击这里给我发消息

    微信号:wx123456