Browse Source

Fixes & additional functionality in the network stack.

cl-refactor
Gav Wood 11 years ago
parent
commit
0a49ab7dec
  1. 15
      TODO
  2. 54
      eth/main.cpp
  3. 28
      libethereum/BlockChain.cpp
  4. 110
      libethereum/PeerNetwork.cpp
  5. 4
      libethereum/PeerNetwork.h
  6. 37
      libethereum/State.cpp
  7. 4
      libethereum/State.h

15
TODO

@ -3,10 +3,6 @@
Tests
- Use standard tests.
Config file & command line options.
Peer network.
Crypto stuff:
- kFromMessage
- Check all the tweak instructions.
@ -22,16 +18,17 @@ Network:
### GAV
Network:
** Don't crash when a peer leaves!
** Check peer utility (useful transactions & blocks passed) for when dismissing.
** Respect peer count & dismiss/collect/stop listening for peers as necessary.
** Manage GetBlocks properly; should work for when > 256 blocks away.
Trie on DB.
- Modularise overlay and DB.
- Iterate.
- Move the restore point stuff into block restore points
- i.e. keep all nodes from last 127 blocks with counter, at 128, kill but keep every (60*24*7)th or so i.e. one per week as a restore point.
- maybe allow this to be configured.
Cache some state
- Contract memory, balances - for single commit into Trie.
### TIM

54
eth/main.cpp

@ -20,6 +20,7 @@
* Ethereum client.
*/
#include <fstream>
#include "Client.h"
#include "PeerNetwork.h"
#include "BlockChain.h"
@ -27,6 +28,26 @@
using namespace std;
using namespace eth;
bytes contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytes();
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
bytes ret(length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
void writeFile(std::string const& _file, bytes const& _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}
int main(int argc, char** argv)
{
short listenPort = 30303;
@ -37,7 +58,23 @@ int main(int argc, char** argv)
eth::uint mining = ~(eth::uint)0;
// Our address.
Address us; // TODO: load from config file?
KeyPair us = KeyPair::create();
Address coinbase = us.address();
string configFile = string(getenv("HOME")) + "/.ethereum/config.rlp";
bytes b = contents(configFile);
if (b.size())
{
RLP config(b);
us = KeyPair(config[0].toHash<Secret>());
coinbase = config[1].toHash<Address>();
}
else
{
RLPStream config(2);
config << us.secret() << coinbase;
writeFile(configFile, config.out());
}
for (int i = 1; i < argc; ++i)
{
@ -49,7 +86,9 @@ int main(int argc, char** argv)
else if (arg == "-p" && i + 1 < argc)
remotePort = atoi(argv[++i]);
else if (arg == "-a" && i + 1 < argc)
us = h160(fromUserHex(argv[++i]));
coinbase = h160(fromUserHex(argv[++i]));
else if (arg == "-s" && i + 1 < argc)
us = KeyPair(h256(fromUserHex(argv[++i])));
else if (arg == "-i")
interactive = true;
else if (arg == "-d" && i + 1 < argc)
@ -65,7 +104,7 @@ int main(int argc, char** argv)
remoteHost = argv[i];
}
Client c("Ethereum(++)/v0.1", us, dbPath);
Client c("Ethereum(++)/v0.1", coinbase, dbPath);
if (interactive)
{
cout << "Ethereum (++)" << endl;
@ -113,6 +152,15 @@ int main(int argc, char** argv)
Address dest = h160(fromUserHex(rechex));
c.transact(secret, dest, amount, fee);
}
else if (cmd == "send")
{
string rechex;
u256 amount;
u256 fee;
cin >> rechex >> amount >> fee;
Address dest = h160(fromUserHex(rechex));
c.transact(us.secret(), dest, amount, fee);
}
}
}
else

28
libethereum/BlockChain.cpp

@ -164,18 +164,19 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
checkConsistency();
cout << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children." << endl;
// cout << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children." << endl;
// This might be the new last block...
if (td > m_details[m_lastBlockHash].totalDifficulty)
{
m_lastBlockHash = newHash;
m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32));
cout << "Block " << newHash << " is best." << endl;
cout << " Imported and best." << endl;
}
else
{
cerr << "*** WARNING: Imported block not newest (otd=" << m_details[m_lastBlockHash].totalDifficulty << ", td=" << td << ")" << endl;
cout << " Imported." << endl;
// cerr << "*** WARNING: Imported block not newest (otd=" << m_details[m_lastBlockHash].totalDifficulty << ", td=" << td << ")" << endl;
}
}
@ -184,17 +185,18 @@ void BlockChain::checkConsistency()
m_details.clear();
ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
{
h256 h((byte const*)it->key().data());
auto dh = details(h);
auto p = dh.parent;
if (p != h256())
if (it->key().size() == 32)
{
auto dp = details(p);
assert(contains(dp.children, h));
assert(dp.number == dh.number - 1);
h256 h((byte const*)it->key().data());
auto dh = details(h);
auto p = dh.parent;
if (p != h256())
{
auto dp = details(p);
assert(contains(dp.children, h));
assert(dp.number == dh.number - 1);
}
}
}
delete it;
}
@ -216,7 +218,7 @@ BlockDetails const& BlockChain::details(h256 _h) const
m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s);
if (s.empty())
{
cout << "Not found in DB: " << _h << endl;
// cout << "Not found in DB: " << _h << endl;
return NullBlockDetails;
}
bool ok;

110
libethereum/PeerNetwork.cpp

@ -40,7 +40,6 @@ PeerSession::~PeerSession()
bool PeerSession::interpret(RLP const& _r)
{
::operator<<(cout, _r) << endl;
switch (_r[0].toInt<unsigned>())
{
case Hello:
@ -68,14 +67,14 @@ bool PeerSession::interpret(RLP const& _r)
return false;
case Ping:
{
cout << std::setw(2) << m_socket.native_handle() << " | Ping" << endl;
// cout << std::setw(2) << m_socket.native_handle() << " | Ping" << endl;
RLPStream s;
sealAndSend(prep(s).appendList(1) << (uint)Pong);
break;
}
case Pong:
m_lastPing = std::chrono::steady_clock::now() - m_ping;
cout << "Latency: " << chrono::duration_cast<chrono::milliseconds>(m_lastPing).count() << " ms" << endl;
// cout << "Latency: " << chrono::duration_cast<chrono::milliseconds>(m_lastPing).count() << " ms" << endl;
break;
case GetPeers:
{
@ -102,12 +101,18 @@ bool PeerSession::interpret(RLP const& _r)
case Transactions:
cout << std::setw(2) << m_socket.native_handle() << " | Transactions (" << _r[1].itemCount() << " entries)" << endl;
for (auto i: _r[1])
{
m_server->m_incomingTransactions.push_back(i.data().toBytes());
m_knownTransactions.insert(sha3(i.data()));
}
break;
case Blocks:
cout << std::setw(2) << m_socket.native_handle() << " | Blocks (" << _r[1].itemCount() << " entries)" << endl;
for (auto i: _r[1])
{
m_server->m_incomingBlocks.push_back(i.data().toBytes());
m_knownBlocks.insert(sha3(i.data()));
}
break;
case GetChain:
{
@ -204,10 +209,12 @@ void PeerSession::sendDestroy(bytes& _msg)
std::shared_ptr<bytes> buffer = std::make_shared<bytes>();
swap(*buffer, _msg);
assert((*buffer)[0] == 0x22);
cout << "Sending " << RLP(bytesConstRef(buffer.get()).cropped(8)) << endl;
// cout << "Sending " << RLP(bytesConstRef(buffer.get()).cropped(8)) << endl;
ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length)
{
cout << length << " bytes written (EC: " << ec << ")" << endl;
if (ec)
disconnect();
// cout << length << " bytes written (EC: " << ec << ")" << endl;
});
}
@ -215,10 +222,12 @@ void PeerSession::send(bytesConstRef _msg)
{
std::shared_ptr<bytes> buffer = std::make_shared<bytes>(_msg.toBytes());
assert((*buffer)[0] == 0x22);
cout << "Sending " << RLP(bytesConstRef(buffer.get()).cropped(8)) << endl;
// cout << "Sending " << RLP(bytesConstRef(buffer.get()).cropped(8)) << endl;
ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length)
{
cout << length << " bytes written (EC: " << ec << ")" << endl;
if (ec)
disconnect();
// cout << length << " bytes written (EC: " << ec << ")" << endl;
});
}
@ -234,8 +243,6 @@ void PeerSession::disconnect()
void PeerSession::start()
{
cout << "Starting session." << endl;
RLPStream s;
prep(s);
s.appendList(4) << (uint)Hello << (uint)0 << (uint)0 << m_server->m_clientVersion;
@ -251,7 +258,9 @@ void PeerSession::doRead()
auto self(shared_from_this());
m_socket.async_read_some(boost::asio::buffer(m_data), [this, self](boost::system::error_code ec, std::size_t length)
{
if (!ec)
if (ec)
disconnect();
else
{
m_incoming.resize(m_incoming.size() + length);
memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length);
@ -266,7 +275,7 @@ void PeerSession::doRead()
else
{
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4));
cout << "Received packet of " << len << " bytes" << endl;
// cout << "Received packet of " << len << " bytes" << endl;
if (m_incoming.size() - 8 < len)
break;
@ -354,12 +363,36 @@ bool PeerServer::connect(string const& _addr, uint _port)
}
}
bool PeerServer::connect(bi::tcp::endpoint _ep)
{
bi::tcp::resolver resolver(m_ioService);
cout << "Attempting connection to " << _ep << endl;
try
{
bi::tcp::socket s(m_ioService);
boost::asio::connect(s, resolver.resolve(_ep));
auto p = make_shared<PeerSession>(this, std::move(s), m_requiredNetworkId);
m_peers.push_back(p);
cout << "Connected." << endl;
p->start();
return true;
}
catch (exception& _e)
{
cout << "Connection refused (" << _e.what() << ")" << endl;
return false;
}
}
void PeerServer::process(BlockChain& _bc)
{
m_ioService.poll();
for (auto i = m_peers.begin(); i != m_peers.end();)
if (auto j = i->lock())
++i;
if (j->m_socket.is_open())
++i;
else
i = m_peers.erase(i);
else
i = m_peers.erase(i);
}
@ -382,29 +415,29 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
m_incomingTransactions.clear();
// Send any new transactions.
if (m_peers.size())
{
bytes b;
uint n = 0;
for (auto const& i: _tq.transactions())
if (!m_transactionsSent.count(i.first))
for (auto j: m_peers)
if (auto p = j.lock())
{
bytes b;
uint n = 0;
for (auto const& i: _tq.transactions())
if (!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first))
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
}
if (n)
{
b += i.second;
++n;
m_transactionsSent.insert(i.first);
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(2) << Transactions;
ts.appendList(n).appendRaw(b).swapOut(b);
PeerSession::seal(b);
p->send(&b);
}
if (n)
{
RLPStream ts;
PeerSession::prep(ts);
ts.appendList(2) << Transactions;
ts.appendList(n).appendRaw(b).swapOut(b);
PeerSession::seal(b);
for (auto j: m_peers)
if (auto p = j.lock())
p->send(&b);
p->m_knownTransactions.clear();
}
}
// Send any new blocks.
{
@ -420,7 +453,11 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
PeerSession::seal(b);
for (auto j: m_peers)
if (auto p = j.lock())
p->send(&b);
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b);
p->m_knownBlocks.clear();
}
}
m_latestBlockSent = h;
}
@ -448,6 +485,13 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
}
}
}
// Connect to additional peers
while (m_peers.size() < m_idealPeerCount && m_incomingPeers.size())
{
connect(m_incomingPeers.back());
m_incomingPeers.pop_back();
}
}
std::vector<PeerInfo> PeerServer::peers() const

4
libethereum/PeerNetwork.h

@ -89,6 +89,9 @@ private:
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::duration m_lastPing;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
};
struct PeerInfo
@ -110,6 +113,7 @@ public:
/// Connect to a peer explicitly.
bool connect(std::string const& _addr = "127.0.0.1", uint _port = 30303);
bool connect(bi::tcp::endpoint _ep);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
/// Conduct I/O, polling, syncing, whatever.

37
libethereum/State.cpp

@ -223,27 +223,23 @@ void State::sync(TransactionQueue& _tq)
// TRANSACTIONS
auto ts = _tq.transactions();
for (auto const& i: ts)
{
if (!m_transactions.count(i.first))
{
// don't have it yet! Execute it now.
try
{
execute(i.second);
}
catch (InvalidNonce in)
catch (InvalidNonce const& in)
{
if (in.required > in.candidate)
// too old
_tq.drop(i.first);
}
catch (...)
catch (std::exception const&)
{
// Something else went wrong - drop it.
_tq.drop(i.first);
}
}
}
}
u256 State::playback(bytesConstRef _block, bool _fullCommit)
@ -338,7 +334,7 @@ void State::commitToMine(BlockChain const& _bc)
if (m_previousBlock != BlockInfo::genesis())
{
// Find uncles if we're not a direct child of the genesis.
cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl;
// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl;
auto us = _bc.details(m_previousBlock.parentHash).children;
assert(us.size() >= 1); // must be at least 1 child of our grandparent - it's our own parent!
uncles.appendList(us.size() - 1); // one fewer - uncles precludes our parent from the list of grandparent's children.
@ -489,26 +485,17 @@ u256 State::contractMemory(Address _id, u256 _memory) const
return RLP(memdb.at(_memory)).toInt<u256>(); // TODO: CHECK: check if this is actually an RLP decode
}
bool State::execute(bytesConstRef _rlp)
void State::execute(bytesConstRef _rlp)
{
// Entry point for a user-executed transaction.
try
{
Transaction t(_rlp);
executeBare(t, t.sender());
// Add to the user-originated transactions that we've executed.
// NOTE: Here, contract-originated transactions will not get added to the transaction list.
// If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and
// don't forget to allow unsigned transactions in the tx list if they concur with the script execution.
m_transactions.insert(make_pair(t.sha3(), t));
return true;
}
catch (...)
{
return false;
}
Transaction t(_rlp);
executeBare(t, t.sender());
// Add to the user-originated transactions that we've executed.
// NOTE: Here, contract-originated transactions will not get added to the transaction list.
// If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and
// don't forget to allow unsigned transactions in the tx list if they concur with the script execution.
m_transactions.insert(make_pair(t.sha3(), t));
}
void State::applyRewards(Addresses const& _uncleAddresses)

4
libethereum/State.h

@ -97,8 +97,8 @@ public:
void sync(TransactionQueue& _tq);
/// Execute a given transaction.
bool execute(bytes const& _rlp) { return execute(&_rlp); }
bool execute(bytesConstRef _rlp);
void execute(bytes const& _rlp) { return execute(&_rlp); }
void execute(bytesConstRef _rlp);
/// Check if the address is a valid normal (non-contract) account address.
bool isNormalAddress(Address _address) const;

Loading…
Cancel
Save