Skip to content

Commit 7030d9e

Browse files
committed
BIP144: Serialization, hashes, relay (sender side)
Contains refactorings by Eric Lombrozo. Contains fixup by Nicolas Dorier. Contains cleanup of CInv::GetCommand by Alex Morcos
1 parent ecacfd9 commit 7030d9e

21 files changed

+339
-90
lines changed

src/core_io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class UniValue;
1717
// core_read.cpp
1818
extern CScript ParseScript(const std::string& s);
1919
extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
20-
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
20+
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
2121
extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
2222
extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
2323
extern uint256 ParseHashStr(const std::string&, const std::string& strName);

src/core_memusage.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,28 @@ static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
2525
return RecursiveDynamicUsage(out.scriptPubKey);
2626
}
2727

28+
static inline size_t RecursiveDynamicUsage(const CScriptWitness& scriptWit) {
29+
size_t mem = memusage::DynamicUsage(scriptWit.stack);
30+
for (std::vector<std::vector<unsigned char> >::const_iterator it = scriptWit.stack.begin(); it != scriptWit.stack.end(); it++) {
31+
mem += memusage::DynamicUsage(*it);
32+
}
33+
return mem;
34+
}
35+
36+
static inline size_t RecursiveDynamicUsage(const CTxinWitness& txinwit) {
37+
return RecursiveDynamicUsage(txinwit.scriptWitness);
38+
}
39+
40+
static inline size_t RecursiveDynamicUsage(const CTxWitness& txwit) {
41+
size_t mem = memusage::DynamicUsage(txwit.vtxinwit);
42+
for (std::vector<CTxinWitness>::const_iterator it = txwit.vtxinwit.begin(); it != txwit.vtxinwit.end(); it++) {
43+
mem += RecursiveDynamicUsage(*it);
44+
}
45+
return mem;
46+
}
47+
2848
static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
29-
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
49+
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
3050
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
3151
mem += RecursiveDynamicUsage(*it);
3252
}
@@ -37,7 +57,7 @@ static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
3757
}
3858

3959
static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
40-
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
60+
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
4161
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
4262
mem += RecursiveDynamicUsage(*it);
4363
}

src/core_read.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,26 @@ CScript ParseScript(const std::string& s)
9090
return result;
9191
}
9292

93-
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx)
93+
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
9494
{
9595
if (!IsHex(strHexTx))
9696
return false;
9797

9898
vector<unsigned char> txData(ParseHex(strHexTx));
99+
100+
if (fTryNoWitness) {
101+
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
102+
try {
103+
ssData >> tx;
104+
if (ssData.eof()) {
105+
return true;
106+
}
107+
}
108+
catch (const std::exception&) {
109+
// Fall through.
110+
}
111+
}
112+
99113
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
100114
try {
101115
ssData >> tx;

src/main.cpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,8 +1029,8 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
10291029
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
10301030
if (tx.vout.empty())
10311031
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
1032-
// Size limits
1033-
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
1032+
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
1033+
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_SIZE)
10341034
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
10351035

10361036
// Check for negative or overflow output values
@@ -3396,7 +3396,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
33963396
// because we receive the wrong transactions for it.
33973397

33983398
// Size limits
3399-
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
3399+
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_SIZE)
34003400
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
34013401

34023402
// First transaction must be coinbase, the rest must not be
@@ -4508,6 +4508,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
45084508
switch (inv.type)
45094509
{
45104510
case MSG_TX:
4511+
case MSG_WITNESS_TX:
45114512
{
45124513
assert(recentRejects);
45134514
if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
@@ -4528,6 +4529,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
45284529
pcoinsTip->HaveCoinsInCache(inv.hash);
45294530
}
45304531
case MSG_BLOCK:
4532+
case MSG_WITNESS_BLOCK:
45314533
return mapBlockIndex.count(inv.hash);
45324534
}
45334535
// Don't know what it is, just say we already got one
@@ -4552,7 +4554,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
45524554
boost::this_thread::interruption_point();
45534555
it++;
45544556

4555-
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK)
4557+
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
45564558
{
45574559
bool send = false;
45584560
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
@@ -4593,6 +4595,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
45934595
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
45944596
assert(!"cannot load block from disk");
45954597
if (inv.type == MSG_BLOCK)
4598+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
4599+
else if (inv.type == MSG_WITNESS_BLOCK)
45964600
pfrom->PushMessage(NetMsgType::BLOCK, block);
45974601
else if (inv.type == MSG_FILTERED_BLOCK)
45984602
{
@@ -4609,7 +4613,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
46094613
// however we MUST always provide at least what the remote peer needs
46104614
typedef std::pair<unsigned int, uint256> PairType;
46114615
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
4612-
pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]);
4616+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]);
46134617
}
46144618
// else
46154619
// no response
@@ -4622,9 +4626,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
46224626
// instead we respond with the full, non-compact block.
46234627
if (mi->second->nHeight >= chainActive.Height() - 10) {
46244628
CBlockHeaderAndShortTxIDs cmpctblock(block);
4625-
pfrom->PushMessage(NetMsgType::CMPCTBLOCK, cmpctblock);
4629+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
46264630
} else
4627-
pfrom->PushMessage(NetMsgType::BLOCK, block);
4631+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
46284632
}
46294633

46304634
// Trigger the peer node to send a getblocks request for the next batch of inventory
@@ -4640,20 +4644,20 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
46404644
}
46414645
}
46424646
}
4643-
else if (inv.type == MSG_TX)
4647+
else if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX)
46444648
{
46454649
// Send stream from relay memory
46464650
bool push = false;
46474651
auto mi = mapRelay.find(inv.hash);
46484652
if (mi != mapRelay.end()) {
4649-
pfrom->PushMessage(NetMsgType::TX, *mi->second);
4653+
pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *mi->second);
46504654
push = true;
46514655
} else if (pfrom->timeLastMempoolReq) {
46524656
auto txinfo = mempool.info(inv.hash);
46534657
// To protect privacy, do not answer getdata using the mempool when
46544658
// that TX couldn't have been INVed in reply to a MEMPOOL request.
46554659
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
4656-
pfrom->PushMessage(NetMsgType::TX, *txinfo.tx);
4660+
pfrom->PushMessageWithFlag(inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0, NetMsgType::TX, *txinfo.tx);
46574661
push = true;
46584662
}
46594663
}
@@ -4665,7 +4669,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
46654669
// Track requests for our stuff.
46664670
GetMainSignals().Inventory(inv.hash);
46674671

4668-
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK)
4672+
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK)
46694673
break;
46704674
}
46714675
}
@@ -5146,7 +5150,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
51465150
}
51475151
resp.txn[i] = block.vtx[req.indexes[i]];
51485152
}
5149-
pfrom->PushMessage(NetMsgType::BLOCKTXN, resp);
5153+
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
51505154
}
51515155

51525156

src/net.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,23 @@ class CNode
598598
}
599599
}
600600

601+
/** Send a message containing a1, serialized with flag flag. */
602+
template<typename T1>
603+
void PushMessageWithFlag(int flag, const char* pszCommand, const T1& a1)
604+
{
605+
try
606+
{
607+
BeginMessage(pszCommand);
608+
WithOrVersion(&ssSend, flag) << a1;
609+
EndMessage(pszCommand);
610+
}
611+
catch (...)
612+
{
613+
AbortMessage();
614+
throw;
615+
}
616+
}
617+
601618
template<typename T1, typename T2>
602619
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
603620
{

src/primitives/block.h

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

123-
124122
/** Describes a place in the block chain to another node such that if the
125123
* other node doesn't have the same branch, it can find a recent common trunk.
126124
* 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, SERIALIZE_TRANSACTION_NO_WITNESS);
6868
}
6969

7070
void CTransaction::UpdateHash() const
7171
{
72-
*const_cast<uint256*>(&hash) = SerializeHash(*this);
72+
*const_cast<uint256*>(&hash) = SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
73+
}
74+
75+
uint256 CTransaction::GetWitnessHash() const
76+
{
77+
return SerializeHash(*this, SER_GETHASH, 0);
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)