The proof is in Bitcoin Core's transaction serialization code and BIP141.
In
src/primitives/transaction.h,
CTxOut contains
nValue and
scriptPubKey. The serialization code shows that transaction outputs and witness stacks are serialized separately:
s << tx.vin;
s << tx.vout;
if (flags & 1) {
for (size_t i = 0; i < tx.vin.size(); i++) {
s << tx.vin[i].scriptWitness.stack;
}
}
s << tx.nLockTime;
Here,
tx.vout contains the transaction outputs, while
scriptWitness.stack contains the witness data. The witness stacks are serialized separately when the witness flag is set.
Bitcoin Core calculates transaction weight using the serialized sizes with and without witness data:
return ::GetSerializeSize(TX_NO_WITNESS(tx)) * (WITNESS_SCALE_FACTOR - 1)
+ ::GetSerializeSize(TX_WITH_WITNESS(tx));
According to BIP141 base transaction size is defined as the transaction serialized without witness data. This means that any
OP_RETURN scripts are part of
tx.vout, which means they are included in base transaction size, rather than the witness data. As such, they do not get the witness discount.