2018-08-14 10:48:46 1562瀏覽
隨著區(qū)塊鏈概念理論的不斷成熟以及強(qiáng)勁技術(shù)的不斷深耕,區(qū)塊鏈已經(jīng)成為投資圈中備受關(guān)注的熱點,從區(qū)塊鏈1.0時代落地數(shù)字貨幣比特幣、萊特幣等,打開了區(qū)塊鏈通向新彎道的高速路口,到區(qū)塊鏈2.0時代開始通過智能合約來解決貨幣支付難題,再到3.0時代區(qū)塊鏈嘗試向各傳統(tǒng)行業(yè)發(fā)力,今天扣丁學(xué)堂區(qū)塊鏈培訓(xùn)技術(shù)給大家介紹一下關(guān)于比特幣探究之交易創(chuàng)建詳解,下面我們一起來看一下吧。const CScript& scriptPubKey = coin.txout.scriptPubKey; SignatureData sigdata; if (!ProduceSignature(*this, MutableTransactionSignatureCreator(&txNew, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata)) { strFailReason = _("Signing transaction failed"); return false; } else { UpdateInput(txNew.vin.at(nIn), sigdata); }
這里的ProduceSignature函數(shù),內(nèi)部流程也比較復(fù)雜。當(dāng)然它的復(fù)雜,來源于簽名機(jī)制的復(fù)雜。為了幫助理解,我畫了一個簡要流程圖。
bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const { CKey key; if (!provider.GetKey(address, key)) return false; //見證腳本必須是壓縮版 if (sigversion == SigVersion::WITNESS_V0 && !key.IsCompressed()) return false; //生成交易哈希,用于簽名 uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); if (!key.Sign(hash, vchSig)) //使用ECDSA橢圓曲線加密算法進(jìn)行簽名 return false; vchSig.push_back((unsigned char)nHashType); return true; }
template <class T> uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { if (sigversion == SigVersion::WITNESS_V0) { //如果是隔離見證,根據(jù)BIP-143的規(guī)定簡化簽名內(nèi)容 uint256 hashPrevouts, hashSequence, hashOutputs; const bool cacheready = cache && cache->ready; //非任何人可付,為所有PrevOut的哈希,否則全0 if (!(nHashType & SIGHASH_ANYONECANPAY)) { hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo); } //非任何人可付,不是SINGLE或NONE,為所有序列號哈希,否則全0 if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { hashSequence = cacheready ? cache->hashSequence : GetSequenceHash(txTo); } if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { //非SINGLE和NONE,為所有輸出的哈希 hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo); } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { //如果是SINGLE,為同一序列號輸出的哈希。其他情況全0 CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; hashOutputs = ss.GetHash(); } CHashWriter ss(SER_GETHASH, 0); ss << txTo.nVersion; ss << hashPrevouts; ss << hashSequence; ss << txTo.vin[nIn].prevout; ss << scriptCode; ss << amount; ss << txTo.vin[nIn].nSequence; ss << hashOutputs; ss << txTo.nLockTime; ss << nHashType; return ss.GetHash(); } //如果不是隔離見證,調(diào)用Serializer輸出哈希,根據(jù)所有的輸入輸出計算得出,其復(fù)雜度高于隔離見證版 CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType); CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; return ss.GetHash(); }
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) { vSolutionsRet.clear(); //P2SH類型,格式為 OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { typeRet = TX_SCRIPTHASH; std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); //返回20字節(jié)的Redeem Script(贖回腳本)的Hash vSolutionsRet.push_back(hashBytes); return true; } int witnessversion; std::vector<unsigned char> witnessprogram; //如果采用了隔離見證,那應(yīng)該是[見證版本] [見證程序]的格式 if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { //長度20,說明是P2WPKH if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) { typeRet = TX_WITNESS_V0_KEYHASH; vSolutionsRet.push_back(witnessprogram); //返回20字節(jié)PubKey Hash return true; } //長度32,說明是P2WSH if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) { typeRet = TX_WITNESS_V0_SCRIPTHASH; vSolutionsRet.push_back(witnessprogram); //返回見證腳本 return true; } if (witnessversion != 0) { //向前兼容,當(dāng)前隔離見證版本號只有0 typeRet = TX_WITNESS_UNKNOWN; vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); return true; } typeRet = TX_NONSTANDARD; //其他情況就是非標(biāo)準(zhǔn)交易了 return false; } //用OP_RETURN帶的一堆直推數(shù)據(jù) if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { typeRet = TX_NULL_DATA; return true; } std::vector<unsigned char> data; //65/33 [65/33字節(jié)公鑰] OP_CHECKSIG,33為壓縮版 if (MatchPayToPubkey(scriptPubKey, data)) { typeRet = TX_PUBKEY; vSolutionsRet.push_back(std::move(data)); return true; } //OP_DUP OP_HASH160 20 [20字節(jié)公鑰哈希] OP_EQUALVERIFY OP_CHECKSIG if (MatchPayToPubkeyHash(scriptPubKey, data)) { typeRet = TX_PUBKEYHASH; vSolutionsRet.push_back(std::move(data)); return true; } unsigned int required; std::vector<std::vector<unsigned char>> keys; //多重簽名:<required> <A pubkey> [B pubkey] [C pubkey...] <keys.size()> OP_CHECKMULTISIG if (MatchMultisig(scriptPubKey, required, keys)) { typeRet = TX_MULTISIG; vSolutionsRet.push_back({static_cast<unsigned char>(required)}); vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); return true; } vSolutionsRet.clear(); typeRet = TX_NONSTANDARD; //以上都不是,那就是非標(biāo)準(zhǔn)交易了 return false; }
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata) { CScript scriptRet; uint160 h160; ret.clear(); std::vector<unsigned char> sig; std::vector<valtype> vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) //判斷scriptPubKey類型 return false; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: //公鑰,調(diào)用CreateSig生成簽名 if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); return true; case TX_PUBKEYHASH: { //公鑰哈希,調(diào)用CreateSig生成簽名,連同公鑰一并返回 CKeyID keyID = CKeyID(uint160(vSolutions[0])); if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); CPubKey pubkey; GetPubKey(provider, sigdata, keyID, pubkey); ret.push_back(ToByteVector(pubkey)); return true; } case TX_SCRIPTHASH: //腳本哈希,取出贖回腳本redeem script if (GetCScript(provider, sigdata, uint160(vSolutions[0]), scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_MULTISIG: { //多重簽名 size_t required = vSolutions.front()[0]; ret.push_back(valtype()); for (size_t i = 1; i < vSolutions.size() - 1; ++i) { CPubKey pubkey = CPubKey(vSolutions[i]); if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) { ret.push_back(std::move(sig)); } } bool ok = ret.size() == required + 1; //簽名數(shù)量夠不夠? for (size_t i = 0; i + ret.size() < required + 1; ++i) { ret.push_back(valtype()); } return ok; } case TX_WITNESS_V0_KEYHASH: //P2WPKH,直接返回20字節(jié)Key Hash ret.push_back(vSolutions[0]); return true; case TX_WITNESS_V0_SCRIPTHASH: //P2WSH,返回見證腳本(m keys n) CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); if (GetCScript(provider, sigdata, h160, scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } return false; default: return false; } }
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) { if (sigdata.complete) return true; std::vector<valtype> result; txnouttype whichType; bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); if (solved && whichType == TX_SCRIPTHASH) { //P2SH,對子腳本(贖回腳本)二次簽名 subscript = CScript(result[0].begin(), result[0].end()); sigdata.redeem_script = subscript; solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH; P2SH = true; } if (solved && whichType == TX_WITNESS_V0_KEYHASH) { //P2WPKH,先組建P2PKH,二次簽名 CScript witnessscript; witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; txnouttype subType; solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata); sigdata.scriptWitness.stack = result; sigdata.witness = true; result.clear(); } else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH) { //P2WSH,m keys n再調(diào)SignStep完成多重簽名 CScript witnessscript(result[0].begin(), result[0].end()); sigdata.witness_script = witnessscript; txnouttype subType; solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end())); sigdata.scriptWitness.stack = result; sigdata.witness = true; result.clear(); } else if (solved && whichType == TX_WITNESS_UNKNOWN) { sigdata.witness = true; } if (P2SH) { //子腳本加上去 result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); //填入scriptSig,注意如果是隔離見證,此前已經(jīng)clear //最后還要驗證一下 sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); return sigdata.complete; }
【關(guān)注微信公眾號獲取更多學(xué)習(xí)資料】
查看更多關(guān)于“區(qū)塊鏈培訓(xùn)技術(shù)資訊”的相關(guān)文章>>