Skip to content

Commit

Permalink
changed elements serialization to new style with no marker 0x00 byte …
Browse files Browse the repository at this point in the history
…and witness data at the end
  • Loading branch information
tdudz committed Oct 8, 2017
1 parent de19cfe commit d3a48d5
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 79 deletions.
23 changes: 6 additions & 17 deletions qa/rpc-tests/test_framework/mininode.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,25 +598,17 @@ def __init__(self, tx=None):

def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
flags = struct.unpack("<B", f.read(1))[0]
self.vin = deser_vector(f, CTxIn)
flags = 0
if len(self.vin) == 0:
flags = struct.unpack("<B", f.read(1))[0]
# Not sure why flags can't be zero, but this
# matches the implementation in bitcoind
if (flags != 0):
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
else:
self.vout = deser_vector(f, CTxOut)
self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
if flags & 1 > 0:
self.wit.vtxinwit = [CTxInWitness() for i in range(len(self.vin))]
self.wit.vtxoutwit = [CTxOutWitness() for i in range(len(self.vout))]
self.wit.deserialize(f)

if flags > 1:
raise TypeError('Extra witness flags:' + str(flags))
self.nLockTime = struct.unpack("<I", f.read(4))[0]

self.sha256 = None
self.hash = None

Expand All @@ -636,12 +628,10 @@ def serialize_with_witness(self):
flags |= 1
r = b""
r += struct.pack("<i", self.nVersion)
if flags:
dummy = []
r += ser_vector(dummy)
r += struct.pack("<B", flags)
r += struct.pack("<B", flags)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
if flags & 1:
if (len(self.wit.vtxinwit) != len(self.vin)):
# vtxinwit must have the same length as vin
Expand All @@ -652,7 +642,6 @@ def serialize_with_witness(self):
for i in range(len(self.wit.vtxoutwit), len(self.vout)):
self.wit.vtxoutwit.append(CTxInWitness())
r += self.wit.serialize()
r += struct.pack("<I", self.nLockTime)
return r

def serialize(self):
Expand Down
2 changes: 1 addition & 1 deletion src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ static int CommandLineRawTx(int argc, char* argv[])
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();

if (!DecodeHexTx(tx, strHexTx, true))
if (!DecodeHexTx(tx, strHexTx))
throw std::runtime_error("invalid transaction encoding");

startArg = 2;
Expand Down
2 changes: 1 addition & 1 deletion src/core_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class UniValue;
// core_read.cpp
CScript ParseScript(const std::string& s);
std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness = false);
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx);
bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
uint256 ParseHashUV(const UniValue& v, const std::string& strName);
uint256 ParseHashStr(const std::string&, const std::string& strName);
Expand Down
15 changes: 1 addition & 14 deletions src/core_read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,26 +88,13 @@ CScript ParseScript(const std::string& s)
return result;
}

bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx)
{
if (!IsHex(strHexTx))
return false;

std::vector<unsigned char> txData(ParseHex(strHexTx));

if (fTryNoWitness) {
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
try {
ssData >> tx;
if (ssData.eof()) {
return true;
}
}
catch (const std::exception&) {
// Fall through.
}
}

CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> tx;
Expand Down
62 changes: 20 additions & 42 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,45 +615,31 @@ class CTxWitness
struct CMutableTransaction;

/**
* Basic transaction serialization format:
* Elements transaction serialization format:
* - int32_t nVersion
* - unsigned char flags
* - bit 1: witness data
* - 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();
tx.wit.SetNull();
/* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */

s >> flags;
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. */
s >> tx.vout;
s >> tx.nLockTime;

if (flags & 1) {
/* The witness flag is present. */
flags ^= 1;
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
const_cast<CTxWitness*>(&tx.wit)->vtxoutwit.resize(tx.vout.size());
Expand All @@ -663,43 +649,35 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
/* 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);

const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
s << tx.nVersion;

unsigned char flags = 0;
// Consistency check
assert(tx.wit.vtxoutwit.size() <= tx.vout.size());
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;

/* Check whether witnesses need to be serialized. */
if (fAllowWitness && tx.HasWitness()) {
flags |= 1;
}

s << flags;
s << tx.vin;
s << tx.vout;
s << tx.nLockTime;

if (flags & 1) {
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
const_cast<CTxWitness*>(&tx.wit)->vtxoutwit.resize(tx.vout.size());
s << tx.wit;
}
s << tx.nLockTime;
}


/** 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
{
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)

CMutableTransaction mtx;

if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
if (!DecodeHexTx(mtx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");

UniValue result(UniValue::VOBJ);
Expand Down
Loading

0 comments on commit d3a48d5

Please sign in to comment.