mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Ledger consensus work.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
32
src/Peer.cpp
32
src/Peer.cpp
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user