Merge pull request #4309

d38da59 Code simplifications after CTransaction::GetHash() caching (Pieter Wuille)
4949004 Add CMutableTransaction and make CTransaction immutable. (Pieter Wuille)
This commit is contained in:
Pieter Wuille 2014-06-22 20:40:53 +02:00
commit d4e4e05435
No known key found for this signature in database
GPG key ID: 8F653255C87992E0
27 changed files with 248 additions and 184 deletions

View file

@ -99,7 +99,7 @@ bool CBloomFilter::IsWithinSizeConstraints() const
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS; return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
} }
bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash) bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
{ {
bool fFound = false; bool fFound = false;
// Match if the filter contains the hash of tx // Match if the filter contains the hash of tx
@ -108,6 +108,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& ha
return true; return true;
if (isEmpty) if (isEmpty)
return false; return false;
const uint256& hash = tx.GetHash();
if (contains(hash)) if (contains(hash))
fFound = true; fFound = true;

View file

@ -83,7 +83,7 @@ public:
bool IsWithinSizeConstraints() const; bool IsWithinSizeConstraints() const;
// Also adds any outputs which match the filter to the filter (to match their spending txes) // Also adds any outputs which match the filter to the filter (to match their spending txes)
bool IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash); bool IsRelevantAndUpdate(const CTransaction& tx);
// Checks for empty and full filters to avoid wasting cpu // Checks for empty and full filters to avoid wasting cpu
void UpdateEmptyFull(); void UpdateEmptyFull();

View file

@ -127,7 +127,7 @@ public:
// CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
// vMerkleTree: 4a5e1e // vMerkleTree: 4a5e1e
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CTransaction txNew; CMutableTransaction txNew;
txNew.vin.resize(1); txNew.vin.resize(1);
txNew.vout.resize(1); txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));

View file

@ -91,11 +91,34 @@ std::string CFeeRate::ToString() const
return result; return result;
} }
uint256 CTransaction::GetHash() const CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
uint256 CMutableTransaction::GetHash() const
{ {
return SerializeHash(*this); return SerializeHash(*this);
} }
void CTransaction::UpdateHash() const
{
*const_cast<uint256*>(&hash) = SerializeHash(*this);
}
CTransaction::CTransaction() : hash(0), nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
UpdateHash();
}
CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<int*>(&nVersion) = tx.nVersion;
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
*const_cast<uint256*>(&hash) = tx.hash;
return *this;
}
int64_t CTransaction::GetValueOut() const int64_t CTransaction::GetValueOut() const
{ {
int64_t nValueOut = 0; int64_t nValueOut = 0;

View file

@ -203,49 +203,59 @@ public:
}; };
struct CMutableTransaction;
/** The basic transaction that is broadcasted on the network and contained in /** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs. * blocks. A transaction can contain multiple inputs and outputs.
*/ */
class CTransaction class CTransaction
{ {
private:
/** Memory only. */
const uint256 hash;
void UpdateHash() const;
public: public:
static CFeeRate minTxFee; static CFeeRate minTxFee;
static CFeeRate minRelayTxFee; static CFeeRate minRelayTxFee;
static const int CURRENT_VERSION=1; static const int CURRENT_VERSION=1;
int nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
unsigned int nLockTime;
CTransaction() // The local variables are made const to prevent unintended modification
{ // without updating the cached hash value. However, CTransaction is not
SetNull(); // actually immutable; deserialization and assignment are implemented,
} // and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
const int nVersion;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
const unsigned int nLockTime;
IMPLEMENT_SERIALIZE /** Construct a CTransaction that qualifies as IsNull() */
( CTransaction();
READWRITE(this->nVersion);
/** Convert a CMutableTransaction into a CTransaction. */
CTransaction(const CMutableTransaction &tx);
CTransaction& operator=(const CTransaction& tx);
IMPLEMENT_SERIALIZE(
READWRITE(*const_cast<int*>(&this->nVersion));
nVersion = this->nVersion; nVersion = this->nVersion;
READWRITE(vin); READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
READWRITE(vout); READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
READWRITE(nLockTime); READWRITE(*const_cast<unsigned int*>(&nLockTime));
if (fRead)
UpdateHash();
) )
void SetNull() bool IsNull() const {
{ return vin.empty() && vout.empty();
nVersion = CTransaction::CURRENT_VERSION;
vin.clear();
vout.clear();
nLockTime = 0;
} }
bool IsNull() const const uint256& GetHash() const {
{ return hash;
return (vin.empty() && vout.empty());
} }
uint256 GetHash() const;
// Return sum of txouts. // Return sum of txouts.
int64_t GetValueOut() const; int64_t GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because // GetValueIn() is a method on CCoinsViewCache, because
@ -261,22 +271,43 @@ public:
friend bool operator==(const CTransaction& a, const CTransaction& b) friend bool operator==(const CTransaction& a, const CTransaction& b)
{ {
return (a.nVersion == b.nVersion && return a.hash == b.hash;
a.vin == b.vin &&
a.vout == b.vout &&
a.nLockTime == b.nLockTime);
} }
friend bool operator!=(const CTransaction& a, const CTransaction& b) friend bool operator!=(const CTransaction& a, const CTransaction& b)
{ {
return !(a == b); return a.hash != b.hash;
} }
std::string ToString() const; std::string ToString() const;
void print() const; void print() const;
}; };
/** A mutable version of CTransaction. */
struct CMutableTransaction
{
int nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
unsigned int nLockTime;
CMutableTransaction();
CMutableTransaction(const CTransaction& tx);
IMPLEMENT_SERIALIZE(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
)
/** Compute the hash of this CMutableTransaction. This is computed on the
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
*/
uint256 GetHash() const;
};
/** wrapper for CTxOut that provides a more compact serialization */ /** wrapper for CTxOut that provides a more compact serialization */
class CTxOutCompressor class CTxOutCompressor
{ {
@ -465,12 +496,6 @@ public:
uint256 BuildMerkleTree() const; uint256 BuildMerkleTree() const;
const uint256 &GetTxHash(unsigned int nIndex) const {
assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
assert(nIndex < vtx.size());
return vMerkleTree[nIndex];
}
std::vector<uint256> GetMerkleBranch(int nIndex) const; std::vector<uint256> GetMerkleBranch(int nIndex) const;
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
void print() const; void print() const;

View file

@ -130,8 +130,8 @@ namespace {
namespace { namespace {
struct CMainSignals { struct CMainSignals {
// Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in. // Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
boost::signals2::signal<void (const uint256 &, const CTransaction &, const CBlock *)> SyncTransaction; boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
// Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). // Notifies listeners of an erased transaction (currently disabled, requires transaction replacement).
boost::signals2::signal<void (const uint256 &)> EraseTransaction; boost::signals2::signal<void (const uint256 &)> EraseTransaction;
// Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). // Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible).
@ -146,7 +146,7 @@ struct CMainSignals {
} }
void RegisterWallet(CWalletInterface* pwalletIn) { void RegisterWallet(CWalletInterface* pwalletIn) {
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
@ -160,7 +160,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn) {
g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
} }
void UnregisterAllWallets() { void UnregisterAllWallets() {
@ -172,8 +172,8 @@ void UnregisterAllWallets() {
g_signals.SyncTransaction.disconnect_all_slots(); g_signals.SyncTransaction.disconnect_all_slots();
} }
void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) { void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
g_signals.SyncTransaction(hash, tx, pblock); g_signals.SyncTransaction(tx, pblock);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -952,7 +952,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
pool.addUnchecked(hash, entry); pool.addUnchecked(hash, entry);
} }
g_signals.SyncTransaction(hash, tx, NULL); g_signals.SyncTransaction(tx, NULL);
return true; return true;
} }
@ -1479,7 +1479,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev)
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
{ {
bool ret; bool ret;
// mark inputs spent // mark inputs spent
@ -1494,7 +1494,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
} }
// add outputs // add outputs
ret = inputs.SetCoins(txhash, CCoins(tx, nHeight)); ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight));
assert(ret); assert(ret);
} }
@ -1767,8 +1767,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) { if (fEnforceBIP30) {
for (unsigned int i = 0; i < block.vtx.size(); i++) { BOOST_FOREACH(const CTransaction& tx, block.vtx) {
uint256 hash = block.GetTxHash(i); const uint256& hash = tx.GetHash();
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30"); REJECT_INVALID, "bad-txns-BIP30");
@ -1829,11 +1829,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
} }
CTxUndo txundo; CTxUndo txundo;
UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i)); UpdateCoins(tx, state, view, txundo, pindex->nHeight);
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo); blockundo.vtxundo.push_back(txundo);
vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
} }
int64_t nTime = GetTimeMicros() - nStart; int64_t nTime = GetTimeMicros() - nStart;
@ -1892,13 +1892,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
assert(ret); assert(ret);
// Watch for transactions paying to me // Watch for transactions paying to me
for (unsigned int i = 0; i < block.vtx.size(); i++) BOOST_FOREACH(const CTransaction& tx, block.vtx)
g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block); g_signals.SyncTransaction(tx, &block);
// Watch for changes to the previous coinbase transaction. // Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase; static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase); g_signals.UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.GetTxHash(0); hashPrevBestCoinBase = block.vtx[0].GetHash();
return true; return true;
} }
@ -1996,7 +1996,7 @@ bool static DisconnectTip(CValidationState &state) {
// Let wallets know transactions went from 1-confirmed to // Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted: // 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) { BOOST_FOREACH(const CTransaction &tx, block.vtx) {
SyncWithWallets(tx.GetHash(), tx, NULL); SyncWithWallets(tx, NULL);
} }
return true; return true;
} }
@ -2036,11 +2036,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
// Tell wallet about transactions that went from mempool // Tell wallet about transactions that went from mempool
// to conflicted: // to conflicted:
BOOST_FOREACH(const CTransaction &tx, txConflicted) { BOOST_FOREACH(const CTransaction &tx, txConflicted) {
SyncWithWallets(tx.GetHash(), tx, NULL); SyncWithWallets(tx, NULL);
} }
// ... and about transactions that got confirmed: // ... and about transactions that got confirmed:
BOOST_FOREACH(const CTransaction &tx, block.vtx) { BOOST_FOREACH(const CTransaction &tx, block.vtx) {
SyncWithWallets(tx.GetHash(), tx, &block); SyncWithWallets(tx, &block);
} }
return true; return true;
} }
@ -2381,16 +2381,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
if (!CheckTransaction(tx, state)) if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed"); return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the
// block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation.
block.BuildMerkleTree();
// Check for duplicate txids. This is caught by ConnectInputs(), // Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack: // but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx; set<uint256> uniqueTx;
for (unsigned int i = 0; i < block.vtx.size(); i++) { BOOST_FOREACH(const CTransaction &tx, block.vtx) {
uniqueTx.insert(block.GetTxHash(i)); uniqueTx.insert(tx.GetHash());
} }
if (uniqueTx.size() != block.vtx.size()) if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"), return state.DoS(100, error("CheckBlock() : duplicate transaction"),
@ -2406,7 +2401,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
REJECT_INVALID, "bad-blk-sigops", true); REJECT_INVALID, "bad-blk-sigops", true);
// Check merkle root // Check merkle root
if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back()) if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
REJECT_INVALID, "bad-txnmrklroot", true); REJECT_INVALID, "bad-txnmrklroot", true);
@ -2682,8 +2677,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
for (unsigned int i = 0; i < block.vtx.size(); i++) for (unsigned int i = 0; i < block.vtx.size(); i++)
{ {
uint256 hash = block.vtx[i].GetHash(); const uint256& hash = block.vtx[i].GetHash();
if (filter.IsRelevantAndUpdate(block.vtx[i], hash)) if (filter.IsRelevantAndUpdate(block.vtx[i]))
{ {
vMatch.push_back(true); vMatch.push_back(true);
vMatchedTxn.push_back(make_pair(i, hash)); vMatchedTxn.push_back(make_pair(i, hash));
@ -3832,7 +3827,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
{ {
mempool.check(pcoinsTip); mempool.check(pcoinsTip);
RelayTransaction(tx, inv.hash); RelayTransaction(tx);
mapAlreadyAskedFor.erase(inv); mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash); vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash); vEraseQueue.push_back(inv.hash);
@ -3862,7 +3857,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
{ {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx, orphanHash); RelayTransaction(orphanTx);
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash));
vWorkQueue.push_back(orphanHash); vWorkQueue.push_back(orphanHash);
vEraseQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash);
@ -3947,7 +3942,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CTransaction tx; CTransaction tx;
bool fInMemPool = mempool.lookup(hash, tx); bool fInMemPool = mempool.lookup(hash, tx);
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx, hash)) || if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) ||
(!pfrom->pfilter)) (!pfrom->pfilter))
vInv.push_back(inv); vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) { if (vInv.size() == MAX_INV_SZ) {

View file

@ -113,7 +113,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn);
/** Unregister all wallets from core */ /** Unregister all wallets from core */
void UnregisterAllWallets(); void UnregisterAllWallets();
/** Push an updated transaction to all registered wallets */ /** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL); void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
/** Register with a network node to receive its signals */ /** Register with a network node to receive its signals */
void RegisterNodeSignals(CNodeSignals& nodeSignals); void RegisterNodeSignals(CNodeSignals& nodeSignals);
@ -294,7 +294,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
std::vector<CScriptCheck> *pvChecks = NULL); std::vector<CScriptCheck> *pvChecks = NULL);
// Apply the effects of this transaction on the UTXO set represented by view // Apply the effects of this transaction on the UTXO set represented by view
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash); void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight);
// Context-independent validity checks // Context-independent validity checks
bool CheckTransaction(const CTransaction& tx, CValidationState& state); bool CheckTransaction(const CTransaction& tx, CValidationState& state);
@ -1129,7 +1129,7 @@ public:
class CWalletInterface { class CWalletInterface {
protected: protected:
virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0; virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) =0;
virtual void EraseFromWallet(const uint256 &hash) =0; virtual void EraseFromWallet(const uint256 &hash) =0;
virtual void SetBestChain(const CBlockLocator &locator) =0; virtual void SetBestChain(const CBlockLocator &locator) =0;
virtual void UpdatedTransaction(const uint256 &hash) =0; virtual void UpdatedTransaction(const uint256 &hash) =0;

View file

@ -86,14 +86,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience CBlock *pblock = &pblocktemplate->block; // pointer for convenience
// Create coinbase tx // Create coinbase tx
CTransaction txNew; CMutableTransaction txNew;
txNew.vin.resize(1); txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull(); txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1); txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].scriptPubKey = scriptPubKeyIn;
// Add our coinbase tx as first transaction // Add dummy coinbase tx as first transaction
pblock->vtx.push_back(txNew); pblock->vtx.push_back(CTransaction());
pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxFees.push_back(-1); // updated at end
pblocktemplate->vTxSigOps.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end
@ -254,8 +254,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
continue; continue;
CTxUndo txundo; CTxUndo txundo;
uint256 hash = tx.GetHash(); const uint256& hash = tx.GetHash();
UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash); UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1);
// Added // Added
pblock->vtx.push_back(tx); pblock->vtx.push_back(tx);
@ -294,7 +294,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
nLastBlockSize = nBlockSize; nLastBlockSize = nBlockSize;
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); // Compute final coinbase transaction.
txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
txNew.vin[0].scriptSig = CScript() << OP_0 << OP_0;
pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees; pblocktemplate->vTxFees[0] = -nFees;
// Fill in header // Fill in header
@ -302,7 +305,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
UpdateTime(*pblock, pindexPrev); UpdateTime(*pblock, pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
pblock->nNonce = 0; pblock->nNonce = 0;
pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
CBlockIndex indexDummy(*pblock); CBlockIndex indexDummy(*pblock);
@ -328,9 +330,11 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
} }
++nExtraNonce; ++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; CMutableTransaction txCoinbase(pblock->vtx[0]);
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
assert(txCoinbase.vin[0].scriptSig.size() <= 100);
pblock->vtx[0] = txCoinbase;
pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->hashMerkleRoot = pblock->BuildMerkleTree();
} }

View file

@ -1812,17 +1812,17 @@ instance_of_cnetcleanup;
void RelayTransaction(const CTransaction& tx, const uint256& hash) void RelayTransaction(const CTransaction& tx)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000); ss.reserve(10000);
ss << tx; ss << tx;
RelayTransaction(tx, hash, ss); RelayTransaction(tx, ss);
} }
void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss) void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{ {
CInv inv(MSG_TX, hash); CInv inv(MSG_TX, tx.GetHash());
{ {
LOCK(cs_mapRelay); LOCK(cs_mapRelay);
// Expire old relay messages // Expire old relay messages
@ -1844,7 +1844,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
LOCK(pnode->cs_filter); LOCK(pnode->cs_filter);
if (pnode->pfilter) if (pnode->pfilter)
{ {
if (pnode->pfilter->IsRelevantAndUpdate(tx, hash)) if (pnode->pfilter->IsRelevantAndUpdate(tx))
pnode->PushInventory(inv); pnode->PushInventory(inv);
} else } else
pnode->PushInventory(inv); pnode->PushInventory(inv);

View file

@ -726,8 +726,8 @@ public:
class CTransaction; class CTransaction;
void RelayTransaction(const CTransaction& tx, const uint256& hash); void RelayTransaction(const CTransaction& tx);
void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss); void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
/** Access to the (IP) address database (peers.dat) */ /** Access to the (IP) address database (peers.dat) */
class CAddrDB class CAddrDB

View file

@ -440,7 +440,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// nPayAmount // nPayAmount
qint64 nPayAmount = 0; qint64 nPayAmount = 0;
bool fDust = false; bool fDust = false;
CTransaction txDummy; CMutableTransaction txDummy;
foreach(const qint64 &amount, CoinControlDialog::payAmounts) foreach(const qint64 &amount, CoinControlDialog::payAmounts)
{ {
nPayAmount += amount; nPayAmount += amount;

View file

@ -349,7 +349,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
Array inputs = params[0].get_array(); Array inputs = params[0].get_array();
Object sendTo = params[1].get_obj(); Object sendTo = params[1].get_obj();
CTransaction rawTx; CMutableTransaction rawTx;
BOOST_FOREACH(const Value& input, inputs) BOOST_FOREACH(const Value& input, inputs)
{ {
@ -554,11 +554,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CTransaction> txVariants; vector<CMutableTransaction> txVariants;
while (!ssData.empty()) while (!ssData.empty())
{ {
try { try {
CTransaction tx; CMutableTransaction tx;
ssData >> tx; ssData >> tx;
txVariants.push_back(tx); txVariants.push_back(tx);
} }
@ -572,7 +572,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
// mergedTx will end up with all the signatures; it // mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx: // starts as a clone of the rawtx:
CTransaction mergedTx(txVariants[0]); CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true; bool fComplete = true;
// Fetch previous transactions (inputs): // Fetch previous transactions (inputs):
@ -713,7 +713,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures: // ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants) BOOST_FOREACH(const CMutableTransaction& txv, txVariants)
{ {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
} }
@ -770,7 +770,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
catch (std::exception &e) { catch (std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
} }
uint256 hashTx = tx.GetHash(); const uint256 &hashTx = tx.GetHash();
CCoinsViewCache &view = *pcoinsTip; CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins; CCoins existingCoins;
@ -780,7 +780,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
// push to local node and sync with wallets // push to local node and sync with wallets
CValidationState state; CValidationState state;
if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees))
SyncWithWallets(hashTx, tx, NULL); SyncWithWallets(tx, NULL);
else { else {
if(state.IsInvalid()) if(state.IsInvalid())
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
@ -790,7 +790,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
} else if (fHaveChain) { } else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
} }
RelayTransaction(tx, hashTx); RelayTransaction(tx);
return hashTx.GetHex(); return hashTx.GetHex();
} }

View file

@ -1636,7 +1636,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
} }
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType) bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{ {
assert(nIn < txTo.vin.size()); assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn]; CTxIn& txin = txTo.vin[nIn];
@ -1671,7 +1671,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0); return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
} }
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{ {
assert(nIn < txTo.vin.size()); assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn]; CTxIn& txin = txTo.vin[nIn];
@ -1689,7 +1689,7 @@ static CScript PushAll(const vector<valtype>& values)
return result; return result;
} }
static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
const vector<valtype>& vSolutions, const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2) vector<valtype>& sigs1, vector<valtype>& sigs2)
{ {

View file

@ -20,6 +20,7 @@
class CCoins; class CCoins;
class CKeyStore; class CKeyStore;
class CTransaction; class CTransaction;
class CMutableTransaction;
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
@ -805,8 +806,8 @@ bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys); void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, // Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,

View file

@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
// 50 orphan transactions: // 50 orphan transactions:
for (int i = 0; i < 50; i++) for (int i = 0; i < 50; i++)
{ {
CTransaction tx; CMutableTransaction tx;
tx.vin.resize(1); tx.vin.resize(1);
tx.vin[0].prevout.n = 0; tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = GetRandHash(); tx.vin[0].prevout.hash = GetRandHash();
@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{ {
CTransaction txPrev = RandomOrphan(); CTransaction txPrev = RandomOrphan();
CTransaction tx; CMutableTransaction tx;
tx.vin.resize(1); tx.vin.resize(1);
tx.vin[0].prevout.n = 0; tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = txPrev.GetHash(); tx.vin[0].prevout.hash = txPrev.GetHash();
@ -201,7 +201,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{ {
CTransaction txPrev = RandomOrphan(); CTransaction txPrev = RandomOrphan();
CTransaction tx; CMutableTransaction tx;
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT; tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
@ -242,10 +242,10 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
// 100 orphan transactions: // 100 orphan transactions:
static const int NPREV=100; static const int NPREV=100;
CTransaction orphans[NPREV]; CMutableTransaction orphans[NPREV];
for (int i = 0; i < NPREV; i++) for (int i = 0; i < NPREV; i++)
{ {
CTransaction& tx = orphans[i]; CMutableTransaction& tx = orphans[i];
tx.vin.resize(1); tx.vin.resize(1);
tx.vin[0].prevout.n = 0; tx.vin[0].prevout.n = 0;
tx.vin[0].prevout.hash = GetRandHash(); tx.vin[0].prevout.hash = GetRandHash();
@ -258,7 +258,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
} }
// Create a transaction that depends on orphans: // Create a transaction that depends on orphans:
CTransaction tx; CMutableTransaction tx;
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT; tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());

View file

@ -83,13 +83,21 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "y"; wtx.mapValue["comment"] = "y";
--wtx.nLockTime; // Just to change the hash :) {
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
*static_cast<CTransaction*>(&wtx) = CTransaction(tx);
}
pwalletMain->AddToWallet(wtx); pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[1]->nTimeReceived = (unsigned int)1333333336; vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
wtx.mapValue["comment"] = "x"; wtx.mapValue["comment"] = "x";
--wtx.nLockTime; // Just to change the hash :) {
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
*static_cast<CTransaction*>(&wtx) = CTransaction(tx);
}
pwalletMain->AddToWallet(wtx); pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nTimeReceived = (unsigned int)1333333329;

View file

@ -118,33 +118,33 @@ BOOST_AUTO_TEST_CASE(bloom_match)
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")); filter.insert(uint256("0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match tx hash"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
// byte-reversed tx hash // byte-reversed tx hash
filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")); filter.insert(ParseHex("6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized tx hash"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01")); filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input signature"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339")); filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match input pub key"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19")); filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx, spendingTx.GetHash()), "Simple Bloom filter didn't add output"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431")); filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431"));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match output address"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match COutPoint"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); COutPoint prevOutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
@ -154,23 +154,23 @@ BOOST_AUTO_TEST_CASE(bloom_match)
memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data); filter.insert(data);
} }
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter didn't match manually serialized COutPoint"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")); filter.insert(uint256("00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436"));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random tx hash"); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431")); filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431"));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched random address"); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1)); filter.insert(COutPoint(uint256("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about"); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0)); filter.insert(COutPoint(uint256("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx, tx.GetHash()), "Simple Bloom filter matched COutPoint for an output we didn't care about"); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
} }
BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_AUTO_TEST_CASE(merkle_block_1)

View file

@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{ {
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
CBlockTemplate *pblocktemplate; CBlockTemplate *pblocktemplate;
CTransaction tx,tx2; CMutableTransaction tx,tx2;
CScript script; CScript script;
uint256 hash; uint256 hash;
@ -68,10 +68,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlock *pblock = &pblocktemplate->block; // pointer for convenience CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1; pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1; pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
pblock->vtx[0].vin[0].scriptSig = CScript(); CMutableTransaction txCoinbase(pblock->vtx[0]);
pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce); txCoinbase.vin[0].scriptSig = CScript();
pblock->vtx[0].vin[0].scriptSig.push_back(chainActive.Height()); txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
pblock->vtx[0].vout[0].scriptPubKey = CScript(); txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = CTransaction(txCoinbase);
if (txFirst.size() < 2) if (txFirst.size() < 2)
txFirst.push_back(new CTransaction(pblock->vtx[0])); txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->hashMerkleRoot = pblock->BuildMerkleTree();

View file

@ -55,13 +55,13 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
CScript escrow; CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
CTransaction txFrom; // Funding transaction CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3); txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow; txFrom.vout[2].scriptPubKey = escrow;
CTransaction txTo[3]; // Spending transaction CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -270,13 +270,13 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
CScript escrow; CScript escrow;
escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG;
CTransaction txFrom; // Funding transaction CMutableTransaction txFrom; // Funding transaction
txFrom.vout.resize(3); txFrom.vout.resize(3);
txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[0].scriptPubKey = a_and_b;
txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[1].scriptPubKey = a_or_b;
txFrom.vout[2].scriptPubKey = escrow; txFrom.vout[2].scriptPubKey = escrow;
CTransaction txTo[3]; // Spending transaction CMutableTransaction txTo[3]; // Spending transaction
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);

View file

@ -36,9 +36,9 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
// build a block with some dummy transactions // build a block with some dummy transactions
CBlock block; CBlock block;
for (unsigned int j=0; j<nTx; j++) { for (unsigned int j=0; j<nTx; j++) {
CTransaction tx; CMutableTransaction tx;
tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique
block.vtx.push_back(tx); block.vtx.push_back(CTransaction(tx));
} }
// calculate actual merkle root and height // calculate actual merkle root and height

View file

@ -30,11 +30,11 @@ static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
{ {
// Create dummy to/from transactions: // Create dummy to/from transactions:
CTransaction txFrom; CMutableTransaction txFrom;
txFrom.vout.resize(1); txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = scriptPubKey; txFrom.vout[0].scriptPubKey = scriptPubKey;
CTransaction txTo; CMutableTransaction txTo;
txTo.vin.resize(1); txTo.vin.resize(1);
txTo.vout.resize(1); txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0; txTo.vin[0].prevout.n = 0;
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(sign)
evalScripts[i].SetDestination(standardScripts[i].GetID()); evalScripts[i].SetDestination(standardScripts[i].GetID());
} }
CTransaction txFrom; // Funding transaction: CMutableTransaction txFrom; // Funding transaction:
string reason; string reason;
txFrom.vout.resize(8); txFrom.vout.resize(8);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(sign)
} }
BOOST_CHECK(IsStandardTx(txFrom, reason)); BOOST_CHECK(IsStandardTx(txFrom, reason));
CTransaction txTo[8]; // Spending transactions CMutableTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set)
keystore.AddCScript(inner[i]); keystore.AddCScript(inner[i]);
} }
CTransaction txFrom; // Funding transaction: CMutableTransaction txFrom; // Funding transaction:
string reason; string reason;
txFrom.vout.resize(4); txFrom.vout.resize(4);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -183,7 +183,7 @@ BOOST_AUTO_TEST_CASE(set)
} }
BOOST_CHECK(IsStandardTx(txFrom, reason)); BOOST_CHECK(IsStandardTx(txFrom, reason));
CTransaction txTo[4]; // Spending transactions CMutableTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
keys.push_back(key[i].GetPubKey()); keys.push_back(key[i].GetPubKey());
} }
CTransaction txFrom; CMutableTransaction txFrom;
txFrom.vout.resize(6); txFrom.vout.resize(6);
// First three are standard: // First three are standard:
@ -299,7 +299,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0)); coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0));
CTransaction txTo; CMutableTransaction txTo;
txTo.vout.resize(1); txTo.vout.resize(1);
txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
@ -326,7 +326,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].scriptSig = t; txTo.vin[i].scriptSig = t;
} }
CTransaction txToNonStd; CMutableTransaction txToNonStd;
txToNonStd.vout.resize(1); txToNonStd.vout.resize(1);
txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID());
txToNonStd.vout[0].nValue = 1000; txToNonStd.vout[0].nValue = 1000;

View file

@ -240,11 +240,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CScript scriptPubKey12; CScript scriptPubKey12;
scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG; scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG;
CTransaction txFrom12; CMutableTransaction txFrom12;
txFrom12.vout.resize(1); txFrom12.vout.resize(1);
txFrom12.vout[0].scriptPubKey = scriptPubKey12; txFrom12.vout[0].scriptPubKey = scriptPubKey12;
CTransaction txTo12; CMutableTransaction txTo12;
txTo12.vin.resize(1); txTo12.vin.resize(1);
txTo12.vout.resize(1); txTo12.vout.resize(1);
txTo12.vin[0].prevout.n = 0; txTo12.vin[0].prevout.n = 0;
@ -274,11 +274,11 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript scriptPubKey23; CScript scriptPubKey23;
scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG; scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG;
CTransaction txFrom23; CMutableTransaction txFrom23;
txFrom23.vout.resize(1); txFrom23.vout.resize(1);
txFrom23.vout[0].scriptPubKey = scriptPubKey23; txFrom23.vout[0].scriptPubKey = scriptPubKey23;
CTransaction txTo23; CMutableTransaction txTo23;
txTo23.vin.resize(1); txTo23.vin.resize(1);
txTo23.vout.resize(1); txTo23.vout.resize(1);
txTo23.vin[0].prevout.n = 0; txTo23.vin[0].prevout.n = 0;
@ -345,11 +345,11 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
keystore.AddKey(key); keystore.AddKey(key);
} }
CTransaction txFrom; CMutableTransaction txFrom;
txFrom.vout.resize(1); txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID()); txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID());
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
CTransaction txTo; CMutableTransaction txTo;
txTo.vin.resize(1); txTo.vin.resize(1);
txTo.vout.resize(1); txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0; txTo.vin[0].prevout.n = 0;

View file

@ -28,7 +28,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
return 1; return 1;
} }
CTransaction txTmp(txTo); CMutableTransaction txTmp(txTo);
// In case concatenating two scripts ends up with two codeseparators, // In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible incompatibilities. // or an extra one at the end, this prevents all those possible incompatibilities.
@ -90,7 +90,7 @@ void static RandomScript(CScript &script) {
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
} }
void static RandomTransaction(CTransaction &tx, bool fSingle) { void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
tx.nVersion = insecure_rand(); tx.nVersion = insecure_rand();
tx.vin.clear(); tx.vin.clear();
tx.vout.clear(); tx.vout.clear();
@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#endif #endif
for (int i=0; i<nRandomTests; i++) { for (int i=0; i<nRandomTests; i++) {
int nHashType = insecure_rand(); int nHashType = insecure_rand();
CTransaction txTo; CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode; CScript scriptCode;
RandomScript(scriptCode); RandomScript(scriptCode);

View file

@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
vector<unsigned char> vch(ch, ch + sizeof(ch) -1); vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
CTransaction tx; CMutableTransaction tx;
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid."); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
@ -224,10 +224,10 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
// paid to a TX_PUBKEYHASH. // paid to a TX_PUBKEYHASH.
// //
static std::vector<CTransaction> static std::vector<CMutableTransaction>
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet) SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet)
{ {
std::vector<CTransaction> dummyTransactions; std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2); dummyTransactions.resize(2);
// Add some keys to the keystore: // Add some keys to the keystore:
@ -261,9 +261,9 @@ BOOST_AUTO_TEST_CASE(test_Get)
CBasicKeyStore keystore; CBasicKeyStore keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy); CCoinsViewCache coins(coinsDummy);
std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CTransaction t1; CMutableTransaction t1;
t1.vin.resize(3); t1.vin.resize(3);
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t1.vin[0].prevout.n = 1; t1.vin[0].prevout.n = 1;
@ -296,9 +296,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
CBasicKeyStore keystore; CBasicKeyStore keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(coinsDummy); CCoinsViewCache coins(coinsDummy);
std::vector<CTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
CTransaction t; CMutableTransaction t;
t.vin.resize(1); t.vin.resize(1);
t.vin[0].prevout.hash = dummyTransactions[0].GetHash(); t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
t.vin[0].prevout.n = 1; t.vin[0].prevout.n = 1;

View file

@ -31,16 +31,18 @@ static vector<COutput> vCoins;
static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
{ {
static int nextLockTime = 0; static int nextLockTime = 0;
CTransaction tx; CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(nInput+1); tx.vout.resize(nInput+1);
tx.vout[nInput].nValue = nValue; tx.vout[nInput].nValue = nValue;
if (fIsFromMe) {
// IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
CWalletTx* wtx = new CWalletTx(&wallet, tx); CWalletTx* wtx = new CWalletTx(&wallet, tx);
if (fIsFromMe) if (fIsFromMe)
{ {
// IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(),
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
wtx->vin.resize(1);
wtx->fDebitCached = true; wtx->fDebitCached = true;
wtx->nDebitCached = 1; wtx->nDebitCached = 1;
} }

View file

@ -603,11 +603,11 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
// Add a transaction to the wallet, or update it. // Add a transaction to the wallet, or update it.
// pblock is optional, but should be provided if the transaction is known to be in a block. // pblock is optional, but should be provided if the transaction is known to be in a block.
// If fUpdate is true, existing transactions will be updated. // If fUpdate is true, existing transactions will be updated.
bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{ {
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
bool fExisted = mapWallet.count(hash); bool fExisted = mapWallet.count(tx.GetHash());
if (fExisted && !fUpdate) return false; if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx)) if (fExisted || IsMine(tx) || IsFromMe(tx))
{ {
@ -621,10 +621,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction&
return false; return false;
} }
void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock) void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true)) if (!AddToWalletIfInvolvingMe(tx, pblock, true))
return; // Not one of ours return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance // If a transaction changes 'conflicted' state, that changes the balance
@ -870,7 +870,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ReadBlockFromDisk(block, pindex); ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx) BOOST_FOREACH(CTransaction& tx, block.vtx)
{ {
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++; ret++;
} }
pindex = chainActive.Next(pindex); pindex = chainActive.Next(pindex);
@ -909,9 +909,8 @@ void CWalletTx::RelayWalletTransaction()
if (!IsCoinBase()) if (!IsCoinBase())
{ {
if (GetDepthInMainChain() == 0) { if (GetDepthInMainChain() == 0) {
uint256 hash = GetHash(); LogPrintf("Relaying wtx %s\n", GetHash().ToString());
LogPrintf("Relaying wtx %s\n", hash.ToString()); RelayTransaction((CTransaction)*this);
RelayTransaction((CTransaction)*this, hash);
} }
} }
} }
@ -1245,6 +1244,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
} }
wtxNew.BindWallet(this); wtxNew.BindWallet(this);
CMutableTransaction txNew;
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
@ -1252,8 +1252,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
nFeeRet = payTxFee.GetFeePerK(); nFeeRet = payTxFee.GetFeePerK();
while (true) while (true)
{ {
wtxNew.vin.clear(); txNew.vin.clear();
wtxNew.vout.clear(); txNew.vout.clear();
wtxNew.fFromMe = true; wtxNew.fFromMe = true;
int64_t nTotalValue = nValue + nFeeRet; int64_t nTotalValue = nValue + nFeeRet;
@ -1267,7 +1267,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
strFailReason = _("Transaction amount too small"); strFailReason = _("Transaction amount too small");
return false; return false;
} }
wtxNew.vout.push_back(txout); txNew.vout.push_back(txout);
} }
// Choose coins to use // Choose coins to use
@ -1331,8 +1331,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
else else
{ {
// Insert change txn at random position: // Insert change txn at random position:
vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); vector<CTxOut>::iterator position = txNew.vout.begin()+GetRandInt(txNew.vout.size()+1);
wtxNew.vout.insert(position, newTxOut); txNew.vout.insert(position, newTxOut);
} }
} }
else else
@ -1340,17 +1340,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Fill vin // Fill vin
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign // Sign
int nIn = 0; int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) if (!SignSignature(*this, *coin.first, txNew, nIn++))
{ {
strFailReason = _("Signing transaction failed"); strFailReason = _("Signing transaction failed");
return false; return false;
} }
// Embed the constructed transaction data in wtxNew.
*static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
// Limit size // Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE) if (nBytes >= MAX_STANDARD_TX_SIZE)

View file

@ -244,8 +244,8 @@ public:
void MarkDirty(); void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false);
void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock); void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void EraseFromWallet(const uint256 &hash); void EraseFromWallet(const uint256 &hash);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions(); void ReacceptWalletTransactions();