EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId):
	HostCapability<EthereumPeer>(),
	Worker		("ethsync"),
	m_chain		(_ch),
	m_tq		(_tq),
	m_bq		(_bq),
	m_networkId	(_networkId)
{
	m_latestBlockSent = _ch.currentHash();
}
Esempio n. 2
0
bool PeerServer::ensureInitialised(BlockChain& _bc, TransactionQueue& _tq)
{
	if (m_latestBlockSent == h256())
	{
		// First time - just initialise.
		m_latestBlockSent = _bc.currentHash();
		clog(NetNote) << "Initialising: latest=" << m_latestBlockSent;

		for (auto const& i: _tq.transactions())
			m_transactionsSent.insert(i.first);
		m_lastPeersRequest = chrono::steady_clock::time_point::min();
		return true;
	}
	return false;
}
EthereumCapability::EthereumCapability(shared_ptr<p2p::CapabilityHostFace> _host,
    BlockChain const& _ch, OverlayDB const& _db, TransactionQueue& _tq, BlockQueue& _bq,
    u256 _networkId)
  : m_host(move(_host)),
    m_chain(_ch),
    m_db(_db),
    m_tq(_tq),
    m_bq(_bq),
    m_networkId(_networkId),
    m_hostData(new EthereumHostData(m_chain, m_db))
{
    // TODO: Composition would be better. Left like that to avoid initialization
    //       issues as BlockChainSync accesses other EthereumHost members.
    m_sync.reset(new BlockChainSync(*this));
    m_peerObserver.reset(new EthereumPeerObserver(m_sync, m_tq));
    m_latestBlockSent = _ch.currentHash();
    m_tq.onImport([this](ImportResult _ir, h256 const& _h, h512 const& _nodeId) { onTransactionImported(_ir, _h, _nodeId); });
    std::random_device seed;
    m_urng = std::mt19937_64(seed());
}
Esempio n. 4
0
bool Block::sync(BlockChain const& _bc)
{
	return sync(_bc, _bc.currentHash());
}
void BasicGasPricer::update(BlockChain const &_bc)
{
    unsigned c = 0;
    h256 p = _bc.currentHash();
    m_gasPerBlock = _bc.info(p).gasLimit();

    map<u256, u256> dist;
    u256 total = 0;

    // make gasPrice versus gasUsed distribution for the last 1000 blocks
    while (c < 1000 && p)
    {
        BlockHeader bi = _bc.info(p);
        if (bi.transactionsRoot() != EmptyTrie)
        {
            auto bb = _bc.block(p);
            RLP r(bb);
            BlockReceipts brs(_bc.receipts(bi.hash()));
            size_t i = 0;
            for (auto const &tr: r[1])
            {
                Transaction tx(tr.data(), CheckTransaction::None);
                u256 gu = brs.receipts[i].gasUsed();
                dist[tx.gasPrice()] += gu;
                total += gu;
                i++;
            }
        }
        p = bi.parentHash();
        ++c;
    }

    // fill m_octiles with weighted gasPrices
    if (total > 0)
    {
        m_octiles[0] = dist.begin()->first;

        // calc mean
        u256 mean = 0;
        for (auto const &i: dist)
            mean += i.first * i.second;
        mean /= total;

        // calc standard deviation
        u256 sdSquared = 0;
        for (auto const &i: dist)
            sdSquared += i.second * (i.first - mean) * (i.first - mean);
        sdSquared /= total;

        if (sdSquared)
        {
            long double sd = sqrt(sdSquared.convert_to<long double>());
            long double normalizedSd = sd / mean.convert_to<long double>();

            // calc octiles normalized to gaussian distribution
            boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01);
            for (size_t i = 1; i < 8; i++)
                m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0));
            m_octiles[8] = dist.rbegin()->first;
        } else
        {
            for (size_t i = 0; i < 9; i++)
                m_octiles[i] = (i + 1) * mean / 5;
        }
    }
}
Esempio n. 6
0
bool PeerServer::sync(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
{
	bool ret = ensureInitialised(_bc, _tq);

	if (sync())
		ret = true;

	if (m_mode == NodeMode::Full)
	{
		for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
			if (_tq.import(*it))
			{}//ret = true;		// just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
			else
				m_transactionsSent.insert(sha3(*it));	// if we already had the transaction, then don't bother sending it on.
		m_incomingTransactions.clear();

		auto h = _bc.currentHash();
		bool resendAll = (h != m_latestBlockSent);

		// Send any new transactions.
		for (auto j: m_peers)
			if (auto p = j.second.lock())
			{
				bytes b;
				uint n = 0;
				for (auto const& i: _tq.transactions())
					if ((!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first)) || p->m_requireTransactions || resendAll)
					{
						b += i.second;
						++n;
						m_transactionsSent.insert(i.first);
					}
				if (n)
				{
					RLPStream ts;
					PeerSession::prep(ts);
					ts.appendList(n + 1) << TransactionsPacket;
					ts.appendRaw(b, n).swapOut(b);
					seal(b);
					p->send(&b);
				}
				p->m_knownTransactions.clear();
				p->m_requireTransactions = false;
			}

		// Send any new blocks.
		if (h != m_latestBlockSent)
		{
			// TODO: find where they diverge and send complete new branch.
			RLPStream ts;
			PeerSession::prep(ts);
			ts.appendList(2) << BlocksPacket;
			bytes b;
			ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b);
			seal(b);
			for (auto j: m_peers)
				if (auto p = j.second.lock())
				{
					if (!p->m_knownBlocks.count(_bc.currentHash()))
						p->send(&b);
					p->m_knownBlocks.clear();
				}
		}
		m_latestBlockSent = h;

		for (int accepted = 1, n = 0; accepted; ++n)
		{
			accepted = 0;

			if (m_incomingBlocks.size())
				for (auto it = prev(m_incomingBlocks.end());; --it)
				{
					try
					{
						_bc.import(*it, _o);
						it = m_incomingBlocks.erase(it);
						++accepted;
						ret = true;
					}
					catch (UnknownParent)
					{
						// Don't (yet) know its parent. Leave it for later.
						m_unknownParentBlocks.push_back(*it);
						it = m_incomingBlocks.erase(it);
					}
					catch (...)
					{
						// Some other error - erase it.
						it = m_incomingBlocks.erase(it);
					}

					if (it == m_incomingBlocks.begin())
						break;
				}
			if (!n && accepted)
			{
				for (auto i: m_unknownParentBlocks)
					m_incomingBlocks.push_back(i);
				m_unknownParentBlocks.clear();
			}
		}

		// Connect to additional peers
		while (m_peers.size() < m_idealPeerCount)
		{
			if (m_freePeers.empty())
			{
				if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
				{
					RLPStream s;
					bytes b;
					(PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
					seal(b);
					for (auto const& i: m_peers)
						if (auto p = i.second.lock())
							if (p->isOpen())
								p->send(&b);
					m_lastPeersRequest = chrono::steady_clock::now();
				}


				if (!m_accepting)
					ensureAccepting();

				break;
			}

			auto x = time(0) % m_freePeers.size();
			m_incomingPeers[m_freePeers[x]].second++;
			connect(m_incomingPeers[m_freePeers[x]].first);
			m_freePeers.erase(m_freePeers.begin() + x);
		}
	}

	// platform for consensus of social contract.
	// restricts your freedom but does so fairly. and that's the value proposition.
	// guarantees that everyone else respect the rules of the system. (i.e. obeys laws).

	// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
	for (uint old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
		while (m_peers.size() > m_idealPeerCount)
		{
			// look for worst peer to kick off
			// first work out how many are old enough to kick off.
			shared_ptr<PeerSession> worst;
			unsigned agedPeers = 0;
			for (auto i: m_peers)
				if (auto p = i.second.lock())
					if ((m_mode != NodeMode::PeerServer || p->m_caps != 0x01) && chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old))	// don't throw off new peers; peer-servers should never kick off other peer-servers.
					{
						++agedPeers;
						if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect)))	// kill older ones
							worst = p;
					}
			if (!worst || agedPeers <= m_idealPeerCount)
				break;
			worst->disconnect(TooManyPeers);
		}

	return ret;
}