dash/src/instantx.cpp

445 lines
14 KiB
C++
Raw Normal View History

#include "bignum.h"
#include "sync.h"
#include "net.h"
#include "key.h"
#include "util.h"
#include "script.h"
#include "hashblock.h"
#include "base58.h"
#include "instantx.h"
#include "masternode.h"
#include "activemasternode.h"
#include "darksend.h"
using namespace std;
using namespace boost;
2014-11-21 16:47:59 +01:00
2014-11-18 18:19:56 +01:00
std::vector<CTransactionLock> vecTxLocks;
std::map<uint256, CTransaction> mapTxLockReq;
std::map<uint256, CTransaction> mapTxLockReqRejected;
2014-11-18 18:19:56 +01:00
std::map<uint256, CTransactionLock> mapTxLocks;
2014-11-28 01:34:04 +01:00
#define INSTANTX_SIGNATURES_REQUIRED 2
2014-11-18 18:19:56 +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)
{
2014-11-18 18:19:56 +01:00
if (strCommand == "txlreq")
{
//LogPrintf("ProcessMessageInstantX::txlreq\n");
CDataStream vMsg(vRecv);
CTransaction tx;
2014-11-21 16:47:59 +01:00
vRecv >> tx;
CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
pfrom->AddInventoryKnown(inv);
if(mapTxLockReq.count(inv.hash) || mapTxLockReqRejected.count(inv.hash)){
2014-11-18 18:19:56 +01:00
return;
}
2014-11-25 21:35:31 +01:00
int nTxAge = GetInputAge(tx.vin[0]);
if(nTxAge < 5){
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlreq - Transaction not found / too new: %s\n", tx.GetHash().ToString().c_str());
2014-11-21 15:50:19 +01:00
return;
}
2014-11-25 21:35:31 +01:00
int nBlockHeight = pindexBest->nHeight - nTxAge; //calculate the height
2014-11-21 15:50:19 +01:00
bool fMissingInputs = false;
CValidationState state;
if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
{
RelayTransactionLockReq(tx, inv.hash);
2014-11-18 18:19:56 +01:00
DoConsensusVote(tx, true, nBlockHeight);
mapTxLockReq.insert(make_pair(inv.hash, tx));
2014-11-28 01:34:04 +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;
2014-11-18 18:19:56 +01:00
} else {
mapTxLockReqRejected.insert(make_pair(inv.hash, tx));
2014-11-18 18:19:56 +01:00
// can we get the conflicting transaction as proof?
RelayTransactionLockReq(tx, inv.hash);
DoConsensusVote(tx, false, nBlockHeight);
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
2014-11-18 18:19:56 +01:00
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;
}
}
else if (strCommand == "txlvote") //InstantX Lock Consensus Votes
{
CConsensusVote ctx;
vRecv >> ctx;
ProcessConsensusVote(ctx);
return;
}
else if (strCommand == "txlock") //InstantX Lock Transaction Inputs
{
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlock\n");
2014-11-18 18:19:56 +01:00
CDataStream vMsg(vRecv);
CTransactionLock ctxl;
vRecv >> ctxl;
CInv inv(MSG_TXLOCK, ctxl.GetHash());
pfrom->AddInventoryKnown(inv);
2014-11-28 01:34:04 +01:00
LogPrintf(" -- ProcessMessageInstantX::txlock %d %s\n", mapTxLocks.count(inv.hash), inv.hash.ToString().c_str());
2014-11-18 18:19:56 +01:00
2014-11-25 21:12:17 +01:00
2014-11-18 18:19:56 +01:00
if(!mapTxLocks.count(inv.hash)){
2014-11-18 20:04:00 +01:00
if(ctxl.CountSignatures() < INSTANTX_SIGNATURES_REQUIRED){
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::txlock - not enough signatures\n");
2014-11-18 18:19:56 +01:00
return;
}
if(!ctxl.SignaturesValid()){
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::txlock - got invalid TransactionLock, rejected\n");
2014-11-18 18:19:56 +01:00
return;
}
if(!ctxl.AllInFavor()){
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::txlock - not all in favor of lock, rejected\n");
2014-11-18 18:19:56 +01:00
return;
2014-11-18 20:04:00 +01:00
}
2014-11-18 18:19:56 +01:00
mapTxLocks.insert(make_pair(inv.hash, ctxl));
2014-11-25 21:12:17 +01:00
//we should have the lock request in place
if(!mapTxLockReq.count(inv.hash)){
//if we don't
bool fMissingInputs = false;
CValidationState state;
if (ctxl.tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
{
mapTxLockReq.insert(make_pair(inv.hash, ctxl.tx));
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : accepted (no reversing) %s\n",
2014-11-25 21:12:17 +01:00
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
ctxl.tx.GetHash().ToString().c_str()
);
} else {
// we have a conflicting transaction (an attack)
CValidationState state;
if(!DisconnectBlockAndInputs(state, ctxl.tx.vin)){
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlock - Couldn't reverse conflicting transaction: %s %s : failed %s\n",
2014-11-25 21:12:17 +01:00
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
ctxl.tx.GetHash().ToString().c_str()
);
2014-11-25 21:29:21 +01:00
} else {
if (ctxl.tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
{
mapTxLockReq.insert(make_pair(inv.hash, ctxl.tx));
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : accepted (reversed) %s\n",
2014-11-25 21:29:21 +01:00
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
ctxl.tx.GetHash().ToString().c_str()
);
} else {
2014-11-28 01:34:04 +01:00
LogPrintf("ProcessMessageInstantX::txlock - Transaction Lock Request: %s %s : rejected (reversed) %s\n",
2014-11-25 21:29:21 +01:00
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
ctxl.tx.GetHash().ToString().c_str()
);
}
2014-11-25 21:12:17 +01:00
}
}
}
2014-11-18 18:19:56 +01:00
//broadcast the new lock
2014-11-18 20:04:00 +01:00
LOCK(cs_vNodes);
2014-11-18 18:19:56 +01:00
BOOST_FOREACH(CNode* pnode, vNodes)
{
if(!pnode->fRelayTxes)
continue;
pnode->PushMessage("txlock", ctxl);
}
2014-11-18 20:04:00 +01:00
pwalletMain->UpdatedTransaction(ctxl.GetHash());
2014-11-18 18:19:56 +01:00
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX :: Got Transaction Lock: %s %s : accepted %s\n",
2014-11-18 18:19:56 +01:00
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
ctxl.GetHash().ToString().c_str()
);
}
}
}
// check if we need to vote on this transaction
void DoConsensusVote(CTransaction& tx, bool approved, int64 nBlockHeight)
{
if(!fMasterNode) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote - Not masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
int winner = GetCurrentMasterNode(1, nBlockHeight);
2014-11-28 01:34:04 +01:00
int n = GetMasternodeRank(activeMasternode.vinMasternode, nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
2014-11-18 18:19:56 +01:00
if(n == -1 || winner == -1)
{
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote - Unknown Masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
if(n == 1)
{ // winner, I'll be keeping track of this
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote - Managing Masternode\n");
2014-11-18 18:19:56 +01:00
CTransactionLock newLock;
newLock.nBlockHeight = nBlockHeight;
newLock.tx = tx;
vecTxLocks.push_back(newLock);
}
CConsensusVote ctx;
ctx.vinMasternode = activeMasternode.vinMasternode;
ctx.approved = approved;
ctx.txHash = tx.GetHash();
ctx.nBlockHeight = nBlockHeight;
if(!ctx.Sign()){
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote - Failed to sign consensus vote\n");
2014-11-18 18:19:56 +01:00
return;
}
if(!ctx.SignatureValid()) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote - Signature invalid\n");
2014-11-18 18:19:56 +01:00
return;
}
if(n == 1){ //I'm the winner
ProcessConsensusVote(ctx);
} else if(n <= 10){ // not winner, but in the top10
if(ConnectNode((CAddress)darkSendMasterNodes[winner].addr, NULL, true)){
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if(darkSendMasterNodes[winner].addr != pnode->addr) continue;
pnode->PushMessage("txlvote", ctx);
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote --- connected, sending vote %s\n", pnode->addr.ToString().c_str());
2014-11-18 18:19:56 +01:00
return;
}
} else {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::DoConsensusVote --- error connecting \n");
2014-11-18 18:19:56 +01:00
return;
}
}
}
2014-11-18 18:19:56 +01:00
//received a consensus vote
void ProcessConsensusVote(CConsensusVote& ctx)
{
if(!fMasterNode) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Not masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
int winner = GetCurrentMasterNode(1, ctx.nBlockHeight);
if(winner == -1) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Can't detect winning masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
//We're not the winning masternode
if(darkSendMasterNodes[winner].vin != activeMasternode.vinMasternode) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - I'm not the winning masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
2014-11-28 01:34:04 +01:00
int n = GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
2014-11-18 18:19:56 +01:00
if(n == -1)
{
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Unknown Masternode\n");
2014-11-18 18:19:56 +01:00
return;
}
if(n > 10)
{
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10\n");
2014-11-18 18:19:56 +01:00
return;
}
if(!ctx.SignatureValid()) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Signature invalid\n");
2014-11-18 18:19:56 +01:00
//don't ban, it could just be a non-synced masternode
return;
}
//compile consessus vote
BOOST_FOREACH(CTransactionLock& ctxl, vecTxLocks){
if(ctxl.nBlockHeight == ctx.nBlockHeight){
ctxl.AddSignature(ctx);
if(ctxl.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
2014-11-28 21:12:23 +01:00
LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete, broadcasting!\n");
2014-11-18 18:19:56 +01:00
CInv inv(MSG_TXLOCK, ctxl.GetHash());
mapTxLocks.insert(make_pair(inv.hash, ctxl));
//broadcast the new lock
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes){
pnode->PushMessage("txlock", ctxl);
}
}
return;
}
}
return;
}
void CleanTransactionLocksList()
{
if(pindexBest == NULL) return;
2014-11-18 18:19:56 +01:00
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
while(it != mapTxLocks.end()) {
if(pindexBest->nHeight - it->second.nBlockHeight > 3){ //keep them for an hour
2014-11-18 18:19:56 +01:00
LogPrintf("Removing old transaction lock %s\n", it->second.GetHash().ToString().c_str());
mapTxLocks.erase(it);
break;
2014-11-18 18:19:56 +01:00
}
}
2014-11-18 18:19:56 +01:00
}
bool CConsensusVote::SignatureValid()
{
std::string errorMessage;
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight) + boost::lexical_cast<std::string>(approved);
2014-11-28 01:34:04 +01:00
LogPrintf("verify strMessage %s \n", strMessage.c_str());
2014-11-18 18:19:56 +01:00
int n = GetMasternodeByVin(vinMasternode);
if(n == -1)
{
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode\n");
2014-11-18 18:19:56 +01:00
return false;
}
2014-11-28 01:34:04 +01:00
LogPrintf("verify addr %s \n", darkSendMasterNodes[0].addr.ToString().c_str());
LogPrintf("verify addr %s \n", darkSendMasterNodes[1].addr.ToString().c_str());
LogPrintf("verify addr %d %s \n", n, darkSendMasterNodes[n].addr.ToString().c_str());
2014-11-18 18:19:56 +01:00
CScript pubkey;
pubkey.SetDestination(darkSendMasterNodes[n].pubkey2.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
2014-11-28 01:34:04 +01:00
LogPrintf("verify pubkey2 %s \n", address2.ToString().c_str());
2014-11-18 18:19:56 +01:00
if(!darkSendSigner.VerifyMessage(darkSendMasterNodes[n].pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
2014-11-28 01:34:04 +01:00
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
2014-11-18 18:19:56 +01:00
return false;
}
return true;
}
bool CConsensusVote::Sign()
{
std::string errorMessage;
CKey key2;
CPubKey pubkey2;
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight) + boost::lexical_cast<std::string>(approved);
2014-11-28 01:34:04 +01:00
LogPrintf("signing strMessage %s \n", strMessage.c_str());
LogPrintf("signing privkey %s \n", strMasterNodePrivKey.c_str());
2014-11-18 18:19:56 +01:00
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
{
2014-11-28 01:34:04 +01:00
LogPrintf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
2014-11-18 18:19:56 +01:00
exit(0);
}
CScript pubkey;
pubkey.SetDestination(pubkey2.GetID());
CTxDestination address1;
ExtractDestination(pubkey, address1);
CBitcoinAddress address2(address1);
2014-11-28 01:34:04 +01:00
LogPrintf("signing pubkey2 %s \n", address2.ToString().c_str());
2014-11-18 18:19:56 +01:00
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
2014-11-28 01:34:04 +01:00
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed");
2014-11-18 18:19:56 +01:00
return false;
}
if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
2014-11-28 01:34:04 +01:00
LogPrintf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed");
2014-11-18 18:19:56 +01:00
return false;
}
return true;
}
bool CTransactionLock::SignaturesValid()
{
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
{
2014-11-28 01:34:04 +01:00
int n = GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
2014-11-18 18:19:56 +01:00
if(n == -1)
{
2014-11-29 02:37:26 +01:00
LogPrintf("InstantX::DoConsensusVote - Unknown Masternode\n");
2014-11-18 18:19:56 +01:00
return false;
}
if(n > 10)
{
2014-11-29 02:37:26 +01:00
LogPrintf("InstantX::DoConsensusVote - Masternode not in the top 10\n");
2014-11-18 18:19:56 +01:00
return false;
}
if(!vote.SignatureValid()){
2014-11-29 02:37:26 +01:00
LogPrintf("InstantX::CTransactionLock::SignaturesValid - Signature not valid\n");
2014-11-18 18:19:56 +01:00
return false;
}
}
return true;
}
bool CTransactionLock::AllInFavor()
{
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
if(vote.approved == false) return false;
return true;
}
void CTransactionLock::AddSignature(CConsensusVote cv)
{
vecConsensusVotes.push_back(cv);
}
int CTransactionLock::CountSignatures()
{
return vecConsensusVotes.size();
}