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. 10
      libethereum/BlockChain.cpp
  4. 74
      libethereum/PeerNetwork.cpp
  5. 4
      libethereum/PeerNetwork.h
  6. 21
      libethereum/State.cpp
  7. 4
      libethereum/State.h

15
TODO

@ -3,10 +3,6 @@
Tests Tests
- Use standard tests. - Use standard tests.
Config file & command line options.
Peer network.
Crypto stuff: Crypto stuff:
- kFromMessage - kFromMessage
- Check all the tweak instructions. - Check all the tweak instructions.
@ -22,16 +18,17 @@ Network:
### GAV ### 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. Trie on DB.
- Modularise overlay and DB.
- Iterate.
- Move the restore point stuff into block restore points - 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. - 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. - maybe allow this to be configured.
Cache some state
- Contract memory, balances - for single commit into Trie.
### TIM ### TIM

54
eth/main.cpp

@ -20,6 +20,7 @@
* Ethereum client. * Ethereum client.
*/ */
#include <fstream>
#include "Client.h" #include "Client.h"
#include "PeerNetwork.h" #include "PeerNetwork.h"
#include "BlockChain.h" #include "BlockChain.h"
@ -27,6 +28,26 @@
using namespace std; using namespace std;
using namespace eth; 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) int main(int argc, char** argv)
{ {
short listenPort = 30303; short listenPort = 30303;
@ -37,7 +58,23 @@ int main(int argc, char** argv)
eth::uint mining = ~(eth::uint)0; eth::uint mining = ~(eth::uint)0;
// Our address. // 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) for (int i = 1; i < argc; ++i)
{ {
@ -49,7 +86,9 @@ int main(int argc, char** argv)
else if (arg == "-p" && i + 1 < argc) else if (arg == "-p" && i + 1 < argc)
remotePort = atoi(argv[++i]); remotePort = atoi(argv[++i]);
else if (arg == "-a" && i + 1 < argc) 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") else if (arg == "-i")
interactive = true; interactive = true;
else if (arg == "-d" && i + 1 < argc) else if (arg == "-d" && i + 1 < argc)
@ -65,7 +104,7 @@ int main(int argc, char** argv)
remoteHost = argv[i]; remoteHost = argv[i];
} }
Client c("Ethereum(++)/v0.1", us, dbPath); Client c("Ethereum(++)/v0.1", coinbase, dbPath);
if (interactive) if (interactive)
{ {
cout << "Ethereum (++)" << endl; cout << "Ethereum (++)" << endl;
@ -113,6 +152,15 @@ int main(int argc, char** argv)
Address dest = h160(fromUserHex(rechex)); Address dest = h160(fromUserHex(rechex));
c.transact(secret, dest, amount, fee); 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 else

10
libethereum/BlockChain.cpp

@ -164,18 +164,19 @@ void BlockChain::import(bytes const& _block, Overlay const& _db)
checkConsistency(); 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... // This might be the new last block...
if (td > m_details[m_lastBlockHash].totalDifficulty) if (td > m_details[m_lastBlockHash].totalDifficulty)
{ {
m_lastBlockHash = newHash; m_lastBlockHash = newHash;
m_detailsDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); 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 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,6 +185,7 @@ void BlockChain::checkConsistency()
m_details.clear(); m_details.clear();
ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions); ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next()) for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().size() == 32)
{ {
h256 h((byte const*)it->key().data()); h256 h((byte const*)it->key().data());
auto dh = details(h); auto dh = details(h);
@ -216,7 +218,7 @@ BlockDetails const& BlockChain::details(h256 _h) const
m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s); m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s);
if (s.empty()) if (s.empty())
{ {
cout << "Not found in DB: " << _h << endl; // cout << "Not found in DB: " << _h << endl;
return NullBlockDetails; return NullBlockDetails;
} }
bool ok; bool ok;

74
libethereum/PeerNetwork.cpp

@ -40,7 +40,6 @@ PeerSession::~PeerSession()
bool PeerSession::interpret(RLP const& _r) bool PeerSession::interpret(RLP const& _r)
{ {
::operator<<(cout, _r) << endl;
switch (_r[0].toInt<unsigned>()) switch (_r[0].toInt<unsigned>())
{ {
case Hello: case Hello:
@ -68,14 +67,14 @@ bool PeerSession::interpret(RLP const& _r)
return false; return false;
case Ping: case Ping:
{ {
cout << std::setw(2) << m_socket.native_handle() << " | Ping" << endl; // cout << std::setw(2) << m_socket.native_handle() << " | Ping" << endl;
RLPStream s; RLPStream s;
sealAndSend(prep(s).appendList(1) << (uint)Pong); sealAndSend(prep(s).appendList(1) << (uint)Pong);
break; break;
} }
case Pong: case Pong:
m_lastPing = std::chrono::steady_clock::now() - m_ping; 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; break;
case GetPeers: case GetPeers:
{ {
@ -102,12 +101,18 @@ bool PeerSession::interpret(RLP const& _r)
case Transactions: case Transactions:
cout << std::setw(2) << m_socket.native_handle() << " | Transactions (" << _r[1].itemCount() << " entries)" << endl; cout << std::setw(2) << m_socket.native_handle() << " | Transactions (" << _r[1].itemCount() << " entries)" << endl;
for (auto i: _r[1]) for (auto i: _r[1])
{
m_server->m_incomingTransactions.push_back(i.data().toBytes()); m_server->m_incomingTransactions.push_back(i.data().toBytes());
m_knownTransactions.insert(sha3(i.data()));
}
break; break;
case Blocks: case Blocks:
cout << std::setw(2) << m_socket.native_handle() << " | Blocks (" << _r[1].itemCount() << " entries)" << endl; cout << std::setw(2) << m_socket.native_handle() << " | Blocks (" << _r[1].itemCount() << " entries)" << endl;
for (auto i: _r[1]) for (auto i: _r[1])
{
m_server->m_incomingBlocks.push_back(i.data().toBytes()); m_server->m_incomingBlocks.push_back(i.data().toBytes());
m_knownBlocks.insert(sha3(i.data()));
}
break; break;
case GetChain: case GetChain:
{ {
@ -204,10 +209,12 @@ void PeerSession::sendDestroy(bytes& _msg)
std::shared_ptr<bytes> buffer = std::make_shared<bytes>(); std::shared_ptr<bytes> buffer = std::make_shared<bytes>();
swap(*buffer, _msg); swap(*buffer, _msg);
assert((*buffer)[0] == 0x22); 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) 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()); std::shared_ptr<bytes> buffer = std::make_shared<bytes>(_msg.toBytes());
assert((*buffer)[0] == 0x22); 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) 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() void PeerSession::start()
{ {
cout << "Starting session." << endl;
RLPStream s; RLPStream s;
prep(s); prep(s);
s.appendList(4) << (uint)Hello << (uint)0 << (uint)0 << m_server->m_clientVersion; 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()); 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) 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); m_incoming.resize(m_incoming.size() + length);
memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length); memcpy(m_incoming.data() + m_incoming.size() - length, m_data.data(), length);
@ -266,7 +275,7 @@ void PeerSession::doRead()
else else
{ {
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4)); 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) if (m_incoming.size() - 8 < len)
break; break;
@ -354,14 +363,38 @@ 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) void PeerServer::process(BlockChain& _bc)
{ {
m_ioService.poll(); m_ioService.poll();
for (auto i = m_peers.begin(); i != m_peers.end();) for (auto i = m_peers.begin(); i != m_peers.end();)
if (auto j = i->lock()) if (auto j = i->lock())
if (j->m_socket.is_open())
++i; ++i;
else else
i = m_peers.erase(i); i = m_peers.erase(i);
else
i = m_peers.erase(i);
} }
void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o) void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
@ -382,12 +415,13 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
m_incomingTransactions.clear(); m_incomingTransactions.clear();
// Send any new transactions. // Send any new transactions.
if (m_peers.size()) for (auto j: m_peers)
if (auto p = j.lock())
{ {
bytes b; bytes b;
uint n = 0; uint n = 0;
for (auto const& i: _tq.transactions()) for (auto const& i: _tq.transactions())
if (!m_transactionsSent.count(i.first)) if (!m_transactionsSent.count(i.first) && !p->m_knownTransactions.count(i.first))
{ {
b += i.second; b += i.second;
++n; ++n;
@ -400,10 +434,9 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
ts.appendList(2) << Transactions; ts.appendList(2) << Transactions;
ts.appendList(n).appendRaw(b).swapOut(b); ts.appendList(n).appendRaw(b).swapOut(b);
PeerSession::seal(b); PeerSession::seal(b);
for (auto j: m_peers)
if (auto p = j.lock())
p->send(&b); p->send(&b);
} }
p->m_knownTransactions.clear();
} }
// Send any new blocks. // Send any new blocks.
@ -420,7 +453,11 @@ void PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
PeerSession::seal(b); PeerSession::seal(b);
for (auto j: m_peers) for (auto j: m_peers)
if (auto p = j.lock()) if (auto p = j.lock())
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b); p->send(&b);
p->m_knownBlocks.clear();
}
} }
m_latestBlockSent = h; 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 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::time_point m_ping;
std::chrono::steady_clock::duration m_lastPing; std::chrono::steady_clock::duration m_lastPing;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
}; };
struct PeerInfo struct PeerInfo
@ -110,6 +113,7 @@ public:
/// Connect to a peer explicitly. /// Connect to a peer explicitly.
bool connect(std::string const& _addr = "127.0.0.1", uint _port = 30303); 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. /// 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. /// Conduct I/O, polling, syncing, whatever.

21
libethereum/State.cpp

@ -223,28 +223,24 @@ void State::sync(TransactionQueue& _tq)
// TRANSACTIONS // TRANSACTIONS
auto ts = _tq.transactions(); auto ts = _tq.transactions();
for (auto const& i: ts) for (auto const& i: ts)
{
if (!m_transactions.count(i.first)) if (!m_transactions.count(i.first))
{
// don't have it yet! Execute it now. // don't have it yet! Execute it now.
try try
{ {
execute(i.second); execute(i.second);
} }
catch (InvalidNonce in) catch (InvalidNonce const& in)
{ {
if (in.required > in.candidate) if (in.required > in.candidate)
// too old // too old
_tq.drop(i.first); _tq.drop(i.first);
} }
catch (...) catch (std::exception const&)
{ {
// Something else went wrong - drop it. // Something else went wrong - drop it.
_tq.drop(i.first); _tq.drop(i.first);
} }
} }
}
}
u256 State::playback(bytesConstRef _block, bool _fullCommit) u256 State::playback(bytesConstRef _block, bool _fullCommit)
{ {
@ -338,7 +334,7 @@ void State::commitToMine(BlockChain const& _bc)
if (m_previousBlock != BlockInfo::genesis()) if (m_previousBlock != BlockInfo::genesis())
{ {
// Find uncles if we're not a direct child of the 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; 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! 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. uncles.appendList(us.size() - 1); // one fewer - uncles precludes our parent from the list of grandparent's children.
@ -489,11 +485,9 @@ 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 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. // Entry point for a user-executed transaction.
try
{
Transaction t(_rlp); Transaction t(_rlp);
executeBare(t, t.sender()); executeBare(t, t.sender());
@ -502,13 +496,6 @@ bool State::execute(bytesConstRef _rlp)
// If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and // 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. // 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)); m_transactions.insert(make_pair(t.sha3(), t));
return true;
}
catch (...)
{
return false;
}
} }
void State::applyRewards(Addresses const& _uncleAddresses) void State::applyRewards(Addresses const& _uncleAddresses)

4
libethereum/State.h

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

Loading…
Cancel
Save