From 0416d64fdc8272c47186acbdf4cc8d6be20aad53 Mon Sep 17 00:00:00 2001 From: jed Date: Thu, 20 Oct 2011 16:34:22 -0700 Subject: [PATCH] . --- Debug/newcoin.exe.embed.manifest.res | Bin 472 -> 68 bytes Ledger.cpp | 51 ++++++++--------- Ledger.h | 20 ++++--- LedgerHistory.cpp | 2 +- LedgerHistory.h | 5 +- LedgerMaster.cpp | 80 ++++++++++++++++----------- LedgerMaster.h | 11 ++-- Peer.cpp | 18 +++--- TimingService.cpp | 7 ++- TimingService.h | 2 + Transaction.h | 2 + ValidationCollection.cpp | 42 +++++++++++--- ValidationCollection.h | 7 ++- Wallet.cpp | 27 ++++++--- Wallet.h | 2 +- newcoin.proto | 1 + 16 files changed, 176 insertions(+), 101 deletions(-) diff --git a/Debug/newcoin.exe.embed.manifest.res b/Debug/newcoin.exe.embed.manifest.res index 9c8df0e3c8e374037f6a16f24fed3e764becd3f9..c4d02afa239886c4a1845b3c376c60dbc9f43471 100644 GIT binary patch delta 42 pcmcb?>@q>*W|Caz_Mj(rU!GM921#-0*NY35vC%HU`*P{VH=NWD|rsCvy82Wg7SBtH8vcp6+h6-krDM$<^ zu5H*<@Nj=qT!N&m!&set_index(mIndex); - ledger->set_hash(mHash); + ledger->set_hash(mHash.begin(),mHash.GetSerializeSize()); pair >& account=pair >(); BOOST_FOREACH(account,mAccounts) @@ -48,12 +54,14 @@ void Ledger::setTo(newcoin::FullLedger& ledger) mAccounts.clear(); mValidSig=false; mValidHash=false; - + + mParentHash=Transaction::protobufToInternalHash(ledger.parenthash()); + int numAccounts=ledger.accounts_size(); for(int n=0; n(account.amount(),account.seqnum()); + mAccounts[ NewcoinAddress::protobufToInternal(account.address()) ] = Account(account.amount(),account.seqnum()); } int numTrans=ledger.transactions_size(); @@ -64,6 +72,15 @@ void Ledger::setTo(newcoin::FullLedger& ledger) } } +Ledger::pointer Ledger::getParent() +{ + if(!mParent) + { + mParent=theApp->getLedgerMaster().getLedger(mParentHash); + } + return(mParent); +} + bool Ledger::load(std::string dir) { string filename=strprintf("%s%u.ledger",dir,mIndex); @@ -114,54 +131,32 @@ Ledger::Account* Ledger::getAccount(uint160& address) return(NULL); } -string& Ledger::getHash() +uint256& Ledger::getHash() { if(!mValidHash) hash(); return(mHash); } -string& Ledger::getSignature() +uint256& Ledger::getSignature() { if(!mValidSig) sign(); return(mSignature); } -void Ledger::publish() +void Ledger::publishValidation() { PackedMessage::pointer packet=Peer::createValidation(shared_from_this()); theApp->getConnectionPool().relayMessage(NULL,packet); } -void Ledger::finalize() -{ - -} - void Ledger::sign() { // TODO: } -void Ledger::calcMoneyMap() -{ -/* - // start with map from the previous ledger - // go through every transaction - Ledger::pointer parent=theApp->getLedgerMaster().getLedger(mIndex-1); - if(parent) - { - mMoneyMap.clear(); - mMoneyMap=parent->getMoneyMap(); - - mBundle.updateMap(mMoneyMap); - // TODO: strip the 0 ones - } */ -} void Ledger::hash() { - calcMoneyMap(); - // TODO: } diff --git a/Ledger.h b/Ledger.h index eda4eade5c..c0ff96a385 100644 --- a/Ledger.h +++ b/Ledger.h @@ -23,8 +23,10 @@ private: bool mFaith; //TODO: if you will bother to validate this ledger or not. You have to accept the first ledger on Faith uint32 mIndex; - std::string mHash; - std::string mSignature; + uint256 mHash; + uint256 mSignature; + uint256 mParentHash; + uint32 mValidationSeqNum; @@ -40,7 +42,6 @@ private: Ledger::pointer mChild; - void calcMoneyMap(); void sign(); void hash(); void addTransactionRecalculate(TransactionPtr trans); @@ -48,6 +49,8 @@ private: public: typedef boost::shared_ptr pointer; Ledger(uint32 index); + Ledger(newcoin::FullLedger& ledger); + void setTo(newcoin::FullLedger& ledger); void save(std::string dir); @@ -55,9 +58,9 @@ public: void recalculate(bool recursive=true); - void publish(); - void finalize(); + void publishValidation(); + std::list& getTransactions(){ return(mTransactions); } bool hasTransaction(TransactionPtr trans); int64 getAmountHeld(uint160& address); @@ -67,13 +70,16 @@ public: void addIgnoredValidation(newcoin::Validation& valid); uint32 getIndex(){ return(mIndex); } - std::string& getHash(); - std::string& getSignature(); + uint256& getHash(); + uint256& getSignature(); + uint32 getValidSeqNum(){ return(mValidationSeqNum); } unsigned int getNumTransactions(){ return(mTransactions.size()); } std::map >& getAccounts(){ return(mAccounts); } Account* getAccount(uint160& address); newcoin::FullLedger* createFullLedger(); + Ledger::pointer getParent(); + }; diff --git a/LedgerHistory.cpp b/LedgerHistory.cpp index 73651622ac..0e2e858b15 100644 --- a/LedgerHistory.cpp +++ b/LedgerHistory.cpp @@ -24,7 +24,7 @@ bool LedgerHistory::loadLedger(uint32 index) // this will see if the ledger is in memory // if not it will check disk and load it // if not it will return NULL -Ledger::pointer LedgerHistory::getLedger(uint32 index) +Ledger::pointer LedgerHistory::getAcceptedLedger(uint32 index) { if(mAcceptedLedgers.count(index)) return(mAcceptedLedgers[index]); diff --git a/LedgerHistory.h b/LedgerHistory.h index 1f89a10319..8a113c9a5a 100644 --- a/LedgerHistory.h +++ b/LedgerHistory.h @@ -23,9 +23,10 @@ public: void load(); void addLedger(Ledger::pointer ledger); + void addAcceptedLedger(Ledger::pointer ledger); - Ledger::pointer getLedger(uint32 index); - Ledger::pointer getLedger(uint256 hash); + Ledger::pointer getAcceptedLedger(uint32 index); + Ledger::pointer getLedger(uint256& hash); }; #endif \ No newline at end of file diff --git a/LedgerMaster.cpp b/LedgerMaster.cpp index f7e22b6713..1c7b53c306 100644 --- a/LedgerMaster.cpp +++ b/LedgerMaster.cpp @@ -35,10 +35,6 @@ int64 LedgerMaster::getAmountHeld(std::string& addr) return(mCurrentLedger->getAmountHeld(NewcoinAddress::humanToInternal(addr))); } -Ledger::pointer LedgerMaster::getLedger(uint32 index) -{ - return(mLedgerHistory.getLedger(index)); -} bool LedgerMaster::isTransactionOnFutureList(TransactionPtr needle) @@ -85,13 +81,16 @@ bool LedgerMaster::addTransaction(TransactionPtr trans) // TODO: since maybe we are adding a whole bunch at once. we should send at the end of the batch // TODO: do we ever really need to re-propose? //if(mAfterProposed) sendProposal(); + theApp->getWallet().transactionChanged(trans); return(true); }else return(false); }else if(trans->ledgerindex()==mCurrentLedger->getIndex()) { if(mCurrentLedger->hasTransaction(trans)) return(false); if(!isValidTransaction(trans)) return(false); - return( mCurrentLedger->addTransaction(trans,false) ); + if(!mCurrentLedger->addTransaction(trans,false)) return(false); + theApp->getWallet().transactionChanged(trans); + return( true ); }else if(trans->ledgerindex()>mCurrentLedger->getIndex()) { // in the future @@ -110,51 +109,68 @@ bool LedgerMaster::addTransaction(TransactionPtr trans) uint32 checkIndex=trans->ledgerindex(); while(checkIndex <= mCurrentLedger->getIndex()) { - Ledger::pointer ledger=mLedgerHistory.getLedger(checkIndex); + Ledger::pointer ledger=mLedgerHistory.getAcceptedLedger(checkIndex); if(ledger) { if(ledger->hasTransaction(trans)) return(false); } checkIndex++; } - - return( mCurrentLedger->addTransaction(trans,false) ); + if(!mCurrentLedger->addTransaction(trans,false)) return(false); + theApp->getWallet().transactionChanged(trans); + return(true); } } -void LedgerMaster::gotFullLedger(newcoin::FullLedger& ledger) + +void LedgerMaster::addFullLedger(newcoin::FullLedger& ledger) { - // TODO: - // if this is a historical ledger we don't have we can add it to the history? - // if this is the same index as the finalized ledger we should go through and look for transactions we missed - // if this is a historical ledger but it has more consensus than the one you have use it. + // check if we already have this ledger + // check that the hash is correct + uint256 inHash=Transaction::protobufToInternalHash(ledger.hash()); + Ledger::pointer existingLedger=mLedgerHistory.getLedger( inHash ); + if(existingLedger) return; + + Ledger::pointer newLedger=Ledger::pointer(new Ledger(ledger)); + if(newLedger->getHash()==inHash) + { + mLedgerHistory.addLedger(newLedger); + + // add all these in case we are missing some + BOOST_FOREACH(TransactionPtr trans, newLedger->getTransactions()) + { + addTransaction(trans); + } + + }else cout << "We were sent a bad ledger hash" << endl; + +} + + +void LedgerMaster::startFinalization() +{ + mFinalizingLedger=mCurrentLedger; + mCurrentLedger=Ledger::pointer(new Ledger(mCurrentLedger->getIndex()+1)); + + applyFutureProposals( mFinalizingLedger->getIndex() ); + applyFutureTransactions( mCurrentLedger->getIndex() ); } void LedgerMaster::sendProposal() { - //mAfterProposed=true; PackedMessage::pointer packet=Peer::createLedgerProposal(mFinalizingLedger); theApp->getConnectionPool().relayMessage(NULL,packet); } -void LedgerMaster::nextLedger() + +void LedgerMaster::endFinalization() { - // publish past ledger - // finalize current ledger - // start a new ledger + mFinalizingLedger->publishValidation(); + mLedgerHistory.addAcceptedLedger(mFinalizingLedger); + mLedgerHistory.addLedger(mFinalizingLedger); - //mAfterProposed=false; - Ledger::pointer closedLedger=mFinalizingLedger; - mFinalizingLedger=mCurrentLedger; - mCurrentLedger=Ledger::pointer(new Ledger(mCurrentLedger->getIndex()+1)); - - mFinalizingLedger->finalize(); - closedLedger->publish(); - mLedgerHistory.addLedger(closedLedger); - - applyFutureProposals( mFinalizingLedger->getIndex() ); - applyFutureTransactions( mCurrentLedger->getIndex() ); + mFinalizingLedger=Ledger::pointer(); } void LedgerMaster::addFutureProposal(Peer::pointer peer,newcoin::ProposeLedger& otherLedger) @@ -195,10 +211,10 @@ void LedgerMaster::checkLedgerProposal(Peer::pointer peer, newcoin::ProposeLedge if(otherLedger.ledgerindex()getIndex()) { // you have already closed this ledger - Ledger::pointer oldLedger=mLedgerHistory.getLedger(otherLedger.ledgerindex()); + Ledger::pointer oldLedger=mLedgerHistory.getAcceptedLedger(otherLedger.ledgerindex()); if(oldLedger) { - if( (oldLedger->getHash()!=otherLedger.hash()) && + if( (oldLedger->getHash()!=Transaction::protobufToInternalHash(otherLedger.hash())) && (oldLedger->getNumTransactions()>=otherLedger.numtransactions())) { peer->sendLedgerProposal(oldLedger); @@ -209,7 +225,7 @@ void LedgerMaster::checkLedgerProposal(Peer::pointer peer, newcoin::ProposeLedge addFutureProposal(peer,otherLedger); }else { // you guys are on the same page - if(mFinalizingLedger->getHash()!=otherLedger.hash()) + if(mFinalizingLedger->getHash()!= Transaction::protobufToInternalHash(otherLedger.hash())) { if( mFinalizingLedger->getNumTransactions()>=otherLedger.numtransactions()) { diff --git a/LedgerMaster.h b/LedgerMaster.h index 0d4ad45580..c50045f83e 100644 --- a/LedgerMaster.h +++ b/LedgerMaster.h @@ -41,17 +41,20 @@ public: void save(); uint32 getCurrentLedgerIndex(); - //int getCurrentLedgerSeconds(); - Ledger::pointer getLedger(uint32 index); + + Ledger::pointer getAcceptedLedger(uint32 index){ return(mLedgerHistory.getAcceptedLedger(index)); } + Ledger::pointer getLedger(uint256& hash){ return(mLedgerHistory.getLedger(hash)); } + int64 getAmountHeld(std::string& addr); int64 getAmountHeld(uint160& addr); Ledger::Account* getAccount(uint160& addr){ return(mCurrentLedger->getAccount(addr)); } bool addTransaction(TransactionPtr trans); - void gotFullLedger(newcoin::FullLedger& ledger); + void addFullLedger(newcoin::FullLedger& ledger); - void nextLedger(); + void startFinalization(); void sendProposal(); + void endFinalization(); void checkLedgerProposal(Peer::pointer peer,newcoin::ProposeLedger& packet); }; diff --git a/Peer.cpp b/Peer.cpp index 57926cbb3b..2d8def08b5 100644 --- a/Peer.cpp +++ b/Peer.cpp @@ -107,9 +107,10 @@ PackedMessage::pointer Peer::createFullLedger(Ledger::pointer ledger) PackedMessage::pointer Peer::createLedgerProposal(Ledger::pointer ledger) { + uint256& hash=ledger->getHash(); newcoin::ProposeLedger* prop=new newcoin::ProposeLedger(); prop->set_ledgerindex(ledger->getIndex()); - prop->set_hash(ledger->getHash()); + prop->set_hash(hash.begin(),hash.GetSerializeSize()); prop->set_numtransactions(ledger->getNumTransactions()); PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(prop),newcoin::PROPOSE_LEDGER)); @@ -118,10 +119,14 @@ PackedMessage::pointer Peer::createLedgerProposal(Ledger::pointer ledger) PackedMessage::pointer Peer::createValidation(Ledger::pointer ledger) { + uint256 hash=ledger->getHash(); + uint256 sig=ledger->getSignature(); + newcoin::Validation* valid=new newcoin::Validation(); valid->set_ledgerindex(ledger->getIndex()); - valid->set_hash(ledger->getHash()); - valid->set_sig(ledger->getSignature()); + valid->set_hash(hash.begin(),hash.GetSerializeSize()); + valid->set_seqnum(ledger->getValidSeqNum()); + valid->set_sig(sig.begin(),sig.GetSerializeSize()); valid->set_hanko(theConfig.HANKO); @@ -268,7 +273,7 @@ void Peer::receiveHello(newcoin::Hello& packet) void Peer::receiveGetFullLedger(newcoin::GetFullLedger& gfl) { - sendFullLedger(theApp->getLedgerMaster().getLedger(gfl.ledgerindex())); + sendFullLedger(theApp->getLedgerMaster().getLedger(Transaction::protobufToInternalHash(gfl.hash()))); } void Peer::receiveValidation(newcoin::Validation& validation) @@ -294,9 +299,6 @@ void Peer::receiveTransaction(TransactionPtr trans) // add to the correct transaction bundle and relay if we need to if(theApp->getLedgerMaster().addTransaction(trans)) { - // tell the wallet in case it was to us - theApp->getWallet().transactionAdded(trans); - // broadcast it to other Peers ConnectionPool& pool=theApp->getConnectionPool(); PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(new newcoin::Transaction(*(trans.get()))),newcoin::TRANSACTION)); @@ -315,7 +317,7 @@ void Peer::receiveProposeLedger(newcoin::ProposeLedger& packet) void Peer::receiveFullLedger(newcoin::FullLedger& packet) { - theApp->getLedgerMaster().gotFullLedger(packet); + theApp->getLedgerMaster().addFullLedger(packet); } void Peer::connectTo(KnownNode& node) diff --git a/TimingService.cpp b/TimingService.cpp index a09f06c358..2f16545671 100644 --- a/TimingService.cpp +++ b/TimingService.cpp @@ -31,7 +31,7 @@ void TimingService::start(boost::asio::io_service& ioService) void TimingService::handleLedger() { cout << "publish ledger" << endl; - theApp->getLedgerMaster().nextLedger(); + theApp->getLedgerMaster().startFinalization(); mLedgerTimer->expires_at(mLedgerTimer->expires_at() + boost::posix_time::seconds(theConfig.LEDGER_SECONDS)); mLedgerTimer->async_wait(boost::bind(&TimingService::handleLedger, this)); @@ -44,3 +44,8 @@ void TimingService::handleProp() theApp->getLedgerMaster().sendProposal(); } +void TimingService::handleValid() +{ + theApp->getLedgerMaster().endFinalization(); +} + diff --git a/TimingService.h b/TimingService.h index b7ae88e3b3..12725cb725 100644 --- a/TimingService.h +++ b/TimingService.h @@ -11,9 +11,11 @@ class TimingService { boost::asio::deadline_timer* mLedgerTimer; boost::asio::deadline_timer* mPropTimer; + boost::asio::deadline_timer* mValidTimer; void handleLedger(); void handleProp(); + void handleValid(); public: TimingService(); void start(boost::asio::io_service& ioService); diff --git a/Transaction.h b/Transaction.h index 332cfb4452..6856bd7989 100644 --- a/Transaction.h +++ b/Transaction.h @@ -17,6 +17,8 @@ public: static bool isSigValid(TransactionPtr trans); static bool isEqual(TransactionPtr t1, TransactionPtr t2); static uint256 calcHash(TransactionPtr trans); + + static uint256 protobufToInternalHash(const std::string& hash); }; diff --git a/ValidationCollection.cpp b/ValidationCollection.cpp index f7ac3f166c..9e60925709 100644 --- a/ValidationCollection.cpp +++ b/ValidationCollection.cpp @@ -1,29 +1,55 @@ #include "ValidationCollection.h" #include "Application.h" +#include "NewcoinAddress.h" +#include +bool ValidationCollection::hasValidation(uint256& ledgerHash,uint160& hanko) +{ + if(mValidations.count(ledgerHash)) + { + BOOST_FOREACH(newcoin::Validation& valid,mValidations[ledgerHash]) + { + if(NewcoinAddress::protobufToInternal(valid.hanko()) == hanko) return(true); + } + } + if(mIgnoredValidations.count(ledgerHash)) + { + BOOST_FOREACH(newcoin::Validation& valid,mIgnoredValidations[ledgerHash]) + { + if(NewcoinAddress::protobufToInternal(valid.hanko()) == hanko) return(true); + } + } + return(false); +} + +// TODO: when do we check if we are with the consensus? void ValidationCollection::addValidation(newcoin::Validation& valid) { - // TODO: - // make sure we don't already have this validation - // check if we care about this hanko - // make sure the validation is valid + // TODO: make sure the validation is valid + uint256 hash=Transaction::protobufToInternalHash(valid.hash()); + uint160 hanko=NewcoinAddress::protobufToInternal(valid.hanko()); + + // make sure we don't already have this validation + if(hasValidation(hash,hanko)) return; + + // check if we care about this hanko if( theApp->getUNL().findHanko(valid.hanko()) ) { - mValidations[valid.hash()].push_back(valid); + mValidations[hash].push_back(valid); }else { - + mIgnoredValidations[hash].push_back(valid); } mMapIndexToValid[valid.ledgerindex()].push_back(valid); } -std::vector* ValidationCollection::getValidations(uint64 ledgerIndex) +std::vector* ValidationCollection::getValidations(uint32 ledgerIndex) { if(mMapIndexToValid.count(ledgerIndex)) { return(&(mMapIndexToValid[ledgerIndex])); } - return(NULL) + return(NULL); } \ No newline at end of file diff --git a/ValidationCollection.h b/ValidationCollection.h index a07f8046b3..9006a52452 100644 --- a/ValidationCollection.h +++ b/ValidationCollection.h @@ -3,19 +3,22 @@ #include "newcoin.pb.h" #include "uint256.h" +#include "types.h" class ValidationCollection { // from ledger hash to the validation std::map > mValidations; std::map > mIgnoredValidations; - std::map > mMapIndexToValid; + std::map > mMapIndexToValid; + + bool hasValidation(uint256& ledgerHash,uint160& hanko); public: ValidationCollection(); void addValidation(newcoin::Validation& valid); - std::vector* getValidations(uint64 ledgerIndex); + std::vector* getValidations(uint32 ledgerIndex); }; #endif \ No newline at end of file diff --git a/Wallet.cpp b/Wallet.cpp index 63dde0354a..3f3f82035f 100644 --- a/Wallet.cpp +++ b/Wallet.cpp @@ -50,9 +50,26 @@ void Wallet::refreshAccounts() } } -void Wallet::transactionAdded(TransactionPtr trans) -{ // TODO: optimize - refreshAccounts(); +void Wallet::transactionChanged(TransactionPtr trans) +{ + + BOOST_FOREACH(Account& account, mYourAccounts) + { + if( account.mAddress == NewcoinAddress::protobufToInternal(trans->from()) || + account.mAddress == NewcoinAddress::protobufToInternal(trans->dest()) ) + { + Ledger::Account* ledgerAccount=theApp->getLedgerMaster().getAccount(account.mAddress); + if(ledgerAccount) + { + account.mAmount= ledgerAccount->first; + account.mSeqNum= ledgerAccount->second; + }else + { + account.mAmount=0; + account.mSeqNum=0; + } + } + } } Wallet::Account* Wallet::consolidateAccountOfSize(int64 amount) @@ -139,10 +156,6 @@ bool Wallet::Account::signTransaction(TransactionPtr trans) } - - - -// Call after CreateTransaction unless you want to abort bool Wallet::commitTransaction(TransactionPtr trans) { if(trans) diff --git a/Wallet.h b/Wallet.h index 444c723d6b..808b77baff 100644 --- a/Wallet.h +++ b/Wallet.h @@ -50,7 +50,7 @@ public: std::string sendMoneyToAddress(uint160& destAddress, int64 amount); // you may need to update your balances - void transactionAdded(TransactionPtr trans); + void transactionChanged(TransactionPtr trans); }; diff --git a/newcoin.proto b/newcoin.proto index 0ffbb7c9ce..b0bf3a2dbe 100644 --- a/newcoin.proto +++ b/newcoin.proto @@ -41,6 +41,7 @@ message Transaction { // Sequence number is incremented if you must change the ledger that you are validating // You will only need to change validation in cases of incompatible ledgers +// hanko is 160 bits. We store the full public key in the UNL message Validation { required uint32 ledgerIndex = 1; required bytes hash = 2;