Skip to content

Commit 093b99f

Browse files
committed
Add segregated witness transaction serialization
Contains refactorings by Eric Lombrozo.
1 parent fbea2f6 commit 093b99f

20 files changed

+294
-90
lines changed

src/core_read.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx)
9696
return false;
9797

9898
vector<unsigned char> txData(ParseHex(strHexTx));
99-
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
99+
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_WITNESS);
100100
try {
101101
ssData >> tx;
102102
}
@@ -113,7 +113,7 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
113113
return false;
114114

115115
std::vector<unsigned char> blockData(ParseHex(strHexBlk));
116-
CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
116+
CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_WITNESS);
117117
try {
118118
ssBlock >> block;
119119
}

src/core_write.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
118118

119119
string EncodeHexTx(const CTransaction& tx)
120120
{
121-
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
121+
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_WITNESS);
122122
ssTx << tx;
123123
return HexStr(ssTx.begin(), ssTx.end());
124124
}

src/main.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
12411241
if (fTxIndex) {
12421242
CDiskTxPos postx;
12431243
if (pblocktree->ReadTxIndex(hash, postx)) {
1244-
CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
1244+
CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
12451245
if (file.IsNull())
12461246
return error("%s: OpenBlockFile failed", __func__);
12471247
CBlockHeader header;
@@ -1300,7 +1300,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
13001300
bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
13011301
{
13021302
// Open history file to append
1303-
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
1303+
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
13041304
if (fileout.IsNull())
13051305
return error("WriteBlockToDisk: OpenBlockFile failed");
13061306

@@ -1323,7 +1323,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus:
13231323
block.SetNull();
13241324

13251325
// Open history file to read
1326-
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
1326+
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
13271327
if (filein.IsNull())
13281328
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
13291329

@@ -1697,7 +1697,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
16971697
fileout << blockundo;
16981698

16991699
// calculate & write checksum
1700-
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
1700+
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_WITNESS);
17011701
hasher << hashBlock;
17021702
hasher << blockundo;
17031703
fileout << hasher.GetHash();
@@ -1723,7 +1723,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
17231723
}
17241724

17251725
// Verify checksum
1726-
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
1726+
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_WITNESS);
17271727
hasher << hashBlock;
17281728
hasher << blockundo;
17291729
if (hashChecksum != hasher.GetHash())
@@ -2101,7 +2101,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
21012101
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
21022102

21032103
vPos.push_back(std::make_pair(tx.GetHash(), pos));
2104-
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
2104+
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
21052105
}
21062106
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
21072107
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
@@ -3153,7 +3153,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
31533153

31543154
// Write block to history file
31553155
try {
3156-
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
3156+
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
31573157
CDiskBlockPos blockPos;
31583158
if (dbp != NULL)
31593159
blockPos = *dbp;
@@ -3673,7 +3673,7 @@ bool InitBlockIndex(const CChainParams& chainparams)
36733673
try {
36743674
CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
36753675
// Start new block file
3676-
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
3676+
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
36773677
CDiskBlockPos blockPos;
36783678
CValidationState state;
36793679
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
@@ -3704,7 +3704,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
37043704
int nLoaded = 0;
37053705
try {
37063706
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
3707-
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
3707+
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION | SERIALIZE_TRANSACTION_WITNESS);
37083708
uint64_t nRewind = blkdat.GetPos();
37093709
while (!blkdat.eof()) {
37103710
boost::this_thread::interruption_point();
@@ -4063,6 +4063,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
40634063
switch (inv.type)
40644064
{
40654065
case MSG_TX:
4066+
case MSG_WITNESS_TX:
40664067
{
40674068
assert(recentRejects);
40684069
if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
@@ -4081,6 +4082,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
40814082
pcoinsTip->HaveCoins(inv.hash);
40824083
}
40834084
case MSG_BLOCK:
4085+
case MSG_WITNESS_BLOCK:
40844086
return mapBlockIndex.count(inv.hash);
40854087
}
40864088
// Don't know what it is, just say we already got one
@@ -4105,7 +4107,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
41054107
boost::this_thread::interruption_point();
41064108
it++;
41074109

4108-
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
4110+
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_WITNESS_BLOCK)
41094111
{
41104112
bool send = false;
41114113
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
@@ -4147,6 +4149,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
41474149
assert(!"cannot load block from disk");
41484150
if (inv.type == MSG_BLOCK)
41494151
pfrom->PushMessage(NetMsgType::BLOCK, block);
4152+
if (inv.type == MSG_WITNESS_BLOCK)
4153+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_WITNESS, NetMsgType::BLOCK, block);
41504154
else // MSG_FILTERED_BLOCK)
41514155
{
41524156
LOCK(pfrom->cs_filter);
@@ -4181,25 +4185,22 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
41814185
}
41824186
}
41834187
}
4184-
else if (inv.IsKnownType())
4188+
else if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)
41854189
{
41864190
// Send stream from relay memory
41874191
bool pushed = false;
41884192
{
4189-
LOCK(cs_mapRelay);
4190-
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
4191-
if (mi != mapRelay.end()) {
4192-
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
4193+
LOCK(cs_mapRelayTx);
4194+
map<uint256, CTransaction>::iterator mi = mapRelayTx.find(inv.hash);
4195+
if (mi != mapRelayTx.end()) {
4196+
pfrom->PushMessageWithFlag(inv.type == MSG_WITNESS_TX ? SERIALIZE_TRANSACTION_WITNESS : 0, NetMsgType::TX, (*mi).second);
41934197
pushed = true;
41944198
}
41954199
}
4196-
if (!pushed && inv.type == MSG_TX) {
4200+
if (!pushed && (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)) {
41974201
CTransaction tx;
41984202
if (mempool.lookup(inv.hash, tx)) {
4199-
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
4200-
ss.reserve(1000);
4201-
ss << tx;
4202-
pfrom->PushMessage(NetMsgType::TX, ss);
4203+
pfrom->PushMessageWithFlag(inv.type == MSG_WITNESS_TX ? SERIALIZE_TRANSACTION_WITNESS : 0, NetMsgType::TX, tx);
42034204
pushed = true;
42044205
}
42054206
}
@@ -4211,7 +4212,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
42114212
// Track requests for our stuff.
42124213
GetMainSignals().Inventory(inv.hash);
42134214

4214-
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
4215+
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_WITNESS_BLOCK)
42154216
break;
42164217
}
42174218
}
@@ -4683,7 +4684,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
46834684
vector<uint256> vWorkQueue;
46844685
vector<uint256> vEraseQueue;
46854686
CTransaction tx;
4686-
vRecv >> tx;
4687+
WithOrVersion(&vRecv, SERIALIZE_TRANSACTION_WITNESS) >> tx;
46874688

46884689
CInv inv(MSG_TX, tx.GetHash());
46894690
pfrom->AddInventoryKnown(inv);
@@ -4912,7 +4913,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
49124913
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
49134914
{
49144915
CBlock block;
4915-
vRecv >> block;
4916+
WithOrVersion(&vRecv, SERIALIZE_TRANSACTION_WITNESS) >> block;
49164917

49174918
CInv inv(MSG_BLOCK, block.GetHash());
49184919
LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id);
@@ -5537,11 +5538,11 @@ bool SendMessages(CNode* pto)
55375538
vInvWait.reserve(pto->vInventoryToSend.size());
55385539
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
55395540
{
5540-
if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash))
5541+
if ((inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) && pto->filterInventoryKnown.contains(inv.hash))
55415542
continue;
55425543

55435544
// trickle out tx inv to protect privacy
5544-
if (inv.type == MSG_TX && !fSendTrickle)
5545+
if ((inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) && !fSendTrickle)
55455546
{
55465547
// 1/4 of tx invs blast to all immediately
55475548
static uint256 hashSalt;

src/net.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ std::string strSubVersion;
8989

9090
vector<CNode*> vNodes;
9191
CCriticalSection cs_vNodes;
92-
map<CInv, CDataStream> mapRelay;
93-
deque<pair<int64_t, CInv> > vRelayExpiration;
94-
CCriticalSection cs_mapRelay;
92+
map<uint256, CTransaction> mapRelayTx;
93+
deque<pair<int64_t, uint256> > vRelayTxExpiration;
94+
CCriticalSection cs_mapRelayTx;
9595
limitedmap<CInv, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
9696

9797
static deque<string> vOneShots;
@@ -2047,28 +2047,20 @@ instance_of_cnetcleanup;
20472047

20482048

20492049
void RelayTransaction(const CTransaction& tx)
2050-
{
2051-
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2052-
ss.reserve(10000);
2053-
ss << tx;
2054-
RelayTransaction(tx, ss);
2055-
}
2056-
2057-
void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
20582050
{
20592051
CInv inv(MSG_TX, tx.GetHash());
20602052
{
2061-
LOCK(cs_mapRelay);
2053+
LOCK(cs_mapRelayTx);
20622054
// Expire old relay messages
2063-
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
2055+
while (!vRelayTxExpiration.empty() && vRelayTxExpiration.front().first < GetTime())
20642056
{
2065-
mapRelay.erase(vRelayExpiration.front().second);
2066-
vRelayExpiration.pop_front();
2057+
mapRelayTx.erase(vRelayTxExpiration.front().second);
2058+
vRelayTxExpiration.pop_front();
20672059
}
20682060

20692061
// Save original serialized message so newer versions are preserved
2070-
mapRelay.insert(std::make_pair(inv, ss));
2071-
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
2062+
mapRelayTx.insert(std::make_pair(inv.hash, tx));
2063+
vRelayTxExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash));
20722064
}
20732065
LOCK(cs_vNodes);
20742066
BOOST_FOREACH(CNode* pnode, vNodes)

src/net.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ extern int nMaxConnections;
161161

162162
extern std::vector<CNode*> vNodes;
163163
extern CCriticalSection cs_vNodes;
164-
extern std::map<CInv, CDataStream> mapRelay;
165-
extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration;
166-
extern CCriticalSection cs_mapRelay;
164+
extern std::map<uint256, CTransaction> mapRelayTx;
165+
extern std::deque<std::pair<int64_t, uint256> > vRelayTxExpiration;
166+
extern CCriticalSection cs_mapRelayTx;
167167
extern limitedmap<CInv, int64_t> mapAlreadyAskedFor;
168168

169169
extern std::vector<std::string> vAddedNodes;
@@ -507,7 +507,7 @@ class CNode
507507
{
508508
{
509509
LOCK(cs_inventory);
510-
if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
510+
if ((inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) && filterInventoryKnown.contains(inv.hash))
511511
return;
512512
vInventoryToSend.push_back(inv);
513513
}
@@ -563,6 +563,23 @@ class CNode
563563
}
564564
}
565565

566+
/** Send a message containing a1, serialized with flag flag. */
567+
template<typename T1>
568+
void PushMessageWithFlag(int flag, const char* pszCommand, const T1& a1)
569+
{
570+
try
571+
{
572+
BeginMessage(pszCommand);
573+
WithOrVersion(&ssSend, flag) << a1;
574+
EndMessage();
575+
}
576+
catch (...)
577+
{
578+
AbortMessage();
579+
throw;
580+
}
581+
}
582+
566583
template<typename T1, typename T2>
567584
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
568585
{
@@ -762,7 +779,6 @@ class CNode
762779

763780
class CTransaction;
764781
void RelayTransaction(const CTransaction& tx);
765-
void RelayTransaction(const CTransaction& tx, const CDataStream& ss);
766782

767783
/** Access to the (IP) address database (peers.dat) */
768784
class CAddrDB

src/primitives/block.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class CBlockHeader
3939
template <typename Stream, typename Operation>
4040
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
4141
READWRITE(this->nVersion);
42-
nVersion = this->nVersion;
4342
READWRITE(hashPrevBlock);
4443
READWRITE(hashMerkleRoot);
4544
READWRITE(nTime);
@@ -121,7 +120,6 @@ class CBlock : public CBlockHeader
121120
std::string ToString() const;
122121
};
123122

124-
125123
/** Describes a place in the block chain to another node such that if the
126124
* other node doesn't have the same branch, it can find a recent common trunk.
127125
* The further back it is, the further before the fork it may be.

src/primitives/transaction.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,28 +60,34 @@ std::string CTxOut::ToString() const
6060
}
6161

6262
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
63-
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
63+
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {}
6464

6565
uint256 CMutableTransaction::GetHash() const
6666
{
67-
return SerializeHash(*this);
67+
return SerializeHash(*this, SER_GETHASH, 0);
6868
}
6969

7070
void CTransaction::UpdateHash() const
7171
{
72-
*const_cast<uint256*>(&hash) = SerializeHash(*this);
72+
*const_cast<uint256*>(&hash) = SerializeHash(*this, SER_GETHASH, 0);
73+
}
74+
75+
uint256 CTransaction::GetWitnessHash() const
76+
{
77+
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_WITNESS);
7378
}
7479

7580
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0) { }
7681

77-
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {
82+
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), wit(tx.wit), nLockTime(tx.nLockTime) {
7883
UpdateHash();
7984
}
8085

8186
CTransaction& CTransaction::operator=(const CTransaction &tx) {
8287
*const_cast<int*>(&nVersion) = tx.nVersion;
8388
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
8489
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
90+
*const_cast<CTxWitness*>(&wit) = tx.wit;
8591
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
8692
*const_cast<uint256*>(&hash) = tx.hash;
8793
return *this;
@@ -136,6 +142,8 @@ std::string CTransaction::ToString() const
136142
nLockTime);
137143
for (unsigned int i = 0; i < vin.size(); i++)
138144
str += " " + vin[i].ToString() + "\n";
145+
for (unsigned int i = 0; i < wit.vtxinwit.size(); i++)
146+
str += " " + wit.vtxinwit[i].scriptWitness.ToString() + "\n";
139147
for (unsigned int i = 0; i < vout.size(); i++)
140148
str += " " + vout[i].ToString() + "\n";
141149
return str;

0 commit comments

Comments
 (0)