aboutsummaryrefslogtreecommitdiff
path: root/src/primitives
diff options
context:
space:
mode:
authorlangerhans <[email protected]>2019-06-09 19:49:48 +0200
committerlangerhans <[email protected]>2019-06-09 19:51:03 +0200
commitd278efaccdc45e7155147d2c86a50f193eafdc07 (patch)
tree05cf92afa059fafff80e460c1619edd5bec231b3 /src/primitives
parentRevert "Change fPIE to fPIC (#1420)" (#1447) (diff)
parentMark 1.14 ready for release (diff)
downloaddiscoin-d278efaccdc45e7155147d2c86a50f193eafdc07.tar.xz
discoin-d278efaccdc45e7155147d2c86a50f193eafdc07.zip
Merge branch '1.14-branding'
Diffstat (limited to 'src/primitives')
-rw-r--r--src/primitives/block.cpp119
-rw-r--r--src/primitives/block.h30
-rw-r--r--src/primitives/pureheader.cpp7
-rw-r--r--src/primitives/pureheader.h187
-rw-r--r--src/primitives/transaction.cpp57
-rw-r--r--src/primitives/transaction.h282
6 files changed, 367 insertions, 315 deletions
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 7bd64d77c..1df912d35 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,125 +15,36 @@ void CBlockHeader::SetAuxpow (CAuxPow* apow)
if (apow)
{
auxpow.reset(apow);
- nVersion.SetAuxpow(true);
+ SetAuxpowFlag(true);
} else
{
auxpow.reset();
- nVersion.SetAuxpow(false);
+ SetAuxpowFlag(false);
}
}
-uint256 CBlock::BuildMerkleTree(bool* fMutated) const
-{
- /* WARNING! If you're reading this because you're learning about crypto
- and/or designing a new system that will use merkle trees, keep in mind
- that the following merkle tree algorithm has a serious flaw related to
- duplicate txids, resulting in a vulnerability (CVE-2012-2459).
-
- The reason is that if the number of hashes in the list at a given time
- is odd, the last one is duplicated before computing the next level (which
- is unusual in Merkle trees). This results in certain sequences of
- transactions leading to the same merkle root. For example, these two
- trees:
-
- A A
- / \ / \
- B C B C
- / \ | / \ / \
- D E F D E F F
- / \ / \ / \ / \ / \ / \ / \
- 1 2 3 4 5 6 1 2 3 4 5 6 5 6
-
- for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
- 6 are repeated) result in the same root hash A (because the hash of both
- of (F) and (F,F) is C).
-
- The vulnerability results from being able to send a block with such a
- transaction list, with the same merkle root, and the same block hash as
- the original without duplication, resulting in failed validation. If the
- receiving node proceeds to mark that block as permanently invalid
- however, it will fail to accept further unmodified (and thus potentially
- valid) versions of the same block. We defend against this by detecting
- the case where we would hash two identical hashes at the end of the list
- together, and treating that identically to the block having an invalid
- merkle root. Assuming no double-SHA256 collisions, this will detect all
- known ways of changing the transactions without affecting the merkle
- root.
- */
- vMerkleTree.clear();
- vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
- for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
- vMerkleTree.push_back(it->GetHash());
- int j = 0;
- bool mutated = false;
- for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
- {
- for (int i = 0; i < nSize; i += 2)
- {
- int i2 = std::min(i+1, nSize-1);
- if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
- // Two identical hashes at the end of the list at a particular level.
- mutated = true;
- }
- vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
- BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
- }
- j += nSize;
- }
- if (fMutated) {
- *fMutated = mutated;
- }
- return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());
-}
-
-std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
-{
- if (vMerkleTree.empty())
- BuildMerkleTree();
- std::vector<uint256> vMerkleBranch;
- int j = 0;
- for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
- {
- int i = std::min(nIndex^1, nSize-1);
- vMerkleBranch.push_back(vMerkleTree[j+i]);
- nIndex >>= 1;
- j += nSize;
- }
- return vMerkleBranch;
-}
-
-uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
-{
- if (nIndex == -1)
- return uint256();
- for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
- {
- if (nIndex & 1)
- hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
- else
- hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
- nIndex >>= 1;
- }
- return hash;
-}
-
std::string CBlock::ToString() const
{
std::stringstream s;
- s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
+ s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
- nVersion.GetFullVersion(),
+ nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
nTime, nBits, nNonce,
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)
{
- s << " " << vtx[i].ToString() << "\n";
+ s << " " << vtx[i]->ToString() << "\n";
}
- s << " vMerkleTree: ";
- for (unsigned int i = 0; i < vMerkleTree.size(); i++)
- s << " " << vMerkleTree[i].ToString();
- s << "\n";
return s.str();
}
+
+int64_t GetBlockWeight(const CBlock& block)
+{
+ // This implements the weight = (stripped_size * 4) + witness_size formula,
+ // using only serialization with and without witness data. As witness_size
+ // is equal to total_size - stripped_size, this formula is identical to:
+ // weight = (stripped_size * 3) + total_size.
+ return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
+}
diff --git a/src/primitives/block.h b/src/primitives/block.h
index d59ac4427..dcde500ab 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -35,11 +35,11 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CPureBlockHeader*)this);
- nVersion = this->nVersion;
- if (this->nVersion.IsAuxpow()) {
+ if (this->IsAuxpow())
+ {
if (ser_action.ForRead())
auxpow.reset(new CAuxPow());
assert(auxpow);
@@ -54,11 +54,6 @@ public:
auxpow.reset();
}
- int64_t GetBlockTime() const
- {
- return (int64_t)nTime;
- }
-
/**
* Set the block's auxpow (or unset it). This takes care of updating
* the version accordingly.
@@ -72,10 +67,10 @@ class CBlock : public CBlockHeader
{
public:
// network and disk
- std::vector<CTransaction> vtx;
+ std::vector<CTransactionRef> vtx;
// memory only
- mutable std::vector<uint256> vMerkleTree;
+ mutable bool fChecked;
CBlock()
{
@@ -91,7 +86,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CBlockHeader*)this);
READWRITE(vtx);
}
@@ -100,7 +95,7 @@ public:
{
CBlockHeader::SetNull();
vtx.clear();
- vMerkleTree.clear();
+ fChecked = false;
}
CBlockHeader GetBlockHeader() const
@@ -127,7 +122,6 @@ public:
std::string ToString() const;
};
-
/** Describes a place in the block chain to another node such that if the
* other node doesn't have the same branch, it can find a recent common trunk.
* The further back it is, the further before the fork it may be.
@@ -146,8 +140,9 @@ struct CBlockLocator
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ int nVersion = s.GetVersion();
+ if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
}
@@ -163,4 +158,7 @@ struct CBlockLocator
}
};
+/** Compute the consensus-critical block weight (see BIP 141). */
+int64_t GetBlockWeight(const CBlock& tx);
+
#endif // BITCOIN_PRIMITIVES_BLOCK_H
diff --git a/src/primitives/pureheader.cpp b/src/primitives/pureheader.cpp
index 94f14499b..9a339bf1f 100644
--- a/src/primitives/pureheader.cpp
+++ b/src/primitives/pureheader.cpp
@@ -10,6 +10,13 @@
#include "hash.h"
#include "utilstrencodings.h"
+void CPureBlockHeader::SetBaseVersion(int32_t nBaseVersion, int32_t nChainId)
+{
+ assert(nBaseVersion >= 1 && nBaseVersion < VERSION_AUXPOW);
+ assert(!IsAuxpow());
+ nVersion = nBaseVersion | (nChainId * VERSION_CHAIN_START);
+}
+
uint256 CPureBlockHeader::GetHash() const
{
return SerializeHash(*this);
diff --git a/src/primitives/pureheader.h b/src/primitives/pureheader.h
index 25f1ce98b..841743632 100644
--- a/src/primitives/pureheader.h
+++ b/src/primitives/pureheader.h
@@ -10,24 +10,30 @@
#include "uint256.h"
/**
- * Encapsulate a block version. This takes care of building it up
- * from a base version, the modifier flags (like auxpow) and
- * also the auxpow chain ID.
+ * A block header without auxpow information. This "intermediate step"
+ * in constructing the full header is useful, because it breaks the cyclic
+ * dependency between auxpow (referencing a parent block header) and
+ * the block header (referencing an auxpow). The parent block header
+ * does not have auxpow itself, so it is a pure header.
*/
-class CBlockVersion
+class CPureBlockHeader
{
-private:
+public:
/* Modifiers to the version. */
static const int32_t VERSION_AUXPOW = (1 << 8);
/** Bits above are reserved for the auxpow chain ID. */
static const int32_t VERSION_CHAIN_START = (1 << 16);
- /** The version as integer. Should not be accessed directly. */
- int nVersion;
+ // header
+ int32_t nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ uint32_t nTime;
+ uint32_t nBits;
+ uint32_t nNonce;
-public:
- inline CBlockVersion()
+ CPureBlockHeader()
{
SetNull();
}
@@ -35,17 +41,69 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
+ inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(this->nVersion);
+ READWRITE(hashPrevBlock);
+ READWRITE(hashMerkleRoot);
+ READWRITE(nTime);
+ READWRITE(nBits);
+ READWRITE(nNonce);
}
- inline void SetNull()
+ void SetNull()
{
nVersion = 0;
+ hashPrevBlock.SetNull();
+ hashMerkleRoot.SetNull();
+ nTime = 0;
+ nBits = 0;
+ nNonce = 0;
+ }
+
+ bool IsNull() const
+ {
+ return (nBits == 0);
+ }
+
+ uint256 GetHash() const;
+
+ uint256 GetPoWHash() const;
+
+ int64_t GetBlockTime() const
+ {
+ return (int64_t)nTime;
+ }
+
+ /* Below are methods to interpret the version with respect to
+ auxpow data and chain ID. This used to be in the CBlockVersion
+ class, but was moved here when we switched back to nVersion being
+ a pure int member as preparation to undoing the "abuse" and
+ allowing BIP9 to work. */
+
+ /**
+ * Extract the base version (without modifiers and chain ID).
+ * @return The base version./
+ */
+ inline int32_t GetBaseVersion() const
+ {
+ return GetBaseVersion(nVersion);
+ }
+ static inline int32_t GetBaseVersion(int32_t ver)
+ {
+ return ver % VERSION_AUXPOW;
}
/**
+ * Set the base version (apart from chain ID and auxpow flag) to
+ * the one given. This should only be called when auxpow is not yet
+ * set, to initialise a block!
+ * @param nBaseVersion The base version.
+ * @param nChainId The auxpow chain ID.
+ */
+ void SetBaseVersion(int32_t nBaseVersion, int32_t nChainId);
+
+ /**
* Extract the chain ID.
* @return The chain ID encoded in the version.
*/
@@ -65,27 +123,8 @@ public:
}
/**
- * Extract the full version. Used for RPC results and debug prints.
- * @return The full version.
- */
- inline int32_t GetFullVersion() const
- {
- return nVersion;
- }
-
- /**
- * Set the genesis block version. This must be a literal write
- * through, to get the correct historic version.
- * @param nGenesisVersion The version to set.
- */
- inline void SetGenesisVersion(int32_t nGenesisVersion)
- {
- nVersion = nGenesisVersion;
- }
-
- /**
* Check if the auxpow flag is set in the version.
- * @return True iff this block version is marked as auxpow.
+ * @return True if this block version is marked as auxpow.
*/
inline bool IsAuxpow() const
{
@@ -96,7 +135,7 @@ public:
* Set the auxpow flag. This is used for testing.
* @param auxpow Whether to mark auxpow as true.
*/
- inline void SetAuxpow(bool auxpow)
+ inline void SetAuxpowFlag(bool auxpow)
{
if (auxpow)
nVersion |= VERSION_AUXPOW;
@@ -111,91 +150,9 @@ public:
inline bool IsLegacy() const
{
return nVersion == 1
+ // Dogecoin: We have a random v2 block with no AuxPoW, treat as legacy
|| (nVersion == 2 && GetChainId() == 0);
}
-
- CBlockVersion& operator=(const CBlockVersion& other)
- {
- nVersion = other.nVersion;
- return *this;
- }
-
- CBlockVersion& operator=(const int nBaseVersion)
- {
- nVersion = (nBaseVersion & 0x000000ff) | (nVersion & 0xffffff00);
- return *this;
- }
-
- operator int() { return nVersion & 0x000000ff; }
- friend inline bool operator==(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) == b; }
- friend inline bool operator!=(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) != b; }
- friend inline bool operator>(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) > b; }
- friend inline bool operator<(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) < b; }
- friend inline bool operator>=(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) >= b; }
- friend inline bool operator<=(const CBlockVersion a, const int b) { return (a.nVersion & 0x000000ff) <= b; }
-};
-
-/**
- * A block header without auxpow information. This "intermediate step"
- * in constructing the full header is useful, because it breaks the cyclic
- * dependency between auxpow (referencing a parent block header) and
- * the block header (referencing an auxpow). The parent block header
- * does not have auxpow itself, so it is a pure header.
- */
-class CPureBlockHeader
-{
-public:
- // header
- static const int32_t CURRENT_VERSION = 3;
- CBlockVersion nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- uint32_t nTime;
- uint32_t nBits;
- uint32_t nNonce;
-
- CPureBlockHeader()
- {
- SetNull();
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
- {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(hashPrevBlock);
- READWRITE(hashMerkleRoot);
- READWRITE(nTime);
- READWRITE(nBits);
- READWRITE(nNonce);
- }
-
- void SetNull()
- {
- nVersion.SetNull();
- hashPrevBlock.SetNull();
- hashMerkleRoot.SetNull();
- nTime = 0;
- nBits = 0;
- nNonce = 0;
- }
-
- bool IsNull() const
- {
- return (nBits == 0);
- }
-
- uint256 GetHash() const;
-
- uint256 GetPoWHash() const;
-
- int64_t GetBlockTime() const
- {
- return (int64_t)nTime;
- }
};
#endif // BITCOIN_PRIMITIVES_PUREHEADER_H
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 606dbea79..28ef1fb46 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,8 +36,8 @@ std::string CTxIn::ToString() const
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig));
else
- str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
- if (nSequence != std::numeric_limits<unsigned int>::max())
+ str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
+ if (nSequence != SEQUENCE_FINAL)
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
@@ -49,14 +49,9 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
scriptPubKey = scriptPubKeyIn;
}
-uint256 CTxOut::GetHash() const
-{
- return SerializeHash(*this);
-}
-
std::string CTxOut::ToString() const
{
- return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
+ return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
@@ -64,28 +59,26 @@ CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.n
uint256 CMutableTransaction::GetHash() const
{
- return SerializeHash(*this);
+ return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}
-void CTransaction::UpdateHash() const
+uint256 CTransaction::ComputeHash() const
{
- *const_cast<uint256*>(&hash) = SerializeHash(*this);
+ return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}
-CTransaction::CTransaction() : 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();
+uint256 CTransaction::GetWitnessHash() const
+{
+ if (!HasWitness()) {
+ return GetHash();
+ }
+ return SerializeHash(*this, SER_GETHASH, 0);
}
-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;
-}
+/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
+CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {}
+CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CAmount CTransaction::GetValueOut() const
{
@@ -94,7 +87,7 @@ CAmount CTransaction::GetValueOut() const
{
nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nValueOut;
}
@@ -115,7 +108,7 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
// Providing any more cleanup incentive than making additional inputs free would
// risk encouraging people to create junk outputs to redeem later.
if (nTxSize == 0)
- nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+ nTxSize = (GetTransactionWeight(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
{
unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
@@ -125,6 +118,11 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
return nTxSize;
}
+unsigned int CTransaction::GetTotalSize() const
+{
+ return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+}
+
std::string CTransaction::ToString() const
{
std::string str;
@@ -136,7 +134,14 @@ std::string CTransaction::ToString() const
nLockTime);
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
+ for (unsigned int i = 0; i < vin.size(); i++)
+ str += " " + vin[i].scriptWitness.ToString() + "\n";
for (unsigned int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
+
+int64_t GetTransactionWeight(const CTransaction& tx)
+{
+ return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 15b31c251..ceb8f6ace 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,6 +11,10 @@
#include "serialize.h"
#include "uint256.h"
+static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
+
+static const int WITNESS_SCALE_FACTOR = 4;
+
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
@@ -24,7 +28,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(hash);
READWRITE(n);
}
@@ -34,7 +38,8 @@ public:
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
- return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
+ int cmp = a.hash.Compare(b.hash);
+ return cmp < 0 || (cmp == 0 && a.n < b.n);
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
@@ -60,29 +65,52 @@ public:
COutPoint prevout;
CScript scriptSig;
uint32_t nSequence;
+ CScriptWitness scriptWitness; //! Only serialized through CTransaction
+
+ /* Setting nSequence to this value for every input in a transaction
+ * disables nLockTime. */
+ static const uint32_t SEQUENCE_FINAL = 0xffffffff;
+
+ /* Below flags apply in the context of BIP 68*/
+ /* If this flag set, CTxIn::nSequence is NOT interpreted as a
+ * relative lock-time. */
+ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
+
+ /* If CTxIn::nSequence encodes a relative lock-time and this flag
+ * is set, the relative lock-time has units of 512 seconds,
+ * otherwise it specifies blocks with a granularity of 1. */
+ static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
+
+ /* If CTxIn::nSequence encodes a relative lock-time, this mask is
+ * applied to extract that lock-time from the sequence field. */
+ static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
+
+ /* In order to use the same number of bits to encode roughly the
+ * same wall-clock duration, and because blocks are naturally
+ * limited to occur every 600s on average, the minimum granularity
+ * for time-based relative lock-time is fixed at 512 seconds.
+ * Converting from CTxIn::nSequence to seconds is performed by
+ * multiplying by 512 = 2^9, or equivalently shifting up by
+ * 9 bits. */
+ static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
CTxIn()
{
- nSequence = std::numeric_limits<unsigned int>::max();
+ nSequence = SEQUENCE_FINAL;
}
- explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max());
- CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=std::numeric_limits<uint32_t>::max());
+ explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
+ CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
- READWRITE(scriptSig);
+ READWRITE(*(CScriptBase*)(&scriptSig));
READWRITE(nSequence);
}
- bool IsFinal() const
- {
- return (nSequence == std::numeric_limits<uint32_t>::max());
- }
-
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
return (a.prevout == b.prevout &&
@@ -117,9 +145,9 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nValue);
- READWRITE(scriptPubKey);
+ READWRITE(*(CScriptBase*)(&scriptPubKey));
}
void SetNull()
@@ -133,30 +161,41 @@ public:
return (nValue == -1);
}
- uint256 GetHash() const;
-
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
{
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
- // A typical txout is 34 bytes big, and will
+ // A typical spendable non-segwit txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
- // so dust is a txout less than 546 satoshis
- // with default minRelayTxFee.
- // size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
- // return 3*minRelayTxFee.GetFee(nSize);
- // Dogecoin: Dust is 1 COIN
- return COIN;
+ // so dust is a spendable txout less than
+ // 546*minRelayTxFee/1000 (in satoshis).
+ // A typical spendable segwit txout is 31 bytes big, and will
+ // need a CTxIn of at least 67 bytes to spend:
+ // so dust is a spendable txout less than
+ // 294*minRelayTxFee/1000 (in satoshis).
+ if (scriptPubKey.IsUnspendable())
+ return 0;
+
+ size_t nSize = GetSerializeSize(*this, SER_DISK, 0);
+ int witnessversion = 0;
+ std::vector<unsigned char> witnessprogram;
+
+ if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
+ // sum the sizes of the parts of a transaction input
+ // with 75% segwit discount applied to the script size.
+ nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
+ } else {
+ nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
+ }
+
+ return 3 * minRelayTxFee.GetFee(nSize);
}
bool IsDust(const CFeeRate &minRelayTxFee) const
{
- // Dogecoin: IsDust() detection disabled, allows any valid dust to be relayed.
- // The fees imposed on each dust txo is considered sufficient spam deterrant.
- // return (nValue < GetDustThreshold(minRelayTxFee));
- return false;
+ return (nValue < GetDustThreshold(minRelayTxFee));
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
@@ -175,19 +214,104 @@ public:
struct CMutableTransaction;
+/**
+ * Basic transaction serialization format:
+ * - int32_t nVersion
+ * - std::vector<CTxIn> vin
+ * - std::vector<CTxOut> vout
+ * - uint32_t nLockTime
+ *
+ * Extended transaction serialization format:
+ * - int32_t nVersion
+ * - unsigned char dummy = 0x00
+ * - unsigned char flags (!= 0)
+ * - std::vector<CTxIn> vin
+ * - std::vector<CTxOut> vout
+ * - if (flags & 1):
+ * - CTxWitness wit;
+ * - uint32_t nLockTime
+ */
+template<typename Stream, typename TxType>
+inline void UnserializeTransaction(TxType& tx, Stream& s) {
+ const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
+
+ s >> tx.nVersion;
+ unsigned char flags = 0;
+ tx.vin.clear();
+ tx.vout.clear();
+ /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
+ s >> tx.vin;
+ if (tx.vin.size() == 0 && fAllowWitness) {
+ /* We read a dummy or an empty vin. */
+ s >> flags;
+ if (flags != 0) {
+ s >> tx.vin;
+ s >> tx.vout;
+ }
+ } else {
+ /* We read a non-empty vin. Assume a normal vout follows. */
+ s >> tx.vout;
+ }
+ if ((flags & 1) && fAllowWitness) {
+ /* The witness flag is present, and we support witnesses. */
+ flags ^= 1;
+ for (size_t i = 0; i < tx.vin.size(); i++) {
+ s >> tx.vin[i].scriptWitness.stack;
+ }
+ }
+ if (flags) {
+ /* Unknown flag in the serialization */
+ throw std::ios_base::failure("Unknown transaction optional data");
+ }
+ s >> tx.nLockTime;
+}
+
+template<typename Stream, typename TxType>
+inline void SerializeTransaction(const TxType& tx, Stream& s) {
+ const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
+
+ s << tx.nVersion;
+ unsigned char flags = 0;
+ // Consistency check
+ if (fAllowWitness) {
+ /* Check whether witnesses need to be serialized. */
+ if (tx.HasWitness()) {
+ flags |= 1;
+ }
+ }
+ if (flags) {
+ /* Use extended format in case witnesses are to be serialized. */
+ std::vector<CTxIn> vinDummy;
+ s << vinDummy;
+ s << flags;
+ }
+ s << tx.vin;
+ s << tx.vout;
+ if (flags & 1) {
+ for (size_t i = 0; i < tx.vin.size(); i++) {
+ s << tx.vin[i].scriptWitness.stack;
+ }
+ }
+ s << tx.nLockTime;
+}
+
+
/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction
{
-private:
- /** Memory only. */
- const uint256 hash;
- void UpdateHash() const;
-
public:
+ // Default transaction version.
+ // Dogecoin: Temporarily restricted to v1 for compatibility with 1.10
static const int32_t CURRENT_VERSION=1;
+ // Changing the default transaction version requires a two step process: first
+ // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date
+ // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and
+ // MAX_STANDARD_VERSION will be equal.
+ static const int32_t MAX_STANDARD_VERSION=2;
+
// The local variables are made const to prevent unintended modification
// without updating the cached hash value. However, CTransaction is not
// actually immutable; deserialization and assignment are implemented,
@@ -198,27 +322,30 @@ public:
const std::vector<CTxOut> vout;
const uint32_t nLockTime;
+private:
+ /** Memory only. */
+ const uint256 hash;
+
+ uint256 ComputeHash() const;
+
+public:
/** Construct a CTransaction that qualifies as IsNull() */
CTransaction();
/** Convert a CMutableTransaction into a CTransaction. */
CTransaction(const CMutableTransaction &tx);
+ CTransaction(CMutableTransaction &&tx);
- CTransaction& operator=(const CTransaction& tx);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*const_cast<int32_t*>(&this->nVersion));
- nVersion = this->nVersion;
- READWRITE(*const_cast<std::vector<CTxIn>*>(&vin));
- READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
- READWRITE(*const_cast<uint32_t*>(&nLockTime));
- if (ser_action.ForRead())
- UpdateHash();
+ template <typename Stream>
+ inline void Serialize(Stream& s) const {
+ SerializeTransaction(*this, s);
}
+ /** This deserializing constructor is provided instead of an Unserialize method.
+ * Unserialize is not possible, since it would require overwriting const fields. */
+ template <typename Stream>
+ CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {}
+
bool IsNull() const {
return vin.empty() && vout.empty();
}
@@ -227,6 +354,9 @@ public:
return hash;
}
+ // Compute a hash that includes both transaction and witness data
+ uint256 GetWitnessHash() const;
+
// Return sum of txouts.
CAmount GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because
@@ -238,6 +368,13 @@ public:
// Compute modified tx size for priority calculation (optionally given tx size)
unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
+ /**
+ * Get the total transaction size in bytes, including witness data.
+ * "Total Size" defined in BIP141 and BIP144.
+ * @return Total transaction size in bytes
+ */
+ unsigned int GetTotalSize() const;
+
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
@@ -254,6 +391,16 @@ public:
}
std::string ToString() const;
+
+ bool HasWitness() const
+ {
+ for (size_t i = 0; i < vin.size(); i++) {
+ if (!vin[i].scriptWitness.IsNull()) {
+ return true;
+ }
+ }
+ return false;
+ }
};
/** A mutable version of CTransaction. */
@@ -267,21 +414,48 @@ struct CMutableTransaction
CMutableTransaction();
CMutableTransaction(const CTransaction& tx);
- ADD_SERIALIZE_METHODS;
+ template <typename Stream>
+ inline void Serialize(Stream& s) const {
+ SerializeTransaction(*this, s);
+ }
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(vin);
- READWRITE(vout);
- READWRITE(nLockTime);
+
+ template <typename Stream>
+ inline void Unserialize(Stream& s) {
+ UnserializeTransaction(*this, s);
+ }
+
+ template <typename Stream>
+ CMutableTransaction(deserialize_type, Stream& s) {
+ Unserialize(s);
}
/** 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;
+
+ friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b)
+ {
+ return a.GetHash() == b.GetHash();
+ }
+
+ bool HasWitness() const
+ {
+ for (size_t i = 0; i < vin.size(); i++) {
+ if (!vin[i].scriptWitness.IsNull()) {
+ return true;
+ }
+ }
+ return false;
+ }
};
+typedef std::shared_ptr<const CTransaction> CTransactionRef;
+static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
+template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
+
+/** Compute the weight of a transaction, as defined by BIP 141 */
+int64_t GetTransactionWeight(const CTransaction &tx);
+
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H