2018-08-14 10:48:46 437浏览
随着区块链概念理论的不断成熟以及强劲技术的不断深耕,区块链已经成为投资圈中备受关注的热点,从区块链1.0时代落地数字货币比特币、莱特币等,打开了区块链通向新弯道的高速路口,到区块链2.0时代开始通过智能合约来解决货币支付难题,再到3.0时代区块链尝试向各传统行业发力,今天扣丁学堂区块链培训技术给大家介绍一下关于比特币探究之交易创建详解,下面我们一起来看一下吧。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函数,内部流程也比较复杂。当然它的复杂,来源于签名机制的复杂。为了帮助理解,我画了一个简要流程图。
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椭圆曲线加密算法进行签名 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) { //如果是隔离见证,根据BIP-143的规定简化签名内容 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(); } //如果不是隔离见证,调用Serializer输出哈希,根据所有的输入输出计算得出,其复杂度高于隔离见证版 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字节的Redeem Script(赎回脚本)的Hash vSolutionsRet.push_back(hashBytes); return true; } int witnessversion; std::vector<unsigned char> witnessprogram; //如果采用了隔离见证,那应该是[见证版本] [见证程序]的格式 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字节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) { //向前兼容,当前隔离见证版本号只有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; //其他情况就是非标准交易了 return false; } //用OP_RETURN带的一堆直推数据 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字节公钥] OP_CHECKSIG,33为压缩版 if (MatchPayToPubkey(scriptPubKey, data)) { typeRet = TX_PUBKEY; vSolutionsRet.push_back(std::move(data)); return true; } //OP_DUP OP_HASH160 20 [20字节公钥哈希] 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; //以上都不是,那就是非标准交易了 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: //公钥,调用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: { //公钥哈希,调用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; //签名数量够不够? for (size_t i = 0; i + ret.size() < required + 1; ++i) { ret.push_back(valtype()); } return ok; } case TX_WITNESS_V0_KEYHASH: //P2WPKH,直接返回20字节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再调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,注意如果是隔离见证,此前已经clear //最后还要验证一下 sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); return sigdata.complete; }
【关注微信公众号获取更多学习资料】