Ledger consensus work.

This commit is contained in:
JoelKatz
2012-05-22 02:35:47 -07:00
parent 485a8a709d
commit 441a27dffd
7 changed files with 248 additions and 63 deletions

View File

@@ -1,16 +1,169 @@
#include "LedgerConsensus.h"
TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), mHaveRoot(false)
{
mMap = boost::make_shared<SHAMap>();
mMap->setSynching();
}
void TransactionAcquire::done()
{
// insert SHAMap in finished set (as valid or invalid), remove ourselves from current set
// WRITEME
}
boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
{
return boost::shared_polymorphic_downcast<PeerSet, TransactionAcquire>(shared_from_this());
}
void TransactionAcquire::trigger(Peer::pointer peer)
{
if (mComplete || mFailed)
return;
if (!mHaveRoot)
{
boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_itype(newcoin::liTS_CANDIDATE);
*(tmGL->add_nodeids()) = SHAMapNode().getRawString();
sendRequest(tmGL);
}
if (mHaveRoot)
{
std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes;
mMap->getMissingNodes(nodeIDs, nodeHashes, 256);
if (nodeIDs.empty())
{
if (mMap->isValid())
mComplete = true;
else
mFailed = true;
}
else
{
boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_itype(newcoin::liTS_CANDIDATE);
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids()) = it->getRawString();
if (peer)
sendRequest(tmGL, peer);
else
sendRequest(tmGL);
return;
}
}
if (mComplete || mFailed)
done();
else
resetTimer();
}
bool TransactionAcquire::takeNode(const std::list<SHAMapNode>& nodeIDs,
const std::list< std::vector<unsigned char> >& data, Peer::pointer peer)
{
if (mComplete || mFailed)
return true;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
std::list< std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
while (nodeIDit != nodeIDs.end())
{
if (nodeIDit->isRoot())
{
if (!mMap->addRootNode(getHash(), *nodeDatait))
return false;
}
else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait))
return false;
++nodeIDit;
++nodeDatait;
}
trigger(peer);
return true;
}
void LedgerConsensus::abort()
{
}
int LedgerConsensus::startup()
{
return 5;
return 1;
}
int LedgerConsensus::timerEntry()
{
return 5;
}
return 1;
}
SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire)
{
boost::unordered_map<uint256, SHAMap::pointer>::iterator it = mComplete.find(hash);
if (it == mComplete.end())
{ // we have not completed acuiqiring this ledger
if (doAcquire)
{
TransactionAcquire::pointer& acquiring = mAcquiring[hash];
if (!acquiring)
{
acquiring = boost::make_shared<TransactionAcquire>(hash);
startAcquiring(acquiring);
}
}
return SHAMap::pointer();
}
return it->second;
}
void LedgerConsensus::startAcquiring(TransactionAcquire::pointer acquire)
{
boost::unordered_map< uint256, std::vector< boost::weak_ptr<Peer> > >::iterator it =
mPeerData.find(acquire->getHash());
if (it != mPeerData.end())
{ // Add any peers we already know have his transaction set
std::vector< boost::weak_ptr<Peer> >& peerList = it->second;
std::vector< boost::weak_ptr<Peer> >::iterator pit = peerList.begin();
while (pit != peerList.end())
{
Peer::pointer pr = pit->lock();
if (!pr)
pit = peerList.erase(pit);
else
{
acquire->peerHas(pr);
++pit;
}
}
}
}
void LedgerConsensus::removePosition(LedgerProposal& position)
{
// WRITEME
}
void LedgerConsensus::addPosition(LedgerProposal& position)
{
// WRITEME
}
bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition)
{
LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()];
if (!currentPosition)
{
if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq())
return false;
// change in position
removePosition(*currentPosition);
}
currentPosition = newPosition;
addPosition(*currentPosition);
return true;
}

View File

@@ -12,36 +12,32 @@
#include "LedgerProposal.h"
#include "Peer.h"
class LCPosition
{ // A position taken by one of our trusted peers
class TransactionAcquire : public PeerSet, public boost::enable_shared_from_this<TransactionAcquire>
{ // A transaction set we are trying to acquire
public:
typedef boost::shared_ptr<TransactionAcquire> pointer;
protected:
uint256 mPubKeyHash;
CKey::pointer mPubKey;
uint256 mPreviousPosition, mCurrentPosition;
uint32 mSequence;
SHAMap::pointer mMap;
bool mHaveRoot;
void onTimer() { trigger(Peer::pointer()); }
void newPeer(Peer::pointer peer) { trigger(peer); }
void done();
void trigger(Peer::pointer);
boost::weak_ptr<PeerSet> pmDowncast();
public:
typedef boost::shared_ptr<LCPosition> pointer;
// for remote positions
LCPosition(uint32 closingSeq, uint32 proposeSeq, const uint256& previousTxHash,
const uint256& currentTxHash, CKey::pointer nodePubKey, const std::string& signature);
TransactionAcquire(const uint256& hash);
// for our initial position
LCPosition(CKey::pointer privKey, uint32 ledgerSeq, const uint256& currentPosition);
SHAMap::pointer getMap() { return mMap; }
// for our subsequent positions
LCPosition(LCPosition::pointer previousPosition, CKey::pointer privKey, const uint256& newPosition);
const uint256& getPubKeyHash() const { return mPubKeyHash; }
const uint256& getCurrentPosition() const { return mCurrentPosition; }
uint32 getSeq() const { return mSequence; }
bool verifySignature(const uint256& hash, const std::vector<unsigned char>& signature) const;
void setPosition(const uint256& position, uint32 sequence);
bool takeNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data,
Peer::pointer);
};
class LCTransaction
{ // A transaction that may be disputed
protected:
@@ -75,19 +71,24 @@ protected:
Ledger::pointer mPreviousLedger, mCurrentLedger;
LedgerProposal::pointer mCurrentProposal;
LCPosition::pointer mOurPosition;
LedgerProposal::pointer mOurPosition;
// Convergence tracking, trusted peers indexed by hash of public key
boost::unordered_map<uint256, LCPosition::pointer> mPeerPositions;
boost::unordered_map<uint256, LedgerProposal::pointer, hash_SMN> mPeerPositions;
// Transaction Sets, indexed by hash of transaction tree
boost::unordered_map<uint256, SHAMap::pointer> mComplete;
boost::unordered_map<uint256, TransactionAcquire::pointer> mAcquiring;
boost::unordered_map<uint256, SHAMap::pointer, hash_SMN> mComplete;
boost::unordered_map<uint256, TransactionAcquire::pointer, hash_SMN> mAcquiring;
// Peer sets
boost::unordered_map<uint256, std::vector< boost::weak_ptr<Peer> > > mPeerData;
boost::unordered_map<uint256, std::vector< boost::weak_ptr<Peer> >, hash_SMN> mPeerData;
void weHave(const uint256& id, Peer::pointer avoidPeer);
void startAcquiring(TransactionAcquire::pointer);
SHAMap::pointer find(const uint256& hash);
void addPosition(LedgerProposal&);
void removePosition(LedgerProposal&);
public:
LedgerConsensus(Ledger::pointer previousLedger, Ledger::pointer currentLedger) :
@@ -98,21 +99,19 @@ public:
Ledger::pointer peekPreviousLedger() { return mPreviousLedger; }
Ledger::pointer peekCurrentLedger() { return mCurrentLedger; }
LCPosition::pointer getCreatePeerPosition(const uint256& pubKeyHash);
SHAMap::pointer getTransactionTree(const uint256& hash);
SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire);
TransactionAcquire::pointer getAcquiring(const uint256& hash);
void acquireComplete(const uint256& hash);
LCPosition::pointer getPeerPosition(const uint256& peer);
// high-level functions
void abort();
bool peerPosition(Peer::pointer peer, const Serializer& report);
int timerEntry(void);
bool peerPosition(LedgerProposal::pointer);
bool peerHasSet(Peer::pointer peer, const std::vector<uint256>& sets);
bool peerGaveNodes(Peer::pointer peer, const uint256& setHash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
int timerEntry(void);
};

View File

@@ -6,8 +6,8 @@
#include "key.h"
#include "Application.h"
LedgerProposal::LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& proposeTx,
const std::string& pubKey) : mPrevHash(prevTx), mCurrentHash(proposeTx),
LedgerProposal::LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeTx,
const std::string& pubKey) : mCurrentHash(proposeTx),
mProposeSeq(proposeSeq), mKey(boost::make_shared<CKey>())
{
if (!mKey->SetPubKey(pubKey))
@@ -25,20 +25,18 @@ LedgerProposal::LedgerProposal(CKey::pointer mPrivateKey, const uint256& prevLgr
LedgerProposal::LedgerProposal(LedgerProposal::pointer previous, const uint256& newp) :
mPeerID(previous->mPeerID), mPreviousLedger(previous->mPreviousLedger),
mPrevHash(previous->mCurrentHash), mCurrentHash(newp),
mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey)
mCurrentHash(newp), mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey)
{
;
}
uint256 LedgerProposal::getSigningHash() const
{
Serializer s(104);
Serializer s(72);
s.add32(sProposeMagic);
s.add32(mProposeSeq);
s.add256(mPreviousLedger);
s.add256(mCurrentHash);
s.add256(mPrevHash);
return s.getSHA512Half();
}

View File

@@ -13,7 +13,7 @@ class LedgerProposal
{
protected:
uint256 mPeerID, mPreviousLedger, mPrevHash, mCurrentHash;
uint256 mPeerID, mPreviousLedger, mCurrentHash;
uint32 mProposeSeq;
CKey::pointer mKey;
// std::vector<uint256> mAddedTx, mRemovedTx;
@@ -25,8 +25,7 @@ public:
typedef boost::shared_ptr<LedgerProposal> pointer;
// proposal from peer
LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& propose,
const std::string& pubKey);
LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& propose, const std::string& pubKey);
// our first proposal
LedgerProposal(CKey::pointer privateKey, const uint256& prevLedger, const uint256& position);
@@ -38,7 +37,6 @@ public:
bool checkSign(const std::string& signature);
const uint256& getPeerID() const { return mPeerID; }
const uint256& getPrevHash() const { return mPrevHash; }
const uint256& getCurrentHash() const { return mCurrentHash; }
const uint256& getPrevLedger() const { return mPreviousLedger; }
uint32 getProposeSeq() const { return mProposeSeq; }

View File

@@ -386,18 +386,36 @@ int NetworkOPs::beginConsensus(Ledger::pointer closingLedger)
return mConsensus->startup();
}
bool NetworkOPs::proposeLedger(uint32 closingSeq, uint32 proposeSeq,
const uint256& prevHash, const uint256& proposeHash, const std::string& pubKey, const std::string& signature)
bool NetworkOPs::proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeHash,
const std::string& pubKey, const std::string& signature)
{
uint256 nodeID = Serializer::getSHA512Half(pubKey);
if (mMode != omFULL)
return true;
LedgerProposal::pointer proposal =
boost::make_shared<LedgerProposal>(closingSeq, proposeSeq, proposeHash, pubKey);
if (!proposal->checkSign(signature))
{
std::cerr << "Ledger proposal fails signature check" << std::endl;
return false;
}
// Is this node on our UNL?
// WRITEME
// Are we currently closing?
Ledger::pointer currentLedger = theApp->getMasterLedger().getCurrentLedger();
// Yes: Is it an update?
// WRITEME
if (!mConsensus)
{
if ((getNetworkTimeNC() + 2) >= currentLedger->getCloseTimeNC())
setStateTimer(beginConsensus(currentLedger));
if (!mConsensus) return true;
}
return true;
return mConsensus->peerPosition(proposal);
}
SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash)
{ // WRITEME
return SHAMap::pointer();
}

View File

@@ -71,8 +71,9 @@ public:
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
// ledger proposal/close functions
bool proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& prevHash, const uint256& proposeHash,
bool proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeHash,
const std::string& pubKey, const std::string& signature);
SHAMap::pointer getTXMap(const uint256& hash);
// network state machine
void checkState(const boost::system::error_code& result);

View File

@@ -603,16 +603,15 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
void Peer::recvPropose(boost::shared_ptr<newcoin::TMProposeSet> packet)
{
if ((packet->previoustxhash().size() != 32) || (packet->currenttxhash().size() != 32) ||
(packet->nodepubkey().size() < 28) || (packet->signature().size() < 56))
if ((packet->currenttxhash().size() != 32) || (packet->nodepubkey().size() < 28) ||
(packet->signature().size() < 56))
return;
uint32 closingSeq = packet->closingseq(), proposeSeq = packet->proposeseq();
uint256 previousTxHash, currentTxHash;
memcpy(previousTxHash.begin(), packet->previoustxhash().data(), 32);
uint256 currentTxHash;
memcpy(currentTxHash.begin(), packet->currenttxhash().data(), 32);
if(theApp->getOPs().proposeLedger(closingSeq, proposeSeq, previousTxHash, currentTxHash,
if(theApp->getOPs().proposeLedger(closingSeq, proposeSeq, currentTxHash,
packet->nodepubkey(), packet->signature()))
{ // FIXME: Not all nodes will want proposals
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
@@ -693,6 +692,25 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
{
if (packet.itype() == newcoin::liTS_CANDIDATE)
{
Ledger::pointer ledger;
if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32))
{
punishPeer(PP_INVALID_REQUEST);
return;
}
uint256 txHash;
memcpy(txHash.begin(), packet.ledgerhash().data(), 32);
SHAMap::pointer txMap = theApp->getOPs().getTXMap(txHash);
if (!txMap)
{
punishPeer(PP_INVALID_REQUEST);
return;
}
// WRITEME
}
// Figure out what ledger they want
Ledger::pointer ledger;
if (packet.has_ledgerhash())
@@ -703,7 +721,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
punishPeer(PP_INVALID_REQUEST);
return;
}
memcpy(&ledgerhash, packet.ledgerhash().data(), 32);
memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32);
ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash);
}
else if (packet.has_ledgerseq())
@@ -750,7 +768,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
SHAMap::pointer map=(packet.itype()==newcoin::liTX_NODE) ? ledger->peekTransactionMap()
: ledger->peekAccountStateMap();
if(!map) return;
if(packet.nodeids_size()==0)
if(packet.nodeids_size() == 0)
{
punishPeer(PP_INVALID_REQUEST);
return;