This commit is contained in:
jed
2011-10-20 16:34:22 -07:00
parent 650ee74391
commit 0416d64fdc
16 changed files with 176 additions and 101 deletions

Binary file not shown.

View File

@@ -17,6 +17,12 @@ Ledger::Ledger(uint32 index)
mIndex=index;
mValidSig=false;
mValidHash=false;
mValidationSeqNum=0;
}
Ledger::Ledger(newcoin::FullLedger& ledger)
{
setTo(ledger);
}
// TODO: we should probably make a shared pointer type for each of these PB types
@@ -25,7 +31,7 @@ newcoin::FullLedger* Ledger::createFullLedger()
// TODO: do we need to hash and create accounts map first?
newcoin::FullLedger* ledger=new newcoin::FullLedger();
ledger->set_index(mIndex);
ledger->set_hash(mHash);
ledger->set_hash(mHash.begin(),mHash.GetSerializeSize());
pair<uint160, pair<uint64,uint32> >& account=pair<uint160, pair<uint64,uint32> >();
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<numAccounts; n++)
{
const newcoin::Account& account=ledger.accounts(n);
mAccounts[ NewcoinAddress::protobufToInternal(account.address()) ] = pair<uint64,uint32>(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:
}

View File

@@ -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<Ledger> 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<TransactionPtr>& 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<uint160, std::pair<int64,uint32> >& getAccounts(){ return(mAccounts); }
Account* getAccount(uint160& address);
newcoin::FullLedger* createFullLedger();
Ledger::pointer getParent();
};

View File

@@ -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]);

View File

@@ -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

View File

@@ -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()<mFinalizingLedger->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())
{

View File

@@ -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);
};

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -1,29 +1,55 @@
#include "ValidationCollection.h"
#include "Application.h"
#include "NewcoinAddress.h"
#include <boost/foreach.hpp>
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<newcoin::Validation>* ValidationCollection::getValidations(uint64 ledgerIndex)
std::vector<newcoin::Validation>* ValidationCollection::getValidations(uint32 ledgerIndex)
{
if(mMapIndexToValid.count(ledgerIndex))
{
return(&(mMapIndexToValid[ledgerIndex]));
}
return(NULL)
return(NULL);
}

View File

@@ -3,19 +3,22 @@
#include "newcoin.pb.h"
#include "uint256.h"
#include "types.h"
class ValidationCollection
{
// from ledger hash to the validation
std::map<uint256, std::vector<newcoin::Validation> > mValidations;
std::map<uint256, std::vector<newcoin::Validation> > mIgnoredValidations;
std::map<uint64, std::vector<newcoin::Validation> > mMapIndexToValid;
std::map<uint32, std::vector<newcoin::Validation> > mMapIndexToValid;
bool hasValidation(uint256& ledgerHash,uint160& hanko);
public:
ValidationCollection();
void addValidation(newcoin::Validation& valid);
std::vector<newcoin::Validation>* getValidations(uint64 ledgerIndex);
std::vector<newcoin::Validation>* getValidations(uint32 ledgerIndex);
};
#endif

View File

@@ -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)

View File

@@ -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);
};

View File

@@ -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;