bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { std::vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; addressRet = pubKey.GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { addressRet = CScriptID(uint160(vSolutions[0])); return true; } // Multisig txns have more than one address... return false; }
/** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion) { CScript scriptRet; uint160 h160; ret.clear(); std::vector<valtype> vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(provider, keyID, creator, scriptPubKey, ret, sigversion)) return false; else { CPubKey vch; provider.GetPubKey(keyID, vch); ret.push_back(ToByteVector(vch)); } return true; case TX_SCRIPTHASH: if (provider.GetCScript(uint160(vSolutions[0]), scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_MULTISIG: ret.push_back(valtype()); // workaround CHECKMULTISIG bug return (SignN(provider, vSolutions, creator, scriptPubKey, ret, sigversion)); case TX_WITNESS_V0_KEYHASH: ret.push_back(vSolutions[0]); return true; case TX_WITNESS_V0_SCRIPTHASH: CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); if (provider.GetCScript(h160, scriptRet)) { ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end())); return true; } return false; default: return false; } }
bool SysTestBase::GetKeyId(string const &addr,CKeyID &KeyId) { if (!CRegID::GetKeyID(addr, KeyId)) { KeyId=CKeyID(addr); if (KeyId.IsEmpty()) return false; } return true; };
bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const { if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) return false; uint160 id; memcpy(&id, &vchData[0], 20); keyID = CKeyID(id); return true; }
CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) return CNoDestination(); uint160 id; memcpy(&id, &vchData[0], 20); if (vchVersion == Params().Base58Prefix(pubkey_address)) return CKeyID(id); else if (vchVersion == Params().Base58Prefix(script_address)) return CScriptID(id); else return CNoDestination(); }
CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest) { // Only supports destinations which map to single public keys, i.e. P2PKH, // P2WPKH, and P2SH-P2WPKH. if (auto id = boost::get<CKeyID>(&dest)) { return *id; } if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) { return CKeyID(*witness_id); } if (auto script_id = boost::get<CScriptID>(&dest)) { CScript script; CTxDestination inner_dest; if (store.GetCScript(*script_id, script) && ExtractDestination(script, inner_dest)) { if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) { return CKeyID(*inner_witness_id); } } } return CKeyID(); }
CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) return CNoDestination(); uint160 id; memcpy(&id, &vchData[0], 20); if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) return CKeyID(id); else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) return CScriptID(id); else return CNoDestination(); }
UniValue operator()(const WitnessV0KeyHash& id) const { UniValue obj(UniValue::VOBJ); CPubKey pubkey; obj.push_back(Pair("isscript", false)); obj.push_back(Pair("iswitness", true)); obj.push_back(Pair("witness_version", 0)); obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end()))); if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) { obj.push_back(Pair("pubkey", HexStr(pubkey))); } return obj; }
bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const { if (!IsValid()) return false; switch (nVersion) { case PUBKEY_ADDRESS: case PUBKEY_ADDRESS_TEST: { uint160 id; memcpy(&id, &vchData[0], 20); keyID = CKeyID(id); return true; } default: return false; } }
//! Simple qt wallet tests. // // Test widgets can be debugged interactively calling show() on them and // manually running the event loop, e.g.: // // sendCoinsDialog.show(); // QEventLoop().exec(); // // This also requires overriding the default minimal Qt platform: // // src/qt/test/test_bitcoin-qt -platform xcb # Linux // src/qt/test/test_bitcoin-qt -platform windows # Windows // src/qt/test/test_bitcoin-qt -platform cocoa # macOS void WalletTests::walletTests() { // Set up wallet and chain with 101 blocks (1 mature block for spending). TestChain100Setup test; test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); bitdb.MakeMock(); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat")); CWallet wallet(std::move(dbw)); bool firstRun; wallet.LoadWallet(firstRun); { LOCK(wallet.cs_wallet); wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive"); wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); } wallet.ScanForWalletTransactions(chainActive.Genesis(), true); wallet.SetBroadcastTransactions(true); // Create widgets for sending coins and listing transactions. std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); SendCoinsDialog sendCoinsDialog(platformStyle.get()); OptionsModel optionsModel; WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel); sendCoinsDialog.setModel(&walletModel); // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 101); uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN); uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN); QCOMPARE(transactionTableModel->rowCount({}), 103); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); bitdb.Flush(true); bitdb.Reset(); }
vector_unsigned_char CVmRunEvn::GetAccountID(CVmOperate value) { vector_unsigned_char accountid; if (value.nacctype == regid) { accountid.assign(value.accountid, value.accountid + 6); } else if (value.nacctype == base58addr) { string addr(value.accountid,value.accountid+sizeof(value.accountid)); CKeyID KeyId = CKeyID(addr); CRegID regid; if(m_view->GetRegId(CUserID(KeyId), regid)){ accountid.assign(regid.GetVec6().begin(),regid.GetVec6().end()); }else{ accountid.assign(value.accountid, value.accountid + 34); } } return accountid; }
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { std::vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; addressRet = pubKey.GetID(); return true; } else if (whichType == TX_PUBKEYHASH) { addressRet = CKeyID(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { addressRet = CScriptID(uint160(vSolutions[0])); return true; } else if (whichType == TX_WITNESS_V0_KEYHASH) { WitnessV0KeyHash hash; std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin()); addressRet = hash; return true; } else if (whichType == TX_WITNESS_V0_SCRIPTHASH) { WitnessV0ScriptHash hash; std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin()); addressRet = hash; return true; } else if (whichType == TX_WITNESS_UNKNOWN) { WitnessUnknown unk; unk.version = vSolutions[0][0]; std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program); unk.length = vSolutions[1].size(); addressRet = unk; return true; } // Multisig txns have more than one address... return false; }
bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const { uint160 id; if (vchVersion == Params().Base58Prefix(CBaseParams::PUBKEY_ADDRESS) && vchData.size() == 20) { memcpy(&id, &vchData[0], 20); keyID = CKeyID(id); return true; } vector<unsigned char> vid; vid.push_back(CBaseParams::ACC_ADDRESS); if (vchData.size() == 26 && vchVersion == vid) { memcpy(keyID.begin(), &vchData[0], 20); return true; } return false; }
CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) return CNoDestination(); switch (nVersion) { case PUBKEY_ADDRESS: case PUBKEY_ADDRESS_TEST: { uint160 id; memcpy(&id, &vchData[0], 20); return CKeyID(id); } case SCRIPT_ADDRESS: case SCRIPT_ADDRESS_TEST: { uint160 id; memcpy(&id, &vchData[0], 20); return CScriptID(id); } } return CNoDestination(); }
CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) return CNoDestination(); if (vchData.size() == 20) { uint160 id; memcpy(&id, &vchData[0], 20); if (vchVersion == Params().Base58Prefix(CBaseParams::PUBKEY_ADDRESS)) return CKeyID(id); else if (vchVersion == Params().Base58Prefix(CBaseParams::SCRIPT_ADDRESS)) return CScriptID(id); else return CNoDestination(); } else { CAccountID id; memcpy(&id, &vchData[0], 26); return id; } }
CTxDestination CSharkfundAddress::Get() const { if (!IsValid()) return CNoDestination(); if (vchData.size() == 20) { uint160 id; memcpy(&id, &vchData[0], 20); if (vchVersion == SysCfg().Base58Prefix(CBaseParams::PUBKEY_ADDRESS)) return CKeyID(id); // else if (vchVersion == Params().Base58Prefix(CBaseParams::SCRIPT_ADDRESS)) // return CScriptID(id); else return CNoDestination(); } else { // assert(0); return CNoDestination(); } }
/** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ 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)) return false; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); return true; case TX_PUBKEYHASH: { CKeyID keyID = CKeyID(uint160(vSolutions[0])); CPubKey pubkey; GetPubKey(provider, sigdata, keyID, pubkey); if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); ret.push_back(ToByteVector(pubkey)); return true; } case TX_SCRIPTHASH: 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()); // workaround CHECKMULTISIG bug 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, 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: ret.push_back(vSolutions[0]); return true; case TX_WITNESS_V0_SCRIPTHASH: 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 CVmRunEvn::OpeatorAccount(const vector<CVmOperate>& listoperate, CAccountViewCache& view, const int nCurHeight) { NewAccont.clear(); for (auto& it : listoperate) { // CTransaction* tx = static_cast<CTransaction*>(listTx.get()); // CFund fund; // memcpy(&fund.value,it.money,sizeof(it.money)); // fund.nHeight = it.outheight; uint64_t value; memcpy(&value, it.money, sizeof(it.money)); auto tem = std::make_shared<CAccount>(); // vector_unsigned_char accountid = GetAccountID(it); // if (accountid.size() == 0) { // return false; // } // vector_unsigned_char accountid(it.accountid,it.accountid+sizeof(it.accountid)); vector_unsigned_char accountid = GetAccountID(it); CRegID userregId; CKeyID userkeyid; if(accountid.size() == 6){ userregId.SetRegID(accountid); if(!view.GetAccount(CUserID(userregId), *tem.get())){ return false; /// 账户不存在 } }else{ string sharkfundaddr(accountid.begin(), accountid.end()); userkeyid = CKeyID(sharkfundaddr); if(!view.GetAccount(CUserID(userkeyid), *tem.get())) { tem->keyID = userkeyid; /// 未产生过交易记录的账户 //return false; /// 账户不存在 } } shared_ptr<CAccount> vmAccount = GetAccount(tem); if (vmAccount.get() == NULL) { RawAccont.push_back(tem); vmAccount = tem; } LogPrint("vm", "account id:%s\r\n", HexStr(accountid).c_str()); LogPrint("vm", "befer account:%s\r\n", vmAccount.get()->ToString().c_str()); bool ret = false; // vector<CScriptDBOperLog> vAuthorLog; //todolist // if(IsSignatureAccount(vmAccount.get()->regID) || vmAccount.get()->regID == boost::get<CRegID>(tx->appRegId)) { ret = vmAccount.get()->OperateAccount((OperType)it.opeatortype, value, nCurHeight); } // else{ // ret = vmAccount.get()->OperateAccount((OperType)it.opeatortype, fund, *m_ScriptDBTip, vAuthorLog, height, &GetScriptRegID().GetVec6(), true); // } // LogPrint("vm", "after account:%s\r\n", vmAccount.get()->ToString().c_str()); if (!ret) { return false; } NewAccont.push_back(vmAccount); // m_dblog->insert(m_dblog->end(), vAuthorLog.begin(), vAuthorLog.end()); } return true; }
CKeyID CPubKey::GetID() const { return CKeyID(Hash160(vch, vch+size())); }
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int unit) { QString strHTML; { LOCK(wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx) + "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase()) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { // Offline transaction if (nNet > 0) { // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) { CTxDestination address = CKeyID(txout.pubKey); if (wallet->IsMine(txout.pubKey)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].name.empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "<br>"; } } break; } } } } // // To // if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) { // Online transaction std::string strAddress = wtx.mapValue["to"]; strHTML += "<b>" + tr("To") + ":</b> "; CTxDestination dest = CBitcoinAddress(strAddress).Get(); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; } // // Amount // if (nNet > 0) { // // Credit // strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nNet) + "<br>"; } else { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) fAllFromMe = fAllFromMe && wallet->IsMine(txin); bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) fAllToMe = fAllToMe && wallet->IsMine(txout); if (fAllFromMe) { // // Debit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) continue; if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty()) { // Offline transaction CTxDestination address = CKeyID(txout.pubKey); strHTML += "<b>" + tr("To") + ":</b> "; if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); strHTML += "<br>"; } strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -txout.nValue) + "<br>"; } if (fAllToMe) { // Payment to self strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nDebit) + "<br>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nCredit) + "<br>"; } uint64_t nTxFee = nDebit - wtx.GetValueOut(); if (nTxFee > 0) strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nTxFee) + "<br>"; } else { // // Mixed debit transaction // BOOST_FOREACH(const CTxIn& txin, wtx.vin) if (wallet->IsMine(txin)) strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetDebit(txin)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (wallet->IsMine(txout)) strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>"; } }
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion) { std::vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { if (keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_UNSOLVABLE; return ISMINE_NO; } CKeyID keyID; switch (whichType) { case TX_NONSTANDARD: case TX_NULL_DATA: break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) { isInvalid = true; return ISMINE_NO; } if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_WITNESS_V0_KEYHASH: { if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) { // We do not support bare witness outputs unless the P2SH version of it would be // acceptable as well. This protects against matching before segwit activates. // This also applies to the P2WSH case. break; } isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SIGVERSION_WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; break; } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (sigversion != SIGVERSION_BASE) { CPubKey pubkey; if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { isInvalid = true; return ISMINE_NO; } } if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: { CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript, isInvalid); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; } break; } case TX_WITNESS_V0_SCRIPTHASH: { if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) { break; } uint160 hash; CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin()); CScriptID scriptID = CScriptID(hash); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript, isInvalid, SIGVERSION_WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; } break; } case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the // keys involved. Multi-signature transactions that are // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); if (sigversion != SIGVERSION_BASE) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { isInvalid = true; return ISMINE_NO; } } } if (HaveKeys(keys, keystore) == keys.size()) return ISMINE_SPENDABLE; break; } } if (keystore.HaveWatchOnly(scriptPubKey)) { // TODO: This could be optimized some by doing some work after the above solver SignatureData sigs; return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, sigs) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE; } return ISMINE_NO; }