/** * Restore the UTXO in a Coin at a given COutPoint * @param undo The Coin to be restored. * @param view The coins view to which to apply the changes. * @param out The out point that corresponds to the tx input. * @return A DisconnectResult as an int */ int CViewManager::ApplyTxInUndo(Coin &&undo, CCoinsViewCache &view, const COutPoint &out) { bool fClean = true; if (view.HaveCoin(out)) fClean = false; // overwriting transaction output if (undo.nHeight == 0) { // Missing undo metadata (height and coinbase). Older versions included this // information only in undo records for the last spend of a transactions' // outputs. This implies that it must be present for some other output of the same tx. const Coin &alternate = AccessByTxid(view, out.hash); if (!alternate.IsSpent()) { undo.nHeight = alternate.nHeight; undo.fCoinBase = alternate.fCoinBase; } else { return DISCONNECT_FAILED; // adding output for transaction without known metadata } } // The potential_overwrite parameter to AddCoin is only allowed to be false if we know for // sure that the coin did not already exist in the cache. As we have queried for that above // using HaveCoin, we don't need to guess. When fClean is false, a coin already existed and // it is an overwrite. view.AddCoin(out, std::move(undo), !fClean); return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; }
// // Helper: create two dummy transactions, each with // two outputs. The first has 11 and 50 CENT outputs // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs // paid to a TX_PUBKEYHASH. // static std::vector<CMutableTransaction> SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) { std::vector<CMutableTransaction> dummyTransactions; dummyTransactions.resize(2); // Add some keys to the keystore: CKey key[4]; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(i % 2); keystoreRet.AddKey(key[i]); } // Create some dummy input transactions dummyTransactions[0].vout.resize(2); dummyTransactions[0].vout[0].nValue = 11*CENT; dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; dummyTransactions[0].vout[1].nValue = 50*CENT; dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0); dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); dummyTransactions[1].vout[1].nValue = 22*CENT; dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0); return dummyTransactions; }
void CNameTxUndo::apply (CCoinsViewCache& view) const { if (isNew) view.DeleteName (name); else view.SetName (name, oldData, true); }
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check) { bool fCoinbase = tx.IsCoinBase(); const uint256& txid = tx.GetHash(); for (size_t i = 0; i < tx.vout.size(); ++i) { bool overwrite = check ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase; // Always set the possible_overwrite flag to AddCoin for coinbase txn, in order to correctly // deal with the pre-BIP30 occurrences of duplicate coinbase transactions. cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite); } }
void NameIterationTester::remove (const std::string& n) { const valtype& name = ValtypeFromString (n); assert (data.count (name) == 1); data.erase (name); hybrid.DeleteName (name); cache.DeleteName (name); verify (); }
void NameIterationTester::update (const std::string& n) { const valtype& name = ValtypeFromString (n); const CNameData testData = getNextData (); assert (data.count (name) == 1); data[name] = testData; hybrid.SetName (name, testData, false); cache.SetName (name, testData, false); verify (); }
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out; std::vector<std::vector<unsigned char> > vSolutions; txnouttype whichType; // get the scriptPubKey corresponding to this input: const CScript& prevScript = prev.scriptPubKey; if (!Solver(prevScript, whichType, vSolutions)) return false; if (whichType == TX_SCRIPTHASH) { std::vector<std::vector<unsigned char> > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) return false; if (stack.empty()) return false; CScript subscript(stack.back().begin(), stack.back().end()); if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { return false; } } } return true; }
void NameIterationTester::verify () { verify (hybrid); hybrid.Flush (); verify (db); verify (cache); }
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); std::vector<std::vector<unsigned char> > vSolutions; txnouttype whichType; // get the scriptPubKey corresponding to this input: const CScript& prevScript = prev.scriptPubKey; if (!Solver(prevScript, whichType, vSolutions)) return false; int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); if (nArgsExpected < 0) return false; // Transactions with extra stuff in their scriptSigs are // non-standard. Note that this EvalScript() call will // be quick, because if there are any operations // beside "push data" in the scriptSig // IsStandardTx() will have already returned false // and this method isn't called. std::vector<std::vector<unsigned char> > stack; if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) return false; if (whichType == TX_SCRIPTHASH) { if (stack.empty()) return false; CScript subscript(stack.back().begin(), stack.back().end()); std::vector<std::vector<unsigned char> > vSolutions2; txnouttype whichType2; if (Solver(subscript, whichType2, vSolutions2)) { int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); if (tmpExpected < 0) return false; nArgsExpected += tmpExpected; } else { // Any other Script with less than 15 sigops OK: unsigned int sigops = subscript.GetSigOpCount(true); // ... extra data left on the stack after execution is OK, too: return (sigops <= MAX_P2SH_SIGOPS); } } if (stack.size() != (unsigned int)nArgsExpected) return false; } return true; }
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) { bool fCoinbase = tx.IsCoinBase(); const uint256& txid = tx.GetHash(); for (size_t i = 0; i < tx.vout.size(); ++i) { // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly // deal with the pre-BIP30 occurrances of duplicate coinbase transactions. cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase); } }
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false, strprintf("%s: inputs missing/spent", __func__)); } CAmount nValueIn = 0; for (unsigned int i = 0; i < tx.vin.size(); ++i) { const COutPoint &prevout = tx.vin[i].prevout; const Coin& coin = inputs.AccessCoin(prevout); assert(!coin.IsSpent()); // If prev is coinbase, check that it's matured if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) { return state.Invalid(false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight)); } // Check for negative or overflow input values nValueIn += coin.out.nValue; if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) { return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); } } const CAmount value_out = tx.GetValueOut(); if (nValueIn < value_out) { return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out))); } // Tally transaction fees const CAmount txfee_aux = nValueIn - value_out; if (!MoneyRange(txfee_aux)) { return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); } txfee = txfee_aux; return true; }
/** * Construct a dummy tx that provides the given script as input * for further tests in the given CCoinsView. The txid is returned * to refer to it. The "index" is always 0. The output's * value is always set to 1000 COIN, since it doesn't matter for * the tests we are interested in. * @param scr The script that should be provided as output. * @param nHeight The height of the coin. * @param view Add it to this view. * @return The txid. */ static uint256 addTestCoin (const CScript& scr, unsigned nHeight, CCoinsViewCache& view) { CMutableTransaction mtx; mtx.vout.push_back (CTxOut (1000 * COIN, scr)); const CTransaction tx(mtx); CCoinsModifier entry = view.ModifyCoins (tx.GetHash ()); *entry = CCoins (tx, nHeight); return tx.GetHash (); }
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { if (tx.IsCoinBase()) return true; // Coinbases are skipped for (unsigned int i = 0; i < tx.vin.size(); i++) { // We don't care if witness for this input is empty, since it must not be bloated. // If the script is invalid without witness, it would be caught sooner or later during validation. if (tx.vin[i].scriptWitness.IsNull()) continue; const CTxOut &prev = mapInputs.AccessCoin(tx.vin[i].prevout).out; // get the scriptPubKey corresponding to this input: CScript prevScript = prev.scriptPubKey; if (prevScript.IsPayToScriptHash()) { std::vector <std::vector<unsigned char> > stack; // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway. // If the check fails at this stage, we know that this txid must be a bad one. if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) return false; if (stack.empty()) return false; prevScript = CScript(stack.back().begin(), stack.back().end()); } int witnessversion = 0; std::vector<unsigned char> witnessprogram; // Non-witness program must not be associated with any witness if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram)) return false; // Check P2WSH standard limits if (witnessversion == 0 && witnessprogram.size() == 32) { if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return false; size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1; if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS) return false; for (unsigned int j = 0; j < sizeWitnessStack; j++) { if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE) return false; } } } return true; }
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */ bool CViewManager::ConnectBlock(const CBlock &block, const CBlockIndex *pIndex, CCoinsViewCache &viewCache) { for (const CTransactionRef &tx : block.vtx) { if (!tx->IsCoinBase()) { for (const CTxIn &txin : tx->vin) { viewCache.SpendCoin(txin.prevout); } } // Pass check = true as every addition may be an overwrite. AddCoins(viewCache, *tx, pIndex->nHeight, true); } return true; }
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) { if (tx.IsCoinBase()) return 0; unsigned int nSigOps = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) { const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout); assert(!coin.IsSpent()); const CTxOut &prevout = coin.out; if (prevout.scriptPubKey.IsPayToScriptHash()) nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); } return nSigOps; }
void CViewManager::UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) { // mark inputs spent if (!tx.IsCoinBase()) { txundo.vprevout.reserve(tx.vin.size()); for (const CTxIn &txin : tx.vin) { txundo.vprevout.emplace_back(); bool is_spent = inputs.SpendCoin(txin.prevout, &txundo.vprevout.back()); assert(is_spent); } } // add outputs AddCoins(inputs, tx, nHeight); }
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags) { int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR; if (tx.IsCoinBase()) return nSigOps; if (flags & SCRIPT_VERIFY_P2SH) { nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR; } for (unsigned int i = 0; i < tx.vin.size(); i++) { const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout); assert(!coin.IsSpent()); const CTxOut &prevout = coin.out; nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags); } return nSigOps; }
/** * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig * and witness such that spendingTx spends output zero of creationTx. * Also inserts creationTx's output into the coins view. */ void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CTxInWitness& witness) { creationTx.nVersion = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); creationTx.wit.vtxinwit.resize(1); creationTx.vout.resize(1); creationTx.vout[0].nValue = 1; creationTx.vout[0].scriptPubKey = scriptPubKey; spendingTx.nVersion = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetHash(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; spendingTx.wit.vtxinwit.resize(1); spendingTx.wit.vtxinwit[0] = witness; spendingTx.vout.resize(1); spendingTx.vout[0].nValue = 1; spendingTx.vout[0].scriptPubKey = CScript(); coins.ModifyCoins(creationTx.GetHash())->FromTx(creationTx, 0); }
void ApplyGameTransactions (const std::vector<CTransaction>& vGameTx, const StepResult& stepResult, unsigned nHeight, CValidationState& state, CCoinsViewCache& view, CBlockUndo& undo) { for (unsigned i = 0; i < vGameTx.size (); ++i) { undo.vtxundo.push_back (CTxUndo ()); UpdateCoins (vGameTx[i], state, view, undo.vtxundo.back (), nHeight); } /* Update name db for killed players. */ const PlayerSet& victims = stepResult.GetKilledPlayers (); if (!victims.empty ()) { assert (!vGameTx.empty ()); const CTransaction& txKills = vGameTx.front (); assert (txKills.vout.empty ()); assert (txKills.vin.size () == victims.size ()); BOOST_FOREACH(const PlayerID& name, victims) { const valtype& vchName = ValtypeFromString (name); LogPrint ("names", "Killing player at height %d: %s\n", nHeight, name.c_str ()); CNameTxUndo opUndo; opUndo.fromOldState (vchName, view); undo.vnameundo.push_back (opUndo); CNameData data; data.setDead (nHeight, txKills.GetHash ()); view.SetName (vchName, data, false); } }
bool MultisigDialog::createMultisigTransaction(vector<CTxIn> vUserIn, vector<CTxOut> vUserOut, string& feeStringRet, string& errorRet) { try{ //attempt to access the given inputs CCoinsViewCache view = getInputsCoinsViewCache(vUserIn); //retrieve total input val and change dest CAmount totalIn = 0; vector<CAmount> vInputVals; CScript changePubKey; bool fFirst = true; for(CTxIn in : vUserIn){ const CCoins* coins = view.AccessCoins(in.prevout.hash); if(!coins->IsAvailable(in.prevout.n) || coins == NULL){ continue; } CTxOut prevout = coins->vout[in.prevout.n]; CScript privKey = prevout.scriptPubKey; vInputVals.push_back(prevout.nValue); totalIn += prevout.nValue; if(!fFirst){ if(privKey != changePubKey){ throw runtime_error("Address mismatch! Inputs must originate from the same multisignature address."); } }else{ fFirst = false; changePubKey = privKey; } } CAmount totalOut = 0; //retrieve total output val for(CTxOut out : vUserOut){ totalOut += out.nValue; } if(totalIn < totalOut){ throw runtime_error("Not enough PIV provided as input to complete transaction (including fee)."); } //calculate change amount CAmount changeAmount = totalIn - totalOut; CTxOut change(changeAmount, changePubKey); //generate random position for change unsigned int changeIndex = rand() % (vUserOut.size() + 1); //insert change into random position if(changeIndex < vUserOut.size()){ vUserOut.insert(vUserOut.begin() + changeIndex, change); }else{ vUserOut.emplace_back(change); } //populate tx CMutableTransaction tx; tx.vin = vUserIn; tx.vout = vUserOut; const CCoins* coins = view.AccessCoins(tx.vin[0].prevout.hash); if(coins == NULL || !coins->IsAvailable(tx.vin[0].prevout.n)){ throw runtime_error("Coins unavailable (unconfirmed/spent)"); } CScript prevPubKey = coins->vout[tx.vin[0].prevout.n].scriptPubKey; //get payment destination CTxDestination address; if(!ExtractDestination(prevPubKey, address)){ throw runtime_error("Could not find address for destination."); } CScriptID hash = boost::get<CScriptID>(address); CScript redeemScript; if (!pwalletMain->GetCScript(hash, redeemScript)){ throw runtime_error("could not redeem"); } txnouttype type; vector<CTxDestination> addresses; int nReq; if(!ExtractDestinations(redeemScript, type, addresses, nReq)){ throw runtime_error("Could not extract destinations from redeem script."); } for(CTxIn& in : tx.vin){ in.scriptSig.clear(); //scale estimate to account for multisig scriptSig for(unsigned int i = 0; i < 50*(nReq+addresses.size()); i++){ in.scriptSig << INT64_MAX; } } //calculate fee unsigned int nBytes = tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); CAmount fee = ::minRelayTxFee.GetFee(nBytes); if(tx.vout.at(changeIndex).nValue > fee){ tx.vout.at(changeIndex).nValue -= fee; feeStringRet = strprintf("%d",((double)fee)/COIN).c_str(); }else{ throw runtime_error("Not enough PIV provided to cover fee"); } //clear junk from script sigs for(CTxIn& in : tx.vin){ in.scriptSig.clear(); } multisigTx = tx; }catch(const runtime_error& e){ errorRet = e.what(); return false; } return true; }
/** Undo the effects of this block (with given index) on the UTXO set represented by coins. * When FAILED is returned, view is left in an indeterminate state. */ DisconnectResult CViewManager::DisconnectBlock(const CBlock &block, const CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean) { if (pfClean) *pfClean = false; bool fClean = true; CBlockUndo blockUndo; CDiskBlockPos pos = pindex->GetUndoPos(); if (pos.IsNull()) { ELogFormat("no undo data available"); return DISCONNECT_FAILED; } if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) { ELogFormat("failure reading undo data"); return DISCONNECT_FAILED; } if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { ELogFormat("block and undo data inconsistent"); return DISCONNECT_FAILED; } // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = *(block.vtx[i]); uint256 hash = tx.GetHash(); bool is_coinbase = tx.IsCoinBase(); // Check that all outputs are available and match the outputs in the block itself // exactly. for (size_t o = 0; o < tx.vout.size(); o++) { if (!tx.vout[o].scriptPubKey.IsUnspendable()) { COutPoint out(hash, o); Coin coin; bool is_spent = view.SpendCoin(out, &coin); if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { fClean = false; // transaction output mismatch } } } // restore inputs if (i > 0) { // not coinbases if(tx.IsCoinBase2()){ continue; //continue } CTxUndo &txundo = blockUndo.vtxundo[i - 1]; if (txundo.vprevout.size() != tx.vin.size()) { ELogFormat("transaction and undo data inconsistent"); return DISCONNECT_FAILED; } for (unsigned int j = tx.vin.size(); j-- > 0;) { const COutPoint &out = tx.vin[j].prevout; int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; fClean = fClean && res != DISCONNECT_UNCLEAN; } // At this point, all of txundo.vprevout should have been moved out. } } // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); //sbtc-vm GET_CONTRACT_INTERFACE(ifContractObj); uint256 hashStateRoot; uint256 hashUTXORoot; CBlock prevblock; if (!ReadBlockFromDisk(prevblock, pindex->pprev, Params().GetConsensus())) { //TODO LogError rLogError("ReadBlockFromDisk failed at %d, hash=%s", pindex->pprev->nHeight, pindex->pprev->GetBlockHash().ToString()); } else { if(prevblock.GetVMState(hashStateRoot, hashUTXORoot) == RET_VM_STATE_ERR) { ILogFormat("GetVMState err"); } } ifContractObj->UpdateState(hashStateRoot, hashUTXORoot); // ifContractObj->UpdateState(pindex->pprev->hashStateRoot, pindex->pprev->hashUTXORoot); GET_CHAIN_INTERFACE(ifChainObj); if (pfClean == NULL && ifChainObj->IsLogEvents()) { ifContractObj->DeleteResults(block.vtx); ifChainObj->GetBlockTreeDB()->EraseHeightIndex(pindex->nHeight); } return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; }