生成地址
如果有人想發送比特幣給你,或者你從別人那里買幾個比特幣,就要把地址給對方,對方才能把幣打到你指定的地址上。那么,如何才能擁有一個地址呢,下面我們就來講講這個問題。
比特幣核心提供了很多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這個方法,讀者可以自行閱讀,這里不再展開。
國務院:推進科普與區塊鏈技術深度融合:為貫徹落實黨中央、國務院關于科普和科學素質建設的重要部署,依據《中華人民共和國科學技術進步法》、《中華人民共和國科學技術普及法》制定《全民科學素質行動規劃綱要(2021-2035年)》,其中要求實施智慧科普建設工程。推進科普與區塊鏈等技術深度融合,強化需求感知、用戶分層、情景應用理念,推動傳播方式、組織動員、運營服務等創新升級,加強“科普中國”建設,強化科普信息落地應用,與智慧教育、智慧城市、智慧社區等深度融合。(新華社)[2021/7/10 0:40:52]
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從密鑰池中取出對應的公鑰。
IMF今日發布的加密貨幣科普視頻實為兩年前舊聞,且存在諸多疏漏:國際貨幣基金組織IMF今日在推特上發布了一條關于加密貨幣的科普視頻,這段時長兩分鐘的視頻最初發布于2018年6月。該視頻稱加密貨幣是“貨幣進化的下一步”,但沒有特別提到DLT、區塊鏈,甚至是代幣名稱等術語。BTC、XRP和ETH只出現在說明加密交易的圖形中。盡管這段視頻到目前為止已經獲得了超過13.7萬的點擊量和2900個贊,但來自加密社區的許多反應都是批評的,他們指出了信息中的漏洞和似乎具有誤導性的措辭。
Reddit用戶nanooverbtc稱:“他們犯了很多錯誤,比如把私鑰稱為密碼。”該視頻也沒有討論挖礦或加密貨幣供應。Kraken策略師Pierre Rochard等知名人士表示:“可證明的稀缺性是比特幣有趣的原因,你忘了提這一點。”(Cointelegraph)[2020/8/24]
作者:區小白
來源:巴比特
整理發出:贏和財經
以上內容采編自互聯網,如內容侵犯您的版權,請聯系郵箱:law@allwin.world,我們會在24小時內刪除相關內容。
人大附中物理老師李永樂科普拜占庭將軍問題和區塊鏈:5月14日,人大附中物理老師、科普視頻網紅李永樂在其公眾號發布視頻《拜占庭將軍問題是什么?區塊鏈如何防范惡意節點?》。李永樂老師在視頻中對拜占庭將軍問題和區塊鏈進行了講解,他表示,拜占庭將軍問題本質上指的是,在分布式計算機網絡中,如果存在故障和惡意節點,是否能夠保持正常節點的網絡一致性問題。在近40年的時間里,人們提出了許多方案解決這一問題,稱為拜占庭容錯法。例如蘭波特自己提出了口頭協議、書面協議法,后來有人提出了實用拜占庭容錯PBFT算法,在2008年,中本聰發明比特幣后,人們又設想了通過區塊鏈的方法解決這一問題。區塊鏈通過算力證明來保持賬本的一致性,也就是必須計算數學題,才能得到記賬的權力,其他人對這個記賬結果進行驗證,如果是對的,就認可你的結果。與拜占庭問題比起來,就增加了叛徒的成本。[2020/5/14]
動態 | 央行官微舊文重發“再科普”:范一飛詳解數字貨幣:據中國經濟網消息,今日,央行官微公眾號頭條重新發布央行副行長范一飛在2018年1月25日題為《關于央行數字貨幣的幾點考慮》的文章,對央行數字貨幣再次進行科普。同時,微信公眾號第二條發布支付司副司長穆長春8月10日在第三屆中國金融四十人伊春論壇上的演講。近年來,各主要國家和地區央行及貨幣當局均在對發行央行數字貨幣開展研究,新加坡央行和瑞典央行等已經開始進行相關試驗,人民銀行也在組織進行積極探索和研究。[2019/8/21]
動態 | 浙江衛視節目科普支付寶區塊鏈防偽溯源產品:昨日,在浙江衛視播出的科普綜藝欄目《智造將來》現場,支付寶首次展示了支付寶區塊鏈防偽溯源產品,以接地氣的方式公開向大眾展示區塊鏈在生活中的應用。[2019/3/4]
中新經緯客戶端8月11日電(李曉萱)一款看起來簡簡單單的紀念幣,在全國發行100萬枚以后,竟然被炒到了上萬元。近期,“麥當勞紀念幣遭瘋搶”的話題登上微博熱搜榜.
1900/1/1 0:00:00礦機作為比特幣系統中的關鍵組成部分,通過消耗計算和電力資源爭奪記賬權,為該系統增加了“信任價值”;從投資角度而言,比特幣礦機可以視為比特幣價格的“看漲期權”,正是因為礦工對未來幣價持看漲態度.
1900/1/1 0:00:00~《幣圈悲情馬奇諾》~ 自從比特幣被爆炒之后,由國內外領先團隊生產形形虛擬貨幣也競相亮相幣圈大炒鍋,都想成為圈內外人士,投資機構追捧的寵兒,成為幣種投資餐桌的一道名角.
1900/1/1 0:00:00有人在“暗網”高價售賣華住旗下酒店1.3億用戶信息,你怎么看?有人在暗網的一個中文交易論壇發帖稱,打包出售華住旗下酒店的住客信息,包括華住官網注冊資料、酒店入住登記的身份信息及酒店開房記錄.
1900/1/1 0:00:00今年雙十一不出意料的又突破了新高,除了亮眼的銷售額外,此次雙十一也加入了新的元素--區塊鏈。據媒體報道,本次雙十一螞蟻區塊鏈首次參戰,覆蓋了全球1.5億件貨品的跨境商品溯源.
1900/1/1 0:00:00來源:區塊鏈Truth 三個不同職業的男性,在不同的時間,因不同的理由加入幣圈。徐磊,90后,創業者.
1900/1/1 0:00:00