mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Network connection state machine. (Partial)
This commit is contained in:
@@ -1,8 +1,13 @@
|
|||||||
|
|
||||||
|
#include "NetworkOPs.h"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "NetworkOPs.h"
|
|
||||||
#include "Transaction.h"
|
#include "Transaction.h"
|
||||||
|
|
||||||
|
|
||||||
// This is the primary interface into the "client" portion of the program.
|
// This is the primary interface into the "client" portion of the program.
|
||||||
// Code that wants to do normal operations on the network such as
|
// Code that wants to do normal operations on the network such as
|
||||||
// creating and monitoring accounts, creating transactions, and so on
|
// creating and monitoring accounts, creating transactions, and so on
|
||||||
@@ -14,6 +19,11 @@
|
|||||||
// code assumes this node is synched (and will continue to do so until
|
// code assumes this node is synched (and will continue to do so until
|
||||||
// there's a functional network.
|
// there's a functional network.
|
||||||
|
|
||||||
|
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service) : mMode(omDISCONNECTED), mNetTimer(io_service)
|
||||||
|
{
|
||||||
|
setStateTimer(5);
|
||||||
|
}
|
||||||
|
|
||||||
uint64 NetworkOPs::getNetworkTime()
|
uint64 NetworkOPs::getNetworkTime()
|
||||||
{
|
{
|
||||||
return time(NULL);
|
return time(NULL);
|
||||||
@@ -26,10 +36,10 @@ uint32 NetworkOPs::getCurrentLedgerID()
|
|||||||
|
|
||||||
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
|
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
|
||||||
{
|
{
|
||||||
Transaction::pointer dbtx=theApp->getMasterTransaction().fetch(trans->getID(), true);
|
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
|
||||||
if(dbtx) return dbtx;
|
if (dbtx) return dbtx;
|
||||||
|
|
||||||
if(!trans->checkSign())
|
if (!trans->checkSign())
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cerr << "Transaction has bad signature" << std::endl;
|
std::cerr << "Transaction has bad signature" << std::endl;
|
||||||
@@ -38,10 +48,10 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
|||||||
return trans;
|
return trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionEngineResult r=theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
|
TransactionEngineResult r = theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
|
||||||
if(r==terFAILED) throw Fault(IO_ERROR);
|
if (r == terFAILED) throw Fault(IO_ERROR);
|
||||||
|
|
||||||
if(r == terPRE_SEQ)
|
if (r == terPRE_SEQ)
|
||||||
{ // transaction should be held
|
{ // transaction should be held
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cerr << "Transaction should be held" << std::endl;
|
std::cerr << "Transaction should be held" << std::endl;
|
||||||
@@ -51,7 +61,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
|||||||
theApp->getMasterLedger().addHeldTransaction(trans);
|
theApp->getMasterLedger().addHeldTransaction(trans);
|
||||||
return trans;
|
return trans;
|
||||||
}
|
}
|
||||||
if ( (r==terPAST_SEQ || r==terPAST_LEDGER) )
|
if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
|
||||||
{ // duplicate or conflict
|
{ // duplicate or conflict
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cerr << "Transaction is obsolete" << std::endl;
|
std::cerr << "Transaction is obsolete" << std::endl;
|
||||||
@@ -60,7 +70,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
|||||||
return trans;
|
return trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r==terSUCCESS)
|
if (r == terSUCCESS)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cerr << "Transaction is now included, synching to wallet" << std::endl;
|
std::cerr << "Transaction is now included, synching to wallet" << std::endl;
|
||||||
@@ -104,20 +114,20 @@ Transaction::pointer NetworkOPs::findTransactionByID(const uint256& transactionI
|
|||||||
int NetworkOPs::findTransactionsBySource(std::list<Transaction::pointer>& txns,
|
int NetworkOPs::findTransactionsBySource(std::list<Transaction::pointer>& txns,
|
||||||
const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
|
const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
|
||||||
{
|
{
|
||||||
AccountState::pointer state=getAccountState(sourceAccount);
|
AccountState::pointer state = getAccountState(sourceAccount);
|
||||||
if(!state) return 0;
|
if (!state) return 0;
|
||||||
if(minSeq>state->getSeq()) return 0;
|
if (minSeq > state->getSeq()) return 0;
|
||||||
if(maxSeq>state->getSeq()) maxSeq=state->getSeq();
|
if (maxSeq > state->getSeq()) maxSeq = state->getSeq();
|
||||||
if(maxSeq>minSeq) return 0;
|
if (maxSeq > minSeq) return 0;
|
||||||
|
|
||||||
int count=0;
|
int count = 0;
|
||||||
for(int i=minSeq; i<=maxSeq; i++)
|
for(int i = minSeq; i <= maxSeq; ++i)
|
||||||
{
|
{
|
||||||
Transaction::pointer txn=Transaction::findFrom(sourceAccount, i);
|
Transaction::pointer txn = Transaction::findFrom(sourceAccount, i);
|
||||||
if(txn)
|
if(txn)
|
||||||
{
|
{
|
||||||
txns.push_back(txn);
|
txns.push_back(txn);
|
||||||
count++;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
@@ -134,3 +144,137 @@ AccountState::pointer NetworkOPs::getAccountState(const NewcoinAddress& accountI
|
|||||||
{
|
{
|
||||||
return theApp->getMasterLedger().getCurrentLedger()->getAccountState(accountID);
|
return theApp->getMasterLedger().getCurrentLedger()->getAccountState(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkOPs::setStateTimer(int seconds)
|
||||||
|
{
|
||||||
|
mNetTimer.expires_from_now(boost::posix_time::seconds(5));
|
||||||
|
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValidationCount
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int trustedValidations, untrustedValidations, nodesUsing;
|
||||||
|
NewcoinAddress highNode;
|
||||||
|
|
||||||
|
ValidationCount() : trustedValidations(0), untrustedValidations(0), nodesUsing(0) { ; }
|
||||||
|
bool operator>(const ValidationCount& v)
|
||||||
|
{
|
||||||
|
if (trustedValidations > v.trustedValidations) return true;
|
||||||
|
if (trustedValidations < v.trustedValidations) return false;
|
||||||
|
if (untrustedValidations > v.untrustedValidations) return true;
|
||||||
|
if (untrustedValidations < v.untrustedValidations) return false;
|
||||||
|
if (nodesUsing > v.nodesUsing) return true;
|
||||||
|
if (nodesUsing < v.nodesUsing) return false;
|
||||||
|
return highNode > v.highNode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void NetworkOPs::checkState()
|
||||||
|
{ // Network state machine
|
||||||
|
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||||
|
|
||||||
|
// do we have sufficient peers? If not, we are disconnected.
|
||||||
|
if (peerList.size() < theConfig.NETWORK_QUORUM)
|
||||||
|
{
|
||||||
|
if (mMode != omDISCONNECTED)
|
||||||
|
{
|
||||||
|
mMode = omDISCONNECTED;
|
||||||
|
std::cerr << "Node count (" << peerList.size() <<
|
||||||
|
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ")." << std::endl;
|
||||||
|
}
|
||||||
|
setStateTimer(5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mMode == omDISCONNECTED)
|
||||||
|
{
|
||||||
|
mMode = omCONNECTED;
|
||||||
|
std::cerr << "Node count (" << peerList.size() << ") is sufficient." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we have sufficient validations for our last closed ledger? Or do sufficient nodes
|
||||||
|
// agree? And do we have no better ledger available?
|
||||||
|
// If so, we are either tracking or full.
|
||||||
|
boost::unordered_map<uint256, ValidationCount, hash_SMN> ledgers;
|
||||||
|
|
||||||
|
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
uint256 peerLedger = (*it)->getClosedLedgerHash();
|
||||||
|
if (!!peerLedger)
|
||||||
|
{
|
||||||
|
ValidationCount& vc = ledgers[peerLedger];
|
||||||
|
if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode))
|
||||||
|
vc.highNode = (*it)->getNodePublic();
|
||||||
|
++vc.nodesUsing;
|
||||||
|
// WRITEME: Validations, trusted peers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ledger::pointer currentClosed = theApp->getMasterLedger().getClosedLedger();
|
||||||
|
uint256 closedLedger = currentClosed->getHash();
|
||||||
|
ValidationCount& vc = ledgers[closedLedger];
|
||||||
|
if ((vc.nodesUsing == 0) || (theApp->getWallet().getNodePublic() > vc.highNode))
|
||||||
|
vc.highNode = theApp->getWallet().getNodePublic();
|
||||||
|
++ledgers[closedLedger].nodesUsing;
|
||||||
|
|
||||||
|
// 3) Is there a network ledger we'd like to switch to? If so, do we have it?
|
||||||
|
bool switchLedgers = false;
|
||||||
|
for(boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
|
||||||
|
it != end; ++it)
|
||||||
|
{
|
||||||
|
if (it->second > vc)
|
||||||
|
{
|
||||||
|
vc = it->second;
|
||||||
|
closedLedger = it->first;
|
||||||
|
switchLedgers = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchLedgers)
|
||||||
|
{
|
||||||
|
std::cerr << "We are not running on the consensus ledger" << std::endl;
|
||||||
|
if ( (mMode == omTRACKING) || (mMode == omFULL) ) mMode = omTRACKING;
|
||||||
|
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(closedLedger);
|
||||||
|
if (!consensus)
|
||||||
|
{
|
||||||
|
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
|
||||||
|
if (!acq || acq->isFailed())
|
||||||
|
{
|
||||||
|
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
|
||||||
|
std::cerr << "Network ledger cannot be acquired" << std::endl;
|
||||||
|
setStateTimer(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!acq->isComplete())
|
||||||
|
{ // add more peers
|
||||||
|
// FIXME: A peer may not have a ledger just because it accepts it as the network's consensus
|
||||||
|
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||||
|
if ((*it)->getClosedLedgerHash() == closedLedger)
|
||||||
|
acq->peerHas(*it);
|
||||||
|
setStateTimer(5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
consensus = acq->getLedger();
|
||||||
|
}
|
||||||
|
// WRITEME switchLedgers(currentClosed, consenus, slNETJUMP);
|
||||||
|
// Function to call Ledger::switchPreviousLedger
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMode == omCONNECTED)
|
||||||
|
{
|
||||||
|
// check if the ledger is good enough to go to omTRACKING
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMode == omTRACKING)
|
||||||
|
{
|
||||||
|
// check if the ledger is good enough to go to omFULL
|
||||||
|
// check if the ledger is bad enough to go to omCONNECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMode == omFULL)
|
||||||
|
{
|
||||||
|
// check if the ledger is bad enough to go to omTRACKING
|
||||||
|
}
|
||||||
|
|
||||||
|
setStateTimer(10);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef __NETWORK_OPS__
|
#ifndef __NETWORK_OPS__
|
||||||
#define __NETWORK_OPS__
|
#define __NETWORK_OPS__
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
#include "Transaction.h"
|
#include "Transaction.h"
|
||||||
#include "AccountState.h"
|
#include "AccountState.h"
|
||||||
|
|
||||||
@@ -31,7 +33,7 @@ protected:
|
|||||||
boost::asio::deadline_timer mNetTimer;
|
boost::asio::deadline_timer mNetTimer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NetworkOPs(boost::asio::io_service& io_service) : mMode(omDISCONNECTED), mNetTimer(io_service) { ; }
|
NetworkOPs(boost::asio::io_service& io_service);
|
||||||
|
|
||||||
// network information
|
// network information
|
||||||
uint64 getNetworkTime();
|
uint64 getNetworkTime();
|
||||||
@@ -55,7 +57,7 @@ public:
|
|||||||
bool findAccountNode(const uint256& nodeHash, std::vector<unsigned char>& rawAccountNode);
|
bool findAccountNode(const uint256& nodeHash, std::vector<unsigned char>& rawAccountNode);
|
||||||
bool findTransactionNode(const uint256& nodeHash, std::vector<unsigned char>& rawTransactionNode);
|
bool findTransactionNode(const uint256& nodeHash, std::vector<unsigned char>& rawTransactionNode);
|
||||||
|
|
||||||
// tree synchronzation operations
|
// tree synchronization operations
|
||||||
bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID,
|
bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID,
|
||||||
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
|
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
|
||||||
bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId,
|
bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId,
|
||||||
@@ -63,6 +65,11 @@ public:
|
|||||||
|
|
||||||
// network state machine
|
// network state machine
|
||||||
void checkState();
|
void checkState();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setStateTimer(int seconds);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user