mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
added instantx support
This commit is contained in:
parent
ed61f5762e
commit
05d3d2c666
@ -2005,6 +2005,7 @@ void ThreadCheckDarkSendPool()
|
||||
}
|
||||
|
||||
masternodePayments.CleanPaymentList();
|
||||
CleanTransactionLocksList();
|
||||
}
|
||||
|
||||
|
||||
|
358
src/instantx.cpp
358
src/instantx.cpp
@ -17,6 +17,13 @@
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
std::vector<CTransactionLock> vecTxLocks;
|
||||
|
||||
std::map<uint256, CTransaction> mapTxLockReq;
|
||||
std::map<uint256, CTransactionLock> mapTxLocks;
|
||||
|
||||
#define INSTANTX_SIGNATURES_REQUIRED 2
|
||||
|
||||
//txlock - Locks transaction
|
||||
//
|
||||
//step 1.) Broadcast intention to lock transaction inputs, "txlreg", CTransaction
|
||||
@ -30,16 +37,28 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
||||
printf("ProcessMessageInstantX::txlreq\n");
|
||||
CDataStream vMsg(vRecv);
|
||||
CTransaction tx;
|
||||
vRecv >> tx;
|
||||
int nBlockHeight;
|
||||
vRecv >> tx >> nBlockHeight;
|
||||
|
||||
CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash());
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
if(mapTxLockReq.count(inv.hash)){
|
||||
printf("ProcessMessageInstantX::txlreq - Already Have Transaction Lock Request: %s %s : accepted %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
tx.GetHash().ToString().c_str()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
bool fMissingInputs = false;
|
||||
CValidationState state;
|
||||
if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
|
||||
{
|
||||
RelayTransactionLockReq(tx, inv.hash);
|
||||
DoConsensusVote(tx, true, nBlockHeight);
|
||||
|
||||
mapTxLockReq.insert(make_pair(inv.hash, tx));
|
||||
|
||||
printf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : accepted %s\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||
@ -47,7 +66,344 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// can we get the conflicting transaction as proof?
|
||||
|
||||
RelayTransactionLockReq(tx, inv.hash);
|
||||
DoConsensusVote(tx, false, nBlockHeight);
|
||||
|
||||
printf("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;
|
||||
}
|
||||
}
|
||||
else if (strCommand == "txlvote") //InstantX Lock Consensus Votes
|
||||
{
|
||||
CConsensusVote ctx;
|
||||
vRecv >> ctx;
|
||||
|
||||
ProcessConsensusVote(ctx);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (strCommand == "txlock") //InstantX Lock Transaction Inputs
|
||||
{
|
||||
printf("ProcessMessageInstantX::txlock\n");
|
||||
|
||||
CDataStream vMsg(vRecv);
|
||||
CTransactionLock ctxl;
|
||||
vRecv >> ctxl;
|
||||
|
||||
CInv inv(MSG_TXLOCK, ctxl.GetHash());
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
printf(" -- ProcessMessageInstantX::txlock %d %s\n", mapTxLocks.count(inv.hash), inv.hash.ToString().c_str());
|
||||
|
||||
if(!mapTxLocks.count(inv.hash)){
|
||||
if(ctxl.CountSignatures() < INSTANTX_SIGNATURES_REQUIRED){
|
||||
printf("InstantX::txlock - not enough signatures\n");
|
||||
return;
|
||||
}
|
||||
if(!ctxl.SignaturesValid()){
|
||||
printf("InstantX::txlock - got invalid TransactionLock, rejected\n");
|
||||
return;
|
||||
}
|
||||
if(!ctxl.AllInFavor()){
|
||||
printf("InstantX::txlock - not all in favor of lock, rejected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mapTxLocks.insert(make_pair(inv.hash, ctxl));
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if(!pnode->fRelayTxes)
|
||||
continue;
|
||||
|
||||
pnode->PushMessage("txlock", ctxl);
|
||||
}
|
||||
|
||||
pwalletMain->UpdatedConfirmations();
|
||||
|
||||
printf("InstantX :: Got Transaction Lock: %s %s : accepted %s\n",
|
||||
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) {
|
||||
printf("InstantX::DoConsensusVote - Not masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int winner = GetCurrentMasterNode(1, nBlockHeight);
|
||||
int n = GetMasternodeRank(activeMasternode.vinMasternode, nBlockHeight);
|
||||
|
||||
if(n == -1 || winner == -1)
|
||||
{
|
||||
printf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n == 1)
|
||||
{ // winner, I'll be keeping track of this
|
||||
printf("InstantX::DoConsensusVote - Managing Masternode\n");
|
||||
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()){
|
||||
printf("InstantX::DoConsensusVote - Failed to sign consensus vote\n");
|
||||
return;
|
||||
}
|
||||
if(!ctx.SignatureValid()) {
|
||||
printf("InstantX::ProcessConsensusVote - Signature invalid\n");
|
||||
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);
|
||||
printf("InstantX::DoConsensusVote --- connected, sending vote %s\n", pnode->addr.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
printf("InstantX::DoConsensusVote --- error connecting \n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//received a consensus vote
|
||||
void ProcessConsensusVote(CConsensusVote& ctx)
|
||||
{
|
||||
if(!fMasterNode) {
|
||||
printf("InstantX::ProcessConsensusVote - Not masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int winner = GetCurrentMasterNode(1, ctx.nBlockHeight);
|
||||
if(winner == -1) {
|
||||
printf("InstantX::ProcessConsensusVote - Can't detect winning masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//We're not the winning masternode
|
||||
if(darkSendMasterNodes[winner].vin != activeMasternode.vinMasternode) {
|
||||
printf("InstantX::ProcessConsensusVote - I'm not the winning masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int n = GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
printf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(n > 10)
|
||||
{
|
||||
printf("InstantX::DoConsensusVote - Masternode not in the top 10\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ctx.SignatureValid()) {
|
||||
printf("InstantX::ProcessConsensusVote - Signature invalid\n");
|
||||
//don't ban, it could just be a non-synced masternode
|
||||
return;
|
||||
}
|
||||
|
||||
//compile consessus vote
|
||||
printf(" -- 1\n");
|
||||
BOOST_FOREACH(CTransactionLock& ctxl, vecTxLocks){
|
||||
printf(" -- 2\n");
|
||||
if(ctxl.nBlockHeight == ctx.nBlockHeight){
|
||||
ctxl.AddSignature(ctx);
|
||||
printf(" -- 3 - %d\n", ctxl.CountSignatures());
|
||||
if(ctxl.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
|
||||
printf("InstantX::ProcessConsensusVote - Transaction Lock Is Complelete, broadcasting!\n");
|
||||
|
||||
CInv inv(MSG_TXLOCK, ctxl.GetHash());
|
||||
mapTxLocks.insert(make_pair(inv.hash, ctxl));
|
||||
|
||||
printf(" -- 4 %d %s\n", mapTxLocks.count(inv.hash), inv.hash.ToString().c_str());
|
||||
|
||||
//broadcast the new lock
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
if(!pnode->fRelayTxes)
|
||||
continue;
|
||||
|
||||
pnode->PushMessage("txlock", ctxl);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void CleanTransactionLocksList()
|
||||
{
|
||||
if(pindexBest == NULL) return;
|
||||
|
||||
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
||||
|
||||
while(it != mapTxLocks.end()) {
|
||||
if(pindexBest->nHeight - it->second.nBlockHeight > 24){ //keep them for an hour
|
||||
LogPrintf("Removing old transaction lock %s\n", it->second.GetHash().ToString().c_str());
|
||||
mapTxLocks.erase(it);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
printf("verify strMessage %s \n", strMessage.c_str());
|
||||
|
||||
int n = GetMasternodeByVin(vinMasternode);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
printf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("verify addr %s \n", darkSendMasterNodes[0].addr.ToString().c_str());
|
||||
printf("verify addr %s \n", darkSendMasterNodes[1].addr.ToString().c_str());
|
||||
printf("verify addr %d %s \n", n, darkSendMasterNodes[n].addr.ToString().c_str());
|
||||
|
||||
CScript pubkey;
|
||||
pubkey.SetDestination(darkSendMasterNodes[n].pubkey2.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
printf("verify pubkey2 %s \n", address2.ToString().c_str());
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(darkSendMasterNodes[n].pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
printf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
|
||||
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);
|
||||
printf("signing strMessage %s \n", strMessage.c_str());
|
||||
printf("signing privkey %s \n", strMasterNodePrivKey.c_str());
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
printf("Invalid masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
CScript pubkey;
|
||||
pubkey.SetDestination(pubkey2.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
printf("signing pubkey2 %s \n", address2.ToString().c_str());
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, key2)) {
|
||||
printf("CActiveMasternode::RegisterAsMasterNode() - Sign message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
|
||||
printf("CActiveMasternode::RegisterAsMasterNode() - Verify message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CTransactionLock::SignaturesValid()
|
||||
{
|
||||
|
||||
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
|
||||
{
|
||||
int n = GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
printf("InstantX::DoConsensusVote - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n > 10)
|
||||
{
|
||||
printf("InstantX::DoConsensusVote - Masternode not in the top 10\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!vote.SignatureValid()){
|
||||
printf("InstantX::CTransactionLock::SignaturesValid - Signature not valid\n");
|
||||
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();
|
||||
}
|
@ -20,7 +20,69 @@
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
class CConsensusVote;
|
||||
class CTransaction;
|
||||
class CTransactionLock;
|
||||
|
||||
extern map<uint256, CTransaction> mapTxLockReq;
|
||||
extern map<uint256, CTransactionLock> mapTxLocks;
|
||||
|
||||
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
|
||||
//check if we need to vote on this transaction
|
||||
void DoConsensusVote(CTransaction& tx, bool approved, int64 nBlockHeight);
|
||||
|
||||
//process consensus vote message
|
||||
void ProcessConsensusVote(CConsensusVote& ctx);
|
||||
|
||||
// keep transaction locks in memory for an hour
|
||||
void CleanTransactionLocksList();
|
||||
|
||||
class CConsensusVote
|
||||
{
|
||||
public:
|
||||
CTxIn vinMasternode;
|
||||
bool approved;
|
||||
uint256 txHash;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
int nBlockHeight;
|
||||
|
||||
bool SignatureValid();
|
||||
bool Sign();
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(txHash);
|
||||
READWRITE(vinMasternode);
|
||||
READWRITE(approved);
|
||||
READWRITE(vchMasterNodeSignature);
|
||||
READWRITE(nBlockHeight);
|
||||
)
|
||||
};
|
||||
|
||||
class CTransactionLock
|
||||
{
|
||||
public:
|
||||
int nBlockHeight;
|
||||
CTransaction tx;
|
||||
std::vector<CConsensusVote> vecConsensusVotes;
|
||||
|
||||
bool SignaturesValid();
|
||||
int CountSignatures();
|
||||
bool AllInFavor();
|
||||
void AddSignature(CConsensusVote cv);
|
||||
uint256 GetHash()
|
||||
{
|
||||
return tx.GetHash();
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(tx);
|
||||
READWRITE(nBlockHeight);
|
||||
READWRITE(vecConsensusVotes);
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
#endif
|
56
src/main.cpp
56
src/main.cpp
@ -711,6 +711,24 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if this conflicts with any TX locks
|
||||
//printf("mapTxLocks start\n");
|
||||
typedef std::map<uint256, CTransactionLock>::iterator it_ctxl;
|
||||
for(it_ctxl it = mapTxLocks.begin(); it != mapTxLocks.end(); it++) {
|
||||
//printf("%s\n", it->second.tx.ToString().c_str());
|
||||
//printf("%s\n", tx.ToString().c_str());
|
||||
for (unsigned int a = 0; a < it->second.tx.vin.size(); a++) {
|
||||
for (unsigned int b = 0; b < tx.vin.size(); b++) {
|
||||
//printf(" compare %d - %d\n", a, b);
|
||||
if(tx.vin[b].prevout == it->second.tx.vin[a].prevout) {
|
||||
return error("CTxMemPool::acceptableInputs()::InstantX : invalid transaction, conflicts with existing transaction lock %s", tx.vin[b].ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("mapTxLocks end\n");
|
||||
|
||||
|
||||
// Check for conflicts with in-memory transactions
|
||||
CTransaction* ptxOld = NULL;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
@ -858,6 +876,20 @@ bool CTxMemPool::acceptableInputs(CValidationState &state, CTransaction &tx, boo
|
||||
return error("CTxMemPool::acceptableInputs() : nonstandard transaction (%s)",
|
||||
strNonStd.c_str());
|
||||
*/
|
||||
|
||||
// See if this conflicts with any TX locks
|
||||
typedef std::map<uint256, CTransactionLock>::iterator it_ctxl;
|
||||
for(it_ctxl it = mapTxLocks.begin(); it != mapTxLocks.end(); it++) {
|
||||
for (unsigned int a = 0; a < it->second.tx.vin.size(); a++) {
|
||||
for (unsigned int b = 0; b < tx.vin.size(); b++) {
|
||||
if(tx.vin[b].prevout == it->second.tx.vin[a].prevout) {
|
||||
return error("CTxMemPool::acceptableInputs()::InstantX : invalid transaction, conflicts with existing transaction lock %s", tx.vin[b].ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for conflicts with in-memory transactions
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
@ -1154,15 +1186,35 @@ void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
|
||||
vtxid.push_back((*mi).first);
|
||||
}
|
||||
|
||||
|
||||
int CMerkleTx::IsTransactionLocked() const
|
||||
{
|
||||
if(nInstantXDepth == 0) return 0;
|
||||
|
||||
//printf("mapTxLocks start\n");
|
||||
typedef std::map<uint256, CTransactionLock>::iterator it_ctxl;
|
||||
|
||||
int found = 0;
|
||||
for (unsigned int b = 0; b < vout.size(); b++) {
|
||||
for(it_ctxl it = mapTxLocks.begin(); it != mapTxLocks.end(); it++) {
|
||||
for (unsigned int a = 0; a < it->second.tx.vout.size(); a++) {
|
||||
if(vout[b] == it->second.tx.vout[a])
|
||||
found++;
|
||||
}
|
||||
if(found > 0) break;
|
||||
}
|
||||
}
|
||||
//printf("mapTxLocks end %d %d\n", found , (int)vout.size());
|
||||
if(found == (int)vout.size()) return nInstantXDepth;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
|
||||
{
|
||||
int minConfirms = 0;
|
||||
minConfirms = IsTransactionLocked();
|
||||
|
||||
if (hashBlock == 0 || nIndex == -1)
|
||||
return 0;
|
||||
|
||||
@ -1184,7 +1236,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
|
||||
}
|
||||
|
||||
pindexRet = pindex;
|
||||
return pindexBest->nHeight - pindex->nHeight + 1;
|
||||
return max(pindexBest->nHeight - pindex->nHeight + 1, minConfirms);
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,7 +157,12 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
funds = "Using <b>ANY AVAILABLE Funds</b>";
|
||||
}
|
||||
|
||||
if(ui->checkInstantX->isChecked()) {
|
||||
printf("!!!! USING INSTANTX\n");
|
||||
recipients[0].useInstantX = true;
|
||||
} else {
|
||||
recipients[0].useInstantX = false;
|
||||
}
|
||||
|
||||
// Format confirmation message
|
||||
QStringList formatted;
|
||||
|
@ -91,12 +91,12 @@ void WalletModel::updateStatus()
|
||||
|
||||
void WalletModel::pollBalanceChanged()
|
||||
{
|
||||
if(nBestHeight != cachedNumBlocks || nDarksendRounds != cachedDarksendRounds)
|
||||
if(nBestHeight != cachedNumBlocks || nDarksendRounds != cachedDarksendRounds || (int)mapTxLocks.size() != cachedTxLocks)
|
||||
{
|
||||
// Balance and number of transactions might have changed
|
||||
cachedNumBlocks = nBestHeight;
|
||||
cachedDarksendRounds = nDarksendRounds;
|
||||
cachedTxLocks = 0;
|
||||
cachedTxLocks = (int)mapTxLocks.size();
|
||||
checkBalanceChanged();
|
||||
}
|
||||
}
|
||||
@ -235,6 +235,10 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
|
||||
}
|
||||
|
||||
std::string strCommand = "tx";
|
||||
if(recipients[0].useInstantX) {
|
||||
printf("!!!! USING INSTANTX2\n");
|
||||
strCommand = "txlreq";
|
||||
}
|
||||
if(!wallet->CommitTransaction(wtx, keyChange, strCommand))
|
||||
{
|
||||
return TransactionCommitFailed;
|
||||
|
Loading…
Reference in New Issue
Block a user