1、基本概念
比特币的所有权是通过数字密钥、比特币地址和数字签名来确定的。数字密钥实际上并不存储在网络中,而是由用户生成之后,存储在钱包文件(wallet.dat)或简单的数据库中。存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需参照区块链或访问网络。
比特币钱包中包含一系列的密钥对,每个密钥对包括一个私钥,和由其衍生出的唯一的公钥。公钥用于接收比特币,而私钥用于比特币支付时的交易签名。数字签名也称为见证(witness),用于支出资金的。
支付比特币时,比特币的当前所有者需要在交易中提交其公钥和签名(每次交易的签名都不同,但均从同一个私钥生成)。比特币网络中的所有人都可以通过所提交的公钥和签名进行验证,并确认该交易是否有效,即确认支付者在该时刻对所交易的比特币拥有所有权。
2、我们动手体验一下地址的生成过程
//启动单机测试链
./bitcoind -regtest &
//用ethan的钱包,生成一个新的地址
./bitcoin-cli -regtest getnewaddress ethan
//查看地址对应的私钥
./bitcoin-cli dumpprivkey 2MyVDtxTHnoFzPRZ5DhvfeBADfiAjw2JrCp
//查看地址全部的信息
./bitcoin-cli getaddressinfo 2MyVDtxTHnoFzPRZ5DhvfeBADfiAjw2JrCp
address:有效的比特币地址
scriptPubKey:由地址加密后得到的十六进制字符串
script:输出的脚本类型
witness_program:数字签名的十六进制形式
pubkey:原生的十六进制公钥
3、接下来我们阅读一下JSON-RPC接口对应的源码,我的源码版本是0.16.3。
//文件路径:src/wallet/rpcwallet.cpp
//接口名:static UniValue getnewaddress(const JSONRPCRequest& request)
getnewaddress()前面还对钱包的有效性进行了校验,这里只贴出来后半部分的代码。新建CPubKey类型的对象。
GetKeyFromPool()调用接口GetKeyFromPool()获取一个公钥,先尝试从密钥池中取预留的key,如果取不到,才会重新生成一个新的。链接钱包数据库,最后会把成功生成的公钥保存在数据库,并刷入磁盘。
MakeNewKey()GenerateNewKey()中新建了一个CKey类型的对象,我这里走软钱包流程,调用接口MakeNewKey()获取强随机数,随机数通过验证,即有效的私钥。
GetPubKey()secp256k1应该就是椭圆曲线算法,secp256k1_ec_pubkey_create()接口中begin()即前面得到的私钥。运算结果校验通过后,返回值即公钥,然后调用接口AddKeyPubKeyWithDB(),将公钥添加到数据库。
LearnRelatedScripts()和GetDestinationForKey()总是在一起使用。前者通过公钥得到数字签名类型和交易脚本,后者对公钥进行hash160签名即双hash运算,得到二进制态的比特币地址。
CTxDestination数据类型包括:CNoDestination、CKeyID、WitnessV0ScriptHash、WitnessV0KeyHash和WitnessUnknown。不同类型对应不同的交易标准,保证节点之间的交易信息能够被识别:CKeyID---P2PKH、CScriptID--P2SH、WitnessV0ScriptHash---P2WSH、WitnessV0KeyHash---P2WPKH
SetAddressBook()将生成的二进制地址保存下来,EncodeDestination(dest)执行后,将数据还原为我们看到的地址形态。
网友评论