Skip to content

Commit

Permalink
Move CTxInWitness inside CTxIn
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Dec 5, 2016
1 parent d04aeba commit f6fb7ac
Show file tree
Hide file tree
Showing 18 changed files with 96 additions and 176 deletions.
5 changes: 2 additions & 3 deletions src/bench/verify_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, co
txSpend.nLockTime = 0;
txSpend.vin.resize(1);
txSpend.vout.resize(1);
txSpend.wit.vtxinwit.resize(1);
txSpend.vin[0].prevout.hash = txCredit.GetHash();
txSpend.vin[0].prevout.n = 0;
txSpend.vin[0].scriptSig = scriptSig;
Expand Down Expand Up @@ -68,7 +67,7 @@ static void VerifyScriptBench(benchmark::State& state)
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
CScriptWitness& witness = txSpend.wit.vtxinwit[0].scriptWitness;
CScriptWitness& witness = txSpend.vin[0].scriptWitness;
witness.stack.emplace_back();
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0);
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
Expand All @@ -80,7 +79,7 @@ static void VerifyScriptBench(benchmark::State& state)
bool success = VerifyScript(
txSpend.vin[0].scriptSig,
txCredit.vout[0].scriptPubKey,
&txSpend.wit.vtxinwit[0].scriptWitness,
&txSpend.vin[0].scriptWitness,
flags,
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
&err);
Expand Down
2 changes: 1 addition & 1 deletion src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
UpdateTransaction(mergedTx, i, sigdata);

if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
fComplete = false;
}

Expand Down
30 changes: 7 additions & 23 deletions src/core_memusage.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,19 @@ static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
}

static inline size_t RecursiveDynamicUsage(const CTxIn& in) {
return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout);
}

static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
return RecursiveDynamicUsage(out.scriptPubKey);
}

static inline size_t RecursiveDynamicUsage(const CScriptWitness& scriptWit) {
size_t mem = memusage::DynamicUsage(scriptWit.stack);
for (std::vector<std::vector<unsigned char> >::const_iterator it = scriptWit.stack.begin(); it != scriptWit.stack.end(); it++) {
mem += memusage::DynamicUsage(*it);
size_t mem = RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout) + memusage::DynamicUsage(in.scriptWitness.stack);
for (std::vector<std::vector<unsigned char> >::const_iterator it = in.scriptWitness.stack.begin(); it != in.scriptWitness.stack.end(); it++) {
mem += memusage::DynamicUsage(*it);
}
return mem;
}

static inline size_t RecursiveDynamicUsage(const CTxInWitness& txinwit) {
return RecursiveDynamicUsage(txinwit.scriptWitness);
}

static inline size_t RecursiveDynamicUsage(const CTxWitness& txwit) {
size_t mem = memusage::DynamicUsage(txwit.vtxinwit);
for (std::vector<CTxInWitness>::const_iterator it = txwit.vtxinwit.begin(); it != txwit.vtxinwit.end(); it++) {
mem += RecursiveDynamicUsage(*it);
}
return mem;
static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
return RecursiveDynamicUsage(out.scriptPubKey);
}

static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
mem += RecursiveDynamicUsage(*it);
}
Expand All @@ -57,7 +41,7 @@ static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
}

static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout) + RecursiveDynamicUsage(tx.wit);
size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
mem += RecursiveDynamicUsage(*it);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
in.pushKV("scriptSig", o);
if (!tx.wit.IsNull() && i < tx.wit.vtxinwit.size() && !tx.wit.vtxinwit[i].IsNull()) {
if (!tx.vin[i].scriptWitness.IsNull()) {
UniValue txinwitness(UniValue::VARR);
for (const auto& item : tx.wit.vtxinwit[i].scriptWitness.stack) {
for (const auto& item : tx.vin[i].scriptWitness.stack) {
txinwitness.push_back(HexStr(item.begin(), item.end()));
}
in.pushKV("txinwitness", txinwitness);
Expand Down
4 changes: 2 additions & 2 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
BOOST_FOREACH (const CTxMemPool::txiter it, package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
if (!fIncludeWitness && !it->GetTx().wit.IsNull())
if (!fIncludeWitness && it->GetTx().HasWitness())
return false;
if (fNeedSizeAccounting) {
uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
Expand Down Expand Up @@ -554,7 +554,7 @@ void BlockAssembler::addPriorityTxs()
}

// cannot accept witness transactions into a non-witness block
if (!fIncludeWitness && !iter->GetTx().wit.IsNull())
if (!fIncludeWitness && iter->GetTx().HasWitness())
continue;

// If tx is dependent on other mempool txs which haven't yet been included
Expand Down
4 changes: 2 additions & 2 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
if (orphanTx.wit.IsNull() && !stateDummy.CorruptionPossible()) {
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
// Do not use rejection cache for witness transactions or
// witness-stripped transactions, as they can have been malleated.
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
Expand Down Expand Up @@ -1708,7 +1708,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
}
} else {
if (tx.wit.IsNull() && !state.CorruptionPossible()) {
if (!tx.HasWitness() && !state.CorruptionPossible()) {
// Do not use rejection cache for witness transactions or
// witness-stripped transactions, as they can have been malleated.
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
Expand Down
8 changes: 4 additions & 4 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
// We don't care if witness for this input is empty, since it must not be bloated.
// If the script is invalid without witness, it would be caught sooner or later during validation.
if (tx.wit.vtxinwit[i].IsNull())
if (tx.vin[i].scriptWitness.IsNull())
continue;

const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);
Expand Down Expand Up @@ -192,13 +192,13 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)

// Check P2WSH standard limits
if (witnessversion == 0 && witnessprogram.size() == 32) {
if (tx.wit.vtxinwit[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
return false;
size_t sizeWitnessStack = tx.wit.vtxinwit[i].scriptWitness.stack.size() - 1;
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
return false;
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
if (tx.wit.vtxinwit[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
return false;
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/primitives/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ 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), wit(tx.wit), nLockTime(tx.nLockTime) {}
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}

uint256 CMutableTransaction::GetHash() const
{
Expand All @@ -74,8 +74,8 @@ uint256 CTransaction::GetWitnessHash() const

/* 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), wit(tx.wit), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), wit(std::move(tx.wit)), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
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
{
Expand Down Expand Up @@ -131,8 +131,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 < 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;
Expand Down
99 changes: 31 additions & 68 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class CTxIn
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. */
Expand Down Expand Up @@ -211,62 +212,6 @@ class CTxOut
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)
{
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)
{
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;

/**
Expand Down Expand Up @@ -294,7 +239,6 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
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 >> tx.vin;
if (tx.vin.size() == 0 && fAllowWitness) {
Expand All @@ -311,8 +255,9 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
if ((flags & 1) && fAllowWitness) {
/* The witness flag is present, and we support witnesses. */
flags ^= 1;
tx.wit.vtxinwit.resize(tx.vin.size());
s >> tx.wit;
for (size_t i = 0; i < tx.vin.size(); i++) {
s >> tx.vin[i].scriptWitness.stack;
}
}
if (flags) {
/* Unknown flag in the serialization */
Expand All @@ -328,10 +273,9 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
s << tx.nVersion;
unsigned char flags = 0;
// Consistency check
assert(tx.wit.vtxinwit.size() <= tx.vin.size());
if (fAllowWitness) {
/* Check whether witnesses need to be serialized. */
if (!tx.wit.IsNull()) {
if (tx.HasWitness()) {
flags |= 1;
}
}
Expand All @@ -345,11 +289,7 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
s << tx.vout;
if (flags & 1) {
for (size_t i = 0; i < tx.vin.size(); i++) {
if (i < tx.wit.vtxinwit.size()) {
s << tx.wit.vtxinwit[i];
} else {
s << CTxInWitness();
}
s << tx.vin[i].scriptWitness.stack;
}
}
s << tx.nLockTime;
Expand Down Expand Up @@ -379,7 +319,6 @@ class CTransaction
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;

private:
Expand Down Expand Up @@ -451,6 +390,16 @@ class CTransaction
}

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. */
Expand All @@ -459,7 +408,6 @@ struct CMutableTransaction
int32_t nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
CTxWitness wit;
uint32_t nLockTime;

CMutableTransaction();
Expand All @@ -485,6 +433,21 @@ struct CMutableTransaction
* 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;
Expand Down
11 changes: 4 additions & 7 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));
}
if (!tx.wit.IsNull()) {
if (!tx.wit.vtxinwit[i].IsNull()) {
if (tx.HasWitness()) {
UniValue txinwitness(UniValue::VARR);
for (unsigned int j = 0; j < tx.wit.vtxinwit[i].scriptWitness.stack.size(); j++) {
std::vector<unsigned char> item = tx.wit.vtxinwit[i].scriptWitness.stack[j];
for (unsigned int j = 0; j < tx.vin[i].scriptWitness.stack.size(); j++) {
std::vector<unsigned char> item = tx.vin[i].scriptWitness.stack[j];
txinwitness.push_back(HexStr(item.begin(), item.end()));
}
in.push_back(Pair("txinwitness", txinwitness));
}

}
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
vin.push_back(in);
Expand Down Expand Up @@ -840,7 +837,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
UpdateTransaction(mergedTx, i, sigdata);

ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx.wit.vtxinwit.size() > i ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}
Expand Down
Loading

0 comments on commit f6fb7ac

Please sign in to comment.