生成地址
如果有人想发送比特币给你,或者你从别人那里买几个比特币,就要把地址给对方,对方才能把币打到你指定的地址上。那么,如何才能拥有一个地址呢,下面我们就来讲讲这个问题。
比特币核心提供了很多RPC来供客户端调用,其中一个就是我们这里要讲的
getnewaddress
生成一个新的地址,通过这个RPC,我们就可以生成一个新的地址,有了这个地址,别人就可以给我们转账了。
getnewaddress
RPC可以接收两个参数,第一个地址的标签,第二个是地址的类型。如果没有提供标签,那么默认的标签就是空,地址的类型当前支持:legacy、p2sh-segwit、bech32,默认类型由
-addresstype
参数指定,当前为p2sh-segwit。
如果我们想看下这个RPC的帮助文档,可以执行如下的命令:
./src/bitcoin-cli-regtesthelpgetnewaddress
就会显示帮助信息
这个 RPC对应的方法实现位于
src/wallet/rpcwallet.cpp
文件,方法名称就是RPC名称,下面我们来看这个方法。
生成地址流程
根据请求参数获得对应的钱包。std::shared_ptr<CWallet>constwallet=GetWalletForJSONRPCRequest(request);CWallet*constpwallet=wallet.get();GetWalletForJSONRPCRequest方法内部实现如下:调用GetWalletNameFromJSONRPCRequest方法,从请求对象中取得钱包的名字,如果用户指定了钱包名字,那么把钱包名字保存在参数wallet_name上,并返回真,否则返回假。如果可以获得用户指定的钱包名称,则调用GetWallet方法,从钱包集合vpwallets中取得指定的钱包,然后返回钱包。如果用户没有指定钱包或指定的钱包不存在,那么调用GetWallets方法,返回钱包集合vpwallets。如果钱包集合中只有一个钱包,或者在用户指定了帮助的情况下,至少有一个以上的钱包,那么返回第一个钱包,即默认的钱包。默认钱包在系统启动时候创建的。接下来,要确保钱包可用。如果钱包不可用,则直接NullUniValue对象。if(!EnsureWalletIsAvailable(pwallet,request.fHelp)){returnNullUniValue;}如果指定了help参数或请求参数数量多于2个,则显示钱包的帮助信息。检查钱包是否设置了禁止私钥,即钱包是只读的watch-only/pubkeys。如果是,则抛出异常。if(pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)){throwJSONRPCError(RPC_WALLET_ERROR,"Error:Privatekeysaredisabledforthiswallet");}如果指定了标签,则调用LabelFromValue方法,检查标签,确保其不是*。如果是,则抛出异常。std::stringlabel;if(!request.params.isNull())label=LabelFromValue(request.params);如果指定了地址类型,则调用ParseOutputType方法,检查地址类型,确保其是legacy、p2sh-segwit、bech32之一,如果不指定则默认是p2sh-segwit,并把地址类型保存在output_type变量中。OutputTypeoutput_type=pwallet->m_default_address_type;if(!request.params.isNull()){if(!ParseOutputType(request.params.get_str(),output_type)){throwJSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,strprintf("Unknownaddresstype'%s'",request.params.get_str()));}}如果钱包没有被锁定,则调用TopUpKeyPool方法填充密钥池。if(!pwallet->IsLocked()){pwallet->TopUpKeyPool();}TopUpKeyPool填充密钥这个方法,我们前面已经讲过,这里只简单解释下,不做详细分析。因为在衍生子钥的过程中,setExternalKeyPool、setInternalKeyPool已经完全填充完了,所以导致missingExternal、missingInternal两个变量都为0,从而不会重新再次衍生子密钥,所以实际上本方法在这里基本没有执行,而直接返回真。调用钱包的GetKeyFromPool方法,从密钥池中生成一个公钥。如果不能生成,则抛出异常。CPubKeynewKey;if(!pwallet->GetKeyFromPool(newKey)){throwJSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT,"Error:Keypoolranout,pleasecallkeypoolrefillfirst");}GetKeyFromPool方法,我们在下面详细讲解,此处略过。调用钱包对象的LearnRelatedScripts方法,对公钥的脚本进行处理。方法内部执行如下:如果公钥是压缩的,并且地址类型是p2sh-segwit,或者bech32,那么:如果目标参数类型是CNoDestination,则调用脚本对象的script方法,清除脚本内容。如果目标参数类型是CKeyID,则:首先调用脚本对象的script方法,清除脚本内容;然后,初始化脚本*script<<OP_DUP<<OP_HASH160<<ToByteVector(keyID)<<OP_EQUALVERIFY<<OP_CHECKSIG。如果目标参数类型是CScriptID,则:首先调用脚本对象的script方法,清除脚本内容;然后,初始化脚本*script<<OP_HASH160<<ToByteVector(scriptID)<<OP_EQUAL。如果目标参数类型是WitnessV0KeyHash,则:首先调用脚本对象的script方法,清除脚本内容;然后,初始化脚本*script<<OP_0<<ToByteVector(id)。如果目标参数类型是WitnessV0ScriptHash,则:首先调用脚本对象的script方法,清除脚本内容;然后,初始化脚本*script<<OP_0<<ToByteVector(id)。如果目标参数类型是WitnessUnknown,则:首先调用脚本对象的script方法,清除脚本内容;然后,初始化脚本*script<<CScript::EncodeOP_N(id.version)<<std::vector(id.program,id.program+id.length)。调用WitnessV0KeyHash方法,生成WitnessV0KeyHash对象。CTxDestinationwitdest=WitnessV0KeyHash(key.GetID());调用GetScriptForDestination方法,获取对应的脚本。CScriptwitprog=GetScriptForDestination(witdest);GetScriptForDestination方法内部调用boost::apply_visitor(CScriptVisitor(&script),dest),以访问者模式来根据不同的id,获取其对应的脚本对象。CScriptVisitor对象继承自boost::static_visitor对象,实现了访问者模式,并通过重载()操作符来定义不同类型的id。调用AddCScript方法,保存脚本对象。AddCScript方法,首先调用CCryptoKeyStore::AddCScript方法,把脚本保存到keystore的mapScripts集合中;然后,调用数据库访问对象的WriteCScript方法,以cscript为键把脚本保存到数据库中。boolCWallet::AddCScript(constCScript&redeemScript){if(!CCryptoKeyStore::AddCScript(redeemScript))returnfalse;returnWalletBatch(*database).WriteCScript(Hash160(redeemScript),redeemScript);}调用GetDestinationForKey方法,获取目的地CTxDestination对象。CTxDestination是一个具有特定目标的交易输出脚本模板。定义如下:typedefboost::variant<CNoDestination,CKeyID,CScriptID,WitnessV0ScriptHash,WitnessV0KeyHash,WitnessUnknown>CTxDestination,可能是以下几种类型之一:GetDestinationForKey方法,使用case表达式来根据不同的地址类型,生成不同的目的CTxDestination。如果公钥不是压缩的,处理方法legacy。if(!key.IsCompressed())returnkey.GetID();否则,生成WitnessV0KeyHash对象,然后调用GetScriptForDestination方法,获取对应的脚本,最后根据不同的地址类型生成的目的。CTxDestinationwitdest=WitnessV0KeyHash(key.GetID());CScriptwitprog=GetScriptForDestination(witdest);if(type==OutputType::P2SH_SEGWIT){returnCScriptID(witprog);}else{returnwitdest;}对于默认的、不传地址类型的情况,就会返回CScriptID类型的CTxDestination,这个返回值在下面两步中都会用到。如果地址类型是legacy,则直接返回公钥的KeyID。内部把公钥的数据通过SHA256和RIPEMD160双重哈希之后,构造一个CKeyID对象。如果地址类型是p2sh-segwit,或bech32,则处理如下:CNoDestination没有目的地设置CKeyIDP2PKH目的CScriptIDP2SH目的WitnessV0ScriptHashP2WSH目的WitnessV0KeyHashP2WPKH目的WitnessUnknown未知目的P2W???调用钱包对象的SetAddressBook方法,来保存公钥地址。pwallet->SetAddressBook(dest,label,"receive");SetAddressBook方法执行如下:从mapAddressBook集合中,取得对应的目的数据。std::map<CTxDestination,CAddressBookData>::iteratormi=mapAddressBook.find(address);根据集合中是否有对应的数据设置变量是否为更新。fUpdated=mi!=mapAddressBook.end();把标签保存为地址对应的CAddressBookData的name属性。mapAddressBook.name=strName;如果参数strPurpose不空,则更新地址对应的CAddressBookData的purpose属性。if(!strPurpose.empty())mapAddressBook.purpose=strPurpose;调用数据库访问对象的WritePurpose方法,保存参数strPurpose到数据库中。if(!strPurpose.empty()&&!WalletBatch(*database).WritePurpose(EncodeDestination(address),strPurpose))returnfalse;调用数据库访问对象的WritePurpose方法,保存地址到数据库中。WalletBatch(*database).WriteName(EncodeDestination(address),strName);strName为用户提供的标签。EncodeDestination方法,我们在下一步讲解。调用EncodeDestination方法,解码目的地址,并返回其结果。EncodeDestination方法同样采用了访问者模式returnboost::apply_visitor(DestinationEncoder(Params()),dest)。DestinationEncoder类继承了boost::static_visitor,实现了访问者模式,通过重载()操作符来定义不同类型的id。与前面相对应,这个方法会处理CKeyID、CScriptID、WitnessV0KeyHash、WitnessV0ScriptHash、WitnessUnknown这几种不同情况。对于我们的默认情况来说,目的地址类型为CScriptID,下面我们就看下这种情况的处理,其他情况可自行阅读。调用当前网络参数的Base58Prefix方法,返回脚本前缀。std::vector<unsignedchar>data=m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);对于主网络前缀是5,测试网络是196,回归测试网络是196。把当前20个字节的数据加在前缀后面形成21个字节的字符串。data.insert(data.end(),id.begin(),id.end());调用EncodeBase58Check方法,编码成Base58Check格式,并返回其值。returnEncodeBase58Check(data);下面,我们来看下EncodeBase58Check这个方法的处理。它的内部执行流程如下:用21个字节的字符串生成一个向量,同时调用Hash方法,生成一个32字节长的哈希字符串;然后把其最前面的4个字节作为校验各加在21个字节的向量尾部,从而生成一个长度为25个字节的字符串;最后,调用EncodeBase58方法,进行Base58编码。std::vector<unsignedchar>vch(vchIn);uint256hash=Hash(vch.begin(),vch.end());vch.insert(vch.end(),(unsignedchar*)&hash,(unsignedchar*)&hash+4);returnEncodeBase58(vch);在Hash这个方法中,使用了双重SHA256哈希算法。EncodeBase58这个方法,读者可以自行阅读,这里不再展开。
民盟中央建议加速元宇宙科普和立法:3月4日消息,民盟中央已起草了《关于“元宇宙”技术发展的提案》,并将提交全国政协十三届五次会议。在提案中,民盟中央建议,在科普层面需加速知识传播,法律层面则需加快立法步伐。民盟中央拟提交的提案指出,目前,在新兴网络层面,相关政策法规相对缺失。“元宇宙”在未来将会带动形成全新的网络形态,当遇到突发舆情,全虚拟的环境、场景将更难进行源头追踪、问题疏导。因此建议应尽早加快立法研究,尽快形成与技术、市场发展相适应的治理模式和法律基础,全面提升我国社会治理的水平。建议组织相关部门,针对“元宇宙”相关需求、风险进行立法研究,并尽快发布。此前消息,民进中央拟向全国政协十三届五次会议提交《关于积极稳妥推进元宇宙技术和产业发展的提案》。建议推进元宇宙技术产业发展,建立相关监管治理体系。(华夏时报)[2022/3/4 13:37:12]
GetKeyFromPool从密钥池中获取公钥
本方法从密钥池中生成一个公钥。第一个参数为公钥的引用,第二个参数
internal
,默认为假。
内部逻辑如下:
如果钱包禁止私钥,则返回假。if(IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)){returnfalse;}调用ReserveKeyFromKeyPool方法,从密钥池中取出一个密钥并获取其公钥。如果不成功,则生成数据库访问对象,然后调用GenerateNewKey方法,生成一个公钥。if(!ReserveKeyFromKeyPool(nIndex,keypool,internal)){if(IsLocked())returnfalse;WalletBatchbatch(*database);result=GenerateNewKey(batch,internal);returntrue;}GenerateNewKey这个方法,在创建钱包过程中,我们已经重点分析,这里不浪费口舌,我们重点看下ReserveKeyFromKeyPool方法。这个方法的执行流程如下:生成一个公钥,并设置为密钥池的vchPubKey属性。nIndex=-1;keypool.vchPubKey=CPubKey();如果钱包没有被锁,则填充密钥池。if(!IsLocked())TopUpKeyPool();TopUpKeyPool这个方法,我们也讲过,这里直接略过。如果钱包启用了HD,并且可以支持HD分割,并且参数fRequestedInternal为真,则设置变量fReturningInternal为真。在调用本方法时,这个参数没有指定,而默认为假,所以变量fRequestedInternal设置假。boolfReturningInternal=IsHDEnabled()&&CanSupportFeature(FEATURE_HD_SPLIT)&&fRequestedInternal;根据集合set_pre_split_keypool是否为空,设置变量use_split_keypool的值。因为这里use_split_keypool集合为空,所以变量use_split_keypool为真。booluse_split_keypool=set_pre_split_keypool.empty();根据变量use_split_keypool、fReturningInternal确定从哪个集合中获取密钥池对象。根据上面分析,我们最终会从setExternalKeyPool集合中取数据。std::set<int64_t>&setKeyPool=use_split_keypool?(fReturningInternal?setInternalKeyPool:setExternalKeyPool):set_pre_split_keypool;如果要数据的集合为为空,则返回假。if(setKeyPool.empty()){returnfalse;}生成数据库访问对象。WalletBatchbatch(*database);从setKeyPool取得其第一个元素,并从集合中删除它。autoit=setKeyPool.begin();nIndex=*it;setKeyPool.erase(it);从数据库取得索引对应的密钥池。如果失败,则抛出异常。if(!batch.ReadPool(nIndex,keypool)){throwstd::runtime_error(std::string(__func__)+":readfailed");}从密钥池中取得公钥对应的ID,并且检测其是否在mapKeys、或mapCryptedKeys集合之一,如果不在,则抛出异常。我们在创建钱包过程时候讲过,生成的私钥根据是否加密会保存在这两个集合之一。if(!HaveKey(keypool.vchPubKey.GetID())){throwstd::runtime_error(std::string(__func__)+":unknownkeyinkeypool");}如果变量use_split_keypool为真,并且密钥池的fInternal属性不等于变量fReturningInternal,那么抛出异常。if(use_split_keypool&&keypool.fInternal!=fReturningInternal){throwstd::runtime_error(std::string(__func__)+":keypoolentrymisclassified");}如果密钥池中保存的公钥是无效的,那么抛出异常。if(!keypool.vchPubKey.IsValid()){throwstd::runtime_error(std::string(__func__)+":keypoolentryinvalid");}从m_pool_key_to_index集合中消除对应的索引。m_pool_key_to_index.erase(keypool.vchPubKey.GetID());返回真。调用KeepKey从密钥池中取出对应的公钥。
国务院:推进科普与区块链技术深度融合:为贯彻落实党中央、国务院关于科普和科学素质建设的重要部署,依据《中华人民共和国科学技术进步法》、《中华人民共和国科学技术普及法》制定《全民科学素质行动规划纲要(2021-2035年)》,其中要求实施智慧科普建设工程。推进科普与区块链等技术深度融合,强化需求感知、用户分层、情景应用理念,推动传播方式、组织动员、运营服务等创新升级,加强“科普中国”建设,强化科普信息落地应用,与智慧教育、智慧城市、智慧社区等深度融合。(新华社)[2021/7/10 0:40:52]
作者:区小白
来源:巴比特
整理发出:赢和财经
以上内容采编自互联网,如内容侵犯您的版权,请联系邮箱:law@allwin.world,我们会在24小时内删除相关内容。
TRON数字钱包科普资料《波场钱包的现在过去与未来》已上线:据最新消息显示,由TokenPocket联合波场TRON官方,以及 TokenPocket 社区志愿者共同撰写的《波场钱包的现在过去与未来》已正式上线。《波场钱包的现在过去与未来》又称为波场钱包小白书,详细介绍了当前TRON钱包与TRON生态密切结合的实例,是目前市面上最为详细的TRON数字钱包科普资料。波场钱包作为波场公链生态中极为重要的入口,是波场生态的重要构成要素。波场钱包从一开始只提供权限管理、转账收款、节点投票等基础功能,到如今不仅可以为用户提供法币交易、闪兑和去中心化交易所等方便快捷的交易服务,还能让用户直接在钱包上体验波场上DApp,挖矿、DeFi、Staking等资产增值服务。详情见原文链接。[2020/8/20]
现场 | 火币中国推出数字经济及区块链产业科普新书:金色财经现场报道,12月6日,由海南省工业和信息化厅主办,南南合作金融中心协办,海南生态软件园、火币中国承办的“海南自贸港数字经济和区块链国际合作论坛”在海口举行,这是全球首次区块链部长级论坛。
在本次论坛上,火币中国举行了“数字经济及区块链产业科普系列新书发布”仪式,希望通过教材、专业教育、培训等多种方式,帮助从业者、高校、研究机构深入了解区块链,从而建立起区块链全局性知识模型,真正推动区块链应用落地。火币中国CEO袁煜明介绍,将联合机械工业出版社面向普通高等教育推出《区块链导论》、《区块链系统设计与应用》和《区块链新商业模式分析》系列教材,这是国内最早推动的区块链教材之一;火币中国还积极参与数字经济的研究,由中信出版社出版的新书《读懂Libra》已经上市;由火币中国负责编写的区块链技术科普读物《区块链技术进阶指南》将于12月面世;首本行业内最全的区块链应用案例集《区块链产业应用100例》在本次论坛进行了首次刊印。[2019/12/6]
动态 | 币安科普MimbleWimble算法:币安官方推特今日发布隐私算法Mimblewimble的科普贴,在下方留言区大量网友留言猜测是否是基于 Mimblewimble算法的隐私币Grin或者Beam即将登陆币安交易所,其中猜测Grin的呼声更高。[2019/9/2]
本文将主要讨论知识图谱在风控领域的图谱构建过程。enjoy~一.知识图谱和金融领域简述 什么是知识图谱? 借鉴其中一个理解: 知识图谱主要的目标是用来描述真实世界中间存在的各种实体和概念,以及它.
1900/1/1 0:00:00区块链应用 ——破解滴滴华住们的“隐私”霸权:区块链技术将规范大数据应用?蚂蚁金服副总裁、技术实验室负责人蒋国飞对21世纪经济报道记者表示,区块链的未来将是比AI影响更为广泛的技术.
1900/1/1 0:00:00PoW是区块链技术中基本的、常见的一种共识机制。加密币中的挖矿,其实就是运用工作量证明来进行的。 一、PoW的起源 工作量证明最早是一个经济学名词,指系统为达到某一目标而设置的衡量机制.
1900/1/1 0:00:00区块链日报:好莱坞女影星唱多比特币,比特币价格走势得到修复早间行情播报:BTC窄幅震荡于6460USDT左右数字货币市场跌多涨少据火币Pro行情显示,今日零时开始BTC持续下跌.
1900/1/1 0:00:00门罗币是一个创建于2014年4月开源加密货币,它着重于隐私、分权和可扩展性。与自比特币衍生的许多加密货币不同,Monero基于CryptoNote协议,并在区块链模糊化方面有显著的算法差异.
1900/1/1 0:00:00一千元人民币能在印度生活多久?说出来你都不敢相信说到印度这个国家,大家都不会陌生,因为无论是从网络还是新闻媒体,印度都是一个曝光率很高的国家,大多数人对印度的印象.
1900/1/1 0:00:00