mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-31 16:24:48 +02:00
BIP144: Serialization, hashes, relay (sender side)
Contains refactorings by Eric Lombrozo. Contains fixup by Nicolas Dorier. Contains cleanup of CInv::GetCommand by Alex Morcos
This commit is contained in:
@@ -38,7 +38,6 @@ public:
|
||||
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);
|
||||
@@ -120,7 +119,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.
|
||||
|
||||
@@ -60,21 +60,26 @@ std::string CTxOut::ToString() 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) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {}
|
||||
|
||||
uint256 CMutableTransaction::GetHash() const
|
||||
{
|
||||
return SerializeHash(*this);
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
}
|
||||
|
||||
void CTransaction::UpdateHash() const
|
||||
{
|
||||
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
||||
*const_cast<uint256*>(&hash) = SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
}
|
||||
|
||||
uint256 CTransaction::GetWitnessHash() const
|
||||
{
|
||||
return SerializeHash(*this, SER_GETHASH, 0);
|
||||
}
|
||||
|
||||
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) {
|
||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {
|
||||
UpdateHash();
|
||||
}
|
||||
|
||||
@@ -82,6 +87,7 @@ 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<CTxWitness*>(&wit) = tx.wit;
|
||||
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
||||
*const_cast<uint256*>(&hash) = tx.hash;
|
||||
return *this;
|
||||
@@ -136,6 +142,8 @@ 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 < wit.vtxinwit.size(); i++)
|
||||
str += " " + wit.vtxinwit[i].scriptWitness.ToString() + "\n";
|
||||
for (unsigned int i = 0; i < vout.size(); i++)
|
||||
str += " " + vout[i].ToString() + "\n";
|
||||
return str;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
|
||||
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
{
|
||||
@@ -194,8 +196,137 @@ public:
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
class CTxinWitness
|
||||
{
|
||||
public:
|
||||
CScriptWitness scriptWitness;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
READWRITE(scriptWitness.stack);
|
||||
}
|
||||
|
||||
bool IsNull() const { return scriptWitness.IsNull(); }
|
||||
|
||||
CTxinWitness() { }
|
||||
};
|
||||
|
||||
class CTxWitness
|
||||
{
|
||||
public:
|
||||
/** In case vtxinwit is missing, all entries are treated as if they were empty CTxInWitnesses */
|
||||
std::vector<CTxinWitness> vtxinwit;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
bool IsEmpty() const { return vtxinwit.empty(); }
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
for (size_t n = 0; n < vtxinwit.size(); n++) {
|
||||
if (!vtxinwit[n].IsNull()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
vtxinwit.clear();
|
||||
}
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
for (size_t n = 0; n < vtxinwit.size(); n++) {
|
||||
READWRITE(vtxinwit[n]);
|
||||
}
|
||||
if (IsNull()) {
|
||||
/* It's illegal to encode a witness when all vtxinwit entries are empty. */
|
||||
throw std::ios_base::failure("Superfluous witness record");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 Operation, typename TxType>
|
||||
inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(*const_cast<int32_t*>(&tx.nVersion));
|
||||
unsigned char flags = 0;
|
||||
if (ser_action.ForRead()) {
|
||||
const_cast<std::vector<CTxIn>*>(&tx.vin)->clear();
|
||||
const_cast<std::vector<CTxOut>*>(&tx.vout)->clear();
|
||||
const_cast<CTxWitness*>(&tx.wit)->SetNull();
|
||||
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
|
||||
READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
|
||||
if (tx.vin.size() == 0 && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
|
||||
/* We read a dummy or an empty vin. */
|
||||
READWRITE(flags);
|
||||
if (flags != 0) {
|
||||
READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
|
||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
|
||||
}
|
||||
} else {
|
||||
/* We read a non-empty vin. Assume a normal vout follows. */
|
||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
|
||||
}
|
||||
if ((flags & 1) && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
|
||||
/* The witness flag is present, and we support witnesses. */
|
||||
flags ^= 1;
|
||||
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
|
||||
READWRITE(tx.wit);
|
||||
}
|
||||
if (flags) {
|
||||
/* Unknown flag in the serialization */
|
||||
throw std::ios_base::failure("Unknown transaction optional data");
|
||||
}
|
||||
} else {
|
||||
// Consistency check
|
||||
assert(tx.wit.vtxinwit.size() <= tx.vin.size());
|
||||
if (!(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) {
|
||||
/* Check whether witnesses need to be serialized. */
|
||||
if (!tx.wit.IsNull()) {
|
||||
flags |= 1;
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Use extended format in case witnesses are to be serialized. */
|
||||
std::vector<CTxIn> vinDummy;
|
||||
READWRITE(vinDummy);
|
||||
READWRITE(flags);
|
||||
}
|
||||
READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin));
|
||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout));
|
||||
if (flags & 1) {
|
||||
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
|
||||
READWRITE(tx.wit);
|
||||
}
|
||||
}
|
||||
READWRITE(*const_cast<uint32_t*>(&tx.nLockTime));
|
||||
}
|
||||
|
||||
/** The basic transaction that is broadcasted on the network and contained in
|
||||
* blocks. A transaction can contain multiple inputs and outputs.
|
||||
*/
|
||||
@@ -224,6 +355,7 @@ public:
|
||||
const int32_t nVersion;
|
||||
const std::vector<CTxIn> vin;
|
||||
const std::vector<CTxOut> vout;
|
||||
CTxWitness wit; // Not const: can change without invalidating the txid cache
|
||||
const uint32_t nLockTime;
|
||||
|
||||
/** Construct a CTransaction that qualifies as IsNull() */
|
||||
@@ -238,13 +370,10 @@ public:
|
||||
|
||||
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())
|
||||
SerializeTransaction(*this, s, ser_action, nType, nVersion);
|
||||
if (ser_action.ForRead()) {
|
||||
UpdateHash();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNull() const {
|
||||
@@ -255,6 +384,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
|
||||
@@ -290,6 +422,7 @@ struct CMutableTransaction
|
||||
int32_t nVersion;
|
||||
std::vector<CTxIn> vin;
|
||||
std::vector<CTxOut> vout;
|
||||
CTxWitness wit;
|
||||
uint32_t nLockTime;
|
||||
|
||||
CMutableTransaction();
|
||||
@@ -299,11 +432,7 @@ struct CMutableTransaction
|
||||
|
||||
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);
|
||||
SerializeTransaction(*this, s, ser_action, nType, nVersion);
|
||||
}
|
||||
|
||||
/** Compute the hash of this CMutableTransaction. This is computed on the
|
||||
|
||||
Reference in New Issue
Block a user