Handle all the weird edge cases, such as:

A remote transaction is received *from* a local account. We neeed
to update our balance and sequence tracking.
A local transaction loses to a conflict.
This commit is contained in:
JoelKatz
2012-01-18 15:33:58 -08:00
parent 60dcb8ac35
commit 94e4e1d04b
6 changed files with 66 additions and 7 deletions

View File

@@ -32,7 +32,7 @@ bool LocalTransaction::makeTransaction()
return true; return true;
} }
void LocalTransaction::applyTransaction() void LocalTransaction::performTransaction()
{ {
mTransaction=theApp->getOPs().processTransaction(mTransaction); mTransaction=theApp->getOPs().processTransaction(mTransaction);
} }

View File

@@ -22,23 +22,30 @@ protected:
uint64 mAmount; uint64 mAmount;
uint32 mTag; uint32 mTag;
std::string mComment; std::string mComment;
bool mPaid;
Transaction::pointer mTransaction; Transaction::pointer mTransaction;
public: public:
LocalTransaction(const uint160 &dest, uint64 amount, uint32 tag) : LocalTransaction(const uint160 &dest, uint64 amount, uint32 tag) :
mDestAcctID(dest), mAmount(amount), mTag(tag) { ; } mDestAcctID(dest), mAmount(amount), mTag(tag), mPaid(false) { ; }
void setComment(const std::string& comment) { mComment=comment; } void setComment(const std::string& comment) { mComment=comment; }
const uint160& getDestinationAccount() const { return mDestAcctID; } const uint160& getDestinationAccount() const { return mDestAcctID; }
uint64 getAmount() const { return mAmount; } uint64 getAmount() const { return mAmount; }
uint32 getTag() const { return mTag; } uint32 getTag() const { return mTag; }
const std::string& getComment() const { return mComment; } const std::string& getComment() const { return mComment; }
Transaction::pointer getTransaction() { return mTransaction; }
void applyTransaction();
bool makeTransaction(); Transaction::pointer getTransaction() { return mTransaction; }
void setTransaction(Transaction::pointer t) { mTransaction=t; }
bool isPaid() const { return mPaid; }
void setPaid() { mPaid=true; }
void setUnpaid() { mPaid=false; }
void performTransaction(); // perform this transaction as if we received it from the network
bool makeTransaction(); // create a transaction object according to these rules
}; };
#endif #endif

View File

@@ -56,8 +56,9 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
if(r==Ledger::TR_SUCCESS) if(r==Ledger::TR_SUCCESS)
{ {
// WRITEME: send to others
trans->setStatus(INCLUDED); trans->setStatus(INCLUDED);
// WRITEME: send to others
theApp->getWallet().applyTransaction(trans);
return trans; return trans;
} }

View File

@@ -365,7 +365,7 @@ Json::Value RPCServer::doSendTo(Json::Value& params)
LocalTransaction::pointer lt(new LocalTransaction(destAccount, iAmount, iTag)); LocalTransaction::pointer lt(new LocalTransaction(destAccount, iAmount, iTag));
if(!lt->makeTransaction()) if(!lt->makeTransaction())
return JSONRPCError(500, "Insufficient funds in unlocked accounts"); return JSONRPCError(500, "Insufficient funds in unlocked accounts");
lt->applyTransaction(); lt->performTransaction();
return lt->getTransaction()->getJson(true); return lt->getTransaction()->getJson(true);
} }

View File

@@ -812,3 +812,53 @@ void Wallet::syncToLedger(bool force, Ledger* ledger)
} }
if(mLedger<ledger->getLedgerSeq()) mLedger=ledger->getLedgerSeq(); if(mLedger<ledger->getLedgerSeq()) mLedger=ledger->getLedgerSeq();
} }
void Wallet::applyTransaction(Transaction::pointer txn)
{
TransStatus st=txn->getStatus();
bool shouldBePaid=(st==INCLUDED) || (st==HELD) || (st==NEW);
boost::recursive_mutex::scoped_lock sl(mLock);
std::map<uint160, LocalAccount::pointer>::iterator lac=mAccounts.find(txn->getFromAccount());
if(lac==mAccounts.end()) return;
if ( (st!=INVALID) && (lac->second->getTxnSeq()==txn->getFromAccountSeq()) )
lac->second->incTxnSeq();
std::map<uint256, LocalTransaction::pointer>::iterator ltx=mTransactions.find(txn->getID());
if(ltx==mTransactions.end())
{ // we don't have this transactions
if(shouldBePaid)
{ // we need it
LocalTransaction::pointer nlt(new
LocalTransaction(txn->getToAccount(), txn->getAmount(), txn->getIdent()));
nlt->setTransaction(txn);
mTransactions.insert(std::make_pair<uint256, LocalTransaction::pointer>(txn->getID(), nlt));
lac->second->debit(txn->getAmount());
ltx->second->setPaid();
}
}
else
{ // we have this transaction in some form (ltx->second)
if( (st==COMMITTED) || (st==INVALID) )
{ // we need to remove it
if(ltx->second->isPaid())
{
lac->second->credit(txn->getAmount());
ltx->second->setUnpaid();
}
mTransactions.erase(txn->getID());
}
else if(ltx->second->isPaid() && !shouldBePaid)
{ // we paid for this transaction and it didn't happen
lac->second->credit(txn->getAmount());
ltx->second->setUnpaid();
}
else if(!ltx->second->isPaid() && shouldBePaid)
{ // this transaction happened, and we haven't paid locally
lac->second->debit(txn->getAmount());
ltx->second->setPaid();
}
}
}

View File

@@ -80,6 +80,7 @@ public:
static uint256 textToPrivKey(const std::string&); static uint256 textToPrivKey(const std::string&);
void syncToLedger(bool force, Ledger* ledger); void syncToLedger(bool force, Ledger* ledger);
void applyTransaction(Transaction::pointer);
static bool unitTest(); static bool unitTest();
}; };