From ae812cf4aa17eb48d750018339c0c6d9abc96e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 15 May 2015 01:04:58 +0200 Subject: [PATCH 01/19] 0.10-only: Assets: base_uint<>::IsNull() and base_uint<>::SetNull() --- src/uint256.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/uint256.h b/src/uint256.h index 56f7f44a16..c32a673a97 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -29,8 +29,7 @@ class base_uint base_uint() { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; + SetNull(); } base_uint(const base_uint& b) @@ -57,6 +56,20 @@ class base_uint explicit base_uint(const std::string& str); explicit base_uint(const std::vector& vch); + bool IsNull() const + { + for (int i = 0; i < WIDTH; i++) + if (pn[i] != 0) + return false; + return true; + } + + void SetNull() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + bool operator!() const { for (int i = 0; i < WIDTH; i++) From 4e411b43752bb1d4d0e6777d2476a629b7710818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 11 Mar 2016 19:16:59 +0100 Subject: [PATCH 02/19] Chainparams: Don't check the genesis block, but store its transactions asvalid (HF for bitcoin) - Like in #6597 (bitcoin), the genesis block shouldn't be checked because it is a consensus rule in itself - On the other hand, some elements like deterministic peg (because the 21M reserve of pegged-coins needs to be created at some point) and multi-assets (because one cannot define new assets without existing utxos to be used as input for the asset definition transactions) --- src/main.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c3c0dd8cd0..ccfa77f56e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1784,6 +1784,24 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck, vector *pvProofTxn) { AssertLockHeld(cs_main); + + CTxUndo undoDummy; + CBlockUndo blockundo; + blockundo.vtxundo.reserve(block.vtx.size() - 1); + + // Special case for the genesis block: it is valid by definition + // but we must connect its transactions (for 2wp and genesis asset) + if (block.GetHash() == Params().HashGenesisBlock()) { + view.SetBestBlock(pindex->GetBlockHash()); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + const CTransaction &tx = block.vtx[i]; + // TODO Refactor: decouple UpdateCoins() from undo stuff: + // genesis transactions will never be rolled back by defintion + UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); + } + return true; + } + // Check it again in case a previous version let a bad block in if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; @@ -1792,13 +1810,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin uint256 hashPrevBlock = pindex->pprev == NULL ? uint256(0) : pindex->pprev->GetBlockHash(); assert(hashPrevBlock == view.GetBestBlock()); - // Special case for the genesis block, skipping connection of its transactions - // (its coinbase is unspendable) - /*if (block.GetHash() == Params().HashGenesisBlock()) { - view.SetBestBlock(pindex->GetBlockHash()); - return true; - }*/ - bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(); // Do not allow blocks that contain transactions which 'overwrite' older transactions, @@ -1841,8 +1852,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; - CBlockUndo blockundo; - CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); int64_t nTimeStart = GetTimeMicros(); @@ -1852,7 +1861,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector > vPos; vPos.reserve(block.vtx.size()); - blockundo.vtxundo.reserve(block.vtx.size() - 1); for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; @@ -1992,7 +2000,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } - CTxUndo undoDummy; if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); } From 5d6d4beed7eb85cde46fd8312d5de8e1f6f4ef0d Mon Sep 17 00:00:00 2001 From: jtimon Date: Tue, 2 Dec 2014 21:52:32 +0100 Subject: [PATCH 03/19] Assets: Introduce bool CTransaction::IsAssetDefinition() --- src/primitives/transaction.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 4cc9d7db3b..a54af3ad58 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -312,6 +312,12 @@ class CTransaction return (vin.size() == 1 && vin[0].prevout.IsNull()); } + //! Asset definition transactions must have more than 1 input + bool IsAssetDefinition() const + { + return (vin.size() > 1 && vin[0].prevout.IsNull()); + } + friend bool operator==(const CTransaction& a, const CTransaction& b) { return a.hash == b.hash; From ddc38c27b8c00dc01a4ab7d6085ec31b145400d1 Mon Sep 17 00:00:00 2001 From: GreenAddress Date: Mon, 14 Mar 2016 18:11:47 +0000 Subject: [PATCH 04/19] Assets: Adapt input loops to asset definition transactions --- src/bloom.cpp | 2 +- src/coins.cpp | 13 ++++++++----- src/core_write.cpp | 2 +- src/main.cpp | 36 +++++++++++++++++++----------------- src/miner.cpp | 2 +- src/primitives/transaction.h | 12 ++++++++++++ src/qt/transactiondesc.cpp | 8 ++++---- src/qt/transactionrecord.cpp | 2 +- src/rpcblockchain.cpp | 2 +- src/txmempool.cpp | 10 +++++----- src/wallet.cpp | 8 ++++---- src/wallet.h | 4 ++-- 12 files changed, 59 insertions(+), 42 deletions(-) diff --git a/src/bloom.cpp b/src/bloom.cpp index da30e6f355..6268eeb767 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -163,7 +163,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) if (fFound) return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { // Match if the filter contains an outpoint tx spends if (contains(txin.prevout)) diff --git a/src/coins.cpp b/src/coins.cpp index daeb6b6a1b..b7c8866661 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -265,9 +265,11 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces unsigned char *p = vchData.data(); if (!tx.IsCoinBase()) { - for (size_t i = 0; i < tx.vin.size(); ++i) + // The first input is null for asset definition transactions + FOREACH_TXIN(txin, tx) { - const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue; + const CTxOut& txOut = GetOutputFor(txin); + const CTxOutValue& val = txOut.nValue; if (val.IsAmount()) nPlainAmount -= val.GetAmount(); else @@ -331,8 +333,9 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { if (!tx.IsCoinBase()) { - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; + // Don't check the null input in asset defintion transactions + FOREACH_TXIN(txin, tx) { + const COutPoint &prevout = txin.prevout; const CCoins* coins = AccessCoins(prevout.hash); if (!coins || !coins->IsAvailable(prevout.n)) { return false; @@ -347,7 +350,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const if (tx.IsCoinBase()) return 0.0; double dResult = 0.0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { const CCoins* coins = AccessCoins(txin.prevout.hash); assert(coins); diff --git a/src/core_write.cpp b/src/core_write.cpp index c3982dfa00..73b632d8c9 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -100,7 +100,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); diff --git a/src/main.cpp b/src/main.cpp index ccfa77f56e..d0938660f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -574,7 +574,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) mapOrphanTransactions[hash].tx = tx; mapOrphanTransactions[hash].fromPeer = peer; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), @@ -587,7 +587,7 @@ void static EraseOrphanTx(uint256 hash) map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return; - BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) + FOREACH_TXIN(txin, it->second.tx) { map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); if (itPrev == mapOrphanTransactionsByPrev.end()) @@ -666,7 +666,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (!txin.scriptSig.IsPushOnly()) { reason = "scriptsig-not-pushonly"; @@ -717,7 +717,7 @@ int64_t LockTime(const CTransaction &tx, int flags, const CCoinsView* pCoinsView // Will remain equal to true if all inputs are finalized (MAX_INT). bool fFinalized = true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { // The relative lock-time is the inverted sequence number so // as to preserve the semantics MAX_INT means an input is // finalized (0 relative lock-time). @@ -895,7 +895,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { nSigOps += txin.scriptSig.GetSigOpCount(false); } @@ -912,11 +912,11 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in return 0; unsigned int nSigOps = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) + FOREACH_TXIN(txin, tx) { - const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); + const CTxOut &prevout = inputs.GetOutputFor(txin); if (prevout.scriptPubKey.IsPayToScriptHash()) - nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); + nSigOps += prevout.scriptPubKey.GetSigOpCount(txin.scriptSig); } return nSigOps; } @@ -967,7 +967,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) // Check for duplicate inputs set vInOutPoints; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (vInOutPoints.count(txin.prevout)) return state.DoS(100, error("CheckTransaction() : duplicate inputs"), @@ -983,9 +983,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) } else { - BOOST_FOREACH(const CTxIn& txin, tx.vin) + // The first input is null for asset definition transactions + FOREACH_TXIN(txin, tx) if (txin.prevout.IsNull()) - return state.DoS(10, error("CheckTransaction() : prevout is null"), + return state.DoS(10, error("CheckTransaction(): prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1080,8 +1081,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). - BOOST_FOREACH(const CTxIn txin, tx.vin) { - if (!view.HaveCoins(txin.prevout.hash)) { + // Don't check the null input in asset defintion transactions + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { + if (!view.HaveCoins(tx.vin[i].prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; return false; @@ -1517,7 +1519,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach // mark inputs spent if (!tx.IsCoinBase()) { txundo.vprevout.reserve(tx.vin.size()); - for (unsigned int i = 0; i < tx.vin.size(); i++) { + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { const CTxIn &txin = tx.vin[i]; txundo.vprevout.push_back(CTxInUndo()); CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); @@ -1561,9 +1563,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // This is also true for mempool checks. CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; int nSpendHeight = pindexPrev->nHeight + 1; - for (unsigned int i = 0; i < tx.vin.size(); i++) + FOREACH_TXIN(txin, tx) { - const COutPoint &prevout = tx.vin[i].prevout; + const COutPoint &prevout = txin.prevout; const CCoins *coins = inputs.AccessCoins(prevout.hash); assert(coins); @@ -1599,7 +1601,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // still computed and checked, and any change will be caught at the next checkpoint. if (fScriptChecks) { CTxOutValue prevValueIn = -1; - for (unsigned int i = 0; i < tx.vin.size(); i++) { + for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; const CCoins* coins = inputs.AccessCoins(prevout.hash); assert(coins); diff --git a/src/miner.cpp b/src/miner.cpp index 5f90d37bdd..592d3a0b74 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -181,7 +181,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) COrphan* porphan = NULL; bool fMissingInputs = false; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index a54af3ad58..61c577db8a 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -318,6 +318,11 @@ class CTransaction return (vin.size() > 1 && vin[0].prevout.IsNull()); } + unsigned int GetFirstInputPos() const + { + return IsAssetDefinition() ? 1 : 0; + } + friend bool operator==(const CTransaction& a, const CTransaction& b) { return a.hash == b.hash; @@ -370,4 +375,11 @@ struct CMutableTransaction uint256 GetHash() const; }; +#define FOREACH_TXIN(VAR, TX) \ + for (unsigned int __txin_i = (TX).GetFirstInputPos(); \ + __txin_i < (TX).vin.size(); \ + ++__txin_i) \ + if (bool __txin_finish = false) {} else \ + for (const CTxIn& VAR = (TX).vin[__txin_i]; !__txin_finish; __txin_finish = true) + #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 9abc7988ef..d60248dd41 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -151,7 +151,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco else { isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { isminetype mine = wallet->IsMine(txin); if(fAllFromMe > mine) fAllFromMe = mine; @@ -220,7 +220,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Mixed debit transaction // - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; for (unsigned int i = 0; i < wtx.vout.size(); i++) @@ -273,7 +273,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (fDebug) { strHTML += "

" + tr("Debug information") + "

"; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) if(wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; for (unsigned int i = 0; i < wtx.vout.size(); i++) @@ -286,7 +286,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { COutPoint prevout = txin.prevout; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 2cc35ff422..5ff77065c4 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -80,7 +80,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { isminetype mine = wallet->IsMine(txin); if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 2230ba5ccd..a06afa8fab 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -178,7 +178,7 @@ Value getrawmempool(const Array& params, bool fHelp) info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); const CTransaction& tx = e.GetTx(); set setDepends; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 51de5e3eb7..7edc06fbd1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -476,7 +476,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txToRemove.push_back(it->second.ptx->GetHash()); } } - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) mapNextTx.erase(txin.prevout); removed.push_back(tx); @@ -494,7 +494,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in list transactionsToRemove; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->second.GetTx(); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + FOREACH_TXIN(txin, tx) { std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; @@ -517,7 +517,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list // Remove transactions which depend on inputs of tx, recursively list result; LOCK(cs); - BOOST_FOREACH(const CTxIn &txin, tx.vin) { + FOREACH_TXIN(txin, tx) { std::map::iterator it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { const CTransaction &txConflict = *it->second.ptx; @@ -577,11 +577,11 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const LOCK(cs); list waitingOnDependants; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - unsigned int i = 0; checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); + unsigned int i = tx.GetFirstInputPos(); bool fDependsWait = false; - BOOST_FOREACH(const CTxIn &txin, tx.vin) { + FOREACH_TXIN(txin, tx) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) { diff --git a/src/wallet.cpp b/src/wallet.cpp index e8e0fd5717..e6aaccdbba 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -333,7 +333,7 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; - BOOST_FOREACH(const CTxIn& txin, wtx.vin) + FOREACH_TXIN(txin, wtx) { if (mapTxSpends.count(txin.prevout) <= 1) continue; // No conflict if zero or one spends @@ -417,7 +417,7 @@ void CWallet::AddToSpends(const uint256& wtxid) if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; - BOOST_FOREACH(const CTxIn& txin, thisTx.vin) + FOREACH_TXIN(txin, thisTx) AddToSpends(txin.prevout, wtxid); } @@ -712,7 +712,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be // recomputed, also: - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); @@ -1756,7 +1756,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // Notify that old coins are spent set setCoins; - BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) + FOREACH_TXIN(txin, wtxNew) { CWalletTx &coin = mapWallet[txin.prevout.hash]; coin.BindWallet(this); diff --git a/src/wallet.h b/src/wallet.h index 1a3758126e..e393cd4ddd 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -363,7 +363,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const { CAmount nDebit = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) + FOREACH_TXIN(txin, tx) { nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) @@ -922,7 +922,7 @@ class CWalletTx : public CMerkleTx return false; // Trusted if all inputs are from us and are in the mempool: - BOOST_FOREACH(const CTxIn& txin, vin) + FOREACH_TXIN(txin, *this) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); From 23186f298ea82f7d4f63896fd54ca5611447645d Mon Sep 17 00:00:00 2001 From: jtimon Date: Wed, 14 Jan 2015 21:16:07 +0100 Subject: [PATCH 05/19] Assets: Introduce CAssetID, CAmountMap and +=, -=, < operators --- src/primitives/transaction.cpp | 27 +++++++++++++++++++++++++++ src/primitives/transaction.h | 17 +++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 58e432a6b8..a6b8e06a4f 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -87,6 +87,33 @@ bool operator!=(const CTxOutValue& a, const CTxOutValue& b) { return !(a == b); } +bool operator<(const CAmountMap& a, const CAmountMap& b) +{ + for(std::map::const_iterator it = b.begin(); it != b.end(); ++it) { + if (a.count(it->first) == 0 || a.find(it->first)->second < it->second) + return true; + } + return false; +} + +CAmountMap& operator+=(CAmountMap& a, const CAmountMap& b) +{ + for(std::map::const_iterator it = b.begin(); it != b.end(); ++it) + a[it->first] += it->second; + return a; +} + +CAmountMap& operator-=(CAmountMap& a, const CAmountMap& b) +{ + for(std::map::const_iterator it = b.begin(); it != b.end(); ++it) { + if (a.count(it->first) > 0) + a[it->first] -= it->second; + else + throw std::runtime_error(strprintf("%s : asset %s is not contained in this map", __func__, it->first.ToString())); + } + return a; +} + std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 61c577db8a..1df69ec4f6 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -155,6 +155,23 @@ class CTxIn std::string ToString() const; }; +/** + * Native Asset Issuance + * + * An asset identifier tag, a 256 bits serialized hash (sha256) of the asset + * definition transaction from which the output’s coins are derived. Each output contains + * coins from a single asset/currency. For the host currency, the similarly-calculated + * hash of the chain’s genesis block is used instead. Within an asset + * definition transaction, the asset being defined is identified with 0 as a hash. + */ +typedef uint256 CAssetID; + +typedef std::map CAmountMap; + +bool operator<(const CAmountMap& a, const CAmountMap& b); +CAmountMap& operator+=(CAmountMap& a, const CAmountMap& b); +CAmountMap& operator-=(CAmountMap& a, const CAmountMap& b); + /** An output of a transaction. It contains the public key that the next input * must be able to sign with to claim it. */ From 635b6293a5eac78e518fe23bd489258fa24e6c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Mon, 18 May 2015 01:32:59 +0200 Subject: [PATCH 06/19] Assets: Introduce -feeasset policy arg --- src/Makefile.am | 2 ++ src/init.cpp | 8 ++++++++ src/policy/fees.cpp | 10 ++++++++++ src/policy/fees.h | 13 +++++++++++++ 4 files changed, 33 insertions(+) create mode 100644 src/policy/fees.cpp create mode 100644 src/policy/fees.h diff --git a/src/Makefile.am b/src/Makefile.am index 9546f8e079..94481d99f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,6 +110,7 @@ BITCOIN_CORE_H = \ netbase.h \ net.h \ noui.h \ + policy/fees.h \ pow.h \ protocol.h \ pubkey.h \ @@ -176,6 +177,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ noui.cpp \ + policy/fees.cpp \ rest.cpp \ rpcblockchain.cpp \ rpcmining.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 0f9d80a6cb..e6ffcc2ce9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -18,6 +18,7 @@ #include "main.h" #include "miner.h" #include "net.h" +#include "policy/fees.h" #include "pubkey.h" #include "rpcserver.h" #include "script/standard.h" @@ -73,6 +74,11 @@ enum BindFlags { static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; CClientUIInterface uiInterface; +inline std::string DefaultFeeAssetIdStr() +{ + return CAssetID(Params().HashGenesisBlock()).GetHex(); +} + ////////////////////////////////////////////////////////////////////////////// // // Shutdown @@ -358,6 +364,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -maxsigcachesize= " + strprintf(_("Limit size of signature cache to entries (default: %u)"), 50000) + "\n"; } strUsage += " -minrelaytxfee= " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n"; + strUsage += " -feeasset " + strprintf(_("Asset id (in hex) used to compute fees in policy decisions (default: %u)"), DefaultFeeAssetIdStr()) + "\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; if (GetBoolArg("-help-debug", false)) { @@ -708,6 +715,7 @@ bool AppInit2(boost::thread_group& threadGroup) else return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), mapArgs["-minrelaytxfee"])); } + feeAssetID = uint256(GetArg("-feeasset", DefaultFeeAssetIdStr())); #ifdef ENABLE_WALLET if (mapArgs.count("-mintxfee")) diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp new file mode 100644 index 0000000000..5a6f172720 --- /dev/null +++ b/src/policy/fees.cpp @@ -0,0 +1,10 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "policy/fees.h" + +#include "uint256.h" + +uint256 feeAssetID; diff --git a/src/policy/fees.h b/src/policy/fees.h new file mode 100644 index 0000000000..ae19f34c57 --- /dev/null +++ b/src/policy/fees.h @@ -0,0 +1,13 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_POLICY_FEES_H +#define BITCOIN_POLICY_FEES_H + +class uint256; + +extern uint256 feeAssetID; + +#endif // BITCOIN_POLICY_FEES_H From 354383491da7b6a0d4f521783ab1f5f6eae52e85 Mon Sep 17 00:00:00 2001 From: jtimon Date: Sun, 30 Nov 2014 21:27:51 +0100 Subject: [PATCH 07/19] HF Assets: Introduce assetID field in CTxOut --- src/primitives/transaction.cpp | 7 +++---- src/primitives/transaction.h | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index a6b8e06a4f..8ca33f6b55 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -148,15 +148,14 @@ std::string CTxIn::ToString() const return str; } -CTxOut::CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn) +CTxOut::CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn, CAssetID assetIDIn) + : nValue(valueIn), assetID(assetIDIn), scriptPubKey(scriptPubKeyIn) { - nValue = valueIn; - scriptPubKey = scriptPubKeyIn; } std::string CTxOut::ToString() const { - return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), scriptPubKey.ToString().substr(0,30)); + return strprintf("CTxOut(nValue=%s, assetID=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), assetID.ToString(), scriptPubKey.ToString().substr(0,30)); } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTxFee(0), nLockTime(0) {} diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1df69ec4f6..c5837f6453 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -179,6 +179,7 @@ class CTxOut { public: CTxOutValue nValue; + CAssetID assetID; CScript scriptPubKey; CTxOut() @@ -186,19 +187,21 @@ class CTxOut SetNull(); } - CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn); + CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn, CAssetID assetID=CAssetID()); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(nValue); + READWRITE(assetID); READWRITE(scriptPubKey); } void SetNull() { nValue = CTxOutValue(); + assetID.SetNull(); scriptPubKey.clear(); } @@ -227,6 +230,7 @@ class CTxOut friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && + a.assetID == b.assetID && a.scriptPubKey == b.scriptPubKey); } From f406c0356882253fcd02f8f660088d5bf6da7d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 22 Mar 2016 00:34:18 +0100 Subject: [PATCH 08/19] HF Assets: primitives/transaction: post-CT: Explicit multi-asset fees Fix CTransaction::GetFee() + Introduce CMutableTransaction::SetFeesFromTxRewardMap --- src/primitives/transaction.cpp | 50 +++++++++++++++++++++++++++++----- src/primitives/transaction.h | 17 +++++++++--- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 8ca33f6b55..39d37813d0 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -158,8 +158,8 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%s, assetID=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), assetID.ToString(), scriptPubKey.ToString().substr(0,30)); } -CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTxFee(0), nLockTime(0) {} -CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) {} +CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), vTxFees(std::vector()), nLockTime(0) {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vTxFees(tx.vTxFees), vout(tx.vout), nLockTime(tx.nLockTime) {} uint256 CMutableTransaction::GetHash() const { @@ -192,15 +192,15 @@ void CTransaction::UpdateHash() const hasher.Finalize((unsigned char*)&hashFull); } -CTransaction::CTransaction() : hash(0), hashFull(0), nVersion(CTransaction::CURRENT_VERSION), vin(), nTxFee(0), vout(), nLockTime(0) { } +CTransaction::CTransaction() : hash(0), hashFull(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vTxFees(std::vector()), vout(), nLockTime(0) { } -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), nTxFee(tx.nTxFee), vout(tx.vout), nLockTime(tx.nLockTime) { +CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vTxFees(tx.vTxFees), vout(tx.vout), nLockTime(tx.nLockTime) { UpdateHash(); } CTransaction& CTransaction::operator=(const CTransaction &tx) { *const_cast(&nVersion) = tx.nVersion; - *const_cast(&nTxFee) = tx.nTxFee; + *const_cast*>(&vTxFees) = tx.vTxFees; *const_cast*>(&vin) = tx.vin; *const_cast*>(&vout) = tx.vout; *const_cast(&nLockTime) = tx.nLockTime; @@ -217,6 +217,42 @@ double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSiz return dPriorityInputs / nTxSize; } +CAmountMap CTransaction::GetTxRewardMap() const +{ + assert(vTxFees.size() <= vout.size()); + CAmountMap mTxReward; + for (unsigned i = 0; i < vTxFees.size(); ++i) + if (vout[i].assetID != 0) + mTxReward[vout[i].assetID] += vTxFees[i]; + return mTxReward; +} + +void CMutableTransaction::SetFeesFromTxRewardMap(const CAmountMap& mTxReward) +{ + assert(mTxReward.size() <= vout.size()); + vTxFees.resize(mTxReward.size()); + for(CAmountMap::const_iterator it = mTxReward.begin(); it != mTxReward.end(); ++it) { + bool fFoundAsset = false; + for (unsigned i = 0; i < vout.size(); ++i) { + if (vout[i].assetID == it->first) { + vTxFees[i] = it->second; + fFoundAsset = true; + break; + } + } + if (!fFoundAsset) + assert(false && "CMutableTransaction::SetFeesFromTxRewardMap: Trying to pay fees without output."); + } +} + +CAmount CTransaction::GetFee(const CAssetID& assetID) const +{ + const CAmountMap mTxReward = GetTxRewardMap(); + if (!mTxReward.count(assetID)) + return 0; + return mTxReward.find(assetID)->second; +} + unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const { // In order to avoid disincentivizing cleaning up the UTXO set we don't count @@ -238,12 +274,12 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u, fee=%u)\n", + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u, vTxFees.size=%u)\n", GetHash().ToString().substr(0,10), nVersion, vin.size(), vout.size(), - nLockTime, nTxFee); + nLockTime, vTxFees.size()); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index c5837f6453..86340a3909 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -267,7 +267,7 @@ class CTransaction // structure, including the hash. const int32_t nVersion; const std::vector vin; - const CAmount nTxFee; + const std::vector vTxFees; const std::vector vout; const uint32_t nLockTime; @@ -290,7 +290,7 @@ class CTransaction assert((nType != SER_GETHASH && !fOnlyWitness && fWitness) || nType == SER_GETHASH); if (!fOnlyWitness) READWRITE(*const_cast(&this->nVersion)); READWRITE(*const_cast*>(&vin)); - if (!fBitcoinTx && !fOnlyWitness) READWRITE(*const_cast(&nTxFee)); + if (!fBitcoinTx && !fOnlyWitness) READWRITE(*const_cast*>(&vTxFees)); if (!fOnlyWitness) READWRITE(*const_cast*>(&vout)); if (!fOnlyWitness) READWRITE(*const_cast(&nLockTime)); if (ser_action.ForRead()) @@ -324,6 +324,11 @@ class CTransaction // Compute priority, given priority of inputs and (optionally) tx size double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; + /** + * @return a CAmountMap with total fees per asset. + */ + CAmountMap GetTxRewardMap() const; + CAmount GetFee(const CAssetID& assetID) const; // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; @@ -362,7 +367,7 @@ struct CMutableTransaction { int32_t nVersion; std::vector vin; - CAmount nTxFee; + std::vector vTxFees; std::vector vout; uint32_t nLockTime; @@ -380,7 +385,7 @@ struct CMutableTransaction assert((nType != SER_GETHASH && !fOnlyWitness && fWitness) || nType == SER_GETHASH); if (!fOnlyWitness) READWRITE(this->nVersion); READWRITE(vin); - if (!fOnlyWitness) READWRITE(nTxFee); + if (!fOnlyWitness) READWRITE(vTxFees); if (!fOnlyWitness) READWRITE(vout); if (!fOnlyWitness) READWRITE(nLockTime); } @@ -394,6 +399,10 @@ struct CMutableTransaction * fly, as opposed to GetHash() in CTransaction, which uses a cached result. */ uint256 GetHash() const; + /** + * Sets the vTxFees to the cannonical representation provided + */ + void SetFeesFromTxRewardMap(const CAmountMap& mTxReward); }; #define FOREACH_TXIN(VAR, TX) \ From ba04aed9d9d0ab22f09ae10da66b02c5cfd9da62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Mon, 1 Jun 2015 17:06:56 +0200 Subject: [PATCH 09/19] HF Assets: coins.cpp: Adapt CCoinsViewCache::VerifyAmounts and CCoins::FromTx() Assets: Adapt CCoins::FromTx() to Asset definition transactions jerzy Assets: coins.cpp fix for txs spending genesis tx --- src/coins.cpp | 67 +++++++++++++++++++++++++++++++++++++++------------ src/coins.h | 14 ++++++++--- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index b7c8866661..27192e0d3d 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -4,6 +4,7 @@ #include "coins.h" +#include "chainparams.h" #include "random.h" #include @@ -255,11 +256,11 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const extern secp256k1_context* secp256k1_bitcoin_verify_context; -bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& excess) const +bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmountMap& mTxReward) const { - CAmount nPlainAmount = excess; + CAmountMap nPlainAmounts = mTxReward; std::vector vchData; - std::vector vpchCommitsIn, vpchCommitsOut; + std::map > vpchCommitsInMap, vpchCommitsOutMap; bool fNullRangeproof = false; vchData.resize(CTxOutValue::nCommitmentSize * (tx.vin.size() + tx.vout.size())); unsigned char *p = vchData.data(); @@ -270,29 +271,45 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces { const CTxOut& txOut = GetOutputFor(txin); const CTxOutValue& val = txOut.nValue; + CAssetID assetID; + if (txOut.assetID.IsNull()) { + bool isPrevGenesis = false; + for (unsigned int j = 0; j < Params().GenesisBlock().vtx.size(); ++j) { + if (Params().GenesisBlock().vtx[j].GetHash() == txin.prevout.hash) + isPrevGenesis = true; + } + assetID = isPrevGenesis ? Params().HashGenesisBlock() : CAssetID(txin.prevout.hash); + } + else + assetID = txOut.assetID; if (val.IsAmount()) - nPlainAmount -= val.GetAmount(); + nPlainAmounts[assetID] -= val.GetAmount(); else { + // Touch the asset ID in the map to later iterate + nPlainAmounts[assetID] += 0; assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize); memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); - vpchCommitsIn.push_back(p); + vpchCommitsInMap[assetID].push_back(p); p += CTxOutValue::nCommitmentSize; } } } for (size_t i = 0; i < tx.vout.size(); ++i) { - const CTxOutValue& val = tx.vout[i].nValue; + const CTxOut& txOut = tx.vout[i]; + const CTxOutValue& val = txOut.nValue; assert(val.vchCommitment.size() == CTxOutValue::nCommitmentSize); if (val.vchNonceCommitment.size() > CTxOutValue::nCommitmentSize || val.vchRangeproof.size() > 5000) return false; if (val.IsAmount()) - nPlainAmount += val.GetAmount(); + nPlainAmounts[txOut.assetID] += val.GetAmount(); else { + // Touch the asset ID in the map to later iterate + nPlainAmounts[txOut.assetID] += 0; memcpy(p, &val.vchCommitment[0], CTxOutValue::nCommitmentSize); - vpchCommitsOut.push_back(p); + vpchCommitsOutMap[txOut.assetID].push_back(p); p += CTxOutValue::nCommitmentSize; if (val.vchRangeproof.empty()) @@ -300,17 +317,33 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces } } + for(std::map::const_iterator it = nPlainAmounts.begin(); it != nPlainAmounts.end(); ++it) { + const CAssetID& assetID = it->first; + const CAmount& nPlainAmount = nPlainAmounts[assetID]; + std::vector& vpchCommitsIn = vpchCommitsInMap[assetID]; + std::vector& vpchCommitsOut = vpchCommitsOutMap[assetID]; // If there are no encrypted input or output values, we can do simple math - if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0) - return (nPlainAmount == 0); + if (vpchCommitsIn.size() + vpchCommitsOut.size() == 0) { + // Within an asset definition transaction, the asset being defined is identified with a 0 + if (assetID.IsNull()) { + // Only asset definitions can have null asset IDs in outputs + if (!tx.IsAssetDefinition()) + return false; + // Cannot issue negative amounts + if (nPlainAmount < 0) + return false; + } else if (nPlainAmount != 0) + return false; + } else { + // Newly issued assets cannot be confidential + if (assetID.IsNull()) + return false; if (!secp256k1_pedersen_verify_tally(secp256k1_bitcoin_verify_context, vpchCommitsIn.data(), vpchCommitsIn.size(), vpchCommitsOut.data(), vpchCommitsOut.size(), nPlainAmount)) return false; - // Rangeproof is optional in this case - if ((!vpchCommitsIn.empty()) && vpchCommitsOut.size() == 1 && nPlainAmount <= 0 && fNullRangeproof) - return true; - + // Rangeproof is optional in case none of the conditions are satisfied + if (!fNullRangeproof || vpchCommitsIn.empty() || vpchCommitsOut.size() != 1 || nPlainAmount > 0) { uint64_t min_value, max_value; for (size_t i = 0; i < tx.vout.size(); ++i) { @@ -320,14 +353,16 @@ bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& exces if (!secp256k1_rangeproof_verify(secp256k1_bitcoin_verify_context, &min_value, &max_value, &val.vchCommitment[0], val.vchRangeproof.data(), val.vchRangeproof.size())) return false; } + } + } + } return true; } bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const { - const CAmount& excess = tx.nTxFee; - return VerifyAmounts(tx, excess); + return VerifyAmounts(tx, tx.GetTxRewardMap()); } bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const diff --git a/src/coins.h b/src/coins.h index a0c2ed6d05..64bf5a658a 100644 --- a/src/coins.h +++ b/src/coins.h @@ -88,6 +88,14 @@ class CCoins void FromTx(const CTransaction &tx, int nHeightIn) { fCoinBase = tx.IsCoinBase(); vout = tx.vout; + // Within an asset definition transaction, the asset being defined is identified with a 0. + if (tx.IsAssetDefinition()) { + const CAssetID assetID = CAssetID(tx.GetHash()); + BOOST_FOREACH(CTxOut& txout, vout) + if (txout.assetID.IsNull()) + txout.assetID = assetID; + } + nHeight = nHeightIn; nVersion = tx.nVersion; ClearUnspendable(); @@ -430,13 +438,13 @@ class CCoinsViewCache : public CCoinsViewBacked unsigned int GetCacheSize() const; /** - * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount. + * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amounts as transaction reward. * * @param[in] tx transaction for which we are checking totals - * @param[in] excess additional amount to consider (eg, fees) + * @param[in] txReward additional amounts to consider (eg, fees and subsidy) * @return True if totals are identical */ - bool VerifyAmounts(const CTransaction& tx, const CAmount& excess) const; + bool VerifyAmounts(const CTransaction& tx, const CAmountMap& mTxReward) const; bool VerifyAmounts(const CTransaction& tx) const; //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view From 2611cec5be259d1558fbcc3cbc0817d9c4803dc0 Mon Sep 17 00:00:00 2001 From: jtimon Date: Wed, 10 Dec 2014 22:45:07 +0100 Subject: [PATCH 10/19] HF Assets: Adapt Consensus functions (main.cpp): -main::CheckInputs -main::CheckTransaction -main::ConnectBlock() fixup! main.cpp by jerzy, also TODO enforce cannonical representation of vTxFees in CheckTransaction() --- src/main.cpp | 58 ++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d0938660f4..e1d4d9d8ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "init.h" #include "merkleblock.h" #include "net.h" +#include "policy/fees.h" #include "pow.h" #include "txdb.h" #include "txmempool.h" @@ -937,13 +938,17 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) if (tx.vout.empty()) return state.DoS(10, error("CheckTransaction() : vout empty"), REJECT_INVALID, "bad-txns-vout-empty"); + // TODO add check to enforce cannonical representation of vTxFees + if (tx.vTxFees.size() > tx.vout.size()) + return state.DoS(10, error("%s: vTxFees bigger than vout", __func__), + REJECT_INVALID, "bad-txns-vtxfees-toolarge"); // Size limits if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckTransaction() : size limits failed"), REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values - CAmount nValueOut = 0; + CAmountMap valuesOut; BOOST_FOREACH(const CTxOut& txout, tx.vout) { if (!txout.nValue.IsValid()) @@ -953,14 +958,11 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) continue; const CAmount nOutAmount = txout.nValue.GetAmount(); - if (nOutAmount < 0) - return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), - REJECT_INVALID, "bad-txns-vout-negative"); - if (nOutAmount > MAX_MONEY) - return state.DoS(100, error("CheckTransaction() : txout.nValue too high"), - REJECT_INVALID, "bad-txns-vout-toolarge"); - nValueOut += nOutAmount; - if (!MoneyRange(nValueOut)) + if (!MoneyRange(nOutAmount)) + return state.DoS(100, error("CheckTransaction(): txout.nValue out of range"), + REJECT_INVALID, "bad-txns-vout-outofrange"); + valuesOut[txout.assetID] += nOutAmount; + if (!MoneyRange(valuesOut[txout.assetID])) return state.DoS(100, error("CheckTransaction() : txout total out of range"), REJECT_INVALID, "bad-txns-txouttotal-toolarge"); } @@ -1068,7 +1070,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CCoinsView dummy; CCoinsViewCache view(&dummy); - CAmount nFees = 0; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(pcoinsTip, pool); @@ -1098,13 +1099,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); - nFees = tx.nTxFee; - if (!view.VerifyAmounts(tx, nFees)) - return state.DoS(0, - error("AcceptToMemoryPool : input amounts do not match output amounts %s", - hash.ToString()), - REJECT_NONSTANDARD, "bad-txns-amount-mismatch"); - // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); } @@ -1143,6 +1137,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa double dPriority = view.GetPriority(tx, chainActive.Height()); + CAmountMap mTxReward = tx.GetTxRewardMap(); + const CAmount nFees = mTxReward.find(feeAssetID)->second; CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); unsigned int nSize = entry.GetTxSize(); @@ -1578,16 +1574,13 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi } } - const CAmount& nTxFee = tx.nTxFee; - if (nTxFee < 0) - return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), - REJECT_INVALID, "bad-txns-fee-negative"); - - if (!MoneyRange(nTxFee)) - return state.DoS(100, error("CheckInputs() : nTxFee out of range"), - REJECT_INVALID, "bad-txns-fee-outofrange"); + const CAmountMap mTxReward = tx.GetTxRewardMap(); + for(CAmountMap::const_iterator it = mTxReward.begin(); it != mTxReward.end(); ++it) + if (!MoneyRange(it->second)) + return state.DoS(100, error("CheckInputs() : nTxFee out of range"), + REJECT_INVALID, "bad-txns-fee-outofrange"); - if (!inputs.VerifyAmounts(tx, nTxFee)) + if (!inputs.VerifyAmounts(tx, mTxReward)) return state.DoS(100, error("CheckInputs() : %s value in != value out", tx.GetHash().ToString()), REJECT_INVALID, "bad-txns-amount-mismatch"); @@ -1599,6 +1592,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // Skip signature verification when connecting blocks // before the last block chain checkpoint. This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. + const CAmount nTxFee = mTxReward.find(feeAssetID)->second; if (fScriptChecks) { CTxOutValue prevValueIn = -1; for (unsigned int i = tx.GetFirstInputPos(); i < tx.vin.size(); i++) { @@ -1785,6 +1779,7 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck, vector *pvProofTxn) { + const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); CTxUndo undoDummy; @@ -1857,7 +1852,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); int64_t nTimeStart = GetTimeMicros(); - CAmount nFees = 0; + CAmountMap mBlockReward; int nInputs = 0; unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); @@ -1890,7 +1885,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-blk-sigops"); } - nFees += tx.nTxFee; + // TODO restore multi-asset block rewards + mBlockReward += tx.GetTxRewardMap(); std::vector vChecks; if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) @@ -2013,10 +2009,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - if (!view.VerifyAmounts(block.vtx[0], -GetBlockValue(pindex->nHeight, nFees))) + mBlockReward[chainparams.HashGenesisBlock()] += GetBlockValue(pindex->nHeight, 0); + if (!view.VerifyAmounts(block.vtx[0], mBlockReward)) return state.DoS(100, - error("ConnectBlock() : coinbase pays too much (actual=UNKNOWN vs limit=%d)", - GetBlockValue(pindex->nHeight, nFees)), + error("%s: coinbase pays too much", __func__), REJECT_INVALID, "bad-cb-amount"); if (!control.Wait()) From 6f0a16fd96bf3be975933fc1e3f08df57b056cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 22 Mar 2016 00:36:47 +0100 Subject: [PATCH 11/19] HF Assets: Adapt miner.cpp fixup! miner.cpp by jerzy --- src/miner.cpp | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 592d3a0b74..3158b4e78e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -10,6 +10,7 @@ #include "primitives/transaction.h" #include "main.h" #include "net.h" +#include "policy/fees.h" #include "pow.h" #include "timedata.h" #include "util.h" @@ -96,7 +97,7 @@ int64_t UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) static CFeeRate CalculateSubjectiveFeeRateAndPriority(const CCoinsViewCache& view, const CTransaction& tx, const unsigned int& nTxSize, double& dPriority) { const uint256& hash = tx.GetHash(); - CAmount nTxFees = tx.nTxFee; + CAmount nTxFees = tx.GetFee(feeAssetID); mempool.ApplyDeltas(hash, dPriority, nTxFees); return CFeeRate(nTxFees, nTxSize); @@ -104,6 +105,7 @@ static CFeeRate CalculateSubjectiveFeeRateAndPriority(const CCoinsViewCache& vie CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { + const CChainParams& chainparams = Params(); // Create new block auto_ptr pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) @@ -115,13 +117,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - // Create coinbase tx - CMutableTransaction txNew; - txNew.vin.resize(1); - txNew.vin[0].prevout.SetNull(); - txNew.vout.resize(1); - txNew.vout[0].scriptPubKey = scriptPubKeyIn; - // Add dummy coinbase tx as first transaction pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end @@ -143,8 +138,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block - CAmount nFees = 0; - + CAmountMap mBlockReward; { LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); @@ -281,8 +275,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!view.HaveInputs(tx)) continue; - const CAmount& nTxFees = tx.nTxFee; - nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; @@ -297,14 +289,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CTxUndo txundo; UpdateCoins(tx, state, view, txundo, nHeight); + const CAmountMap mTxReward = tx.GetTxRewardMap(); // Added pblock->vtx.push_back(tx); - pblocktemplate->vTxFees.push_back(nTxFees); + pblocktemplate->vTxFees.push_back(mTxReward.find(feeAssetID)->second); pblocktemplate->vTxSigOps.push_back(nTxSigOps); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; - nFees += nTxFees; + mBlockReward += mTxReward; if (fPrintPriority) { @@ -336,11 +329,23 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); - // Compute final coinbase transaction. - txNew.vout[0].nValue = GetBlockValue(nHeight, nFees); + // Create and Compute final coinbase transaction. + CMutableTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; + + mBlockReward[chainparams.HashGenesisBlock()] += GetBlockValue(nHeight, 0); + txNew.vout.resize(mBlockReward.size()); + unsigned int i = 0; + for(CAmountMap::const_iterator it = mBlockReward.begin(); it != mBlockReward.end(); ++it) { + txNew.vout[i].scriptPubKey = scriptPubKeyIn; + txNew.vout[i].assetID = it->first; + txNew.vout[i].nValue = it->second; + ++i; + } pblock->vtx[0] = txNew; - pblocktemplate->vTxFees[0] = -nFees; + pblocktemplate->vTxFees[0] = -mBlockReward.find(feeAssetID)->second; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); From e109041401b87a14b374eceafff43788d298df0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 18 Aug 2015 16:51:08 +0200 Subject: [PATCH 12/19] HF Assets: Adapt bitcoin-tx.cpp With String parsing and optional argument handling fixes by jerzy --- src/bitcoin-tx.cpp | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 6254a7de9e..83cafd1574 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -73,17 +73,18 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage = _("Commands:") + "\n"; strUsage += " delin=N " + _("Delete input N from TX") + "\n"; strUsage += " delout=N " + _("Delete output N from TX") + "\n"; - strUsage += " in=TXID:VOUT:VALUE:SEQ " + _("Add input to TX") + "\n"; - strUsage += " blind=B1::B3:B4:... " + _("Blind transaction outputs") + "\n"; + strUsage += " in=TXID:VOUT:VALUE:SEQ[:ASSETID] " + _("Add input to TX") + "\n"; + strUsage += " blind=B1:B3:B4:... " + _("Blind transaction outputs") + "\n"; strUsage += " locktime=N " + _("Set TX lock time to N") + "\n"; strUsage += " nversion=N " + _("Set TX version to N") + "\n"; - strUsage += " outaddr=VALUE:ADDRESS " + _("Add address-based output to TX") + "\n"; - strUsage += " outscript=VALUE:SCRIPT " + _("Add raw script output to TX") + "\n"; + strUsage += " outaddr=VALUE:ADDRESS[:ASSETID] " + _("Add address-based output to TX") + "\n"; + strUsage += " outscript=VALUE:SCRIPT[:ASSETID]" + _("Add raw script output to TX") + "\n"; strUsage += " sign=SIGHASH-FLAGS " + _("Add zero or more signatures to transaction") + "\n"; strUsage += " This command requires JSON registers:\n"; strUsage += " prevtxs=JSON object\n"; strUsage += " privatekeys=JSON object\n"; strUsage += " See signrawtransaction docs for format of sighash flags, JSON objects.\n"; + strUsage += " newasset=1 " + _("Make it a transaction definition transaction. An error will be raised if used after the transaction already has inputs.") + "\n"; strUsage += "\n"; fprintf(stdout, "%s", strUsage.c_str()); @@ -209,26 +210,34 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) throw runtime_error("invalid TX input vout"); // Remove vout - pos = strVout.find(':'); + pos = strVout.find(':', pos + 1); strVout = strVout.substr(pos + 1, string::npos); // extract and validate VALUE - pos = strVout.find(':'); + pos = strVout.find(':', pos + 1); if (pos == string::npos) throw runtime_error("TX input missing separator"); - string strValue = strVout.substr(0, pos); + string strValue = strVout.substr(pos + 1, strVout.find(':', pos + 1) - pos - 1); CAmount value; if (!ParseMoney(strValue, value)) throw runtime_error("invalid TX output value"); + CAssetID assetID = CAssetID(Params().HashGenesisBlock()); // extract and validate sequence number uint32_t nSequence = ~(uint32_t)0; - pos = strVout.find(':'); + pos = strVout.find(':', pos + 1); if (pos != string::npos) { if ((pos == 0) || (pos == (strVout.size() - 1))) throw runtime_error("empty TX input field"); string strSeq = strVout.substr(pos + 1, string::npos); + size_t posAsset = strVout.find(':', pos + 1); + if (posAsset != string::npos && posAsset != 0 && posAsset != (strVout.size() - 1)) { + strSeq = strVout.substr(pos + 1, posAsset); + string strAsset = strVout.substr(posAsset + 1, string::npos); + assetID = CAssetID(uint256(strAsset)); + } + strVout.resize(pos); int64_t nSeq = atoi64(strSeq); @@ -251,7 +260,9 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) // append to transaction input list CTxIn txin(txid, vout, CScript(), nSequence); tx.vin.push_back(txin); - tx.nTxFee += value; + CAmountMap mTxReward = CTransaction(tx).GetTxRewardMap(); + mTxReward[assetID] += value; + tx.SetFeesFromTxRewardMap(mTxReward); } static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) @@ -271,6 +282,14 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) // extract and validate ADDRESS string strAddr = strInput.substr(pos + 1, string::npos); + CAssetID assetID = CAssetID(Params().HashGenesisBlock()); + size_t posAsset = strInput.find(':', pos + 1); + if (posAsset != string::npos && posAsset != 0 && posAsset != (strInput.size() - 1)) { + strAddr = strInput.substr(pos + 1, posAsset - pos - 1); + string strAsset = strInput.substr(posAsset + 1, string::npos); + assetID = CAssetID(uint256(strAsset)); + } + CBitcoinAddress addr(strAddr); if (!addr.IsValid()) throw runtime_error("invalid TX output address"); @@ -279,13 +298,15 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) CScript scriptPubKey = GetScriptForDestination(addr.Get()); // construct TxOut, append to transaction output list - CTxOut txout(value, scriptPubKey); + CTxOut txout(value, scriptPubKey, assetID); if (addr.IsBlinded()) { CPubKey pubkey = addr.GetBlindingKey(); txout.nValue.vchNonceCommitment = std::vector(pubkey.begin(), pubkey.end()); } - tx.nTxFee -= value; tx.vout.push_back(txout); + CAmountMap mTxReward = CTransaction(tx).GetTxRewardMap(); + mTxReward[assetID] -= value; + tx.SetFeesFromTxRewardMap(mTxReward); } static void MutateTxBlind(CMutableTransaction& tx, const string& strInput) @@ -349,24 +370,32 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput // extract and validate script string strScript = strInput.substr(pos + 1, string::npos); + CAssetID assetID = CAssetID(Params().HashGenesisBlock()); + size_t posAsset = strInput.find(':', pos + 1); + if (posAsset != string::npos && posAsset != 0 && posAsset != (strInput.size() - 1)) { + strScript = strInput.substr(pos, posAsset); + string strAsset = strInput.substr(posAsset + 1, string::npos); + assetID = CAssetID(uint256(strAsset)); + } CScript scriptPubKey = ParseScript(strScript); // throws on err + CAmountMap mTxReward = CTransaction(tx).GetTxRewardMap(); + mTxReward[assetID] -= value; + tx.SetFeesFromTxRewardMap(mTxReward); // construct TxOut, append to transaction output list - CTxOut txout(value, scriptPubKey); + CTxOut txout(value, scriptPubKey, assetID); tx.vout.push_back(txout); - tx.nTxFee -= value; } static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx) { - // TODO: reduce nTxFee - // parse requested deletion index int inIdx = atoi(strInIdx); if (inIdx < 0 || inIdx >= (int)tx.vin.size()) { string strErr = "Invalid TX input index '" + strInIdx + "'"; throw runtime_error(strErr.c_str()); } + // TODO: reduce fees (SetFeesFromTxRewardMap) // delete input from transaction tx.vin.erase(tx.vin.begin() + inIdx); @@ -374,8 +403,6 @@ static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx) static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx) { - // TODO: increase nTxFee - // parse requested deletion index int outIdx = atoi(strOutIdx); if (outIdx < 0 || outIdx >= (int)tx.vout.size()) { @@ -383,6 +410,13 @@ static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx) throw runtime_error(strErr.c_str()); } + if (!tx.vout[outIdx].nValue.IsAmount()) + throw runtime_error("Cannot delete confidential outputs"); + + CAmountMap mTxReward = CTransaction(tx).GetTxRewardMap(); + CTxOut txOut = tx.vout[outIdx]; + mTxReward[txOut.assetID] -= txOut.nValue.GetAmount(); + tx.SetFeesFromTxRewardMap(mTxReward); // delete output from transaction tx.vout.erase(tx.vout.begin() + outIdx); } @@ -624,6 +658,16 @@ static void MutateTxWithdrawSign(CMutableTransaction& tx, const string& flagStr) } } +static void MutateTxAssetDefinition(CMutableTransaction& tx) +{ + if (tx.vin.size() > 0) + throw runtime_error("Asset definition transaction already has inputs"); + + tx.vin.resize(1); + tx.vin[0].prevout.SetNull(); + tx.vin[0].scriptSig = CScript(); +} + class Secp256k1Init { public: @@ -661,6 +705,8 @@ static void MutateTx(CMutableTransaction& tx, const string& command, MutateTxBlind(tx, commandVal); } else if (command == "withdrawsign") MutateTxWithdrawSign(tx, commandVal); + else if (command == "newasset") + MutateTxAssetDefinition(tx); else if (command == "load") RegisterLoad(commandVal); From aee6723f721d268b94bffaa24e39fa567d0a8868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 17 Jul 2015 21:25:40 +0200 Subject: [PATCH 13/19] HF Assets: Adapt rpcrawtransaction.cpp fixup! src/rpcrawtransaction.cpp by jerzy jerzy: Assets: Fixed createrawtransaction JSON created by bitcoin-cli --- src/rpcclient.cpp | 2 ++ src/rpcrawtransaction.cpp | 57 ++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 3df492c028..a89a4031e4 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -72,6 +72,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, { "createrawtransaction", 1 }, + { "createrawtransaction", 2 }, + { "createrawtransaction", 3 }, { "signrawtransaction", 1 }, { "signrawtransaction", 2 }, { "sendrawtransaction", 1 }, diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 8664dc8dde..d21d766f0a 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -12,6 +12,7 @@ #include "main.h" #include "merkleblock.h" #include "net.h" +#include "policy/fees.h" #include "rpcserver.h" #include "script/script.h" #include "script/sign.h" @@ -64,7 +65,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); - entry.push_back(Pair("fee", ValueFromAmount(tx.nTxFee))); + entry.push_back(Pair("fee", ValueFromAmount(tx.GetFee(feeAssetID)))); // TODO improve ? Array vin; BOOST_FOREACH(const CTxIn& txin, tx.vin) { Object in; @@ -453,7 +454,7 @@ Value listunspent(const Array& params, bool fHelp) Value createrawtransaction(const Array& params, bool fHelp) { - if (fHelp || params.size() != 2) + if (fHelp || params.size() < 2) throw runtime_error( "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" @@ -468,6 +469,7 @@ Value createrawtransaction(const Array& params, bool fHelp) " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n (numeric, required) The output number\n" " \"nValue\":x.xxx, (numeric, required) The amount being spent\n" + " \"assetid\":\"id\",(string, optional) The assetID of the input being spent (-feeasset by default)\n" " }\n" " ,...\n" " ]\n" @@ -476,6 +478,13 @@ Value createrawtransaction(const Array& params, bool fHelp) " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n" " ,...\n" " }\n" + "3. \"output asset ids\" (object, optional) a json object with addresses as keys and asset ids as values\n" + " All addresses not contained here default to -feeasset\n" + " {\n" + " \"address\": \"id\" (string, optional) The key is the bitcoin address, the value is the asset id\n" + " ,...\n" + " }\n" + "4. Asset definition (boolean, optional, default=false) Make it an asset definition transaction. Outputs with assetID = 0 will represent the newly issued assets.\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" @@ -485,14 +494,33 @@ Value createrawtransaction(const Array& params, bool fHelp) + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") ); - RPCTypeCheck(params, list_of(array_type)(obj_type)); + if (params.size() == 2) { + RPCTypeCheck(params, list_of(array_type)(obj_type)); + } else if (params.size() == 3) { + RPCTypeCheck(params, list_of(array_type)(obj_type)(obj_type)); + } else if (params.size() == 4) { + RPCTypeCheck(params, list_of(array_type)(obj_type)(obj_type)(bool_type)); + } Array inputs = params[0].get_array(); Object sendTo = params[1].get_obj(); + Object sendToAssets; + if (params.size() > 2) { + sendToAssets = params[2].get_obj(); + } + bool fAssetDefinition = false; + if (params.size() > 3) + fAssetDefinition = params[3].get_bool(); CMutableTransaction rawTx; + CAmountMap mInputValues; + CAmountMap mOutputValues; - CAmount inputValue = 0; + if (fAssetDefinition) { + rawTx.vin.resize(1); + rawTx.vin[0].prevout.SetNull(); + rawTx.vin[0].scriptSig = CScript(); + } BOOST_FOREACH(const Value& input, inputs) { const Object& o = input.get_obj(); @@ -506,15 +534,19 @@ Value createrawtransaction(const Array& params, bool fHelp) if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + CAssetID assetID = feeAssetID; + if (params.size() > 2) { + try { + assetID = ParseHashO(o, "assetid"); + } catch (...) {}; + } const Value& vout_value = find_value(o, "nValue"); - inputValue += AmountFromValue(vout_value); + mInputValues[assetID] += AmountFromValue(vout_value); CTxIn in(COutPoint(txid, nOutput)); rawTx.vin.push_back(in); } - CAmount outputValue = 0; - set setAddress; BOOST_FOREACH(const Pair& s, sendTo) { CBitcoinAddress address(s.name_); @@ -527,9 +559,12 @@ Value createrawtransaction(const Array& params, bool fHelp) CScript scriptPubKey = GetScriptForDestination(address.Get()); CAmount nAmount = AmountFromValue(s.value_); - outputValue += nAmount; + CAssetID assetID = feeAssetID; + if (params.size() > 2) + assetID = ParseHashO(sendToAssets, s.name_); + mOutputValues[assetID] += nAmount; - CTxOut out(nAmount, scriptPubKey); + CTxOut out(nAmount, scriptPubKey, assetID); if (address.IsBlinded()) { CPubKey confidentiality_pubkey = address.GetBlindingKey(); if (!confidentiality_pubkey.IsValid()) @@ -539,7 +574,9 @@ Value createrawtransaction(const Array& params, bool fHelp) rawTx.vout.push_back(out); } - rawTx.nTxFee = inputValue - outputValue; + CAmountMap mTxReward = mInputValues; + mTxReward -= mOutputValues; + rawTx.SetFeesFromTxRewardMap(mTxReward); return EncodeHexTx(rawTx); } From 6d72a1e403d00a221e9c4085207385eb0e92ec8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Mon, 1 Jun 2015 23:20:04 +0200 Subject: [PATCH 14/19] Assets?: Make sure there's a chainActive.Tip() before calling some functions --- src/main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e1d4d9d8ae..1d5e2a533c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1453,7 +1453,8 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) pindexBestForkBase = pfork; } - CheckForkWarningConditions(); + if (chainActive.Tip()) + CheckForkWarningConditions(); } // Requires cs_main. @@ -1488,7 +1489,8 @@ void static InvalidChainFound(CBlockIndex* pindexNew) LogPrintf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n", chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime())); - CheckForkWarningConditions(); + if (chainActive.Tip()) + CheckForkWarningConditions(); } void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { @@ -3029,7 +3031,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis return error("%s : AcceptBlock FAILED", __func__); } - if (!ActivateBestChain(state, pblock)) + if (chainActive.Tip() && !ActivateBestChain(state, pblock)) return error("%s : ActivateBestChain failed", __func__); return true; @@ -3376,7 +3378,7 @@ bool InitBlockIndex() { CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); - if (!ActivateBestChain(state, &block)) + if (chainActive.Tip() && !ActivateBestChain(state, &block)) return error("LoadBlockIndex() : genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesnt check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); From b4f6f6f411b6efebf12f99698bc3f1f40a78b7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 26 Nov 2015 14:50:09 +0100 Subject: [PATCH 15/19] UNDO: Assets: comment CTransaction::nTxFee in wallet --- src/rpcwallet.cpp | 8 ++++---- src/wallet.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 6d97292072..6fdf8a544a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1601,11 +1601,11 @@ Value gettransaction(const Array& params, bool fHelp) CAmount nCredit = wtx.GetCredit(filter); CAmount nDebit = wtx.GetDebit(filter); CAmount nNet = nCredit - nDebit; - CAmount nFee = (wtx.IsFromMe(filter) ? wtx.nTxFee : 0); + // CAmount nFee = (wtx.IsFromMe(filter) ? wtx.nTxFee : 0); - entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe(filter)) - entry.push_back(Pair("fee", ValueFromAmount(nFee))); + // entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + // if (wtx.IsFromMe(filter)) + // entry.push_back(Pair("fee", ValueFromAmount(nFee))); WalletTxToJSON(wtx, entry); diff --git a/src/wallet.cpp b/src/wallet.cpp index e6aaccdbba..6136ea0522 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -864,8 +864,8 @@ void CWalletTx::GetAmounts(list& listReceived, // Compute fee: CAmount nDebit = GetDebit(filter); - if (nDebit > 0) // debit>0 means we signed/sent this transaction - nFee = nTxFee; + // if (nDebit > 0) // debit>0 means we signed/sent this transaction + // nFee = nTxFee; // Sent/received. for (unsigned int i = 0; i < vout.size(); ++i) @@ -1633,7 +1633,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, const vectorGetHash(),coin.second)); - txNew.nTxFee = nValueIn - nValueOut; + // txNew.nTxFee = nValueIn - nValueOut; LogPrintf("Created transaction (before blinding): %s", CTransaction(txNew).ToString()); // Create blinded outputs From 3a9809c054790345bfaa294af6cb23023a7156ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 26 Nov 2015 14:50:39 +0100 Subject: [PATCH 16/19] UNDO: Assets: comment CTransaction::nTxFee in qt --- src/qt/transactiondesc.cpp | 4 ++-- src/qt/transactionrecord.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index d60248dd41..333a3c9d66 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -212,8 +212,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "" + tr("Total credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "
    "; } - if (wtx.nTxFee > 0) - strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wtx.nTxFee) + "
    "; + // if (wtx.nTxFee > 0) + // strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wtx.nTxFee) + "
    "; } else { diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 5ff77065c4..7f14d568ce 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -109,7 +109,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // // Debit // - CAmount nTxFee = wtx.nTxFee; + // CAmount nTxFee = wtx.nTxFee; for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { @@ -141,11 +141,11 @@ QList TransactionRecord::decomposeTransaction(const CWallet * CAmount nValue = wtx.GetValueOut(nOut); /* Add fee to first output */ - if (nTxFee > 0) - { - nValue += nTxFee; - nTxFee = 0; - } + // if (nTxFee > 0) + // { + // nValue += nTxFee; + // nTxFee = 0; + // } sub.debit = -nValue; parts.append(sub); From dad4286d4d799bdc587b6b4f7efc42b6a34b794b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 26 Nov 2015 14:51:00 +0100 Subject: [PATCH 17/19] UNDO: Assets: Test: Comments in blind_tests.cpp --- src/test/blind_tests.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/blind_tests.cpp b/src/test/blind_tests.cpp index ca67119eb8..44216c8619 100644 --- a/src/test/blind_tests.cpp +++ b/src/test/blind_tests.cpp @@ -49,8 +49,8 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) tx3.vin[1].prevout.n = 0; tx3.vout.resize(1); tx3.vout[0].nValue = 100; - tx3.nTxFee = 22; - BOOST_CHECK(cache.VerifyAmounts(tx3)); + // tx3.nTxFee = 22; + // BOOST_CHECK(cache.VerifyAmounts(tx3)); std::vector input_blinds; std::vector output_blinds; @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) output_pubkeys.push_back(pubkey1); BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx3); BOOST_CHECK(!tx3.vout[0].nValue.IsAmount()); - BOOST_CHECK(cache.VerifyAmounts(tx3)); + // BOOST_CHECK(cache.VerifyAmounts(tx3)); CAmount unblinded_amount; BOOST_CHECK(UnblindOutput(key2, tx3.vout[0], unblinded_amount, blind3) == 0); @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) in3->vout.resize(1); in3->vout[0] = tx3.vout[0]; - tx3.nTxFee--; + // tx3.nTxFee--; BOOST_CHECK(!cache.VerifyAmounts(tx3)); } @@ -88,8 +88,8 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) tx4.vout[0].nValue = 30; tx4.vout[1].nValue = 40; tx4.vout[2].nValue = 50; - tx4.nTxFee = 100 + 111 - 30 - 40 - 50; - BOOST_CHECK(cache.VerifyAmounts(tx4)); + // tx4.nTxFee = 100 + 111 - 30 - 40 - 50; + // BOOST_CHECK(cache.VerifyAmounts(tx4)); std::vector input_blinds; std::vector output_blinds; @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) BOOST_CHECK(!tx4.vout[0].nValue.IsAmount()); BOOST_CHECK(tx4.vout[1].nValue.IsAmount()); BOOST_CHECK(!tx4.vout[2].nValue.IsAmount()); - BOOST_CHECK(cache.VerifyAmounts(tx4)); + // BOOST_CHECK(cache.VerifyAmounts(tx4)); CAmount unblinded_amount; BOOST_CHECK(UnblindOutput(key1, tx4.vout[0], unblinded_amount, blind4) == 0); @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(naive_blinding_test) in4->vout[1] = tx4.vout[1]; in4->vout[2] = tx4.vout[2]; - tx4.nTxFee--; + // tx4.nTxFee--; BOOST_CHECK(!cache.VerifyAmounts(tx4)); } } From 4186ff295a5905b21d7bdbc9e60d84172c2ecae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 26 Nov 2015 14:35:29 +0100 Subject: [PATCH 18/19] Assets: Update genesis_tests.cpp --- src/test/genesis_tests.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/test/genesis_tests.cpp b/src/test/genesis_tests.cpp index e33f923760..c976b26dfd 100644 --- a/src/test/genesis_tests.cpp +++ b/src/test/genesis_tests.cpp @@ -18,13 +18,7 @@ BOOST_AUTO_TEST_CASE(genesis_mainnet) BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), params->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), - "b811a5eeaf27432278c032a0b520f829be2b92fafff9789efe2755fff8ef547b"); - // Check that unittest genesis hash is same as the mainnet one - const CChainParams *params2 = &Params(); - BOOST_CHECK_EQUAL(params2->HashGenesisBlock().GetHex(), - params2->GenesisBlock().GetHash().GetHex()); - BOOST_CHECK_EQUAL(params2->HashGenesisBlock().GetHex(), - "b811a5eeaf27432278c032a0b520f829be2b92fafff9789efe2755fff8ef547b"); + "4d055eb17dad11aec976bc4b46b2708f91aac0ffedb3b9a3f3451b64d106a9a6"); } // Goal: check that the standard testnet genesis block is computed correctly @@ -35,7 +29,7 @@ BOOST_AUTO_TEST_CASE(genesis_testnet) BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), params->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), - "f7f0ca371b1003dc7346bab766b4a131f9e3a5d68820a364d70921cb15b95eaa"); + "ad5cb13bc360f0cbc4ba3dca881e6a771d05052469edb73e54956b5225918846"); // Return params to base case for other tests SelectParams(CBaseChainParams::MAIN); } @@ -48,7 +42,7 @@ BOOST_AUTO_TEST_CASE(genesis_regtest) BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), params->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params->HashGenesisBlock().GetHex(), - "b41d03dc310957765223df2bf2f4b3609c79b8b6ac0a0764b20754f972d48b6c"); + "095cdb4b50450887a3fba5fa77bdd7ce969868b78e2e7a75886d8e324c9e331d"); // Return params to base case for other tests SelectParams(CBaseChainParams::MAIN); } @@ -63,21 +57,21 @@ BOOST_AUTO_TEST_CASE(genesis_customscript) BOOST_CHECK_EQUAL(params1->HashGenesisBlock().GetHex(), params1->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params1->HashGenesisBlock().GetHex(), - "2ec431e3858cef95882cd7d627599fd757afa81938f0b886bee691a48b1e9b58"); + "431a10b6cfd6b593adcc1f243b348042a3d46efdf9ac7c939994647349754d21"); SelectParams(CBaseChainParams::TESTNET, unsignable); const CChainParams *params2 = &Params(); BOOST_CHECK_EQUAL(params2->HashGenesisBlock().GetHex(), params2->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params2->HashGenesisBlock().GetHex(), - "e28e10e75c6f55edfdb914831b8d48c79fd858b6020963a038ee97dcaae2b355"); + "24e37fa582f78e10706be56a3ad166d92517c9eab9bbf9861fd5d6b6ac3d560b"); SelectParams(CBaseChainParams::REGTEST, unsignable); const CChainParams *params3 = &Params(); BOOST_CHECK_EQUAL(params3->HashGenesisBlock().GetHex(), params3->GenesisBlock().GetHash().GetHex()); BOOST_CHECK_EQUAL(params3->HashGenesisBlock().GetHex(), - "a99a962c80d71fe1eb0b30217a6f14bc571e3eee97bc16663cf42d9e22eb6cb2"); + "dac4000e5ed09f558c27b442c555f4ea4fa8ce60e11d39898881412741c571a5"); // Return params to base case for other tests SelectParams(CBaseChainParams::MAIN); From 9f71ca485c92f7ab9a4c5ced0cc6e19a721de3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 11 Mar 2016 03:35:46 +0100 Subject: [PATCH 19/19] Assets: Update script Automatically generated test cases --- src/test/data/script_invalid.json | 38 +++++++++++++++---------------- src/test/data/script_valid.json | 28 +++++++++++------------ 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 0856b556fa..ce09035151 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -519,115 +519,115 @@ ["Automatically generated test cases"], [ - "0x41 0x6863d8947a48d1de1023e80fbbda9bcc39c6d51f7d20aa487d6dd712ee9d2faece2f3baed30776dcb7d858d5123be1652eccb284fb0c79a59787093afb67613e01", + "0x41 0xbc653c883c42bea9d7bc3bd033a20dd9a8f845e6dc4efa300fc2ef0ce8a6bcde61d67e333a877816450ed926078d99855f83ebad15ecc703912ab720266b553401", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK, bad sig" ], [ - "0x41 0x98ff11789ee5f9a71af7328289e9a46aec0bd87b99050c8ac6b03c9dc3f9c59d18357cd7e10627cf428bff1864aef8d8eb3be014faa9dd54438435d9fbad6e3f01 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", + "0x41 0xde5f97c12d4b3b84f7953bed6dd8473fffdfbce5e201a361626f925dc5881faa23547ffd56e53d6daab1e3bb02cb28d76b62768fc50231e87d81a75c1ebc3a4e01 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", "P2PKH, bad pubkey" ], [ - "0x41 0x24a1b836adccc99fe3f4a7f867d7fb23abc8d75e82da17ddd02bd672534052c178d601c92f6d1a4469b1c20f92ed02f0be0166393a3f58a571b465b2a8580f3101", + "0x41 0x1ab8806fe69bc50c0f65459e7d59623efe4bea87ad1f4750d23a3145eb0740d4979778ad1580e2d46f13014e2c04f6a103505b1db7c05ff65ae0150c127f1b4101", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay marked with normal hashtype" ], [ - "0x41 0xcb1e1098bb0ddaf5d6a6f50db6413215650b4e835491fce4298e8184cacde6db43ce6ff01009da60261f3d1f2b44a9f88cac3dbf49376903c126af9752e6010301 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "0x41 0x2ccde48935848cfd172f60c33d790e9811f3f3aae7b726fd1f1453381c117052fdd25ca88d94b350c705e80ee1dbdb73a3fd3af9dfde6698600161e15982e49c01 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK), bad redeemscript" ], [ - "0x41 0x2ad332eb13e9a12fb8523f3fc111f24f1cda20640d18e4d919e2eea55787577db86ca96927864bef877392002877102ffa9758b4229d551605d1ba2dd4cf0c3e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "0x41 0xdfaee8edb040d86958d3f446b02e23dd30d2c14fd03644c4a11558ad53136a122e09bdd7cb8deda6957d19bae03ddc100c9e67c06033e60fdf902dc81b89d6cd01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", "P2SH(P2PKH), bad sig" ], [ - "0 0x41 0x082a5b36197f3ef39b4ea265f4097060fe417ab1aa20fc05242a839d348ba17637c3cc8c1b9f7c450f89fe9e97d8fdb1920c96032e96ecebfebb19e556acdb7501 0x41 0x8146998a3deda65def2fd9c86ca5d890e662068ebffe6b678c8c9e2860460f5580ec3974d07f319b98b760e97457896b4a235c270f3ec2f2a0b96cf1013a972801 0", + "0 0x41 0x9918e4d3e0e088abf416d2d45e91f74ec601ed4ef4be603e8798622040716424225d6008bd5963ee3f100cc55a6602f557c7d6cfe28f77f53ea0966dc24bb75601 0x41 0x823d7396045b22e8b1c3cddf6cbb2988868dfb54f4e8e845acb40e5a6cb556fa37091a741684cd4349aa00d06c10120f428dff0b9b74b40e65461e5b9f8ab94301 0", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3, 2 sigs" ], [ - "0 0x41 0xee6fd0ab43c8119f331c973f25b9e546d02dea5611114d06ec1a041f59713bcc3fa8bb5e2bb866169f40524bf774fdfb5915765f7140da74c3f1ae556f8bd8e301 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "0 0x41 0xf5ba2f91d8b09654955fcafcab8fdf2c1842d9d89fdcbb3f3e6123204efb4dab5dbe2dce914d0902d4bd226c237939fb0b121ba325aa632d27d5904cc6727b5d01 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3), 1 sig" ], [ - "0x41 0x985b28b02ac1e49e31d6b299606793792ea66b400853bab3189a851b558f5b4732faf7ffda7e238517d26117b50b609bd89eb8071529c0d7c91419914c4fc4ed01", + "0x41 0x1411b61907edd0eeadf2efd9c96c3a45e9a4f3e4249df52fb11d43588621dfec255ef8fc44ac761054a4128b504db7db39a6beafe9fc6495c25edb7530a6779f01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "STRICTENC", "P2PK with hybrid pubkey" ], [ - "0x41 0x80a861c6a095e1e69d2505430b1b44b935ddffd39b4bc5b1dc4fbe98ded4f571721d87e56928475115519ffbb5b6670196c19c33362c3779183ef694cd31194401", + "0x41 0xb4d1504ca255a69cb362bf2922021137b2bb327572aaf84af153b805aa22072c7efcfcd5e9bca6c3e2fa0edbd0d332e02a1dc1d547b4dadd314779764235c9b001", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "", "P2PK NOT with hybrid pubkey but no STRICTENC" ], [ - "0x41 0x80a861c6a095e1e69d2505430b1b44b935ddffd39b4bc5b1dc4fbe98ded4f571721d87e56928475115519ffbb5b6670196c19c33362c3779183ef694cd31194401", + "0x41 0xb4d1504ca255a69cb362bf2922021137b2bb327572aaf84af153b805aa22072c7efcfcd5e9bca6c3e2fa0edbd0d332e02a1dc1d547b4dadd314779764235c9b001", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", "P2PK NOT with hybrid pubkey" ], [ - "0x41 0x80a861c6a095e1e69d2504430b1b44b935ddffd39b4bc5b1dc4fbe98ded4f571721d87e56928475115519ffbb5b6670196c19c33362c3779183ef694cd31194401", + "0x41 0xb4d1504ca255a69cb362be2922021137b2bb327572aaf84af153b805aa22072c7efcfcd5e9bca6c3e2fa0edbd0d332e02a1dc1d547b4dadd314779764235c9b001", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", "STRICTENC", "P2PK NOT with invalid hybrid pubkey" ], [ - "0 0x41 0x21a03de07f902ac03755ba1a39ffc9f7ca99dc0dba841af056e1662a819f4d7c2a3677800041148f003ce89a43a40cccaa9f0ab8fae98857e08e8f6898efd97601", + "0 0x41 0x950ac881e2e4ed062eb3fae3d0ae984046d1502355ad84673550d8c1a02919d294db3ac63c3e3061543384ab7f22cc8b8964c2187ee4db754d9a13ebd6949d3d01", "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG", "STRICTENC", "1-of-2 with the first 1 hybrid pubkey" ], [ - "0x41 0x363b42595805a7ce5a43626f0c6ede3b10100df481870c92fd08f1bf5934c5ee8e57be83ffdb63d4456a994ede9ec8f31b90b0e82cace0dbeb1a6cdefd405fbc05", + "0x41 0x86120ba9ad643a814ff0814d3d9d048aaa05b345733ac456e23b141eb7c416518f319dc0706d9866674d9e1b2cc35db719182a897be8f701b1168fcf66f79fa005", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "STRICTENC", "P2PK with undefined hashtype" ], [ - "0x41 0xce7fe6391f5c5bee94a12ebaec43545c239a1672040549b56c0959172dd15fe0c317befd2f35bb81e8763e98a5f1a6b41978b74c3b32662fa0681cb8dd9f52d105", + "0x41 0x6efb8ddef13ae9c690374478bf203447a292ee0a159d2f3f241166e7239dfc348353b4ec95d3af7afd4ed626330049b5d62420b9566fa8d4cfda21ad0da4695705", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", "STRICTENC", "P2PK NOT with invalid sig and undefined hashtype" ], [ - "1 0x41 0x082a5b36197f3ef39b4ea265f4097060fe417ab1aa20fc05242a839d348ba17637c3cc8c1b9f7c450f89fe9e97d8fdb1920c96032e96ecebfebb19e556acdb7501 0x41 0x8146998a3deda65def2fd9c86ca5d890e662068ebffe6b678c8c9e2860460f5580ec3974d07f319b98b760e97457896b4a235c270f3ec2f2a0b96cf1013a972801 0x41 0xaacbc3c37cbef61dc7fd3c8a10fad5c6980100b2ed665a1e43ab7560527e550f188a2203c24ef8a68638bc2ce628ea30a0706f62ac6731deb07829d4266ee6fe01", + "1 0x41 0x9918e4d3e0e088abf416d2d45e91f74ec601ed4ef4be603e8798622040716424225d6008bd5963ee3f100cc55a6602f557c7d6cfe28f77f53ea0966dc24bb75601 0x41 0x823d7396045b22e8b1c3cddf6cbb2988868dfb54f4e8e845acb40e5a6cb556fa37091a741684cd4349aa00d06c10120f428dff0b9b74b40e65461e5b9f8ab94301 0x41 0x30605bc13ac4b2732f8aee470f57588366c6ff3b1605797fbed33ba78e60ca2c29dfd8191aabde950b2a2665c6de0586f5b2ff633ba591ebfc9d30d8ca24c44e01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", "3-of-3 with nonzero dummy" ], [ - "1 0x41 0x84ac522998336dd40c0a2c3a2457f654c37464b31db8585c5f90c58a63357037390618aaaf9fc8b082a89fc6f93aad43a4371c23b256780f6eb906ad1ed6ebdb01 0x41 0xe5f9f8716c641f7f03fd1297277c66c674d147fc46298b338259556a874c25301c0b9ef736fa50c93f064219bf9f09bb00a3aa26a790a61c4de0e0defeb8c46f01 0x41 0x0d2bf3b5b70b67496d10d2a9f0f6e9d49dda2b2ca48804f65ec2d31421a991836a7b8b74219ceb2cd26c0b85faabff5b58f69e99ac70350ef4b3289c8d4971e701", + "1 0x41 0xbeaaa08d81fca9a8aa386296c0e59a05a30d7884397078fcc627083640b8da4c2474648934f099b169cd60a767e7f6470a09cecd1794176ff6def5047beb42c901 0x41 0x8236cba519ffec23122acf94423dcdd52eed5f3b11f5f2028d93e3b14c40e14358f04202d6c0dfb8ac0c171d1ffbfd042a0996509831a7a28347580f9460518901 0x41 0x9875ad30f099d1e76d3182cf8057274efe59e9bd857f6f1017e1a104da325e8f672aef91e04df364e4a7e1b2cbac08242516613f8d64381d5c6b3995f56f8bf701", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", "NULLDUMMY", "3-of-3 NOT with invalid sig with nonzero dummy" ], [ - "0 0x41 0x8838a35a1b419f133675e6ef0a613a89f22992d9ca8277f63b737994e7c850bfd73055e480fcdcb62485db8c155d1d4dc0b10fa218c65794c36325ed882437f401 DUP", + "0 0x41 0xbff394ac2b758a2d9c087ff8c7eb107ed243ca5b46c7cc63077b61c842ea191d4a2f8b5f13af6a716477c85334cc9d0e76589cef061ba59fd32a48556eaa0ccb01 DUP", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "SIGPUSHONLY", "2-of-2 with two identical keys and sigs pushed using OP_DUP" ], [ - "0x41 0xf6a6842282c43f8332d00e5931d333befcd5816330a297ef0e057f54a4f56dbcc618a0ece107f1081c10d9f7bc805ffeae9efaae5636a6610ac94c1749d6f59101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x41 0xb7fce298e65e2bc670fb103276ee8590d9616f4f727e78156655666a3fa5f7e7f7ecca4e1ab5c11bff4d0d72fc2df073b16acc8c1ea5230b6f851a804e71e44801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "", "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY" ], [ - "0x41 0xf6a6842282c43f8332d00e5931d333befcd5816330a297ef0e057f54a4f56dbcc618a0ece107f1081c10d9f7bc805ffeae9efaae5636a6610ac94c1749d6f59101 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", + "0x41 0xb7fce298e65e2bc670fb103276ee8590d9616f4f727e78156655666a3fa5f7e7f7ecca4e1ab5c11bff4d0d72fc2df073b16acc8c1ea5230b6f851a804e71e44801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "SIGPUSHONLY", "P2SH(P2PK) with non-push scriptSig" diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index cabe2c08e1..aada3ad72f 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -767,85 +767,85 @@ ["Automatically generated test cases"], [ - "0x41 0x6863d8947a48d1de1023e90fbbda9bcc39c6d51f7d20aa487d6dd712ee9d2faece2f3baed30776dcb7d858d5123be1652eccb284fb0c79a59787093afb67613e01", + "0x41 0xbc653c883c42bea9d7bc3ad033a20dd9a8f845e6dc4efa300fc2ef0ce8a6bcde61d67e333a877816450ed926078d99855f83ebad15ecc703912ab720266b553401", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK" ], [ - "0x41 0xe14f9c272b2c0c4315a9a3a961452bdfe1c85393250894d8705435a92a1d507fb417b04b17672fc36599f8989a1501db6adf49f872c2129b053e1ee4d19a2fee01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", + "0x41 0x3e70cb59236ff33bb7e80480548da658530f9d43cb3ea43e77c6068e03933efe212f940316f36b011afd11700fbdbe7d2252e58e1ee5647d73e37d2b71e692cd01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", "", "P2PKH" ], [ - "0x41 0x24a1b836adccc99fe3f4a7f867d7fb23abc8d75e82da17ddd02bd672534052c178d601c92f6d1a4469b1c20f92ed02f0be0166393a3f58a571b465b2a8580f3181", + "0x41 0x1ab8806fe69bc50c0f65459e7d59623efe4bea87ad1f4750d23a3145eb0740d4979778ad1580e2d46f13014e2c04f6a103505b1db7c05ff65ae0150c127f1b4181", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay" ], [ - "0x41 0xcb1e1098bb0ddaf5d6a6f50db6413215650b4e835491fce4298e8184cacde6db43ce6ff01009da60261f3d1f2b44a9f88cac3dbf49376903c126af9752e6010301 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "0x41 0x2ccde48935848cfd172f60c33d790e9811f3f3aae7b726fd1f1453381c117052fdd25ca88d94b350c705e80ee1dbdb73a3fd3af9dfde6698600161e15982e49c01 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK)" ], [ - "0x41 0x2ad332eb13e9a12fb8523f3fc111f24f1cda20640d18e4d919e2eea55787577db86ca96927864bef877392002877102ffa9758b4229d551605d1ba2dd4cf0c3e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "0x41 0xdfaee8edb040d86958d3f446b02e23dd30d2c14fd03644c4a11558ad53136a122e09bdd7cb8deda6957d19bae03ddc100c9e67c06033e60fdf902dc81b89d6cd01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "", "P2SH(P2PKH), bad sig but no VERIFY_P2SH" ], [ - "0 0x41 0x082a5b36197f3ef39b4ea265f4097060fe417ab1aa20fc05242a839d348ba17637c3cc8c1b9f7c450f89fe9e97d8fdb1920c96032e96ecebfebb19e556acdb7501 0x41 0x8146998a3deda65def2fd9c86ca5d890e662068ebffe6b678c8c9e2860460f5580ec3974d07f319b98b760e97457896b4a235c270f3ec2f2a0b96cf1013a972801 0x41 0xaacbc3c37cbef61dc7fd3c8a10fad5c6980100b2ed665a1e43ab7560527e550f188a2203c24ef8a68638bc2ce628ea30a0706f62ac6731deb07829d4266ee6fe01", + "0 0x41 0x9918e4d3e0e088abf416d2d45e91f74ec601ed4ef4be603e8798622040716424225d6008bd5963ee3f100cc55a6602f557c7d6cfe28f77f53ea0966dc24bb75601 0x41 0x823d7396045b22e8b1c3cddf6cbb2988868dfb54f4e8e845acb40e5a6cb556fa37091a741684cd4349aa00d06c10120f428dff0b9b74b40e65461e5b9f8ab94301 0x41 0x30605bc13ac4b2732f8aee470f57588366c6ff3b1605797fbed33ba78e60ca2c29dfd8191aabde950b2a2665c6de0586f5b2ff633ba591ebfc9d30d8ca24c44e01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3" ], [ - "0 0x41 0xee6fd0ab43c8119f331c973f25b9e546d02dea5611114d06ec1a041f59713bcc3fa8bb5e2bb866169f40524bf774fdfb5915765f7140da74c3f1ae556f8bd8e301 0x41 0xfe509993538960f7283ae7e2bd522dbae231d82df5747362acdd5bb5a8af7a6111175adcb712e19e413dea5b2fefeea12c5be84c8fa9244475eed443e835e1aa01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "0 0x41 0xf5ba2f91d8b09654955fcafcab8fdf2c1842d9d89fdcbb3f3e6123204efb4dab5dbe2dce914d0902d4bd226c237939fb0b121ba325aa632d27d5904cc6727b5d01 0x41 0xc2ff053a20bb2b37f60fd06216a8fce0338e88e871e7be4897f8893b482882c129120ae631f9c4280f2f094dbc574394ad1cfb3ed518c9de55f5e39e041ce43b01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3)" ], [ - "0x41 0x985b28b02ac1e49e31d6b299606793792ea66b400853bab3189a851b558f5b4732faf7ffda7e238517d26117b50b609bd89eb8071529c0d7c91419914c4fc4ed01", + "0x41 0x1411b61907edd0eeadf2efd9c96c3a45e9a4f3e4249df52fb11d43588621dfec255ef8fc44ac761054a4128b504db7db39a6beafe9fc6495c25edb7530a6779f01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK with hybrid pubkey but no STRICTENC" ], [ - "0 0x41 0x89030f48b7bbecea19c6342eb6d06cff8e9c77bef4d42baee29c233e98d6b07c9dcc81e8b23f66c21fcbfb343a4e98e892e3c2fbe88db6f36a40699db678be8901", + "0 0x41 0xee25e77ef86e2286fb999e794a13d1017cd558f9d0899381690192279ec5ff1b66dab8d9f87d2f40547dfa05b3275d0ee3a9130c63d125bdde6694d929f2cd8f01", "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "", "1-of-2 with the second 1 hybrid pubkey and no STRICTENC" ], [ - "0 0x41 0x89030f48b7bbecea19c6342eb6d06cff8e9c77bef4d42baee29c233e98d6b07c9dcc81e8b23f66c21fcbfb343a4e98e892e3c2fbe88db6f36a40699db678be8901", + "0 0x41 0xee25e77ef86e2286fb999e794a13d1017cd558f9d0899381690192279ec5ff1b66dab8d9f87d2f40547dfa05b3275d0ee3a9130c63d125bdde6694d929f2cd8f01", "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "STRICTENC", "1-of-2 with the second 1 hybrid pubkey" ], [ - "0x41 0x363b42595805a7ce5a43626f0c6ede3b10100df481870c92fd08f1bf5934c5ee8e57be83ffdb63d4456a994ede9ec8f31b90b0e82cace0dbeb1a6cdefd405fbc05", + "0x41 0x86120ba9ad643a814ff0814d3d9d048aaa05b345733ac456e23b141eb7c416518f319dc0706d9866674d9e1b2cc35db719182a897be8f701b1168fcf66f79fa005", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK with undefined hashtype but no STRICTENC" ], [ - "1 0x41 0x082a5b36197f3ef39b4ea265f4097060fe417ab1aa20fc05242a839d348ba17637c3cc8c1b9f7c450f89fe9e97d8fdb1920c96032e96ecebfebb19e556acdb7501 0x41 0x8146998a3deda65def2fd9c86ca5d890e662068ebffe6b678c8c9e2860460f5580ec3974d07f319b98b760e97457896b4a235c270f3ec2f2a0b96cf1013a972801 0x41 0xaacbc3c37cbef61dc7fd3c8a10fad5c6980100b2ed665a1e43ab7560527e550f188a2203c24ef8a68638bc2ce628ea30a0706f62ac6731deb07829d4266ee6fe01", + "1 0x41 0x9918e4d3e0e088abf416d2d45e91f74ec601ed4ef4be603e8798622040716424225d6008bd5963ee3f100cc55a6602f557c7d6cfe28f77f53ea0966dc24bb75601 0x41 0x823d7396045b22e8b1c3cddf6cbb2988868dfb54f4e8e845acb40e5a6cb556fa37091a741684cd4349aa00d06c10120f428dff0b9b74b40e65461e5b9f8ab94301 0x41 0x30605bc13ac4b2732f8aee470f57588366c6ff3b1605797fbed33ba78e60ca2c29dfd8191aabde950b2a2665c6de0586f5b2ff633ba591ebfc9d30d8ca24c44e01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3 with nonzero dummy but no NULLDUMMY" ], [ - "0 0x41 0x8838a35a1b419f133675e6ef0a613a89f22992d9ca8277f63b737994e7c850bfd73055e480fcdcb62485db8c155d1d4dc0b10fa218c65794c36325ed882437f401 DUP", + "0 0x41 0xbff394ac2b758a2d9c087ff8c7eb107ed243ca5b46c7cc63077b61c842ea191d4a2f8b5f13af6a716477c85334cc9d0e76589cef061ba59fd32a48556eaa0ccb01 DUP", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "", "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY" ], [ - "0 0x41 0x8838a35a1b419f133675e6ef0a613a89f22992d9ca8277f63b737994e7c850bfd73055e480fcdcb62485db8c155d1d4dc0b10fa218c65794c36325ed882437f401 0x41 0x8838a35a1b419f133675e6ef0a613a89f22992d9ca8277f63b737994e7c850bfd73055e480fcdcb62485db8c155d1d4dc0b10fa218c65794c36325ed882437f401", + "0 0x41 0xbff394ac2b758a2d9c087ff8c7eb107ed243ca5b46c7cc63077b61c842ea191d4a2f8b5f13af6a716477c85334cc9d0e76589cef061ba59fd32a48556eaa0ccb01 0x41 0xbff394ac2b758a2d9c087ff8c7eb107ed243ca5b46c7cc63077b61c842ea191d4a2f8b5f13af6a716477c85334cc9d0e76589cef061ba59fd32a48556eaa0ccb01", "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG", "SIGPUSHONLY", "2-of-2 with two identical keys and sigs pushed"