Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ BITCOIN_CORE_H = \
util/message.h \
util/moneystr.h \
util/ranges.h \
util/underlying.h \
util/serfloat.h \
util/settings.h \
util/sock.h \
Expand Down
5 changes: 3 additions & 2 deletions src/evo/providertx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <consensus/validation.h>
#include <hash.h>
#include <script/standard.h>
#include <util/underlying.h>

maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
{
Expand Down Expand Up @@ -80,7 +81,7 @@ std::string CProRegTx::ToString() const
}

return strprintf("CProRegTx(nVersion=%d, nType=%d, collateralOutpoint=%s, addr=%s, nOperatorReward=%f, ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s, platformNodeID=%s, platformP2PPort=%d, platformHTTPPort=%d)",
nVersion, static_cast<int>(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
}

maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
Expand All @@ -101,7 +102,7 @@ std::string CProUpServTx::ToString() const
}

return strprintf("CProUpServTx(nVersion=%d, nType=%d, proTxHash=%s, addr=%s, operatorPayoutAddress=%s, platformNodeID=%s, platformP2PPort=%d, platformHTTPPort=%d)",
nVersion, static_cast<int>(nType), proTxHash.ToString(), addr.ToString(), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
nVersion, ToUnderlying(nType), proTxHash.ToString(), addr.ToString(), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
}

maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
Expand Down
5 changes: 3 additions & 2 deletions src/evo/providertx.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <pubkey.h>
#include <tinyformat.h>
#include <univalue.h>
#include <util/underlying.h>

class CBlockIndex;
class CCoinsViewCache;
Expand Down Expand Up @@ -92,7 +93,7 @@ class CProRegTx
obj.clear();
obj.setObject();
obj.pushKV("version", nVersion);
obj.pushKV("type", static_cast<uint16_t>(nType));
obj.pushKV("type", ToUnderlying(nType));
obj.pushKV("collateralHash", collateralOutpoint.hash.ToString());
obj.pushKV("collateralIndex", (int)collateralOutpoint.n);
obj.pushKV("service", addr.ToString(false));
Expand Down Expand Up @@ -178,7 +179,7 @@ class CProUpServTx
obj.clear();
obj.setObject();
obj.pushKV("version", nVersion);
obj.pushKV("type", static_cast<uint16_t>(nType));
obj.pushKV("type", ToUnderlying(nType));
obj.pushKV("proTxHash", proTxHash.ToString());
obj.pushKV("service", addr.ToString(false));
CTxDestination dest;
Expand Down
5 changes: 3 additions & 2 deletions src/evo/simplifiedmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <univalue.h>
#include <validation.h>
#include <key_io.h>
#include <util/underlying.h>

CSimplifiedMNListEntry::CSimplifiedMNListEntry(const CDeterministicMN& dmn) :
proRegTxHash(dmn.proTxHash),
Expand Down Expand Up @@ -57,7 +58,7 @@ std::string CSimplifiedMNListEntry::ToString() const
}

return strprintf("CSimplifiedMNListEntry(nType=%d, proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d, payoutAddress=%s, operatorPayoutAddress=%s, platformHTTPPort=%d, platformNodeID=%s)",
static_cast<int>(nType), proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), EncodeDestination(PKHash(keyIDVoting)), isValid, payoutAddress, operatorPayoutAddress, platformHTTPPort, platformNodeID.ToString());
ToUnderlying(nType), proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), EncodeDestination(PKHash(keyIDVoting)), isValid, payoutAddress, operatorPayoutAddress, platformHTTPPort, platformNodeID.ToString());
}

void CSimplifiedMNListEntry::ToJson(UniValue& obj, bool extended) const
Expand All @@ -71,7 +72,7 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj, bool extended) const
obj.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
obj.pushKV("isValid", isValid);
obj.pushKV("nVersion", nVersion);
obj.pushKV("nType", static_cast<uint16_t>(nType));
obj.pushKV("nType", ToUnderlying(nType));
if (nType == MnType::HighPerformance) {
obj.pushKV("platformHTTPPort", platformHTTPPort);
obj.pushKV("platformNodeID", platformNodeID.ToString());
Expand Down
31 changes: 16 additions & 15 deletions src/llmq/blockprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <saltedhasher.h>
#include <sync.h>
#include <util/irange.h>
#include <util/underlying.h>
#include <validation.h>

#include <map>
Expand Down Expand Up @@ -60,7 +61,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m

if (!Params().HasLLMQ(qc.llmqType)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__,
uint8_t(qc.llmqType), peer.GetId());
ToUnderlying(qc.llmqType), peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100));
return;
}
Expand Down Expand Up @@ -100,7 +101,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
}
if (HasMinedCommitment(type, qc.quorumHash)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- commitment for quorum hash[%s], type[%d], quorumIndex[%d] is already mined, peer=%d\n",
__func__, qc.quorumHash.ToString(), uint8_t(type), qc.quorumIndex, peer.GetId());
__func__, qc.quorumHash.ToString(), ToUnderlying(type), qc.quorumIndex, peer.GetId());
// NOTE: do not punish here
return;
}
Expand All @@ -123,13 +124,13 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
if (!qc.Verify(pQuorumBaseBlockIndex, true)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- commitment for quorum %s:%d is not valid quorumIndex[%d] nversion[%d], peer=%d\n",
__func__, qc.quorumHash.ToString(),
uint8_t(qc.llmqType), qc.quorumIndex, qc.nVersion, peer.GetId());
ToUnderlying(qc.llmqType), qc.quorumIndex, qc.nVersion, peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100));
return;
}

LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- received commitment for quorum %s:%d, validMembers=%d, signers=%d, peer=%d\n", __func__,
qc.quorumHash.ToString(), uint8_t(qc.llmqType), qc.CountValidMembers(), qc.CountSigners(), peer.GetId());
qc.quorumHash.ToString(), ToUnderlying(qc.llmqType), qc.CountValidMembers(), qc.CountSigners(), peer.GetId());

AddMineableCommitment(qc);
}
Expand Down Expand Up @@ -184,7 +185,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
for (const auto& p : qcs) {
const auto& qc = p.second;
if (!ProcessCommitment(pindex->nHeight, blockHash, qc, state, fJustCheck, fBLSChecks)) {
LogPrintf("[ProcessBlock] failed h[%d] llmqType[%d] version[%d] quorumIndex[%d] quorumHash[%s]\n", pindex->nHeight, static_cast<int>(qc.llmqType), qc.nVersion, qc.quorumIndex, qc.quorumHash.ToString());
LogPrintf("[ProcessBlock] failed h[%d] llmqType[%d] version[%d] quorumIndex[%d] quorumHash[%s]\n", pindex->nHeight, ToUnderlying(qc.llmqType), qc.nVersion, qc.quorumIndex, qc.quorumHash.ToString());
return false;
}
}
Expand Down Expand Up @@ -217,7 +218,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
uint256 quorumHash = GetQuorumBlockHash(llmq_params, nHeight, qc.quorumIndex);

LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s fJustCheck[%d] processing commitment from block.\n", __func__,
nHeight, uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString(), fJustCheck);
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString(), fJustCheck);

// skip `bad-qc-block` checks below when replaying blocks after the crash
if (::ChainActive().Tip() == nullptr) {
Expand All @@ -226,19 +227,19 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH

if (quorumHash.IsNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s quorumHash is null.\n", __func__,
nHeight, uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
}
if (quorumHash != qc.quorumHash) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, qc.quorumHash=%s signers=%s, validMembers=%d, quorumPublicKey=%s non equal quorumHash.\n", __func__,
nHeight, uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-block");
}

if (qc.IsNull()) {
if (!qc.VerifyNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%dqc verifynull failed.\n", __func__,
nHeight, uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid-null");
}
return true;
Expand All @@ -258,7 +259,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH

if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__,
nHeight, uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
nHeight, ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-invalid");
}

Expand Down Expand Up @@ -291,7 +292,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
}

LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- processed commitment from block. type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s\n", __func__,
uint8_t(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
ToUnderlying(qc.llmqType), qc.quorumIndex, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());

return true;
}
Expand Down Expand Up @@ -442,10 +443,10 @@ bool CQuorumBlockProcessor::IsMiningPhase(const Consensus::LLMQParams& llmqParam
int quorumCycleMiningEndHeight = quorumCycleStartHeight + llmqParams.dkgMiningWindowEnd;

if (nHeight >= quorumCycleMiningStartHeight && nHeight <= quorumCycleMiningEndHeight) {
LogPrint(BCLog::LLMQ, "[IsMiningPhase] nHeight[%d] llmqType[%d] quorumCycleStartHeight[%d] -- mining[%d-%d]\n", nHeight, int(llmqParams.type), quorumCycleStartHeight, quorumCycleMiningStartHeight, quorumCycleMiningEndHeight);
LogPrint(BCLog::LLMQ, "[IsMiningPhase] nHeight[%d] llmqType[%d] quorumCycleStartHeight[%d] -- mining[%d-%d]\n", nHeight, ToUnderlying(llmqParams.type), quorumCycleStartHeight, quorumCycleMiningStartHeight, quorumCycleMiningEndHeight);
return true;
}
LogPrint(BCLog::LLMQ, "[IsMiningPhase] nHeight[%d] llmqType[%d] quorumCycleStartHeight[%d] -- NOT mining[%d-%d]\n", nHeight, int(llmqParams.type), quorumCycleStartHeight, quorumCycleMiningStartHeight, quorumCycleMiningEndHeight);
LogPrint(BCLog::LLMQ, "[IsMiningPhase] nHeight[%d] llmqType[%d] quorumCycleStartHeight[%d] -- NOT mining[%d-%d]\n", nHeight, ToUnderlying(llmqParams.type), quorumCycleStartHeight, quorumCycleMiningStartHeight, quorumCycleMiningEndHeight);

return false;
}
Expand Down Expand Up @@ -481,11 +482,11 @@ uint256 CQuorumBlockProcessor::GetQuorumBlockHash(const Consensus::LLMQParams& l

uint256 quorumBlockHash;
if (!GetBlockHash(quorumBlockHash, quorumStartHeight)) {
LogPrint(BCLog::LLMQ, "[GetQuorumBlockHash] llmqType[%d] h[%d] qi[%d] quorumStartHeight[%d] quorumHash[EMPTY]\n", int(llmqParams.type), nHeight, quorumIndex, quorumStartHeight);
LogPrint(BCLog::LLMQ, "[GetQuorumBlockHash] llmqType[%d] h[%d] qi[%d] quorumStartHeight[%d] quorumHash[EMPTY]\n", ToUnderlying(llmqParams.type), nHeight, quorumIndex, quorumStartHeight);
return {};
}

LogPrint(BCLog::LLMQ, "[GetQuorumBlockHash] llmqType[%d] h[%d] qi[%d] quorumStartHeight[%d] quorumHash[%s]\n", int(llmqParams.type), nHeight, quorumIndex, quorumStartHeight, quorumBlockHash.ToString());
LogPrint(BCLog::LLMQ, "[GetQuorumBlockHash] llmqType[%d] h[%d] qi[%d] quorumStartHeight[%d] quorumHash[%s]\n", ToUnderlying(llmqParams.type), nHeight, quorumIndex, quorumStartHeight, quorumBlockHash.ToString());
return quorumBlockHash;
}

Expand Down
5 changes: 3 additions & 2 deletions src/llmq/commitment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <llmq/utils.h>
#include <logging.h>
#include <validation.h>
#include <util/underlying.h>

namespace llmq
{
Expand Down Expand Up @@ -46,7 +47,7 @@ bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool che
}

if (!Params().HasLLMQ(llmqType)) {
LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), ToUnderlying(llmqType));
return false;
}
const auto& llmq_params = GetLLMQParams(llmqType);
Expand Down Expand Up @@ -149,7 +150,7 @@ bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool che
bool CFinalCommitment::VerifyNull() const
{
if (!Params().HasLLMQ(llmqType)) {
LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), ToUnderlying(llmqType));
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion src/llmq/commitment.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <primitives/transaction.h>
#include <util/irange.h>
#include <util/strencodings.h>
#include <util/underlying.h>

#include <univalue.h>

Expand Down Expand Up @@ -114,7 +115,7 @@ class CFinalCommitment
{
obj.setObject();
obj.pushKV("version", int{nVersion});
obj.pushKV("llmqType", int(llmqType));
obj.pushKV("llmqType", ToUnderlying(llmqType));
obj.pushKV("quorumHash", quorumHash.ToString());
obj.pushKV("quorumIndex", quorumIndex);
obj.pushKV("signersCount", CountSigners());
Expand Down
7 changes: 4 additions & 3 deletions src/llmq/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <evo/deterministicmns.h>
#include <llmq/utils.h>
#include <util/irange.h>
#include <util/underlying.h>

namespace llmq
{
Expand All @@ -30,10 +31,10 @@ UniValue CDKGDebugSessionStatus::ToJson(int quorumIndex, int detailLevel) const
}
}

ret.pushKV("llmqType", static_cast<uint8_t>(llmqType));
ret.pushKV("llmqType", ToUnderlying(llmqType));
ret.pushKV("quorumHash", quorumHash.ToString());
ret.pushKV("quorumHeight", (int)quorumHeight);
ret.pushKV("phase", (int)phase);
ret.pushKV("phase", ToUnderlying(phase));

ret.pushKV("sentContributions", sentContributions);
ret.pushKV("sentComplaint", sentComplaint);
Expand Down Expand Up @@ -164,7 +165,7 @@ void CDKGDebugManager::InitLocalSessionStatus(const Consensus::LLMQParams& llmqP
session.llmqType = llmqParams.type;
session.quorumHash = quorumHash;
session.quorumHeight = (uint32_t)quorumHeight;
session.phase = 0;
session.phase = QuorumPhase{0};
session.statusBitset = 0;
session.members.clear();
session.members.resize((size_t)llmqParams.size);
Expand Down
4 changes: 3 additions & 1 deletion src/llmq/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <functional>
#include <set>

#include <llmq/dkgsessionhandler.h>

class CDataStream;
class CInv;
class CScheduler;
Expand Down Expand Up @@ -51,7 +53,7 @@ class CDKGDebugSessionStatus
Consensus::LLMQType llmqType{Consensus::LLMQType::LLMQ_NONE};
uint256 quorumHash;
uint32_t quorumHeight{0};
uint8_t phase{0};
QuorumPhase phase{0};

union {
struct
Expand Down
11 changes: 6 additions & 5 deletions src/llmq/dkgsession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@
#include <cxxtimer.hpp>
#include <memory>
#include <util/irange.h>
#include <util/underlying.h>

namespace llmq
{
static std::array<std::atomic<double>, int(DKGError::type::_COUNT)> simDkgErrorMap{};
static std::array<std::atomic<double>, ToUnderlying(DKGError::type::_COUNT)> simDkgErrorMap{};

void SetSimulatedDKGErrorRate(DKGError::type type, double rate)
{
if (int(type) >= DKGError::type::_COUNT) return;
simDkgErrorMap[int(type)] = rate;
if (type >= DKGError::type::_COUNT) return;
simDkgErrorMap[ToUnderlying(type)] = rate;
}

double GetSimulatedErrorRate(DKGError::type type)
{
if (int(type) >= DKGError::type::_COUNT) return 0;
return simDkgErrorMap[int(type)];
if (ToUnderlying(type) >= DKGError::type::_COUNT) return 0;
return simDkgErrorMap[ToUnderlying(type)];
}

bool CDKGSession::ShouldSimulateError(DKGError::type type) const
Expand Down
3 changes: 2 additions & 1 deletion src/llmq/dkgsession.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <llmq/commitment.h>
#include <llmq/utils.h>
#include <util/underlying.h>

#include <optional>

Expand Down Expand Up @@ -42,7 +43,7 @@ class CDKGContribution
template<typename Stream>
inline void SerializeWithoutSig(Stream& s) const
{
s << uint8_t(llmqType);
s << ToUnderlying(llmqType);
s << quorumHash;
s << proTxHash;
s << *vvec;
Expand Down
Loading