Example #1
0
bool State::cull(TransactionQueue& _tq) const
{
	bool ret = false;
	auto ts = _tq.transactions();
	for (auto const& i: ts)
	{
		if (!m_transactionSet.count(i.first))
		{
			try
			{
				Transaction t(i.second, CheckSignature::Sender);
				if (t.nonce() <= transactionsFrom(t.sender()))
				{
					_tq.drop(i.first);
					ret = true;
				}
			}
			catch (...)
			{
				_tq.drop(i.first);
				ret = true;
			}
		}
	}
	return ret;
}
Example #2
0
void consolidateTransaction(TransactionQueue& queue, Transaction& singleBatch) {
    while (!queue.empty()) {
        const auto& transaction = queue.front();
        singleBatch.merge(transaction);
        queue.pop();
    };
}
Example #3
0
uint32_t Collection::enqueueFrame() {
    TransactionQueue localTransactionQueue;
    {
        std::unique_lock<std::mutex> lock(_transactionQueueMutex);
        localTransactionQueue.swap(_transactionQueue);
    }

    Transaction consolidatedTransaction;
    consolidatedTransaction.merge(std::move(localTransactionQueue));
    {
        std::unique_lock<std::mutex> lock(_transactionFramesMutex);
        _transactionFrames.push_back(consolidatedTransaction);
    }

    return ++_transactionFrameNumber;
}
Example #4
0
bool State::sync(TransactionQueue& _tq)
{
	// TRANSACTIONS
	bool ret = false;
	auto ts = _tq.transactions();
	vector<pair<h256, bytes>> futures;

	for (int goodTxs = 1; goodTxs;)
	{
		goodTxs = 0;
		for (auto const& i: ts)
		{
			if (!m_transactionSet.count(i.first))
			{
				// don't have it yet! Execute it now.
				try
				{
					execute(i.second);
					ret = true;
					_tq.noteGood(i);
					++goodTxs;
				}
				catch (InvalidNonce const& in)
				{
					if (in.required > in.candidate)
					{
						// too old
						_tq.drop(i.first);
						ret = true;
					}
					else
						_tq.setFuture(i);
				}
				catch (std::exception const&)
				{
					// Something else went wrong - drop it.
					_tq.drop(i.first);
					ret = true;
				}
			}
		}
	}
	return ret;
}
Example #5
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;
}
Example #6
0
TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
{
	// TRANSACTIONS
	TransactionReceipts ret;
	auto ts = _tq.transactions();

	auto lh = getLastHashes(_bc, _bc.number());

	for (int goodTxs = 1; goodTxs;)
	{
		goodTxs = 0;
		for (auto const& i: ts)
			if (!m_transactionSet.count(i.first))
			{
				// don't have it yet! Execute it now.
				try
				{
					uncommitToMine();
//					boost::timer t;
					execute(lh, i.second);
					ret.push_back(m_receipts.back());
					_tq.noteGood(i);
					++goodTxs;
//					cnote << "TX took:" << t.elapsed() * 1000;
				}
				catch (InvalidNonce const& in)
				{
					if (in.required > in.candidate)
					{
						// too old
						_tq.drop(i.first);
						if (o_transactionQueueChanged)
							*o_transactionQueueChanged = true;
					}
					else
						_tq.setFuture(i);
				}
				catch (Exception const& _e)
				{
					// Something else went wrong - drop it.
					_tq.drop(i.first);
					if (o_transactionQueueChanged)
						*o_transactionQueueChanged = true;
					cwarn << "Sync went wrong\n" << diagnostic_information(_e);
				}
				catch (std::exception const&)
				{
					// Something else went wrong - drop it.
					_tq.drop(i.first);
					if (o_transactionQueueChanged)
						*o_transactionQueueChanged = true;
				}
			}
	}
	return ret;
}
nsresult
TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
                                nsIRunnable* aRunnable,
                                bool aFinish,
                                nsIRunnable* aFinishRunnable)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aTransaction, "Null pointer!");
  NS_ASSERTION(aRunnable, "Null pointer!");

  if (aTransaction->mDatabase->IsInvalidated() && !aFinish) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  bool canRun;
  TransactionQueue* existingQueue;
  nsresult rv = TransactionCanRun(aTransaction, &canRun, &existingQueue);
  NS_ENSURE_SUCCESS(rv, rv);

  if (!canRun) {
    QueuedDispatchInfo* info = mDelayedDispatchQueue.AppendElement();
    NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);

    info->transaction = aTransaction;
    info->runnable = aRunnable;
    info->finish = aFinish;
    info->finishRunnable = aFinishRunnable;

    return NS_OK;
  }

  if (existingQueue) {
    existingQueue->Dispatch(aRunnable);
    if (aFinish) {
      existingQueue->Finish(aFinishRunnable);
    }
    return NS_OK;
  }

  nsIAtom* databaseId = aTransaction->mDatabase->Id();

#ifdef DEBUG
  if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
    NS_ASSERTION(!mTransactionsInProgress.Get(databaseId, nsnull),
                 "Shouldn't have anything in progress!");
  }
#endif

  DatabaseTransactionInfo* dbTransactionInfo;
  nsAutoPtr<DatabaseTransactionInfo> autoDBTransactionInfo;

  if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
    // Make a new struct for this transaction.
    autoDBTransactionInfo = new DatabaseTransactionInfo();
    dbTransactionInfo = autoDBTransactionInfo;
  }

  const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;

  nsTArray<nsString>& storesInUse =
    aTransaction->mMode == nsIIDBTransaction::READ_WRITE ?
    dbTransactionInfo->storesWriting :
    dbTransactionInfo->storesReading;

  if (!storesInUse.AppendElements(objectStoreNames)) {
    NS_WARNING("Out of memory!");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  nsTArray<TransactionInfo>& transactionInfoArray =
    dbTransactionInfo->transactions;

  TransactionInfo* transactionInfo = transactionInfoArray.AppendElement();
  NS_ENSURE_TRUE(transactionInfo, NS_ERROR_OUT_OF_MEMORY);

  transactionInfo->transaction = aTransaction;
  transactionInfo->queue = new TransactionQueue(aTransaction, aRunnable);
  if (aFinish) {
    transactionInfo->queue->Finish(aFinishRunnable);
  }

  if (!transactionInfo->objectStoreNames.AppendElements(objectStoreNames)) {
    NS_WARNING("Out of memory!");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  if (autoDBTransactionInfo) {
    if (!mTransactionsInProgress.Put(databaseId, autoDBTransactionInfo)) {
      NS_WARNING("Failed to put!");
      return NS_ERROR_OUT_OF_MEMORY;
    }
    autoDBTransactionInfo.forget();
  }

  return mThreadPool->Dispatch(transactionInfo->queue, NS_DISPATCH_NORMAL);
}
Example #8
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;
}