Merge #974: Slightly refactor sporks

6648716 Slightly refactor sporks, rename spork9 to SPORK_9_SUPERBLOCKS_ENABLED, remove SPORK_11_RESET_BUDGET (not used anymore)
This commit is contained in:
UdjinM6 2016-08-29 23:16:02 +04:00 committed by Holger Schinzel
parent bf335ddfb3
commit 0cf75d0ef7
4 changed files with 115 additions and 109 deletions

View File

@ -89,7 +89,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar
}
// triggered but invalid? that's weird
if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT)) {
if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)) {
LogPrintf("IsBlockValueValid -- ERROR: Invalid superblock detected at height %d: %s", nBlockHeight, block.vtx[0].ToString());
// should NOT allow invalid superblocks, when superblock enforcement is enabled
return false;
@ -155,7 +155,7 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc
return true;
}
if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT)) {
if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)) {
LogPrintf("IsBlockPayeeValid -- ERROR: Invalid superblock detected at height %d: %s", nBlockHeight, txNew.ToString());
// should NOT allow such superblocks, when superblock enforcement is enabled
return false;
@ -187,7 +187,7 @@ void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blo
{
// only create superblocks if spork is enabled AND if superblock is actually triggered
// (height should be validated inside)
if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT) &&
if(sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED) &&
CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) {
LogPrint("gobject", "FillBlockPayments -- triggered superblock creation at height %d\n", nBlockHeight);
CSuperblockManager::CreateSuperblock(txNew, nBlockHeight, voutSuperblockRet);

View File

@ -638,7 +638,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
}
result.push_back(Pair("superblock", superblockObjArray));
result.push_back(Pair("superblocks_started", pindexPrev->nHeight + 1 > Params().GetConsensus().nSuperblockStartBlock));
result.push_back(Pair("superblocks_enabled", sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT)));
result.push_back(Pair("superblocks_enabled", sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)));
return result;
}

View File

@ -19,8 +19,8 @@ void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStr
{
if(fLiteMode) return; // disable all Dash specific functionality
if (strCommand == NetMsgType::SPORK)
{
if (strCommand == NetMsgType::SPORK) {
// LogPrintf("CSporkManager::ProcessSpork\n");
CDataStream vMsg(vRecv);
CSporkMessage spork;
@ -31,17 +31,17 @@ void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStr
uint256 hash = spork.GetHash();
if(mapSporksActive.count(spork.nSporkID)) {
if(mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned){
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- seen %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
if (mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned) {
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- seen %s block %d\n", hash.ToString(), chainActive.Tip()->nHeight);
return;
} else {
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- got updated spork %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
if(fDebug) LogPrintf("CSporkManager::ProcessSpork -- got updated spork %s block %d\n", hash.ToString(), chainActive.Tip()->nHeight);
}
}
LogPrintf("spork -- new %s ID %d Time %d bestHeight %d\n", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight);
LogPrintf("spork -- hash: %s id: %d value: %10d bestHeight: %d new\n", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight);
if(!spork.CheckSignature()){
if(!spork.CheckSignature()) {
LogPrintf("CSporkManager::ProcessSpork -- invalid signature\n");
Misbehaving(pfrom->GetId(), 100);
return;
@ -53,9 +53,9 @@ void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStr
//does a task if needed
ExecuteSpork(spork.nSporkID, spork.nValue);
}
if (strCommand == NetMsgType::GETSPORKS)
{
} else if (strCommand == NetMsgType::GETSPORKS) {
std::map<int, CSporkMessage>::iterator it = mapSporksActive.begin();
while(it != mapSporksActive.end()) {
@ -68,10 +68,6 @@ void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStr
void CSporkManager::ExecuteSpork(int nSporkID, int nValue)
{
// if(nSporkID == SPORK_11_RESET_BUDGET && nValue == 1){
// budget.Clear();
// }
//correct fork via spork technology
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0) {
LogPrintf("CSporkManager::ExecuteSpork -- Reconsider Last %d Blocks\n", nValue);
@ -85,7 +81,7 @@ bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue)
CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetTime());
if(spork.Sign(strMasterPrivKey)){
if(spork.Sign(strMasterPrivKey)) {
spork.Relay();
mapSporks[spork.GetHash()] = spork;
mapSporksActive[nSporkID] = spork;
@ -103,20 +99,22 @@ bool CSporkManager::IsSporkActive(int nSporkID)
if(mapSporksActive.count(nSporkID)){
r = mapSporksActive[nSporkID].nValue;
} else {
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
if(nSporkID == SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT) r = SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT_DEFAULT;
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
if(nSporkID == SPORK_13_OLD_SUPERBLOCK_FLAG) r = SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT;
if(r == -1) LogPrintf("CSporkManager::IsSporkActive -- Unknown Spork %d\n", nSporkID);
switch (nSporkID) {
case SPORK_2_INSTANTX: r = SPORK_2_INSTANTX_DEFAULT; break;
case SPORK_3_INSTANTX_BLOCK_FILTERING: r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT; break;
case SPORK_5_MAX_VALUE: r = SPORK_5_MAX_VALUE_DEFAULT; break;
case SPORK_7_MASTERNODE_SCANNING: r = SPORK_7_MASTERNODE_SCANNING_DEFAULT; break;
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT; break;
case SPORK_9_SUPERBLOCKS_ENABLED: r = SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT; break;
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT; break;
case SPORK_12_RECONSIDER_BLOCKS: r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT; break;
case SPORK_13_OLD_SUPERBLOCK_FLAG: r = SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT; break;
default:
LogPrintf("CSporkManager::IsSporkActive -- Unknown Spork %d\n", nSporkID);
r = 4070908800; // 2099-1-1 i.e. off by default
break;
}
}
if(r == -1) r = 4070908800; //return 2099-1-1 by default
return r < GetTime();
}
@ -124,58 +122,58 @@ bool CSporkManager::IsSporkActive(int nSporkID)
// grab the value of the spork on the network, or the default
int64_t CSporkManager::GetSporkValue(int nSporkID)
{
int64_t r = -1;
if (mapSporksActive.count(nSporkID))
return mapSporksActive[nSporkID].nValue;
if(mapSporksActive.count(nSporkID)){
r = mapSporksActive[nSporkID].nValue;
} else {
if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
if(nSporkID == SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT) r = SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT_DEFAULT;
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
if(nSporkID == SPORK_13_OLD_SUPERBLOCK_FLAG) r = SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT;
if(r == -1) LogPrintf("CSporkManager::GetSporkValue -- Unknown Spork %d\n", nSporkID);
switch (nSporkID) {
case SPORK_2_INSTANTX: return SPORK_2_INSTANTX_DEFAULT;
case SPORK_3_INSTANTX_BLOCK_FILTERING: return SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
case SPORK_5_MAX_VALUE: return SPORK_5_MAX_VALUE_DEFAULT;
case SPORK_7_MASTERNODE_SCANNING: return SPORK_7_MASTERNODE_SCANNING_DEFAULT;
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
case SPORK_9_SUPERBLOCKS_ENABLED: return SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT;
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: return SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT;
case SPORK_12_RECONSIDER_BLOCKS: return SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
case SPORK_13_OLD_SUPERBLOCK_FLAG: return SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT;
default:
LogPrintf("CSporkManager::GetSporkValue -- Unknown Spork ID %d\n", nSporkID);
return -1;
}
return r;
}
int CSporkManager::GetSporkIDByName(std::string strName)
{
if(strName == "SPORK_2_INSTANTX") return SPORK_2_INSTANTX;
if(strName == "SPORK_3_INSTANTX_BLOCK_FILTERING") return SPORK_3_INSTANTX_BLOCK_FILTERING;
if(strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE;
if(strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING;
if(strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT;
if(strName == "SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT") return SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT;
if(strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES;
if(strName == "SPORK_11_RESET_BUDGET") return SPORK_11_RESET_BUDGET;
if(strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS;
if(strName == "SPORK_13_OLD_SUPERBLOCK_FLAG") return SPORK_13_OLD_SUPERBLOCK_FLAG;
if (strName == "SPORK_2_INSTANTX") return SPORK_2_INSTANTX;
if (strName == "SPORK_3_INSTANTX_BLOCK_FILTERING") return SPORK_3_INSTANTX_BLOCK_FILTERING;
if (strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE;
if (strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING;
if (strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT;
if (strName == "SPORK_9_SUPERBLOCKS_ENABLED") return SPORK_9_SUPERBLOCKS_ENABLED;
if (strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_PAY_UPDATED_NODES;
if (strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS;
if (strName == "SPORK_13_OLD_SUPERBLOCK_FLAG") return SPORK_13_OLD_SUPERBLOCK_FLAG;
LogPrintf("CSporkManager::GetSporkIDByName -- Unknown Spork name '%s'\n", strName);
return -1;
}
std::string CSporkManager::GetSporkNameByID(int nSporkID)
{
if(nSporkID == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
if(nSporkID == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
if(nSporkID == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
if(nSporkID == SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT) return "SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT";
if(nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";
if(nSporkID == SPORK_11_RESET_BUDGET) return "SPORK_11_RESET_BUDGET";
if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) return "SPORK_12_RECONSIDER_BLOCKS";
if(nSporkID == SPORK_13_OLD_SUPERBLOCK_FLAG) return "SPORK_13_OLD_SUPERBLOCK_FLAG";
return "Unknown";
switch (nSporkID) {
case SPORK_2_INSTANTX: return "SPORK_2_INSTANTX_DEFAULT";
case SPORK_3_INSTANTX_BLOCK_FILTERING: return "SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT";
case SPORK_5_MAX_VALUE: return "SPORK_5_MAX_VALUE_DEFAULT";
case SPORK_7_MASTERNODE_SCANNING: return "SPORK_7_MASTERNODE_SCANNING_DEFAULT";
case SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT: return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT";
case SPORK_9_SUPERBLOCKS_ENABLED: return "SPORK_9_SUPERBLOCKS_ENABLED";
case SPORK_10_MASTERNODE_PAY_UPDATED_NODES: return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT";
case SPORK_12_RECONSIDER_BLOCKS: return "SPORK_12_RECONSIDER_BLOCKS_DEFAULT";
case SPORK_13_OLD_SUPERBLOCK_FLAG: return "SPORK_13_OLD_SUPERBLOCK_FLAG";
default:
LogPrintf("CSporkManager::GetSporkNameByID -- Unknown Spork ID %d\n", nSporkID);
return "Unknown";
}
}
bool CSporkManager::SetPrivKey(std::string strPrivKey)

View File

@ -9,37 +9,35 @@
#include "net.h"
#include "utilstrencodings.h"
class CSporkMessage;
class CSporkManager;
/*
Don't ever reuse these IDs for other sporks
- This would result in old clients getting confused about which spork is for what
*/
#define SPORK_START 10001
#define SPORK_END 10012
static const int SPORK_START = 10001;
static const int SPORK_END = 10012;
#define SPORK_2_INSTANTX 10001
#define SPORK_3_INSTANTX_BLOCK_FILTERING 10002
#define SPORK_5_MAX_VALUE 10004
#define SPORK_7_MASTERNODE_SCANNING 10006
#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT 10007
#define SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT 10008
#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES 10009
#define SPORK_11_RESET_BUDGET 10010
#define SPORK_12_RECONSIDER_BLOCKS 10011
#define SPORK_13_OLD_SUPERBLOCK_FLAG 10012
static const int SPORK_2_INSTANTX = 10001;
static const int SPORK_3_INSTANTX_BLOCK_FILTERING = 10002;
static const int SPORK_5_MAX_VALUE = 10004;
static const int SPORK_7_MASTERNODE_SCANNING = 10006;
static const int SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT = 10007;
static const int SPORK_9_SUPERBLOCKS_ENABLED = 10008;
static const int SPORK_10_MASTERNODE_PAY_UPDATED_NODES = 10009;
static const int SPORK_12_RECONSIDER_BLOCKS = 10011;
static const int SPORK_13_OLD_SUPERBLOCK_FLAG = 10012;
#define SPORK_2_INSTANTX_DEFAULT 978307200 //2001-1-1
#define SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT 1424217600 //2015-2-18
#define SPORK_5_MAX_VALUE_DEFAULT 1000 //1000 DASH
#define SPORK_7_MASTERNODE_SCANNING_DEFAULT 978307200 //2001-1-1
#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT 4070908800 //OFF
#define SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT_DEFAULT 4070908800 //OFF
#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT 4070908800 //OFF
#define SPORK_11_RESET_BUDGET_DEFAULT 0
#define SPORK_12_RECONSIDER_BLOCKS_DEFAULT 0
#define SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT 4070908800 //OFF
class CSporkMessage;
class CSporkManager;
static const int64_t SPORK_2_INSTANTX_DEFAULT = 978307200; //2001-1-1
static const int64_t SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT = 1424217600; //2015-2-18
static const int64_t SPORK_5_MAX_VALUE_DEFAULT = 1000; //1000 DASH
static const int64_t SPORK_7_MASTERNODE_SCANNING_DEFAULT = 978307200; //2001-1-1
static const int64_t SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT = 4070908800; //OFF
static const int64_t SPORK_9_SUPERBLOCKS_ENABLED_DEFAULT = 4070908800; //OFF
static const int64_t SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT = 4070908800; //OFF
static const int64_t SPORK_12_RECONSIDER_BLOCKS_DEFAULT = 0;
static const int64_t SPORK_13_OLD_SUPERBLOCK_FLAG_DEFAULT = 4070908800; //OFF
extern std::map<uint256, CSporkMessage> mapSporks;
extern CSporkManager sporkManager;
@ -59,10 +57,30 @@ public:
int64_t nValue;
int64_t nTimeSigned;
CSporkMessage(int nSporkID, int64_t nValue, int64_t nTimeSigned) : nSporkID(nSporkID), nValue(nValue), nTimeSigned(nTimeSigned) {}
CSporkMessage() : nSporkID(0), nValue(0), nTimeSigned(0) {}
CSporkMessage(int nSporkID, int64_t nValue, int64_t nTimeSigned) :
nSporkID(nSporkID),
nValue(nValue),
nTimeSigned(nTimeSigned)
{}
uint256 GetHash()
CSporkMessage() :
nSporkID(0),
nValue(0),
nTimeSigned(0)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(nSporkID);
READWRITE(nValue);
READWRITE(nTimeSigned);
READWRITE(vchSig);
}
uint256 GetHash() const
{
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << nSporkID;
@ -74,16 +92,6 @@ public:
bool Sign(std::string strSignKey);
bool CheckSignature();
void Relay();
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(nSporkID);
READWRITE(nValue);
READWRITE(nTimeSigned);
READWRITE(vchSig);
}
};