2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "bignum.h"
|
|
|
|
#include "sync.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "script.h"
|
|
|
|
#include "base58.h"
|
|
|
|
#include "protocol.h"
|
|
|
|
#include "instantx.h"
|
|
|
|
#include "masternode.h"
|
|
|
|
#include "activemasternode.h"
|
|
|
|
#include "darksend.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace boost;
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
std::map<uint256, CTransaction> mapTxLockReq;
|
|
|
|
std::map<uint256, CTransaction> mapTxLockReqRejected;
|
2015-02-01 16:53:49 +01:00
|
|
|
std::map<uint256, int> mapTxLockVote;
|
2014-12-09 02:17:57 +01:00
|
|
|
std::map<uint256, CTransactionLock> mapTxLocks;
|
2015-02-02 15:36:00 +01:00
|
|
|
std::map<uint256, int> mapUnknownVotes; //track votes with no tx for DOS
|
2015-02-01 21:04:20 +01:00
|
|
|
int nCompleteTXLocks;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
//txlock - Locks transaction
|
|
|
|
//
|
|
|
|
//step 1.) Broadcast intention to lock transaction inputs, "txlreg", CTransaction
|
|
|
|
//step 2.) Top 10 masternodes, open connect to top 1 masternode. Send "txvote", CTransaction, Signature, Approve
|
|
|
|
//step 3.) Top 1 masternode, waits for 10 messages. Upon success, sends "txlock'
|
|
|
|
|
|
|
|
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
|
|
|
{
|
2015-01-18 16:28:16 +01:00
|
|
|
if(fLiteMode) return; //disable all darksend/masternode related functionality
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
if (strCommand == "txlreq")
|
|
|
|
{
|
|
|
|
//LogPrintf("ProcessMessageInstantX::txlreq\n");
|
|
|
|
CDataStream vMsg(vRecv);
|
|
|
|
CTransaction tx;
|
|
|
|
vRecv >> tx;
|
|
|
|
|
|
|
|
CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
|
|
|
|
pfrom->AddInventoryKnown(inv);
|
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
if(mapTxLockReq.count(tx.GetHash()) || mapTxLockReqRejected.count(tx.GetHash())){
|
2014-12-09 02:17:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-01 17:16:31 +01:00
|
|
|
int nTxAge = 0;
|
|
|
|
BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){
|
|
|
|
nTxAge = GetInputAge(i);
|
|
|
|
if(nTxAge <= 5){
|
|
|
|
LogPrintf("ProcessMessageInstantX::txlreq - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString().c_str());
|
|
|
|
return;
|
|
|
|
}
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
int nBlockHeight = chainActive.Tip()->nHeight - nTxAge; //calculate the height
|
|
|
|
|
|
|
|
BOOST_FOREACH(const CTxOut o, tx.vout){
|
|
|
|
if(!o.scriptPubKey.IsNormalPaymentScript()){
|
2015-02-01 16:53:49 +01:00
|
|
|
printf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fMissingInputs = false;
|
|
|
|
CValidationState state;
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
|
|
|
{
|
2015-02-02 15:36:00 +01:00
|
|
|
RelayTransactionLockReq(tx, tx.GetHash());
|
2014-12-31 03:54:00 +01:00
|
|
|
DoConsensusVote(tx, true, nBlockHeight);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : accepted %s\n",
|
|
|
|
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
|
|
|
tx.GetHash().ToString().c_str()
|
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
mapTxLockReqRejected.insert(make_pair(inv.hash, tx));
|
|
|
|
|
|
|
|
// can we get the conflicting transaction as proof?
|
|
|
|
|
|
|
|
RelayTransactionLockReq(tx, inv.hash);
|
2014-12-31 03:54:00 +01:00
|
|
|
DoConsensusVote(tx, false, nBlockHeight);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
|
|
|
|
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
|
|
|
tx.GetHash().ToString().c_str()
|
|
|
|
);
|
|
|
|
|
|
|
|
//record prevout, increment the amount of times seen. Ban if over 100
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2014-12-31 03:54:00 +01:00
|
|
|
}
|
2014-12-09 02:17:57 +01:00
|
|
|
else if (strCommand == "txlvote") //InstantX Lock Consensus Votes
|
|
|
|
{
|
|
|
|
CConsensusVote ctx;
|
|
|
|
vRecv >> ctx;
|
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
CInv inv(MSG_TXLOCK_VOTE, ctx.GetHash());
|
2014-12-09 02:17:57 +01:00
|
|
|
pfrom->AddInventoryKnown(inv);
|
|
|
|
|
2015-02-01 21:37:20 +01:00
|
|
|
if(mapTxLockVote.count(ctx.GetHash())){
|
2015-02-01 16:53:49 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-01 21:37:20 +01:00
|
|
|
mapTxLockVote.insert(make_pair(ctx.GetHash(), 1));
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
if(ProcessConsensusVote(ctx)){
|
|
|
|
//Spam/Dos protection
|
|
|
|
if(!mapTxLockReq.count(ctx.txHash) && !mapTxLockReqRejected.count(ctx.txHash)){
|
|
|
|
if(!mapUnknownVotes.count(ctx.vinMasternode.prevout.hash)){
|
|
|
|
//TODO: Make an algorithm to calculate the average time per IX/MNCOUNT
|
|
|
|
mapUnknownVotes[ctx.vinMasternode.prevout.hash] = GetTime()+(60*10);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mapUnknownVotes[ctx.vinMasternode.prevout.hash] > GetTime()){
|
|
|
|
LogPrintf("ProcessMessageInstantX::txlreq - masternode is spamming transaction votes: %s %s : rejected %s\n",
|
|
|
|
ctx.vinMasternode.ToString().c_str(),
|
|
|
|
ctx.txHash.ToString().c_str()
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
mapUnknownVotes[ctx.vinMasternode.prevout.hash] = GetTime()+(60*10);
|
|
|
|
}
|
|
|
|
}
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
LOCK(cs_vNodes);
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes)
|
|
|
|
{
|
|
|
|
if(!pnode->fRelayTxes)
|
|
|
|
continue;
|
2015-02-02 13:01:06 +01:00
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
pnode->PushMessage("txlvote", ctx);
|
|
|
|
}
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
2015-02-01 21:37:20 +01:00
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
return;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if we need to vote on this transaction
|
|
|
|
void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight)
|
|
|
|
{
|
2015-02-01 16:53:49 +01:00
|
|
|
if(!fMasterNode) return;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
CConsensusVote ctx;
|
2014-12-06 20:41:53 +01:00
|
|
|
ctx.vinMasternode = activeMasternode.vin;
|
2015-02-02 13:24:04 +01:00
|
|
|
ctx.txHash = tx.GetHash();
|
2014-12-31 03:54:00 +01:00
|
|
|
ctx.nBlockHeight = nBlockHeight;
|
2014-12-09 02:17:57 +01:00
|
|
|
if(!ctx.Sign()){
|
|
|
|
LogPrintf("InstantX::DoConsensusVote - Failed to sign consensus vote\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!ctx.SignatureValid()) {
|
|
|
|
LogPrintf("InstantX::DoConsensusVote - Signature invalid\n");
|
|
|
|
return;
|
|
|
|
}
|
2015-02-02 13:01:06 +01:00
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
LOCK(cs_vNodes);
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes)
|
|
|
|
{
|
|
|
|
//LogPrintf("%s::check -- %s %s\n", vecMasternodes[winner].addr.ToString().c_str(), pnode->addr.ToString().c_str());
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
pnode->PushMessage("txlvote", ctx);
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//received a consensus vote
|
2015-02-02 15:36:00 +01:00
|
|
|
bool ProcessConsensusVote(CConsensusVote& ctx)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
int n = GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
|
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(n == -1)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - Unknown Masternode\n");
|
2015-02-02 15:36:00 +01:00
|
|
|
return false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(n > 10)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10\n");
|
2015-02-02 15:36:00 +01:00
|
|
|
return false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!ctx.SignatureValid()) {
|
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - Signature invalid\n");
|
|
|
|
//don't ban, it could just be a non-synced masternode
|
2015-02-02 15:36:00 +01:00
|
|
|
return false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
2015-02-02 13:24:04 +01:00
|
|
|
if (!mapTxLocks.count(ctx.txHash)){
|
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str());
|
2015-02-01 21:04:20 +01:00
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
CTransactionLock newLock;
|
|
|
|
newLock.nBlockHeight = ctx.nBlockHeight;
|
2015-02-01 21:04:20 +01:00
|
|
|
newLock.nExpiration = GetTime()+(60*60);
|
2015-02-02 13:24:04 +01:00
|
|
|
newLock.txHash = ctx.txHash;
|
|
|
|
mapTxLocks.insert(make_pair(ctx.txHash, newLock));
|
2015-02-01 21:04:20 +01:00
|
|
|
} else {
|
2015-02-02 13:24:04 +01:00
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Exists %s !\n", ctx.txHash.ToString().c_str());
|
2015-02-01 16:53:49 +01:00
|
|
|
}
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
//compile consessus vote
|
2015-02-02 13:24:04 +01:00
|
|
|
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(ctx.txHash);
|
2015-02-01 16:53:49 +01:00
|
|
|
if (i != mapTxLocks.end()){
|
|
|
|
(*i).second.AddSignature(ctx);
|
|
|
|
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
|
2015-02-01 18:47:56 +01:00
|
|
|
LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str());
|
2015-02-02 13:24:04 +01:00
|
|
|
if(pwalletMain->UpdatedTransaction((*i).second.txHash))
|
2015-02-02 13:06:43 +01:00
|
|
|
nCompleteTXLocks++;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
2015-02-02 15:36:00 +01:00
|
|
|
return true;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
|
2015-02-02 15:36:00 +01:00
|
|
|
return false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CleanTransactionLocksList()
|
|
|
|
{
|
|
|
|
if(chainActive.Tip() == NULL) return;
|
|
|
|
|
|
|
|
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
while(it != mapTxLocks.end()) {
|
2015-02-01 21:04:20 +01:00
|
|
|
if(GetTime() > it->second.nExpiration){ //keep them for an hour
|
2015-02-02 13:24:04 +01:00
|
|
|
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
mapTxLocks.erase(it++);
|
|
|
|
} else {
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
uint256 CConsensusVote::GetHash() const
|
|
|
|
{
|
2015-02-02 13:24:04 +01:00
|
|
|
return vinMasternode.prevout.hash + txHash;
|
2015-02-01 16:53:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
bool CConsensusVote::SignatureValid()
|
|
|
|
{
|
|
|
|
std::string errorMessage;
|
2015-02-02 15:36:00 +01:00
|
|
|
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight);
|
2015-02-01 16:53:49 +01:00
|
|
|
//LogPrintf("verify strMessage %s \n", strMessage.c_str());
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
int n = GetMasternodeByVin(vinMasternode);
|
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(n == -1)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-01 16:53:49 +01:00
|
|
|
//LogPrintf("verify addr %s \n", vecMasternodes[0].addr.ToString().c_str());
|
|
|
|
//LogPrintf("verify addr %s \n", vecMasternodes[1].addr.ToString().c_str());
|
|
|
|
//LogPrintf("verify addr %d %s \n", n, vecMasternodes[n].addr.ToString().c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
CScript pubkey;
|
2014-12-31 03:54:00 +01:00
|
|
|
pubkey.SetDestination(vecMasternodes[n].pubkey2.GetID());
|
2014-12-09 02:17:57 +01:00
|
|
|
CTxDestination address1;
|
|
|
|
ExtractDestination(pubkey, address1);
|
|
|
|
CBitcoinAddress address2(address1);
|
2015-02-01 16:53:49 +01:00
|
|
|
//LogPrintf("verify pubkey2 %s \n", address2.ToString().c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(!darkSendSigner.VerifyMessage(vecMasternodes[n].pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
2014-12-09 02:17:57 +01:00
|
|
|
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CConsensusVote::Sign()
|
|
|
|
{
|
|
|
|
std::string errorMessage;
|
|
|
|
|
|
|
|
CKey key2;
|
|
|
|
CPubKey pubkey2;
|
2015-02-02 15:36:00 +01:00
|
|
|
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight);
|
2015-02-01 16:53:49 +01:00
|
|
|
//LogPrintf("signing strMessage %s \n", strMessage.c_str());
|
|
|
|
//LogPrintf("signing privkey %s \n", strMasterNodePrivKey.c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
|
|
|
|
{
|
2015-01-18 16:28:16 +01:00
|
|
|
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
|
|
|
return false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CScript pubkey;
|
|
|
|
pubkey.SetDestination(pubkey2.GetID());
|
|
|
|
CTxDestination address1;
|
|
|
|
ExtractDestination(pubkey, address1);
|
|
|
|
CBitcoinAddress address2(address1);
|
2015-02-01 16:53:49 +01:00
|
|
|
//LogPrintf("signing pubkey2 %s \n", address2.ToString().c_str());
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
|
|
|
|
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
|
|
|
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CTransactionLock::SignaturesValid()
|
|
|
|
{
|
|
|
|
|
|
|
|
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
|
|
|
|
{
|
|
|
|
int n = GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
|
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(n == -1)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
LogPrintf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
if(n > 10)
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
|
|
|
LogPrintf("InstantX::DoConsensusVote - Masternode not in the top 10\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!vote.SignatureValid()){
|
|
|
|
LogPrintf("InstantX::CTransactionLock::SignaturesValid - Signature not valid\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTransactionLock::AddSignature(CConsensusVote cv)
|
|
|
|
{
|
|
|
|
vecConsensusVotes.push_back(cv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CTransactionLock::CountSignatures()
|
|
|
|
{
|
|
|
|
return vecConsensusVotes.size();
|
2014-12-06 20:41:53 +01:00
|
|
|
}
|