This commit is contained in:
jed
2011-10-25 16:56:15 -07:00
parent 11a964ffed
commit fed4350ccc
5 changed files with 139 additions and 82 deletions

View File

@@ -6,6 +6,14 @@
#include <boost/foreach.hpp>
using namespace std;
/*
We need to group validations into compatible groups.
We can make one super ledger of all the transactions in each compatible group.
Then we just have to check this ledger to see if a new ledger is compatible
This is also the ledger we hand back when we ask for the consensus ledger
*/
bool ValidationCollection::hasValidation(uint256& ledgerHash,uint160& hanko,uint32 seqnum)
{
@@ -46,6 +54,8 @@ void ValidationCollection::addValidation(newcoin::Validation& valid)
if( theApp->getUNL().findHanko(valid.hanko()) )
{
mValidations[hash].push_back(valid);
mIndexValidations[valid.ledgerindex()].push_back(valid);
addToGroup(valid);
theApp->getLedgerMaster().checkConsensus(valid.ledgerindex());
}else
@@ -55,24 +65,37 @@ void ValidationCollection::addValidation(newcoin::Validation& valid)
}
bool ValidationCollection::Group::addIfCompatible(Ledger::pointer ledger,newcoin::Validation& valid)
{
if(mSuperLedger)
{
if(mSuperLedger->isCompatible(ledger))
{
mValidations.push_back(valid);
mSuperLedger->mergeIn(ledger);
}
}
return(false);
}
// TODO: optimize. We can at least cache what ledgers are compatible
// a validation can be in multiple groups since compatibility isn't transitive
// Sometimes things are just complex
void ValidationCollection::addToGroup(newcoin::Validation& newValid)
{
if(mGroupValidations.count(newValid.ledgerindex()))
if(mIndexGroups.count(newValid.ledgerindex()))
{
bool canReturn=false;
// see if this hash is already on the list. If so add it there.
vector< vector<newcoin::Validation> >& groups=mGroupValidations[newValid.ledgerindex()];
vector<newcoin::Validation>& groupList=vector<newcoin::Validation>();
BOOST_FOREACH(groupList,groups)
vector< Group >& groups=mIndexGroups[newValid.ledgerindex()];
BOOST_FOREACH(Group& group,groups)
{
BOOST_FOREACH(newcoin::Validation& valid,groupList)
BOOST_FOREACH(newcoin::Validation& valid,group.mValidations)
{
if(valid.hash()==newValid.hash())
{
groupList.push_back(newValid);
group.mValidations.push_back(newValid);
canReturn=true;
break;
}
@@ -86,49 +109,47 @@ void ValidationCollection::addToGroup(newcoin::Validation& newValid)
Ledger::pointer newLedger=theApp->getLedgerMaster().getLedger(newHash);
if(newLedger)
{ // see if this ledger is compatible with any groups
BOOST_FOREACH(groupList,groups)
bool foundGroup=false;
BOOST_FOREACH(Group& group,groups)
{
bool compatible=true;
BOOST_FOREACH(newcoin::Validation& valid,groupList)
if(group.addIfCompatible(newLedger,newValid)) foundGroup=true;
}
if(!foundGroup)
{ // this validation didn't fit in any of the other groups
// we need to make a new group for it and see what validations fit it
Group& newGroup=mIndexGroups[newValid.ledgerindex()][groups.size()];
newGroup.mValidations.push_back(newValid);
newGroup.mSuperLedger=Ledger::pointer(new Ledger(newLedger)); // since this super ledger gets modified and we don't want to screw the original
BOOST_FOREACH(newcoin::Validation& valid,mIndexValidations[newValid.ledgerindex()])
{
uint256 hash=Transaction::protobufToInternalHash(valid.hash());
Ledger::pointer ledger=theApp->getLedgerMaster().getLedger(hash);
if(ledger)
{
if(!ledger->isCompatible(newLedger))
{ // not compatible with this group
compatible=false;
break;
}
}else
{ // we can't tell if it is compatible
compatible=false;
break;
}
newGroup.addIfCompatible(ledger,valid);
}
if(compatible) groupList.push_back(newValid);
}
}else
{ // we don't have a ledger for this validation
// add to its own group since we can't check if it is compatible
int newIndex=groups.size();
mIndexGroups[newValid.ledgerindex()][newIndex].mValidations.push_back(newValid);
}
// also add to its own group in case
groupList.push_back(newValid);
groups.push_back(groupList);
}else
{ // this is the first validation of this ledgerindex
mGroupValidations[newValid.ledgerindex()][0].push_back(newValid);
uint256 newHash=Transaction::protobufToInternalHash(newValid.hash());
mIndexGroups[newValid.ledgerindex()][0].mValidations.push_back(newValid);
mIndexGroups[newValid.ledgerindex()][0].mSuperLedger=theApp->getLedgerMaster().getLedger(newHash);
}
}
vector<newcoin::Validation>* ValidationCollection::getValidations(uint32 ledgerIndex)
{
if(mGroupValidations.count(ledgerIndex))
if(mIndexValidations.count(ledgerIndex))
{
return(&(mGroupValidations[ledgerIndex]));
return(&(mIndexValidations[ledgerIndex]));
}
return(NULL);
}
@@ -137,38 +158,36 @@ vector<newcoin::Validation>* ValidationCollection::getValidations(uint32 ledgerI
// look through all the validated hashes at that index
// put the ledgers into compatible groups
// Pick the group with the most votes
bool ValidationCollection::getConsensusLedgers(uint32 ledgerIndex, list<uint256>& retHashs)
bool ValidationCollection::getConsensusLedger(uint32 ledgerIndex, uint256& ourHash, Ledger::pointer& retLedger, uint256& retHash)
{
vector<newcoin::Validation>* valids=getValidations(ledgerIndex);
if(valids)
bool ret=false;
if(mIndexGroups.count(ledgerIndex))
{
vector< pair<int, list<uint256> > > compatibleGroups;
map<uint256, int> voteCounts;
BOOST_FOREACH(newcoin::Validation valid,*valids)
unsigned int maxVotes=theConfig.MIN_VOTES_FOR_CONSENSUS;
vector<newcoin::Validation>& mostValid=vector<newcoin::Validation>();
vector< Group >& groups=mIndexGroups[ledgerIndex];
Group& maxGroup=Group();
BOOST_FOREACH(Group& group,groups)
{
uint256 hash=Transaction::protobufToInternalHash(valid.hash());
Ledger::pointer testLedger=theApp->getLedgerMaster().getLedger(hash);
if(testLedger)
if(group.mValidations.size()>maxVotes)
{
}
voteCounts[ ] += 1;
}
bool ret=false;
int maxVotes=theConfig.MIN_VOTES_FOR_CONSENSUS;
pair<uint256, int>& vote=pair<uint256, int>();
BOOST_FOREACH(vote,voteCounts)
{
if(vote.second>maxVotes)
{
maxVotes=vote.second;
retHash=vote.first;
maxVotes=group.mValidations.size();
retLedger=group.mSuperLedger;
maxGroup=group;
if(!retLedger) retHash=Transaction::protobufToInternalHash(group.mValidations[0].hash());
ret=true;
}
}
return(ret);
if(ret)
{
// should also return false if we are in the consensus
BOOST_FOREACH(newcoin::Validation& valid, maxGroup.mValidations)
{
if(Transaction::protobufToInternalHash(valid.hash()) == ourHash) return(false);
}
}
}
return(false);
return(ret);
}