生成地址
如果有人想發送比特幣給你,或者你從別人那里買幾個比特幣,就要把地址給對方,對方才能把幣打到你指定的地址上。那么,如何才能擁有一個地址呢,下面我們就來講講這個問題。
比特幣核心提供了很多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這個方法,讀者可以自行閱讀,這里不再展開。
美國說唱歌手Megan Thee Stallion與Cash App合作發布比特幣科普視頻:美國說唱歌手Megan Thee Stallion與由Square開發的移動支付服務Cash App合作發布了一段名為“Bitcoin for Hotties”的視頻。該視頻從她的角度解釋了什么是比特幣,為什么比特幣有價值等內容。Megan Thee Stallion在Instagram上擁有超過2410萬粉絲,在 Twitter上擁有640萬粉絲。(Bitcoin News)[2021/8/8 1:41:10]
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從密鑰池中取出對應的公鑰。
現場 | 火幣中國推出數字經濟及區塊鏈產業科普新書:金色財經現場報道,12月6日,由海南省工業和信息化廳主辦,南南合作金融中心協辦,海南生態軟件園、火幣中國承辦的“海南自貿港數字經濟和區塊鏈國際合作論壇”在海口舉行,這是全球首次區塊鏈部長級論壇。
在本次論壇上,火幣中國舉行了“數字經濟及區塊鏈產業科普系列新書發布”儀式,希望通過教材、專業教育、培訓等多種方式,幫助從業者、高校、研究機構深入了解區塊鏈,從而建立起區塊鏈全局性知識模型,真正推動區塊鏈應用落地。火幣中國CEO袁煜明介紹,將聯合機械工業出版社面向普通高等教育推出《區塊鏈導論》、《區塊鏈系統設計與應用》和《區塊鏈新商業模式分析》系列教材,這是國內最早推動的區塊鏈教材之一;火幣中國還積極參與數字經濟的研究,由中信出版社出版的新書《讀懂Libra》已經上市;由火幣中國負責編寫的區塊鏈技術科普讀物《區塊鏈技術進階指南》將于12月面世;首本行業內最全的區塊鏈應用案例集《區塊鏈產業應用100例》在本次論壇進行了首次刊印。[2019/12/6]
作者:區小白
來源:巴比特
整理發出:贏和財經
以上內容采編自互聯網,如內容侵犯您的版權,請聯系郵箱:law@allwin.world,我們會在24小時內刪除相關內容。
動態 | 浙江衛視節目科普支付寶區塊鏈防偽溯源產品:昨日,在浙江衛視播出的科普綜藝欄目《智造將來》現場,支付寶首次展示了支付寶區塊鏈防偽溯源產品,以接地氣的方式公開向大眾展示區塊鏈在生活中的應用。[2019/3/4]
聲音 | 中科院姚建銓:要加快推進區塊鏈與物聯網融合的科普 培訓:據新華網消息,日前,在區塊鏈與物聯網融合發展峰會上,中國科學院院士姚建銓說,關注區塊鏈技術里面的大數據,跟區塊鏈技術結合起來進行測量和檢測,能更好地提升激光清洗技術。姚建銓建議,無錫今后要加快推進區塊鏈與物聯網融合的科普、培訓,正確引導廣大人民群眾對技術的認知;同時,建立專業、權威,但又普適、成套的理論體系和標準,以此切入區塊鏈的實際應用。[2018/9/18]
財政部副部長朱光耀:數字經濟還處在發展的過程中,要以科普、推動的態度來推進數字經濟發展:今日,在中國發展高層論壇2018年會上,財政部副部長朱光耀表示:“數字經濟還處在發展的過程中,要以科普、推動的態度來推進數字經濟發展。也要關注數字經濟的其他影響,包括稅收征管、反洗錢監管措施等要跟上。”[2018/3/25]
據icoexaminer9月22日報道,聯合國兒童基金會法國辦事處已宣布接受瑞波和恒星幣的捐贈,該辦事處可接受的加密貨幣從7種增加到了9種.
1900/1/1 0:00:00在比特幣的世界中,中國人算是較早踏入的領航者,無論是交易所、礦機、礦池還是錢包,都有嗅覺敏銳的中國投資者緊緊跟隨。然而,同樣一個暴利的比特幣領域,卻少有中國人的身影.
1900/1/1 0:00:00澳洲是一個物種富饒繁盛的地方,澳洲出產的“神獸”可真的是不少呢。比如說袋鼠啊,考拉啊,都可以說是澳洲的代表生物了,它們受到了來自世界各地人們群眾的歡迎,并且憑借自身出色的氣質成為了網紅動物.
1900/1/1 0:00:00中新經緯客戶端11月17日電據央行網站消息,中國人民銀行決定自2018年11月16日起陸續發行慶祝改革開放40周年紀念幣一套.
1900/1/1 0:00:00Kcash獲千萬級融資用戶破70萬“我們要為1億人次用戶免gas費。”Kcash創始人兼CEO祝雪嬌聲音平穩且堅定。此時,他目光如炬,一是為獲得千萬級別的融資,二是破70萬的用戶.
1900/1/1 0:00:00區塊鏈是由一系列技術實現的全新去中心化經濟組織模式,2009年誕生于比特幣系統的構建,2017年成為全球經濟熱點.
1900/1/1 0:00:00