Proposal Security Overhaul

Submissions to the network now require a fee to be paid to the network (mining fee) using a special transaction with a OP_RETURN && ProposalHash in one of the outputs. This allows the network to filter spam quickly, while also allowing anyone to submit a proposal to the network.

To implement these changes we've introduced a few new commands:

mnbudget prepare PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN [USE_IX(TRUE|FALSE)]
- To create the special transaction

mnbudget submit PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN FEE_TX
- After the transaction is accepted by the network and has 3 confirmations, you can submit the transaction to the network here

mnbudget show
- Get the proposal hash from here

mnbudget vote PROPOSAL-HASH YES|NO|ABSTAIN
- You can now simply vote by hash using this command
This commit is contained in:
Evan Duffield 2015-07-09 15:08:26 -07:00
parent 0e89bbae92
commit c701839a43
14 changed files with 385 additions and 566 deletions

View File

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 12)
define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 11)
define(_CLIENT_VERSION_BUILD, 12)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash])

View File

@ -17,7 +17,7 @@
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 11
#define CLIENT_VERSION_BUILD 12
//! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true

View File

@ -2374,19 +2374,21 @@ void ThreadCheckDarkSendPool()
if(pnode->HasFulfilledRequest("mnsync")) continue;
pnode->FulfilledRequest("mnsync");
LogPrintf("Successfully synced, asking for Masternode list and payment list\n");
//request full mn list only if Masternodes.dat was updated quite a long time ago
if(RequestedMasternodeAssets == 0 || RequestedMasternodeAssets == 1){
LogPrintf("Successfully synced, asking for Masternode list\n");
mnodeman.DsegUpdate(pnode);
pnode->PushMessage("getsporks"); //get current network sporks
}
if(RequestedMasternodeAssets == 2 || RequestedMasternodeAssets == 3)
if(RequestedMasternodeAssets == 2 || RequestedMasternodeAssets == 3){
LogPrintf("Successfully synced, asking for Masternode payee list\n");
pnode->PushMessage("mnget"); //sync payees
}
if(RequestedMasternodeAssets == 4 || RequestedMasternodeAssets == 5){
LogPrintf("Successfully synced, asking for Masternode Budget votes / Finalized budgets\n");
uint256 n = 0;
pnode->PushMessage("mnvs", n); //sync masternode votes
}

View File

@ -38,9 +38,9 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
if(!IsSporkActive(SPORK_2_INSTANTX)) return;
if(IsInitialBlockDownload()) return;
if (strCommand == "txlreq")
if (strCommand == "ix")
{
//LogPrintf("ProcessMessageInstantX::txlreq\n");
//LogPrintf("ProcessMessageInstantX::ix\n");
CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
@ -58,7 +58,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
BOOST_FOREACH(const CTxOut o, tx.vout){
if(!o.scriptPubKey.IsNormalPaymentScript()){
LogPrintf("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str());
LogPrintf("ProcessMessageInstantX::ix - Invalid Script %s\n", tx.ToString().c_str());
return;
}
}
@ -81,7 +81,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : accepted %s\n",
LogPrintf("ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : accepted %s\n",
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
tx.GetHash().ToString().c_str()
);
@ -93,7 +93,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
// can we get the conflicting transaction as proof?
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
LogPrintf("ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : rejected %s\n",
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
tx.GetHash().ToString().c_str()
);
@ -110,7 +110,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
//we only care if we have a complete tx lock
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
if(!CheckForConflictingLocks(tx)){
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
LogPrintf("ProcessMessageInstantX::ix - Found Existing Complete IX Lock\n");
CValidationState state;
DisconnectBlockAndInputs(state, tx);
@ -150,7 +150,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
if(mapUnknownVotes[ctx.vinMasternode.prevout.hash] > GetTime() &&
mapUnknownVotes[ctx.vinMasternode.prevout.hash] - GetAverageVoteTime() > 60*10){
LogPrintf("ProcessMessageInstantX::txlreq - masternode is spamming transaction votes: %s %s\n",
LogPrintf("ProcessMessageInstantX::ix - masternode is spamming transaction votes: %s %s\n",
ctx.vinMasternode.ToString().c_str(),
ctx.txHash.ToString().c_str()
);

View File

@ -27,7 +27,7 @@ class CConsensusVote;
class CTransaction;
class CTransactionLock;
static const int MIN_INSTANTX_PROTO_VERSION = 70085;
static const int MIN_INSTANTX_PROTO_VERSION = 70086;
extern map<uint256, CTransaction> mapTxLockReq;
extern map<uint256, CTransaction> mapTxLockReqRejected;

View File

@ -3957,19 +3957,11 @@ bool static AlreadyHave(const CInv& inv)
case MSG_BUDGET_VOTE:
return mapSeenMasternodeBudgetVotes.count(inv.hash);
case MSG_BUDGET_PROPOSAL:
if(!mapSeenMasternodeBudgetProposals.count(inv.hash)){
return false;
} else {
return !mapSeenMasternodeBudgetProposals[inv.hash].fInvalid;
}
return mapSeenMasternodeBudgetProposals.count(inv.hash);
case MSG_BUDGET_FINALIZED_VOTE:
return mapSeenFinalizedBudgetVotes.count(inv.hash);
case MSG_BUDGET_FINALIZED:
if(!mapSeenFinalizedBudgets.count(inv.hash)){
return false;
} else {
return !mapSeenFinalizedBudgets[inv.hash].fInvalid;
}
return mapSeenFinalizedBudgets.count(inv.hash);
case MSG_MASTERNODE_ANNOUNCE:
return mapSeenMasternodeBroadcast.count(inv.hash);
case MSG_MASTERNODE_PING:
@ -4111,7 +4103,7 @@ void static ProcessGetData(CNode* pfrom)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(1000);
ss << mapTxLockReq[inv.hash];
pfrom->PushMessage("txlreq", ss);
pfrom->PushMessage("ix", ss);
pushed = true;
}
}

View File

@ -32,6 +32,73 @@ int GetBudgetPaymentCycleBlocks(){
return 50;
}
bool IsBudgetCollateralValid(uint256 nTxCollateralHash, std::string& strError)
{
return true;
CTransaction txCollateral;
uint256 hash;
if(!GetTransaction(nTxCollateralHash, txCollateral, hash, true)){
LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - Can't find collateral tx %s\n", txCollateral.ToString().c_str());
return false;
}
if(txCollateral.vout.size() < 1) return false;
if(txCollateral.nLockTime != 0) return false;
int64_t nValueIn = 0;
int64_t nValueOut = 0;
bool missingTx = false;
BOOST_FOREACH(const CTxOut o, txCollateral.vout){
nValueOut += o.nValue;
if(!o.scriptPubKey.IsNormalPaymentScript()){
LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - Invalid Script %s\n", txCollateral.ToString().c_str());
return false;
}
}
bool foundOpReturn = false;
BOOST_FOREACH(const CTxIn i, txCollateral.vin){
CTransaction tx2;
uint256 hash;
if(GetTransaction(i.prevout.hash, tx2, hash, true)){
if(tx2.vout.size() > i.prevout.n) {
nValueIn += tx2.vout[i.prevout.n].nValue;
}
} else{
missingTx = true;
}
}
if(!foundOpReturn){
}
if(missingTx){
if(fDebug) LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString().c_str());
return false;
}
//collateral transactions are required to pay out BUDGET_FEE_TX as a fee to the miners
if(nValueIn - nValueOut < BUDGET_FEE_TX) {
if(fDebug) LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - did not include enough fees in transaction %d\n%s\n", nValueOut-nValueIn, txCollateral.ToString().c_str());
return false;
}
if(fDebug) LogPrintf("CBudgetProposalBroadcast::FeeTXValid %s\n", txCollateral.ToString().c_str());
CValidationState state;
if(!AcceptableInputs(mempool, state, txCollateral, true, NULL)){
if(fDebug) LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - didn't pass IsAcceptable\n");
return false;
}
return true;
return true;
}
void CBudgetManager::CheckOrphanVotes()
{
std::map<uint256, CBudgetVote>::iterator it1 = mapOrphanMasternodeBudgetVotes.begin();
@ -54,154 +121,6 @@ void CBudgetManager::CheckOrphanVotes()
}
}
void CBudgetManager::ResignInvalidProposals()
{
if(!fMasterNode){
CheckSignatureValidity();
return;
}
CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return;
//pick a few masternodes responsible for this each cycle
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, pindexPrev->nHeight, MIN_BUDGET_PEER_PROTO_VERSION);
if(n == -1)
{
CheckSignatureValidity();
LogPrintf("CBudgetManager::ResignInvalidProposals - Unknown Masternode\n");
return;
}
if(n > 3)
{
CheckSignatureValidity();
LogPrintf("CBudgetManager::ResignInvalidProposals - Masternode not in the top %s\n", MIN_BUDGET_PEER_PROTO_VERSION);
return;
}
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if(pmn == NULL) {
LogPrintf("CBudgetManager::ResignInvalidProposals - unknown masternode - vin:%s \n", pmn->vin.ToString().c_str());
return;
}
std::map<uint256, CBudgetProposal>::iterator it1 = mapProposals.begin();
while(it1 != mapProposals.end())
{
if(pmn->nVotedTimes+VOTE_PROP_INC > 100) return; //can't submit to the network anyway
CBudgetProposal* pbudgetProposal = &((*it1).second);
CBudgetProposalBroadcast budgetProposalBroadcast(*pbudgetProposal);
if(!budgetProposalBroadcast.SignatureValid()){
budgetProposalBroadcast.vin = activeMasternode.vin;
LogPrintf("CBudgetManager::ResignInvalidProposals -- proposal - resigning proposal\n");
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)){
LogPrintf("CBudgetManager::ResignInvalidProposals - Error upon calling SetKey");
return;
}
if(!budgetProposalBroadcast.Sign(keyMasternode, pubKeyMasternode)){
LogPrintf("CBudgetManager::ResignInvalidProposals - Failure to sign");
return;
}
std::string strError = "";
if(budgetProposalBroadcast.IsValid(strError)){
//delete if it exists and insert the new object
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())) mapSeenMasternodeBudgetProposals.erase(budgetProposalBroadcast.GetHash());
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
} else {
LogPrintf("CBudgetManager::ResignInvalidProposals -- proposal - still invalid with new signature\n");
}
}
++it1;
}
std::map<uint256, CFinalizedBudget>::iterator it2 = mapFinalizedBudgets.begin();
while(it2 != mapFinalizedBudgets.end()){
if(pmn->nVotedTimes+VOTE_PROP_INC > 100) return; //can't submit to the network anyway
CFinalizedBudget* pfinalizedBudget = &((*it2).second);
if(!pfinalizedBudget->IsValid()) continue;
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(*pfinalizedBudget);
if(!finalizedBudgetBroadcast.SignatureValid()){
finalizedBudgetBroadcast.vin = activeMasternode.vin;
LogPrintf("CBudgetManager::ResignInvalidProposals -- finalized budget - resigning finalized budget\n");
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)){
LogPrintf("CBudgetManager::ResignInvalidProposals - Error upon calling SetKey");
return;
}
if(!finalizedBudgetBroadcast.Sign(keyMasternode, pubKeyMasternode)){
LogPrintf("CBudgetManager::ResignInvalidProposals - Failure to sign");
return;
}
if(!finalizedBudgetBroadcast.IsValid()){
//delete if it exists and insert the new object
if(mapFinalizedBudgets.count(finalizedBudgetBroadcast.GetHash())) mapFinalizedBudgets.erase(finalizedBudgetBroadcast.GetHash());
mapFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast));
finalizedBudgetBroadcast.Relay();
} else {
LogPrintf("CBudgetManager::ResignInvalidProposals -- finalized budget - still invalid with new signature\n");
}
}
++it2;
}
}
void CBudgetManager::CheckSignatureValidity()
{
std::map<uint256, CBudgetProposal>::iterator it1 = mapProposals.begin();
while(it1 != mapProposals.end())
{
CBudgetProposal* pbudgetProposal = &((*it1).second);
CBudgetProposalBroadcast budgetProposalBroadcast(*pbudgetProposal);
if(!budgetProposalBroadcast.SignatureValid()){
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())) {
mapSeenMasternodeBudgetProposals[budgetProposalBroadcast.GetHash()].fInvalid = true;
}
}
++it1;
}
std::map<uint256, CFinalizedBudget>::iterator it2 = mapFinalizedBudgets.begin();
while(it2 != mapFinalizedBudgets.end())
{
CFinalizedBudget* pfinalizedBudget = &((*it2).second);
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(*pfinalizedBudget);
if(!finalizedBudgetBroadcast.SignatureValid()){
if(mapSeenFinalizedBudgets.count(finalizedBudgetBroadcast.GetHash())) {
mapSeenFinalizedBudgets[finalizedBudgetBroadcast.GetHash()].fInvalid = true;
}
}
++it2;
}
}
void CBudgetManager::SubmitFinalBudget()
{
CBlockIndex* pindexPrev = chainActive.Tip();
@ -238,11 +157,11 @@ void CBudgetManager::SubmitFinalBudget()
LogPrintf("SubmitFinalBudget - Error upon calling SetKey\n");
}
//create fee tx
uint256 hash = 0;
//create the proposal incase we're the first to make it
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(activeMasternode.vin, strBudgetName, nBlockStart, vecTxBudgetPayments);
if(!finalizedBudgetBroadcast.Sign(keyMasternode, pubKeyMasternode)){
LogPrintf("SubmitFinalBudget - Failure to sign.\n");
}
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(strBudgetName, nBlockStart, vecTxBudgetPayments, hash);
if(!finalizedBudgetBroadcast.IsValid()){
LogPrintf("SubmitFinalBudget - Invalid finalized budget broadcast (are all the hashes correct?)\n");
@ -408,13 +327,7 @@ void CBudgetManager::AddFinalizedBudget(CFinalizedBudget& finalizedBudget)
LOCK(cs);
if(!finalizedBudget.IsValid()) return;
if(mapFinalizedBudgets.count(finalizedBudget.GetHash()) && mapFinalizedBudgets[finalizedBudget.GetHash()].vin != finalizedBudget.vin) {
//this finalized budget must have went invalid, so update the vin to the new one
LogPrintf("CBudgetManager::AddFinalizedBudget -- updated vin of invalid finalized budget %s (%s to %s)\n",
finalizedBudget.strBudgetName,
mapFinalizedBudgets[finalizedBudget.GetHash()].vin.prevout.ToStringShort(),
finalizedBudget.vin.prevout.ToStringShort());
mapFinalizedBudgets[finalizedBudget.GetHash()].vin = finalizedBudget.vin;
if(mapFinalizedBudgets.count(finalizedBudget.GetHash())) {
return;
}
@ -430,13 +343,7 @@ void CBudgetManager::AddProposal(CBudgetProposal& budgetProposal)
return;
}
if(mapProposals.count(budgetProposal.GetHash()) && mapProposals[budgetProposal.GetHash()].vin != budgetProposal.vin) {
//this budget proposal must have went invalid, so update the vin to the new one
LogPrintf("CBudgetManager::AddProposal -- updated vin of invalid budget proposal %s (%s to %s)\n",
budgetProposal.strProposalName,
mapProposals[budgetProposal.GetHash()].vin.prevout.ToStringShort().c_str(),
budgetProposal.vin.prevout.ToStringShort().c_str());
mapProposals[budgetProposal.GetHash()].vin = budgetProposal.vin;
if(mapProposals.count(budgetProposal.GetHash())) {
return;
}
@ -761,8 +668,6 @@ void CBudgetManager::NewBlock()
SubmitFinalBudget();
}
ResignInvalidProposals();
//this function should be called 1/6 blocks, allowing up to 100 votes per day on all proposals
if(chainActive.Height() % 6 != 0) return;
@ -813,30 +718,20 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
vRecv >> budgetProposalBroadcast;
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())){
//if this proposal went inactive, we'll update it with the new re-signature
if(!mapSeenMasternodeBudgetProposals[budgetProposalBroadcast.GetHash()].fInvalid){
return;
}
return;
}
//set time we first saw this prop
budgetProposalBroadcast.nTime = GetAdjustedTime();
CMasternode* pmn = mnodeman.Find(budgetProposalBroadcast.vin);
if(pmn == NULL) {
if(fDebug) LogPrintf("mprop - unknown masternode - vin: %s\n", budgetProposalBroadcast.vin.ToString());
return;
}
if(!budgetProposalBroadcast.SignatureValid()){
LogPrintf("mprop - signature invalid\n");
Misbehaving(pfrom->GetId(), 20);
return;
}
std::string strError = "";
if(!IsBudgetCollateralValid(budgetProposalBroadcast.nFeeTXHash, strError)){
LogPrintf("Proposal FeeTX is not valid - %s - %s\n", budgetProposalBroadcast.nFeeTXHash.ToString(), strError);
return;
}
if(!budgetProposalBroadcast.IsValid(strError)) {
LogPrintf("mprop - invalid budget proposal - %s\n", strError.c_str());
LogPrintf("mprop - invalid budget proposal - %s\n", strError);
return;
}
@ -844,20 +739,12 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())) mapSeenMasternodeBudgetProposals.erase(budgetProposalBroadcast.GetHash());
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
if(IsSyncingMasternodeAssets() || pmn->nVotedTimes < 100){
CBudgetProposal budgetProposal(budgetProposalBroadcast);
budget.AddProposal(budgetProposal);
budgetProposalBroadcast.Relay();
CBudgetProposal budgetProposal(budgetProposalBroadcast);
budget.AddProposal(budgetProposal);
budgetProposalBroadcast.Relay();
//can only do this six times a day on the network
if(!IsSyncingMasternodeAssets()) pmn->nVotedTimes+=VOTE_PROP_INC;
//We might have active votes for this proposal that are valid now
CheckOrphanVotes();
} else {
LogPrintf("mvote - masternode can't vote again - vin: %s\n", pmn->vin.ToString());
return;
}
//We might have active votes for this proposal that are valid now
CheckOrphanVotes();
}
if (strCommand == "mvote") { //Masternode Vote
@ -881,7 +768,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
}
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
if(IsSyncingMasternodeAssets() || pmn->nVotedTimes < 100){
if(pmn->nVotedTimes < 100){
budget.UpdateProposal(vote, pfrom);
vote.Relay();
if(!IsSyncingMasternodeAssets()) pmn->nVotedTimes++;
@ -896,21 +783,12 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
vRecv >> finalizedBudgetBroadcast;
if(mapSeenFinalizedBudgets.count(finalizedBudgetBroadcast.GetHash())){
//if this budget went inactive, we'll update it with the new re-signature
if(!mapSeenFinalizedBudgets[finalizedBudgetBroadcast.GetHash()].fInvalid){
return;
}
}
CMasternode* pmn = mnodeman.Find(finalizedBudgetBroadcast.vin);
if(pmn == NULL) {
if(fDebug) LogPrintf("fbs - unknown masternode - vin: %s\n", finalizedBudgetBroadcast.vin.ToString());
return;
}
if(!finalizedBudgetBroadcast.SignatureValid()){
LogPrintf("fbs - signature invalid\n");
Misbehaving(pfrom->GetId(), 20);
std::string strError = "";
if(!IsBudgetCollateralValid(finalizedBudgetBroadcast.nFeeTXHash, strError)){
LogPrintf("Finalized Budget FeeTX is not valid - %s - %s\n", finalizedBudgetBroadcast.nFeeTXHash.ToString(), strError);
return;
}
@ -923,19 +801,12 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
if(mapSeenFinalizedBudgets.count(finalizedBudgetBroadcast.GetHash())) mapSeenFinalizedBudgets.erase(finalizedBudgetBroadcast.GetHash());
mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast));
if(IsSyncingMasternodeAssets() || pmn->nVotedTimes < 100){
CFinalizedBudget finalizedBudget(finalizedBudgetBroadcast);
budget.AddFinalizedBudget(finalizedBudget);
finalizedBudgetBroadcast.Relay();
CFinalizedBudget finalizedBudget(finalizedBudgetBroadcast);
budget.AddFinalizedBudget(finalizedBudget);
finalizedBudgetBroadcast.Relay();
if(!IsSyncingMasternodeAssets()) pmn->nVotedTimes+=VOTE_PROP_INC;
//we might have active votes for this budget that are now valid
CheckOrphanVotes();
} else {
LogPrintf("fbs - masternode can't vote again - vin: %s\n", pmn->vin.ToString());
return;
}
//we might have active votes for this budget that are now valid
CheckOrphanVotes();
}
if (strCommand == "fbvote") { //Finalized Budget Vote
@ -959,7 +830,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
}
mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
if(IsSyncingMasternodeAssets() || pmn->nVotedTimes < 100){
if(pmn->nVotedTimes < 100){
budget.UpdateFinalizedBudget(vote, pfrom);
vote.Relay();
if(!IsSyncingMasternodeAssets()) pmn->nVotedTimes++;
@ -1072,7 +943,6 @@ bool CBudgetManager::UpdateFinalizedBudget(CFinalizedBudgetVote& vote, CNode* pf
CBudgetProposal::CBudgetProposal()
{
vin = CTxIn();
strProposalName = "unknown";
nBlockStart = 0;
nBlockEnd = 0;
@ -1080,9 +950,8 @@ CBudgetProposal::CBudgetProposal()
nTime = 0;
}
CBudgetProposal::CBudgetProposal(CTxIn vinIn, std::string strProposalNameIn, std::string strURLIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn)
CBudgetProposal::CBudgetProposal(std::string strProposalNameIn, std::string strURLIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn, uint256 nFeeTXHashIn)
{
vin = vinIn;
strProposalName = strProposalNameIn;
strURL = strURLIn;
nBlockStart = nBlockStartIn;
@ -1090,11 +959,11 @@ CBudgetProposal::CBudgetProposal(CTxIn vinIn, std::string strProposalNameIn, std
address = addressIn;
nAmount = nAmountIn;
nTime = 0;
nFeeTXHash = nFeeTXHashIn;
}
CBudgetProposal::CBudgetProposal(const CBudgetProposal& other)
{
vin = other.vin;
strProposalName = other.strProposalName;
strURL = other.strURL;
nBlockStart = other.nBlockStart;
@ -1102,6 +971,8 @@ CBudgetProposal::CBudgetProposal(const CBudgetProposal& other)
address = other.address;
nAmount = other.nAmount;
nTime = other.nTime;
nFeeTXHash = other.nFeeTXHash;
mapVotes = other.mapVotes;
}
bool CBudgetProposal::IsValid(std::string& strError)
@ -1252,31 +1123,28 @@ int CBudgetProposal::GetRemainingPaymentCount()
CBudgetProposalBroadcast::CBudgetProposalBroadcast()
{
vin = CTxIn();
strProposalName = "unknown";
strURL = "";
nBlockStart = 0;
nBlockEnd = 0;
nAmount = 0;
nTime = 0;
fInvalid = false;
nFeeTXHash = 0;
}
CBudgetProposalBroadcast::CBudgetProposalBroadcast(const CBudgetProposal& other)
{
vin = other.vin;
strProposalName = other.strProposalName;
strURL = other.strURL;
nBlockStart = other.nBlockStart;
nBlockEnd = other.nBlockEnd;
address = other.address;
nAmount = other.nAmount;
fInvalid = false;
nFeeTXHash = other.nFeeTXHash;
}
CBudgetProposalBroadcast::CBudgetProposalBroadcast(CTxIn vinIn, std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn)
CBudgetProposalBroadcast::CBudgetProposalBroadcast(std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn, uint256 nFeeTXHashIn)
{
vin = vinIn;
strProposalName = strProposalNameIn;
strURL = strURLIn;
@ -1289,26 +1157,7 @@ CBudgetProposalBroadcast::CBudgetProposalBroadcast(CTxIn vinIn, std::string strP
address = addressIn;
nAmount = nAmountIn;
fInvalid = false;
}
bool CBudgetProposalBroadcast::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{
// Choose coins to use
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
std::string errorMessage;
std::string strMessage = vin.prevout.ToStringShort() + strProposalName + strURL + boost::lexical_cast<std::string>(nBlockStart) +
boost::lexical_cast<std::string>(nBlockEnd) + address.ToString() + boost::lexical_cast<std::string>(nAmount);
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode))
return(" Error upon calling SignMessage");
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage))
return(" Error upon calling VerifyMessage");
return true;
nFeeTXHash = nFeeTXHashIn;
}
void CBudgetProposalBroadcast::Relay()
@ -1317,29 +1166,6 @@ void CBudgetProposalBroadcast::Relay()
RelayInv(inv, MIN_BUDGET_PEER_PROTO_VERSION);
}
bool CBudgetProposalBroadcast::SignatureValid()
{
std::string errorMessage;
std::string strMessage = vin.prevout.ToStringShort() + strProposalName + strURL + boost::lexical_cast<std::string>(nBlockStart) +
boost::lexical_cast<std::string>(nBlockEnd) + address.ToString() + boost::lexical_cast<std::string>(nAmount);
CMasternode* pmn = mnodeman.Find(vin);
if(pmn == NULL)
{
LogPrintf("CBudgetProposalBroadcast::SignatureValid() - Unknown Masternode - %s\n", vin.ToString().c_str());
return false;
}
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)) {
LogPrintf("CBudgetProposalBroadcast::SignatureValid() - Verify message failed\n");
return false;
}
return true;
}
CBudgetVote::CBudgetVote()
{
vin = CTxIn();
@ -1403,21 +1229,21 @@ bool CBudgetVote::SignatureValid()
CFinalizedBudget::CFinalizedBudget()
{
vin = CTxIn();
strBudgetName = "";
nBlockStart = 0;
vecProposals.clear();
mapVotes.clear();
nFeeTXHash = 0;
}
CFinalizedBudget::CFinalizedBudget(const CFinalizedBudget& other)
{
vin = other.vin;
strBudgetName = other.strBudgetName;
nBlockStart = other.nBlockStart;
vecProposals = other.vecProposals;
mapVotes = other.mapVotes;
nFeeTXHash = other.nFeeTXHash;
}
void CFinalizedBudget::AddOrUpdateVote(CFinalizedBudgetVote& vote)
@ -1473,11 +1299,6 @@ void CFinalizedBudget::AutoCheck()
}
}
// Feature : Masternodes can delegate finalized budgets to a 3rd party simply by adding this option to the configuration
else if (strBudgetMode == vin.prevout.ToStringShort())
{
SubmitVote();
}
}
// If masternode voted for a proposal, but is now invalid -- remove the vote
void CFinalizedBudget::CleanAndRemove()
@ -1633,31 +1454,30 @@ void CFinalizedBudget::SubmitVote()
CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast()
{
vin = CTxIn();
strBudgetName = "";
nBlockStart = 0;
vecProposals.clear();
mapVotes.clear();
vchSig.clear();
nFeeTXHash = 0;
}
CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(const CFinalizedBudget& other)
{
vin = other.vin;
strBudgetName = other.strBudgetName;
nBlockStart = other.nBlockStart;
BOOST_FOREACH(CTxBudgetPayment out, other.vecProposals) vecProposals.push_back(out);
mapVotes = other.mapVotes;
nFeeTXHash = other.nFeeTXHash;
}
CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(CTxIn& vinIn, std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> vecProposalsIn)
CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> vecProposalsIn, uint256 nFeeTXHashIn)
{
vin = vinIn;
printf("%s\n", vin.ToString().c_str());
strBudgetName = strBudgetNameIn;
nBlockStart = nBlockStartIn;
BOOST_FOREACH(CTxBudgetPayment out, vecProposalsIn) vecProposals.push_back(out);
mapVotes.clear();
nFeeTXHash = nFeeTXHashIn;
}
void CFinalizedBudgetBroadcast::Relay()
@ -1666,48 +1486,6 @@ void CFinalizedBudgetBroadcast::Relay()
RelayInv(inv, MIN_BUDGET_PEER_PROTO_VERSION);
}
bool CFinalizedBudgetBroadcast::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{
// Choose coins to use
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
std::string errorMessage;
std::string strMessage = vin.prevout.ToStringShort() + strBudgetName + boost::lexical_cast<std::string>(nBlockStart);
BOOST_FOREACH(CTxBudgetPayment& payment, vecProposals) strMessage += payment.nProposalHash.ToString().c_str();
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode))
return(" Error upon calling SignMessage");
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage))
return(" Error upon calling VerifyMessage");
return true;
}
bool CFinalizedBudgetBroadcast::SignatureValid()
{
std::string errorMessage;
std::string strMessage = vin.prevout.ToStringShort() + strBudgetName + boost::lexical_cast<std::string>(nBlockStart);
BOOST_FOREACH(CTxBudgetPayment& payment, vecProposals) strMessage += payment.nProposalHash.ToString().c_str();
CMasternode* pmn = mnodeman.Find(vin);
if(pmn == NULL)
{
LogPrintf("CFinalizedBudgetBroadcast::SignatureValid() - Unknown Masternode\n");
return false;
}
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)) {
LogPrintf("CFinalizedBudgetBroadcast::SignatureValid() - Verify message failed\n");
return false;
}
return true;
}
CFinalizedBudgetVote::CFinalizedBudgetVote()
{
vin = CTxIn();

View File

@ -13,7 +13,7 @@
#include "base58.h"
#include "masternode.h"
#include <boost/lexical_cast.hpp>
#include "init.h"
using namespace std;
@ -29,7 +29,8 @@ class CTxBudgetPayment;
#define VOTE_ABSTAIN 0
#define VOTE_YES 1
#define VOTE_NO 2
#define VOTE_PROP_INC 15 //how many "votes" to count for a new proposal
static const int64_t BUDGET_FEE_TX = (0.5*COIN);
extern std::map<uint256, CBudgetProposalBroadcast> mapSeenMasternodeBudgetProposals;
extern std::map<uint256, CBudgetVote> mapSeenMasternodeBudgetVotes;
@ -42,6 +43,9 @@ void DumpBudgets();
//Amount of blocks in a months period of time (using 2.6 minutes per)
int GetBudgetPaymentCycleBlocks();
//Check the collateral transaction for the budget proposal/finalized budget
bool IsBudgetCollateralValid(uint256 nTxCollateralHash, std::string& strError);
/** Save Budget Manager (budget.dat)
*/
class CBudgetDB
@ -114,10 +118,6 @@ public:
std::string GetRequiredPaymentsString(int64_t nBlockHeight);
void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees);
//Have masternodes resign proposals with masternodes that have went inactive
void ResignInvalidProposals();
void CheckSignatureValidity();
void CheckOrphanVotes();
void Clear(){
LogPrintf("Budget object cleared\n");
@ -185,10 +185,10 @@ private:
public:
std::string strBudgetName;
CTxIn vin;
int nBlockStart;
std::vector<CTxBudgetPayment> vecProposals;
map<uint256, CFinalizedBudgetVote> mapVotes;
uint256 nFeeTXHash;
CFinalizedBudget();
CFinalizedBudget(const CFinalizedBudget& other);
@ -204,7 +204,6 @@ public:
std::string GetProposals();
int GetBlockStart() {return nBlockStart;}
int GetBlockEnd() {return nBlockStart + (int)(vecProposals.size()-1);}
std::string GetSubmittedBy() {return vin.prevout.ToStringShort();}
int GetVoteCount() {return (int)mapVotes.size();}
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight);
bool GetProposalByBlock(int64_t nBlockHeight, CTxBudgetPayment& payment)
@ -236,13 +235,6 @@ public:
string GetStatus();
uint256 GetHash(){
/*
vin is not included on purpose
- Any masternode can make a proposal and the hashes should match regardless of who made it.
- Someone could hyjack a new proposal by changing the vin and the signature check will fail.
However, the network will still propagate the correct version and the incorrect one will be rejected.
*/
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << strBudgetName;
ss << nBlockStart;
@ -258,7 +250,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(LIMITED_STRING(strBudgetName, 20));
READWRITE(vin);
READWRITE(nFeeTXHash);
READWRITE(nBlockStart);
READWRITE(vecProposals);
@ -273,13 +265,10 @@ private:
std::vector<unsigned char> vchSig;
public:
bool fInvalid;
CFinalizedBudgetBroadcast();
CFinalizedBudgetBroadcast(const CFinalizedBudget& other);
CFinalizedBudgetBroadcast(CTxIn& vinIn, std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> vecProposalsIn);
CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> vecProposalsIn, uint256 nFeeTXHashIn);
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
bool SignatureValid();
void Relay();
ADD_SERIALIZE_METHODS;
@ -289,10 +278,9 @@ public:
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
//for syncing with other clients
READWRITE(LIMITED_STRING(strBudgetName, 20));
READWRITE(vin);
READWRITE(nBlockStart);
READWRITE(vecProposals);
READWRITE(vchSig);
READWRITE(nFeeTXHash);
}
};
@ -354,19 +342,19 @@ public:
This allows the proposal website to stay 100% decentralized
*/
std::string strURL;
CTxIn vin;
int nBlockStart;
int nBlockEnd;
int64_t nAmount;
CScript address;
int64_t nTime;
uint256 nFeeTXHash;
map<uint256, CBudgetVote> mapVotes;
//cache object
CBudgetProposal();
CBudgetProposal(const CBudgetProposal& other);
CBudgetProposal(CTxIn vinIn, std::string strProposalNameIn, std::string strURLIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn);
CBudgetProposal(std::string strProposalNameIn, std::string strURLIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn, uint256 nFeeTXHashIn);
void Calculate();
void AddOrUpdateVote(CBudgetVote& vote);
@ -394,34 +382,9 @@ public:
void SetAllotted(int64_t nAllotedIn) {nAlloted = nAllotedIn;}
int64_t GetAllotted() {return nAlloted;}
std::string GetVoteCommand()
{
//c4 mnbudget vote one http://www.one.com/one.json 100 1000 xx9FwiqeRbuxBn5Sh3SNeoxmgpwQNSuMC4 1000 yes
int nPayments = GetTotalPaymentCount();
CTxDestination address1;
ExtractDestination(address, address1);
CBitcoinAddress address2(address1);
std::string strCommand = "dash-cli mnbudget vote " + strProposalName + " " + strURL + " " + boost::lexical_cast<std::string>(nPayments);
strCommand += " " + boost::lexical_cast<std::string>(nBlockStart) + " " + address2.ToString() + " " + boost::lexical_cast<std::string>(nAmount/COIN) + " yes|no";
return strCommand;
}
void CleanAndRemove();
uint256 GetHash(){
/*
vin is not included on purpose
- Any masternode can make a proposal and the hashes should match regardless of who made it.
- Someone could hyjack a new proposal by changing the vin and the signature check will fail.
However, the network will still propagate the correct version and the incorrect one will be rejected.
*/
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << strProposalName;
ss << strURL;
@ -441,12 +404,12 @@ public:
//for syncing with other clients
READWRITE(LIMITED_STRING(strProposalName, 20));
READWRITE(LIMITED_STRING(strURL, 64));
READWRITE(vin);
READWRITE(nBlockStart);
READWRITE(nBlockEnd);
READWRITE(nAmount);
READWRITE(address);
READWRITE(nTime);
READWRITE(nFeeTXHash);
//for saving to the serialized db
READWRITE(mapVotes);
@ -460,13 +423,10 @@ private:
std::vector<unsigned char> vchSig;
public:
bool fInvalid;
CBudgetProposalBroadcast();
CBudgetProposalBroadcast(const CBudgetProposal& other);
CBudgetProposalBroadcast(CTxIn vinIn, std::string strProposalNameIn, std::string strURL, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn);
CBudgetProposalBroadcast(std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn, uint256 nFeeTXHashIn);
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
bool SignatureValid();
void Relay();
ADD_SERIALIZE_METHODS;
@ -477,12 +437,11 @@ public:
READWRITE(LIMITED_STRING(strProposalName, 20));
READWRITE(LIMITED_STRING(strURL, 64));
READWRITE(vin);
READWRITE(nBlockStart);
READWRITE(nBlockEnd);
READWRITE(nAmount);
READWRITE(address);
READWRITE(vchSig);
READWRITE(nFeeTXHash);
}
};

View File

@ -1797,7 +1797,7 @@ void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll)
if(!relayToAll && !pnode->fRelayTxes)
continue;
pnode->PushMessage("txlreq", tx);
pnode->PushMessage("ix", tx);
}
}

View File

@ -347,7 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
transaction.getRecipients();
if(!wallet->CommitTransaction(*newTx, *keyChange, (recipients[0].useInstantX) ? "txlreq" : "tx"))
if(!wallet->CommitTransaction(*newTx, *keyChange, (recipients[0].useInstantX) ? "ix" : "tx"))
return TransactionCommitFailed;
CTransaction* t = (CTransaction*)newTx;

View File

@ -25,11 +25,13 @@ Value mnbudget(const Array& params, bool fHelp)
strCommand = params[0].get_str();
if (fHelp ||
(strCommand != "vote-many" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check"))
(strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check"))
throw runtime_error(
"mnbudget \"command\"... ( \"passphrase\" )\n"
"Vote or show current budgets\n"
"\nAvailable commands:\n"
" prepare - Prepare proposal for network by signing and creating tx\n"
" submit - Submit proposal for network\n"
" vote-many - Vote on a Dash initiative\n"
" vote-alias - Vote on a Dash initiative\n"
" vote - Vote on a Dash initiative/budget\n"
@ -40,7 +42,7 @@ Value mnbudget(const Array& params, bool fHelp)
" check - Scan proposals and remove invalid\n"
);
if(strCommand == "vote-many")
if(strCommand == "prepare")
{
int nBlockMin = 0;
CBlockIndex* pindexPrev = chainActive.Tip();
@ -48,114 +50,8 @@ Value mnbudget(const Array& params, bool fHelp)
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
if (params.size() != 8)
throw runtime_error("Correct usage of vote-many is 'mnbudget vote-many PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN'");
std::string strProposalName = params[1].get_str();
if(strProposalName.size() > 20)
return "Invalid proposal name, limit of 20 characters.";
std::string strURL = params[2].get_str();
if(strURL.size() > 64)
return "Invalid url, limit of 64 characters.";
int nPaymentCount = params[3].get_int();
if(nPaymentCount < 1)
return "Invalid payment count, must be more than zero.";
//set block min
if(pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - GetBudgetPaymentCycleBlocks()*(nPaymentCount+1);
int nBlockStart = params[4].get_int();
if(nBlockStart % GetBudgetPaymentCycleBlocks() != 0){
int nNext = pindexPrev->nHeight-(pindexPrev->nHeight % GetBudgetPaymentCycleBlocks())+GetBudgetPaymentCycleBlocks();
return "Invalid block start - must be a budget cycle block. Next Valid Block: " + boost::lexical_cast<std::string>(nNext);
}
int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks()*nPaymentCount);
if(nBlockStart < nBlockMin)
return "Invalid payment count, must be more than current height.";
if(nBlockEnd < pindexPrev->nHeight)
return "Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.";
CBitcoinAddress address(params[5].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
// Parse Dash address
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(params[6]);
std::string strVote = params[7].get_str().c_str();
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if(strVote == "yes") nVote = VOTE_YES;
if(strVote == "no") nVote = VOTE_NO;
int success = 0;
int failed = 0;
Object resultObj;
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
std::string errorMessage;
std::vector<unsigned char> vchMasterNodeSignature;
std::string strMasterNodeSignMessage;
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyMasternode;
CKey keyMasternode;
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
printf(" Error upon calling SetKey for %s\n", mne.getAlias().c_str());
failed++;
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if(pmn == NULL)
{
printf("Can't find masternode by pubkey for %s\n", mne.getAlias().c_str());
failed++;
continue;
}
//create the proposal incase we're the first to make it
CBudgetProposalBroadcast budgetProposalBroadcast(pmn->vin, strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart);
if(!budgetProposalBroadcast.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
}
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
CBudgetVote vote(pmn->vin, budgetProposalBroadcast.GetHash(), nVote);
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
}
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
success++;
}
return("Voted successfully " + boost::lexical_cast<std::string>(success) + " time(s) and failed " + boost::lexical_cast<std::string>(failed) + " time(s).");
}
if(strCommand == "vote")
{
int nBlockMin = 0;
CBlockIndex* pindexPrev = chainActive.Tip();
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
if (params.size() != 8)
throw runtime_error("Correct usage of vote-many is 'mnbudget vote PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN'");
if (params.size() != 8 || params.size() != 9)
throw runtime_error("Correct usage of vote-many is 'mnbudget prepare PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN [USE_IX(TRUE|FALSE)]'");
std::string strProposalName = params[1].get_str();
if(strProposalName.size() > 20)
@ -208,17 +104,199 @@ Value mnbudget(const Array& params, bool fHelp)
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
return(" Error upon calling SetKey");
//*************************************************************************
CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, 0);
std::string strCommand = "tx";
bool useIX = true;
if (params.size() > 8)
useIX = params[8].get_bool();
if(useIX)
{
strCommand = "ix";
}
CWalletTx wtx;
pwalletMain->GetBudgetSystemCollateralTX(wtx, budgetProposalBroadcast.GetHash(), useIX);
// make our change address
CReserveKey reservekey(pwalletMain);
//send the tx to the network
pwalletMain->CommitTransaction(wtx, reservekey, strCommand);
return wtx.GetHash().ToString().c_str();
}
if(strCommand == "submit")
{
int nBlockMin = 0;
CBlockIndex* pindexPrev = chainActive.Tip();
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
if (params.size() != 9)
throw runtime_error("Correct usage of vote-many is 'mnbudget submit PROPOSAL-NAME URL PAYMENT_COUNT BLOCK_START DASH_ADDRESS DASH_AMOUNT YES|NO|ABSTAIN FEE_TX'");
// Check these inputs the same way we check the vote commands:
// **********************************************************
std::string strProposalName = params[1].get_str();
if(strProposalName.size() > 20)
return "Invalid proposal name, limit of 20 characters.";
std::string strURL = params[2].get_str();
if(strURL.size() > 64)
return "Invalid url, limit of 64 characters.";
int nPaymentCount = params[3].get_int();
if(nPaymentCount < 1)
return "Invalid payment count, must be more than zero.";
//set block min
if(pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - GetBudgetPaymentCycleBlocks()*(nPaymentCount+1);
int nBlockStart = params[4].get_int();
if(nBlockStart % GetBudgetPaymentCycleBlocks() != 0){
int nNext = pindexPrev->nHeight-(pindexPrev->nHeight % GetBudgetPaymentCycleBlocks())+GetBudgetPaymentCycleBlocks();
return "Invalid block start - must be a budget cycle block. Next valid block: " + boost::lexical_cast<std::string>(nNext);
}
int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks()*nPaymentCount);
if(nBlockStart < nBlockMin)
return "Invalid payment count, must be more than current height.";
if(nBlockEnd < pindexPrev->nHeight)
return "Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.";
CBitcoinAddress address(params[5].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
// Parse Dash address
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(params[6]);
std::string strVote = params[7].get_str().c_str();
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if(strVote == "yes") nVote = VOTE_YES;
if(strVote == "no") nVote = VOTE_NO;
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
return(" Error upon calling SetKey");
uint256 hash = ParseHashV(params[8], "parameter 1");
//create the proposal incase we're the first to make it
CBudgetProposalBroadcast budgetProposalBroadcast(activeMasternode.vin, strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart);
if(!budgetProposalBroadcast.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, hash);
std::string strError = "";
if(!IsBudgetCollateralValid(hash ,strError)){
return "Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError;
}
if(!budgetProposalBroadcast.IsValid(strError)){
return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError;
}
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
budget.AddProposal(budgetProposalBroadcast);
CBudgetVote vote(activeMasternode.vin, budgetProposalBroadcast.GetHash(), nVote);
}
if(strCommand == "vote-many")
{
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
if (params.size() != 3)
throw runtime_error("Correct usage of vote-many is 'mnbudget vote-many PROPOSAL-HASH YES|NO|ABSTAIN'");
uint256 hash = ParseHashV(params[1], "parameter 1");
std::string strVote = params[2].get_str().c_str();
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if(strVote == "yes") nVote = VOTE_YES;
if(strVote == "no") nVote = VOTE_NO;
int success = 0;
int failed = 0;
Object resultObj;
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
std::string errorMessage;
std::vector<unsigned char> vchMasterNodeSignature;
std::string strMasterNodeSignMessage;
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyMasternode;
CKey keyMasternode;
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
printf(" Error upon calling SetKey for %s\n", mne.getAlias().c_str());
failed++;
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if(pmn == NULL)
{
printf("Can't find masternode by pubkey for %s\n", mne.getAlias().c_str());
failed++;
continue;
}
CBudgetVote vote(pmn->vin, hash, nVote);
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
}
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
success++;
}
return("Voted successfully " + boost::lexical_cast<std::string>(success) + " time(s) and failed " + boost::lexical_cast<std::string>(failed) + " time(s).");
}
if(strCommand == "vote")
{
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
if (params.size() != 3)
throw runtime_error("Correct usage of vote-many is 'mnbudget vote PROPOSAL-HASH YES|NO|ABSTAIN'");
uint256 hash = ParseHashV(params[1], "parameter 1");
std::string strVote = params[2].get_str().c_str();
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if(strVote == "yes") nVote = VOTE_YES;
if(strVote == "no") nVote = VOTE_NO;
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
return(" Error upon calling SetKey");
CBudgetVote vote(activeMasternode.vin, hash, nVote);
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
}
@ -226,7 +304,6 @@ Value mnbudget(const Array& params, bool fHelp)
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
budget.UpdateProposal(vote, NULL);
}
if(strCommand == "projection")
@ -244,7 +321,6 @@ Value mnbudget(const Array& params, bool fHelp)
CBitcoinAddress address2(address1);
Object bObj;
bObj.push_back(Pair("VoteCommand", pbudgetProposal->GetVoteCommand().c_str()));
bObj.push_back(Pair("URL", pbudgetProposal->GetURL()));
bObj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString().c_str()));
bObj.push_back(Pair("BlockStart", (int64_t)pbudgetProposal->GetBlockStart()));
@ -261,11 +337,6 @@ Value mnbudget(const Array& params, bool fHelp)
std::string strError = "";
bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError)));
bObj.push_back(Pair("Owner", pbudgetProposal->vin.prevout.ToStringShort().c_str()));
if(mapSeenMasternodeBudgetProposals.count(pbudgetProposal->GetHash())) {
bObj.push_back(Pair("SignatureValid", mapSeenMasternodeBudgetProposals[pbudgetProposal->GetHash()].SignatureValid()));
}
resultObj.push_back(Pair(pbudgetProposal->GetName().c_str(), bObj));
}
@ -288,7 +359,6 @@ Value mnbudget(const Array& params, bool fHelp)
CBitcoinAddress address2(address1);
Object bObj;
bObj.push_back(Pair("VoteCommand", pbudgetProposal->GetVoteCommand().c_str()));
bObj.push_back(Pair("URL", pbudgetProposal->GetURL()));
bObj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString().c_str()));
bObj.push_back(Pair("BlockStart", (int64_t)pbudgetProposal->GetBlockStart()));
@ -304,11 +374,7 @@ Value mnbudget(const Array& params, bool fHelp)
std::string strError = "";
bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError)));
bObj.push_back(Pair("Owner", pbudgetProposal->vin.prevout.ToStringShort().c_str()));
if(mapSeenMasternodeBudgetProposals.count(pbudgetProposal->GetHash())) {
bObj.push_back(Pair("SignatureValid", mapSeenMasternodeBudgetProposals[pbudgetProposal->GetHash()].SignatureValid()));
}
resultObj.push_back(Pair(pbudgetProposal->GetName().c_str(), bObj));
}
@ -332,7 +398,6 @@ Value mnbudget(const Array& params, bool fHelp)
CBitcoinAddress address2(address1);
Object obj;
obj.push_back(Pair("VoteCommand", pbudgetProposal->GetVoteCommand().c_str()));
obj.push_back(Pair("Name", pbudgetProposal->GetName().c_str()));
obj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString().c_str()));
obj.push_back(Pair("URL", pbudgetProposal->GetURL().c_str()));
@ -349,12 +414,6 @@ Value mnbudget(const Array& params, bool fHelp)
std::string strError = "";
obj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError)));
obj.push_back(Pair("Owner", pbudgetProposal->vin.prevout.ToStringShort().c_str()));
if(mapSeenMasternodeBudgetProposals.count(pbudgetProposal->GetHash())) {
obj.push_back(Pair("SignatureValid", mapSeenMasternodeBudgetProposals[pbudgetProposal->GetHash()].SignatureValid()));
}
return obj;
}
@ -452,11 +511,11 @@ Value mnfinalbudget(const Array& params, bool fHelp)
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
return(" Error upon calling SetKey");
//create transaction
uint256 hash = 0;
//create the proposal incase we're the first to make it
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(activeMasternode.vin, strBudgetName, nBlockStart, vecPayments);
if(!finalizedBudgetBroadcast.Sign(keyMasternode, pubKeyMasternode)){
return "Failure to sign.";
}
CFinalizedBudgetBroadcast finalizedBudgetBroadcast(strBudgetName, nBlockStart, vecPayments, hash);
if(!finalizedBudgetBroadcast.IsValid())
return "Invalid finalized budget broadcast (are all the hashes correct?)";
@ -573,11 +632,11 @@ Value mnfinalbudget(const Array& params, bool fHelp)
BOOST_FOREACH(CFinalizedBudget* finalizedBudget, winningFbs)
{
Object bObj;
bObj.push_back(Pair("SubmittedBy", finalizedBudget->GetSubmittedBy().c_str()));
bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString().c_str()));
bObj.push_back(Pair("Hash", finalizedBudget->GetHash().ToString().c_str()));
bObj.push_back(Pair("BlockStart", (int64_t)finalizedBudget->GetBlockStart()));
bObj.push_back(Pair("BlockEnd", (int64_t)finalizedBudget->GetBlockEnd()));
bObj.push_back(Pair("finalizedBudgetosals", finalizedBudget->GetProposals().c_str()));
bObj.push_back(Pair("Proposals", finalizedBudget->GetProposals().c_str()));
bObj.push_back(Pair("VoteCount", (int64_t)finalizedBudget->GetVoteCount()));
bObj.push_back(Pair("Status", finalizedBudget->GetStatus().c_str()));
resultObj.push_back(Pair(finalizedBudget->GetName().c_str(), bObj));

View File

@ -10,7 +10,7 @@
* network protocol versioning
*/
static const int PROTOCOL_VERSION = 70085;
static const int PROTOCOL_VERSION = 70086;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@ -22,16 +22,16 @@ static const int GETHEADERS_VERSION = 70077;
static const int MIN_PEER_PROTO_VERSION = 70066;
//! minimum peer version accepted by DarksendPool
static const int MIN_POOL_PEER_PROTO_VERSION = 70085;
static const int MIN_POOL_PEER_PROTO_VERSION = 70086;
//! minimum peer version for masternode budgets
static const int MIN_BUDGET_PEER_PROTO_VERSION = 70085;
static const int MIN_BUDGET_PEER_PROTO_VERSION = 70086;
//! minimum peer version that can receive masternode payments
// V1 - Last protocol version before update
// V2 - Newest protocol version
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70066;
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70085;
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70086;
//! nTime field added to CAddress, starting with this version;
//! if possible, avoid requesting addresses nodes older than this

View File

@ -10,6 +10,7 @@
#include "checkpoints.h"
#include "coincontrol.h"
#include "net.h"
#include "masternode-budget.h"
#include "darksend.h"
#include "keepass.h"
#include "instantx.h"
@ -1086,7 +1087,7 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand)
uint256 hash = GetHash();
LogPrintf("Relaying wtx %s\n", hash.ToString());
if(strCommand == "txlreq"){
if(strCommand == "ix"){
mapTxLockReq.insert(make_pair(hash, (CTransaction)*this));
CreateNewLock(((CTransaction)*this));
RelayTransactionLockReq((CTransaction)*this, true);
@ -1927,7 +1928,7 @@ bool CWallet::SelectCoinsWithoutDenomination(int64_t nTargetValue, set<pair<cons
return (nValueRet >= nTargetValue);
}
bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string strReason)
bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason)
{
/*
To doublespend a collateral transaction, it will require a fee higher than this. So there's
@ -1979,6 +1980,30 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
return true;
}
bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX)
{
// make our change address
CReserveKey reservekey(pwalletMain);
CScript scriptChange;
scriptChange << OP_RETURN << ToByteVector(hash);
int64_t nFeeRet = 0;
std::string strFail = "";
vector< pair<CScript, int64_t> > vecSend;
vecSend.push_back(make_pair(scriptChange, CENT));
CCoinControl *coinControl=NULL;
bool success = CreateTransaction(vecSend, tx, reservekey, nFeeRet, strFail, coinControl, ALL_COINS, useIX, (CAmount)BUDGET_FEE_TX);
if(!success){
LogPrintf("GetBudgetSystemCollateralTX: Error - %s\n", strFail.c_str());
return false;
}
return true;
}
bool CWallet::ConvertList(std::vector<CTxIn> vCoins, std::vector<int64_t>& vecAmounts)
{
BOOST_FOREACH(CTxIn i, vCoins){
@ -1996,8 +2021,10 @@ bool CWallet::ConvertList(std::vector<CTxIn> vCoins, std::vector<int64_t>& vecAm
}
bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX)
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX, CAmount nPayFee)
{
if(useIX && nPayFee < CENT) nPayFee = CENT;
CAmount nValue = 0;
CAmount nFeeDelta = 0;
BOOST_FOREACH (const PAIRTYPE(CScript, CAmount)& s, vecSend)
@ -2023,7 +2050,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
LOCK2(cs_main, cs_wallet);
{
nFeeRet = 0;
if(useIX) nFeeRet = CENT;
if(nPayFee!=0) nFeeRet = nPayFee;
while (true)
{
txNew.vin.clear();
@ -2206,11 +2233,11 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
}
bool CWallet::CreateTransaction(CScript scriptPubKey, const CAmount& nValue,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX)
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX, CAmount nPayFee)
{
vector< pair<CScript, CAmount> > vecSend;
vecSend.push_back(make_pair(scriptPubKey, nValue));
return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl, coin_type, useIX);
return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl, coin_type, useIX, nPayFee);
}
/**

View File

@ -319,13 +319,13 @@ public:
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
bool CreateTransaction(const std::vector<std::pair<CScript, CAmount> >& vecSend,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS, bool useIX=false);
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS, bool useIX=false, CAmount nPayFee=0);
bool CreateTransaction(CScript scriptPubKey, const CAmount& nValue,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS, bool useIX=false);
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS, bool useIX=false, CAmount nPayFee=0);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand="tx");
std::string PrepareDarksendDenominate(int minRounds, int maxRounds);
int GenerateDarksendOutputs(int nTotalValue, std::vector<CTxOut>& vout);
bool CreateCollateralTransaction(CMutableTransaction &txCollateral, std::string strReason);
bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason);
bool ConvertList(std::vector<CTxIn> vCoins, std::vector<int64_t>& vecAmounts);
static CFeeRate minTxFee;
@ -345,6 +345,8 @@ public:
std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX);
bool IsDenominated(const CTxIn &txin) const;
bool IsDenominated(const CTransaction& tx) const