結論
flagに0セットしてWitness部分を取り除いたものをdouble sha256する。
コード読み
core_write.cppのTxToUnivというgetrawtransactionの結果を作っていると思われる関数に、
entry.pushKV("txid", tx.GetHash().GetHex());
という箇所があった。ここではTransactionからtxidを作成しているっぽい。
tx.GetHash()は、SERIALIZE_TRANSACTION_NO_WITNESSフラグを設定してSerializeHashを呼ぶ
// primitives/transaction.cpp
uint256 CMutableTransaction::GetHash() const
{
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
}
SERIALiZE_NO_WITNESSをVersionに設定したCHashWriterを作り、<<にtxを送ると
// hash.h
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
CHashWriter ss(nType, nVersion);
ss << obj;
return ss.GetHash();
}
CTransactionのSerializeが、CHashWriterをStreamとして受け取る
// hash.h
template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj); return (*this);
}
グローバルのジェネリックな::Serializeを介してCTransactionのSerializeが呼ばれる
template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a)
{
a.Serialize(os);
}
そしてグローバルのSerializeTransactionが呼ばれる
template <typename Stream>
inline void Serialize(Stream& s) const {
SerializeTransaction(*this, s);
}
SerializeTransactionでは、serialize.hで定義された型ごとのシリアライザによって、シリアライズされたCTransactionがCHashWriterに書き込まれる。上でCHashWriterにセットしたバージョン(SERIALIZE_TRANSACTION_NO_WITNESS)によってflagsに0が設定されるので、witness部分はシリアライズされない。
template<typename Stream, typename TxType>
inline void SerializeTransaction(const TxType& tx, Stream& s) {
const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
s << tx.nVersion;
// Consistency check
assert(tx.witness.vtxinwit.size() <= tx.vin.size());
assert(tx.witness.vtxoutwit.size() <= tx.vout.size());
// Check whether witnesses need to be serialized.
unsigned char flags = 0;
if (fAllowWitness && tx.HasWitness()) {
flags |= 1;
}
// Witness serialization is different between Elements and Core.
if (g_con_elementsmode) {
// In Elements-style serialization, all normal data is serialized first and the
// witnesses all in the end.
s << flags;
s << tx.vin;
s << tx.vout;
s << tx.nLockTime;
if (flags & 1) {
const_cast<CTxWitness*>(&tx.witness)->vtxinwit.resize(tx.vin.size());
const_cast<CTxWitness*>(&tx.witness)->vtxoutwit.resize(tx.vout.size());
s << tx.witness;
}
}
...
SerializeHashに戻って、CHashWriterのGetHashが呼ばれる。
// hash.h
class CHashWriter
{
private:
CHash256 ctx;
...
// invalidates the object
uint256 GetHash() {
uint256 result;
ctx.Finalize((unsigned char*)&result);
return result;
}
...
GetHashは、シリアライズ時にCHashWriterに書き込まれたデーターのdouble SHA-256を返す
// hash.h
private:
CSHA256 sha;
public:
...
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
unsigned char buf[CSHA256::OUTPUT_SIZE];
sha.Finalize(buf);
sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
}
...
GetHash()の戻り値uint256に対してGetHex()が呼ばれて、txid文字列が作られる。(終)