生成地址
如果有人想發送比特幣給你,或者你從別人那里買幾個比特幣,就要把地址給對方,對方才能把幣打到你指定的地址上。那么,如何才能擁有一個地址呢,下面我們就來講講這個問題。
比特幣核心提供了很多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從密鑰池中取出對應的公鑰。
火幣推出《一分鐘讀懂DeFi》系列科普視頻:據官方消息,8月24日,火幣推出《一分鐘讀懂DeFi》系列科普視頻,并與微博財經合作冠名播出,布道DeFi認知,助力行業發展《一分鐘讀懂DeFi》是由火幣成長學院打造的業內首個系統全面講解DeFi的系列科普動畫,繼推出《區塊鏈100問》后的再續佳作。《一分鐘讀懂DeFi》系列動畫對DeFi的發展進行系統梳理,適合想要由淺入深、全面系統了解區塊鏈DeFi的人們輕松了解DeFi。目前視頻已由火幣網官方微博發布。[2020/8/24]
作者:區小白
來源:巴比特
整理發出:贏和財經
以上內容采編自互聯網,如內容侵犯您的版權,請聯系郵箱:law@allwin.world,我們會在24小時內刪除相關內容。
IMF今日發布的加密貨幣科普視頻實為兩年前舊聞,且存在諸多疏漏:國際貨幣基金組織IMF今日在推特上發布了一條關于加密貨幣的科普視頻,這段時長兩分鐘的視頻最初發布于2018年6月。該視頻稱加密貨幣是“貨幣進化的下一步”,但沒有特別提到DLT、區塊鏈,甚至是代幣名稱等術語。BTC、XRP和ETH只出現在說明加密交易的圖形中。盡管這段視頻到目前為止已經獲得了超過13.7萬的點擊量和2900個贊,但來自加密社區的許多反應都是批評的,他們指出了信息中的漏洞和似乎具有誤導性的措辭。
Reddit用戶nanooverbtc稱:“他們犯了很多錯誤,比如把私鑰稱為密碼。”該視頻也沒有討論挖礦或加密貨幣供應。Kraken策略師Pierre Rochard等知名人士表示:“可證明的稀缺性是比特幣有趣的原因,你忘了提這一點。”(Cointelegraph)[2020/8/24]
人民數字FINTECH推出區塊鏈科普動畫:人民日報數字傳播發布微博稱,人民數字FINTECH出品《趣味科普|區塊鏈動畫》。[2020/3/31]
財政部副部長朱光耀:數字經濟還處在發展的過程中,要以科普、推動的態度來推進數字經濟發展:今日,在中國發展高層論壇2018年會上,財政部副部長朱光耀表示:“數字經濟還處在發展的過程中,要以科普、推動的態度來推進數字經濟發展。也要關注數字經濟的其他影響,包括稅收征管、反洗錢監管措施等要跟上。”[2018/3/25]
第0章引言 在BCH社區,CSW博士提出了要穩定協議的呼吁,有人認同,也有人反對,反對者認為BCH應該為改進用戶體驗而努力。現在這兩派鬧著要離婚.
1900/1/1 0:00:00英國經濟歷史學家——比特幣是未來的金融體系NiallFerguson是一位著名的歷史學家,評論員,也是包括《金錢崛起》和《羅斯柴爾德之家》在內的15本書的作者.
1900/1/1 0:00:00中新經緯客戶端6月6日電“一個匯集幣圈內幕的社區,掃碼獲悉下一個‘暴漲幣種’。”近年來,以比特幣為代表的“虛擬幣”由于其價格猛漲,吸引了不少投資者的目光.
1900/1/1 0:00:00什么是比特幣?區塊鏈小白上手指南對于區塊鏈新手而言,起初我們的疑問很多,不知道該怎么快速了解和進入區塊鏈,比特幣是區塊鏈當中一個很重要的衍生物,今天小編帶大家來了解比特幣,作為新手.
1900/1/1 0:00:00今天在群中閑聊時有朋友提出了這樣一個問題:虛擬貨幣的真假如何判斷,真假虛擬貨幣的特征如何區分?如圖有人羅列了7條號稱分辨虛擬貨幣真假的七條基本屬性.
1900/1/1 0:00:00上世紀七十年代,美國著名經濟學家、諾貝爾獎獲得者赫伯特·西蒙在其著作中指出,信息時代,信息資源的極大豐富將導致注意力稀缺。按照經濟學理論,促進信息消費則需最大化利用稀缺的注意力資源.
1900/1/1 0:00:00