Skip to content

Commit

Permalink
pos: Fail coinstakes where the kernel is spent too far back in the
Browse files Browse the repository at this point in the history
chain.
  • Loading branch information
tecnovert committed Jun 29, 2019
1 parent cd66edf commit 9c7ee2f
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/insight/insight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
#include <script/interpreter.h>
#include <util/system.h>

bool fAddressIndex = false;
bool fTimestampIndex = false;
bool fSpentIndex = false;

bool ExtractIndexInfo(const CScript *pScript, int &scriptType, std::vector<uint8_t> &hashBytes)
{
CScript tmpScript;
Expand Down
4 changes: 4 additions & 0 deletions src/insight/insight.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

extern CCriticalSection cs_main;

extern bool fAddressIndex;
extern bool fSpentIndex;
extern bool fTimestampIndex;

class CTxOutBase;

bool ExtractIndexInfo(const CScript *pScript, int &scriptType, std::vector<uint8_t> &hashBytes);
Expand Down
21 changes: 20 additions & 1 deletion src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,10 +1027,29 @@ bool IncDuplicateHeaders(NodeId node_id) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true;
}

void IncPersistentMisbehaviour(NodeId node_id, int howmuch)
{
CNodeState *state = State(node_id);
if (state == nullptr) {
return;
}
auto it = map_dos_state.find(state->address);
if (it != map_dos_state.end()) {
if (state->nMisbehavior < it->second.m_misbehavior) {
state->nMisbehavior = it->second.m_misbehavior;
LogPrint(BCLog::NET, "%s: %s peer=%d Inherited misbehavior (%d)\n", __func__, state->name, node_id, state->nMisbehavior);
}
it->second.m_misbehavior += howmuch;
return;
}
map_dos_state[state->address].m_misbehavior = howmuch;
return;
}

int GetNumDOSStates()
{
return map_dos_state.size();
};
}

//////////////////////////////////////////////////////////////////////////////
//
Expand Down
1 change: 1 addition & 0 deletions src/net_processing.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ void DecMisbehaving(NodeId nodeid, int howmuch) EXCLUSIVE_LOCKS_REQUIRED(cs_main

NodeId GetBlockSource(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

void IncPersistentMisbehaviour(NodeId node_id, int howmuch) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
int GetNumDOSStates() EXCLUSIVE_LOCKS_REQUIRED(cs_main);

#endif // BITCOIN_NET_PROCESSING_H
61 changes: 61 additions & 0 deletions src/pos/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <policy/policy.h>
#include <consensus/validation.h>
#include <coins.h>
#include <insight/insight.h>
#include <txmempool.h>

/**
* Stake Modifier (hash modifier of proof-of-stake):
Expand Down Expand Up @@ -145,6 +147,61 @@ static bool CheckAge(const CBlockIndex *pindexTip, const uint256 &hashKernelBloc
return true;
}

int MAX_REORG_DEPTH = 1024;
static bool SpendTooDeep(const COutPoint &prevout) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
LogPrint(BCLog::POS, "%s: SpendTooDeep %s.\n", __func__, prevout.ToString());
CBlockIndex *pindexTip = ::ChainActive().Tip();

if (fSpentIndex) {
CSpentIndexKey key(prevout.hash, prevout.n);
CSpentIndexValue value;
if (GetSpentIndex(key, value)) {
if (value.blockHeight < 0 || pindexTip->nHeight - value.blockHeight <= MAX_REORG_DEPTH) {
return false;
}
}
return true;
}

// Check for spend in mempool
LOCK(::mempool.cs);
auto iters = ::mempool.GetSortedDepthAndScore();
for (auto it : iters) {
for (const CTxIn &txin : it->GetSharedTx()->vin) {
if (txin.IsAnonInput()) {
continue;
}
if (txin.prevout == prevout) {
return false;
}
}
}

// Check for spend in blocks
CBlockIndex *pindex = pindexTip;
CBlock block;
while (pindex && pindexTip->nHeight - pindex->nHeight < MAX_REORG_DEPTH) {
if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), Params().GetConsensus())) {
LogPrintf("%s: Error reading block %s.\n", __func__, pindex->GetBlockHash().ToString());
return true;
}
for (const auto &tx : block.vtx) {
for (const CTxIn &txin : tx->vin) {
if (txin.IsAnonInput()) {
continue;
}
if (txin.prevout == prevout) {
return false;
}
}
}
pindex = pindex->pprev;
}

return true;
}

// Check kernel hash target and coinstake signature
bool CheckProofOfStake(CValidationState &state, const CBlockIndex *pindexPrev, const CTransaction &tx, int64_t nTime, unsigned int nBits, uint256 &hashProofOfStake, uint256 &targetProofOfStake)
{
Expand Down Expand Up @@ -193,6 +250,10 @@ bool CheckProofOfStake(CValidationState &state, const CBlockIndex *pindexPrev, c
return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");
}

if (SpendTooDeep(txin.prevout)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: Tried to stake spent kernel", __func__), REJECT_INVALID, "invalid-prevout");
}

kernelPubKey = *outPrev->GetPScriptPubKey();
amount = outPrev->GetValue();
nBlockFromTime = blockKernel.nTime;
Expand Down
1 change: 1 addition & 0 deletions src/txmempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ class CTxMemPool
void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);

public:
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs);

public:
Expand Down
5 changes: 2 additions & 3 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,6 @@ std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
std::atomic_bool fSkipRangeproof(false);
std::atomic_bool fBusyImporting(false); // covers ActivateBestChain too
bool fAddressIndex = false;
bool fTimestampIndex = false;
bool fSpentIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
Expand Down Expand Up @@ -4639,6 +4636,7 @@ class DelayedBlock
std::list<DelayedBlock> list_delayed_blocks;

extern void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="") EXCLUSIVE_LOCKS_REQUIRED(cs_main);
extern void IncPersistentMisbehaviour(NodeId node_id, int howmuch) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
extern bool AddNodeHeader(NodeId node_id, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
extern void RemoveNodeHeader(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
extern void RemoveNonReceivedHeaderFromNodes(BlockMap::iterator mi) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
Expand Down Expand Up @@ -5060,6 +5058,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali

if (state.nFlags & BLOCK_STAKE_KERNEL_SPENT && !(state.nFlags & BLOCK_FAILED_DUPLICATE_STAKE)) {
if (state.nodeId > -1) {
IncPersistentMisbehaviour(state.nodeId, 20);
Misbehaving(state.nodeId, 20, "Spent kernel");
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,6 @@ extern std::atomic_bool fReindex;
extern std::atomic_bool fSkipRangeproof;
extern std::atomic_bool fBusyImporting;
extern int nScriptCheckThreads;
extern bool fAddressIndex;
extern bool fSpentIndex;
extern bool fTimestampIndex;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
Expand Down

0 comments on commit 9c7ee2f

Please sign in to comment.