Browse Source

Peers have IDs to solve duplicate peers issue.

No post-mine state visible in advance.
Additional parts of protocol no longer optional.
Protocol version bump.
Various GUI improvements.
Better (more dynamic) and more correct handling of fee structure.
cl-refactor
Gav Wood 11 years ago
parent
commit
b7ab00a798
  1. 88
      alethzero/Main.ui
  2. 65
      alethzero/MainWin.cpp
  3. 10
      alethzero/MainWin.h
  4. 10
      eth/main.cpp
  5. 30
      libethereum/Client.cpp
  6. 4
      libethereum/Client.h
  7. 47
      libethereum/Common.cpp
  8. 8
      libethereum/Common.h
  9. 122
      libethereum/PeerNetwork.cpp
  10. 26
      libethereum/PeerNetwork.h
  11. 3
      libethereum/RLP.h
  12. 125
      libethereum/State.cpp
  13. 42
      libethereum/State.h
  14. 5
      libethereum/Transaction.cpp
  15. 3
      libethereum/Transaction.h
  16. 1
      test/crypto.cpp
  17. 1
      test/state.cpp

88
alethzero/Main.ui

@ -277,7 +277,7 @@
</property>
<property name="minimumSize">
<size>
<width>349</width>
<width>408</width>
<height>251</height>
</size>
</property>
@ -298,26 +298,6 @@
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="2" colspan="3">
<widget class="QLineEdit" name="destination">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QPushButton" name="send">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item row="2" column="3" colspan="2">
<widget class="QComboBox" name="feeUnits"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label5_2">
<property name="text">
@ -325,6 +305,9 @@
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
@ -338,6 +321,16 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Data</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label5">
<property name="sizePolicy">
@ -351,44 +344,45 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="fee">
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>100</number>
<item row="3" column="0" colspan="5">
<widget class="QPlainTextEdit" name="data"/>
</item>
<item row="4" column="4">
<widget class="QPushButton" name="send">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item row="1" column="3" colspan="2">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label5_3">
<property name="text">
<string>Fee</string>
<item row="0" column="2" colspan="3">
<widget class="QLineEdit" name="destination">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>(Create Contract)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<item row="2" column="2" colspan="3">
<widget class="QLabel" name="fee">
<property name="text">
<string>Data</string>
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="5">
<widget class="QPlainTextEdit" name="data"/>
<item row="4" column="0" colspan="4">
<widget class="QLabel" name="total">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>

65
alethzero/MainWin.cpp

@ -24,8 +24,6 @@ Main::Main(QWidget *parent) :
{
setWindowFlags(Qt::Window);
ui->setupUi(this);
initUnits(ui->valueUnits);
initUnits(ui->feeUnits);
g_logPost = [=](std::string const& s, char const*) { ui->log->addItem(QString::fromStdString(s)); };
m_client = new Client("AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM));
@ -51,6 +49,7 @@ Main::Main(QWidget *parent) :
on_verbosity_sliderMoved();
initUnits(ui->valueUnits);
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->blockChain);
@ -137,9 +136,8 @@ void Main::refresh()
for (pair<h256, bytes> const& i: m_client->transactionQueue().transactions())
{
Transaction t(i.second);
ui->transactionQueue->addItem(QString("%1 (%2 fee) @ %3 <- %4")
ui->transactionQueue->addItem(QString("%1 @ %2 <- %3")
.arg(formatBalance(t.value).c_str())
.arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().asArray()).c_str()) );
}
@ -153,9 +151,8 @@ void Main::refresh()
for (auto const& i: RLP(bc.block(h))[1])
{
Transaction t(i.data());
ui->transactions->addItem(QString("%1 (%2) @ %3 <- %4")
ui->transactions->addItem(QString("%1 @ %2 <- %3")
.arg(formatBalance(t.value).c_str())
.arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().asArray()).c_str()) );
}
@ -189,6 +186,51 @@ void Main::on_accounts_doubleClicked()
qApp->clipboard()->setText(ui->accounts->currentItem()->text().section(" @ ", 1));
}
void Main::on_destination_textChanged()
{
updateFee();
}
void Main::on_data_textChanged()
{
m_data = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"), QString::SkipEmptyParts);
updateFee();
}
u256 Main::fee() const
{
return (ui->destination->text().isEmpty() || !ui->destination->text().toInt()) ? m_client->state().fee(m_data.size()) : m_client->state().fee();
}
u256 Main::value() const
{
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
}
u256 Main::total() const
{
return value() + fee();
}
void Main::updateFee()
{
ui->fee->setText(QString("(fee: %1)").arg(formatBalance(fee()).c_str()));
auto totalReq = total();
ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str()));
bool ok = false;
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
{
ok = true;
break;
}
ui->send->setEnabled(ok);
QPalette p = ui->total->palette();
p.setColor(QPalette::WindowText, QColor(ok ? 0x00 : 0x80, 0x00, 0x00));
ui->total->setPalette(p);
}
void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
@ -233,9 +275,7 @@ void Main::on_mine_triggered()
void Main::on_send_clicked()
{
u256 value = ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
u256 fee = ui->fee->value() * units()[units().size() - 1 - ui->feeUnits->currentIndex()].first;
u256 totalReq = value + fee;
u256 totalReq = value() + fee();
m_client->lock();
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq)
@ -243,12 +283,11 @@ void Main::on_send_clicked()
m_client->unlock();
Secret s = m_myKeys.front().secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString()));
auto ds = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"));
u256s data;
data.reserve(ds.size());
for (QString const& i: ds)
data.reserve(m_data.size());
for (QString const& i: m_data)
data.push_back(u256(i.toStdString()));
m_client->transact(s, r, value, fee, data);
m_client->transact(s, r, value(), data);
refresh();
return;
}

10
alethzero/MainWin.h

@ -32,6 +32,10 @@ private slots:
void on_verbosity_sliderMoved();
void on_ourAccounts_doubleClicked();
void on_accounts_doubleClicked();
void on_destination_textChanged();
void on_data_textChanged();
void on_value_valueChanged() { updateFee(); }
void on_valueUnits_currentIndexChanged() { updateFee(); }
void on_log_doubleClicked();
void on_about_triggered();
void on_quit_triggered() { close(); }
@ -39,9 +43,14 @@ private slots:
void refresh();
private:
void updateFee();
void readSettings();
void writeSettings();
eth::u256 fee() const;
eth::u256 total() const;
eth::u256 value() const;
Ui::Main *ui;
eth::Client* m_client;
@ -50,6 +59,7 @@ private:
QTimer* m_refresh;
QStringList m_servers;
QVector<eth::KeyPair> m_myKeys;
QStringList m_data;
QNetworkAccessManager m_webCtrl;
};

10
eth/main.cpp

@ -207,20 +207,18 @@ int main(int argc, char** argv)
string sechex;
string rechex;
u256 amount;
u256 fee;
cin >> sechex >> rechex >> amount >> fee;
cin >> sechex >> rechex >> amount;
Secret secret = h256(fromUserHex(sechex));
Address dest = h160(fromUserHex(rechex));
c.transact(secret, dest, amount, fee);
c.transact(secret, dest, amount);
}
else if (cmd == "send")
{
string rechex;
u256 amount;
u256 fee;
cin >> rechex >> amount >> fee;
cin >> rechex >> amount;
Address dest = h160(fromUserHex(rechex));
c.transact(us.secret(), dest, amount, fee);
c.transact(us.secret(), dest, amount);
}
else if (cmd == "exit")
{

30
libethereum/Client.cpp

@ -32,7 +32,8 @@ Client::Client(std::string const& _clientVersion, Address _us, std::string const
m_clientVersion(_clientVersion),
m_bc(_dbPath),
m_stateDB(State::openDB(_dbPath)),
m_s(_us, m_stateDB)
m_s(_us, m_stateDB),
m_mined(_us, m_stateDB)
{
Defaults::setDBPath(_dbPath);
@ -95,6 +96,7 @@ void Client::stopNetwork()
void Client::startMining()
{
m_doMine = true;
m_miningStarted = true;
}
void Client::stopMining()
@ -102,14 +104,13 @@ void Client::stopMining()
m_doMine = false;
}
void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data)
void Client::transact(Secret _secret, Address _dest, u256 _amount, u256s _data)
{
m_lock.lock();
Transaction t;
t.nonce = m_s.transactionsFrom(toAddress(_secret));
t.receiveAddress = _dest;
t.value = _amount;
t.fee = _fee;
t.data = _data;
t.sign(_secret);
m_tq.attemptImport(t.rlp());
@ -120,12 +121,14 @@ void Client::transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u2
void Client::work()
{
m_lock.lock();
bool changed = false;
// Process network events.
// Synchronise block chain with network.
// Will broadcast any of our (new) transactions and blocks, and collect & add any of their (new) transactions and blocks.
if (m_net)
if (m_net->process(m_bc, m_tq, m_stateDB))
m_changed = true;
changed = true;
// Synchronise state to block chain.
// This should remove any transactions on our queue that are included within our state.
@ -135,16 +138,23 @@ void Client::work()
// all blocks.
// Resynchronise state with block chain & trans
if (m_s.sync(m_bc))
m_changed = true;
changed = true;
if (m_s.sync(m_tq))
m_changed = true;
changed = true;
m_lock.unlock();
if (m_doMine)
{
if (changed || m_miningStarted)
{
m_mined = m_s;
m_mined.commitToMine(m_bc);
}
m_miningStarted = false;
// Mine for a while.
m_s.commitToMine(m_bc);
MineInfo mineInfo = m_s.mine(100);
MineInfo mineInfo = m_mined.mine(100);
m_mineProgress.best = max(m_mineProgress.best, mineInfo.best);
m_mineProgress.current = mineInfo.best;
m_mineProgress.requirement = mineInfo.requirement;
@ -153,7 +163,7 @@ void Client::work()
{
// Import block.
m_lock.lock();
m_bc.attemptImport(m_s.blockData(), m_stateDB);
m_bc.attemptImport(m_mined.blockData(), m_stateDB);
m_mineProgress.best = 0;
m_lock.unlock();
m_changed = true;
@ -161,6 +171,8 @@ void Client::work()
}
else
this_thread::sleep_for(chrono::milliseconds(100));
m_changed = m_changed || changed;
}
void Client::lock()

4
libethereum/Client.h

@ -62,7 +62,7 @@ public:
~Client();
/// Executes the given transaction.
void transact(Secret _secret, Address _dest, u256 _amount, u256 _fee, u256s _data = u256s());
void transact(Secret _secret, Address _dest, u256 _amount, u256s _data = u256s());
/// Requires transactions involving this address be queued for inspection.
void setInterest(Address _dest);
@ -131,6 +131,7 @@ private:
TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain.
Overlay m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
State m_s; ///< The present state of the client.
State m_mined; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
PeerServer* m_net = nullptr; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
#if defined(__APPLE__)
@ -143,6 +144,7 @@ private:
enum { Active = 0, Deleting, Deleted } m_workState = Active;
bool m_doMine = false; ///< Are we supposed to be mining?
MineProgress m_mineProgress;
mutable bool m_miningStarted = false;
mutable bool m_changed;
};

47
libethereum/Common.cpp

@ -190,13 +190,50 @@ Address eth::toAddress(Secret _private)
KeyPair KeyPair::create()
{
secp256k1_start();
static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<byte> d(0, 255);
KeyPair ret;
for (uint i = 0; i < 32; ++i)
ret.m_secret[i] = d(s_eng);
ret.m_address = toAddress(ret.m_secret);
return ret;
for (int i = 0; i < 100; ++i)
{
h256 sec;
for (uint i = 0; i < 32; ++i)
sec[i] = d(s_eng);
KeyPair ret(sec);
if (ret.address())
return ret;
}
return KeyPair();
}
KeyPair::KeyPair(h256 _sec):
m_secret(_sec)
{
int ok = secp256k1_ecdsa_seckey_verify(m_secret.data());
if (!ok)
return;
byte pubkey[65];
int pubkeylen = 65;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0);
if (!ok || pubkeylen != 65)
return;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65);
if (!ok)
return;
m_secret = m_secret;
memcpy(m_public.data(), &(pubkey[1]), 64);
m_address = right160(eth::sha3(bytesConstRef(&(pubkey[1]), 64)));
#if ETH_ADDRESS_DEBUG
cout << "---- ADDRESS -------------------------------" << endl;
cout << "SEC: " << m_secret << endl;
cout << "PUB: " << m_public << endl;
cout << "ADR: " << m_address << endl;
#endif
}
static const vector<pair<u256, string>> g_units =

8
libethereum/Common.h

@ -127,6 +127,7 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
return _out;
}
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h256s = std::vector<h256>;
@ -135,6 +136,7 @@ using h256Set = std::set<h256>;
using h160Set = std::set<h160>;
using Secret = h256;
using Public = h512;
using Address = h160;
using Addresses = h160s;
@ -434,15 +436,19 @@ class KeyPair
{
public:
KeyPair() {}
KeyPair(Secret _k): m_secret(_k), m_address(toAddress(_k)) {}
KeyPair(Secret _k);
static KeyPair create();
Secret const& secret() const { return m_secret; }
Secret const& sec() const { return m_secret; }
Public const& pub() const { return m_public; }
Address const& address() const { return m_address; }
private:
Secret m_secret;
Public m_public;
Address m_address;
};

122
libethereum/PeerNetwork.cpp

@ -95,21 +95,29 @@ bool PeerSession::interpret(RLP const& _r)
m_protocolVersion = _r[1].toInt<uint>();
m_networkId = _r[2].toInt<uint>();
auto clientVersion = _r[3].toString();
m_caps = _r.itemCount() > 4 ? _r[4].toInt<uint>() : 0x07;
m_listenPort = _r.itemCount() > 5 ? _r[5].toInt<short>() : 0;
m_caps = _r[4].toInt<uint>();
m_listenPort = _r[5].toInt<short>();
m_id = _r[6].toHash<h512>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << showbase << hex << m_caps << dec << m_listenPort;
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << asHex(m_id.ref().cropped(0, 4)) << showbase << hex << m_caps << dec << m_listenPort;
if (m_protocolVersion != 1 || m_networkId != m_reqNetworkId)
if (m_server->m_peers.count(m_id) || !m_id)
{
disconnect();
// Already connected.
disconnect(DuplicatePeer);
}
m_server->m_peers[m_id] = shared_from_this();
if (m_protocolVersion != 2 || m_networkId != m_reqNetworkId)
{
disconnect(IncompatibleProtocol);
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), (short)m_socket.remote_endpoint().port(), std::chrono::steady_clock::duration()}); }
catch (...)
{
disconnect();
disconnect(BadProtocol);
return false;
}
@ -132,13 +140,30 @@ bool PeerSession::interpret(RLP const& _r)
break;
}
case DisconnectPacket:
clogS(NetMessageSummary) << "Disconnect";
{
string reason = "Unspecified";
if (_r.itemCount() > 1 && _r[1].isInt())
switch (_r[1].toInt<int>())
{
case DisconnectRequested: reason = "Disconnect was requested."; break;
case TCPError: reason = "Low-level TCP communication error."; break;
case BadProtocol: reason = "Data format error."; break;
case UselessPeer: reason = "We had no use to peer."; break;
case TooManyPeers: reason = "Peer had too many connections."; break;
case DuplicatePeer: reason = "Peer was already connected."; break;
case WrongGenesis: reason = "Disagreement over genesis block."; break;
case IncompatibleProtocol: reason = "Peer protocol versions are incompatible."; break;
case ClientQuit: reason = "Peer is exiting."; break;
}
clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")";
if (m_socket.is_open())
clogS(NetNote) << "Closing " << m_socket.remote_endpoint();
else
clogS(NetNote) << "Remote closed.";
m_socket.close();
return false;
}
case PingPacket:
{
// clogS(NetMessageSummary) << "Ping";
@ -153,14 +178,14 @@ bool PeerSession::interpret(RLP const& _r)
case GetPeersPacket:
{
clogS(NetMessageSummary) << "GetPeers";
std::vector<bi::tcp::endpoint> peers = m_server->potentialPeers();
auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
for (auto i: peers)
{
clogS(NetMessageDetail) << "Sending peer " << i;
s.appendList(2) << i.address().to_v4().to_bytes() << i.port();
clogS(NetMessageDetail) << "Sending peer " << asHex(i.first.ref().cropped(0, 4)) << i.second;
s.appendList(3) << i.second.address().to_v4().to_bytes() << i.second.port() << i.first;
}
sealAndSend(s);
break;
@ -170,7 +195,16 @@ bool PeerSession::interpret(RLP const& _r)
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto ep = bi::tcp::endpoint(bi::address_v4(_r[i][0].toArray<byte, 4>()), _r[i][1].toInt<short>());
clogS(NetAllDetail) << "Checking: " << ep;
Public id;
if (_r[i].itemCount() > 2)
id = _r[i][2].toHash<Public>();
clogS(NetAllDetail) << "Checking: " << ep << "(" << asHex(id.ref().cropped(0, 4)) << ")";
// check that it's not us or one we already know:
if (id && (m_server->m_key.pub() == id || m_server->m_peers.count(id) || m_server->m_incomingPeers.count(id)))
goto CONTINUE;
// check that we're not already connected to addr:
if (!ep.port())
goto CONTINUE;
@ -178,16 +212,16 @@ bool PeerSession::interpret(RLP const& _r)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
for (auto i: m_server->m_peers)
if (shared_ptr<PeerSession> p = i.lock())
if (shared_ptr<PeerSession> p = i.second.lock())
{
clogS(NetAllDetail) << " ...against " << p->endpoint();
if (p->m_socket.is_open() && p->endpoint() == ep)
goto CONTINUE;
}
for (auto i: m_server->m_incomingPeers)
if (i == ep)
if (i.second == ep)
goto CONTINUE;
m_server->m_incomingPeers.push_back(ep);
m_server->m_incomingPeers.insert(make_pair(id, ep));
clogS(NetMessageDetail) << "New peer: " << ep;
CONTINUE:;
}
@ -314,7 +348,7 @@ bool PeerSession::interpret(RLP const& _r)
if (noGood == m_server->m_chain->genesisHash())
{
clogS(NetWarn) << "Discordance over genesis block! Disconnect.";
disconnect();
disconnect(WrongGenesis);
}
else
{
@ -366,7 +400,6 @@ void PeerServer::seal(bytes& _b)
_b[5] = (len >> 16) & 0xff;
_b[6] = (len >> 8) & 0xff;
_b[7] = len & 0xff;
cerr << "Sealed " << _b.size() << ": " << asHex(_b) << endl;
}
void PeerSession::sealAndSend(RLPStream& _s)
@ -412,14 +445,14 @@ void PeerSession::dropped()
}catch (...){}
m_socket.close();
for (auto i = m_server->m_peers.begin(); i != m_server->m_peers.end(); ++i)
if (i->lock().get() == this)
if (i->second.lock().get() == this)
{
m_server->m_peers.erase(i);
break;
}
}
void PeerSession::disconnect()
void PeerSession::disconnect(int _reason)
{
if (m_socket.is_open())
{
@ -427,7 +460,7 @@ void PeerSession::disconnect()
{
RLPStream s;
prep(s);
s.appendList(1) << DisconnectPacket;
s.appendList(1) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
@ -448,9 +481,7 @@ void PeerSession::start()
{
RLPStream s;
prep(s);
s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)1 << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0);
if (m_server->m_public.port())
s << m_server->m_public.port();
s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)1 << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
@ -518,31 +549,34 @@ PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch,
m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_requiredNetworkId(_networkId)
{
populateAddresses();
determinePublic(_publicAddress, _upnp);
ensureAccepting();
clog(NetNote) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
clog(NetNote) << "Id:" << asHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (_m == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId):
PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m):
m_clientVersion(_clientVersion),
m_mode(_m),
m_listenPort(-1),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService),
m_key(KeyPair::create()),
m_requiredNetworkId(_networkId)
{
// populate addresses.
populateAddresses();
clog(NetNote) << "Genesis: " << m_chain->genesisHash();
clog(NetNote) << "Id:" << asHex(m_key.address().ref().cropped(0, 4)) << "Mode: " << (m_mode == NodeMode::PeerServer ? "PeerServer" : "Full");
}
PeerServer::~PeerServer()
{
for (auto const& i: m_peers)
if (auto p = i.lock())
p->disconnect();
if (auto p = i.second.lock())
p->disconnect(ClientQuit);
delete m_upnp;
}
@ -656,17 +690,17 @@ void PeerServer::populateAddresses()
#endif
}
std::vector<bi::tcp::endpoint> PeerServer::potentialPeers()
std::map<Public, bi::tcp::endpoint> PeerServer::potentialPeers()
{
std::vector<bi::tcp::endpoint> ret;
std::map<Public, bi::tcp::endpoint> ret;
if (!m_public.address().is_unspecified())
ret.push_back(m_public);
ret.insert(make_pair(m_key.pub(), m_public));
for (auto i: m_peers)
if (auto j = i.lock())
if (auto j = i.second.lock())
{
auto ep = j->endpoint();
if (ep.port())
ret.push_back(ep);
if (ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
}
return ret;
}
@ -686,7 +720,6 @@ void PeerServer::ensureAccepting()
clog(NetNote) << "Accepted connection from " << m_socket.remote_endpoint();
} catch (...){}
auto p = std::make_shared<PeerSession>(this, std::move(m_socket), m_requiredNetworkId);
m_peers.push_back(p);
p->start();
}
catch (std::exception const& _e)
@ -714,7 +747,6 @@ void PeerServer::connect(bi::tcp::endpoint const& _ep)
else
{
auto p = make_shared<PeerSession>(this, std::move(*s), m_requiredNetworkId);
m_peers.push_back(p);
clog(NetNote) << "Connected to " << p->endpoint();
p->start();
}
@ -735,7 +767,7 @@ bool PeerServer::process(BlockChain& _bc)
if (fullProcess)
for (auto i = m_peers.begin(); i != m_peers.end();)
{
auto p = i->lock();
auto p = i->second.lock();
if (p && p->m_socket.is_open() &&
(p->m_disconnect == chrono::steady_clock::time_point::max() || chrono::steady_clock::now() - p->m_disconnect < chrono::seconds(1))) // kill old peers that should be disconnected.
++i;
@ -784,7 +816,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
if (fullProcess)
{
for (auto j: m_peers)
if (auto p = j.lock())
if (auto p = j.second.lock())
{
bytes b;
uint n = 0;
@ -820,7 +852,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
ts.appendRaw(_bc.block(_bc.currentHash())).swapOut(b);
seal(b);
for (auto j: m_peers)
if (auto p = j.lock())
if (auto p = j.second.lock())
{
if (!p->m_knownBlocks.count(_bc.currentHash()))
p->send(&b);
@ -869,7 +901,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
(PeerSession::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.lock())
if (auto p = i.second.lock())
if (p->isOpen())
p->send(&b);
m_lastPeersRequest = chrono::steady_clock::now();
@ -881,8 +913,8 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
break;
}
connect(m_incomingPeers.back());
m_incomingPeers.pop_back();
connect(m_incomingPeers.begin()->second);
m_incomingPeers.erase(m_incomingPeers.begin());
}
}
}
@ -902,7 +934,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
shared_ptr<PeerSession> worst;
unsigned agedPeers = 0;
for (auto i: m_peers)
if (auto p = i.lock())
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;
@ -911,7 +943,7 @@ bool PeerServer::process(BlockChain& _bc, TransactionQueue& _tq, Overlay& _o)
}
if (!worst || agedPeers <= m_idealPeerCount)
break;
worst->disconnect();
worst->disconnect(TooManyPeers);
}
}
@ -924,7 +956,7 @@ std::vector<PeerInfo> PeerServer::peers() const
this_thread::sleep_for(chrono::milliseconds(200));
std::vector<PeerInfo> ret;
for (auto& i: m_peers)
if (auto j = i.lock())
if (auto j = i.second.lock())
if (j->m_socket.is_open())
ret.push_back(j->m_info);
return ret;
@ -933,6 +965,6 @@ std::vector<PeerInfo> PeerServer::peers() const
void PeerServer::pingAll()
{
for (auto& i: m_peers)
if (auto j = i.lock())
if (auto j = i.second.lock())
j->ping();
}

26
libethereum/PeerNetwork.h

@ -21,6 +21,7 @@
#pragma once
#include <map>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
@ -60,6 +61,19 @@ enum PacketType
GetTransactionsPacket
};
enum DisconnectReason
{
DisconnectRequested = 0,
TCPError,
BadProtocol,
UselessPeer,
TooManyPeers,
DuplicatePeer,
WrongGenesis,
IncompatibleProtocol,
ClientQuit
};
class PeerServer;
struct PeerInfo
@ -79,7 +93,7 @@ public:
~PeerSession();
void start();
void disconnect();
void disconnect(int _reason);
void ping();
@ -102,6 +116,7 @@ private:
bi::tcp::socket m_socket;
std::array<byte, 65536> m_data;
PeerInfo m_info;
Public m_id;
bytes m_incoming;
uint m_protocolVersion;
@ -137,7 +152,7 @@ public:
/// Start server, listening for connections on the given port.
PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, short _port, NodeMode _m = NodeMode::Full, std::string const& _publicAddress = std::string(), bool _upnp = true);
/// Start server, but don't listen.
PeerServer(std::string const& _clientVersion, uint _networkId);
PeerServer(std::string const& _clientVersion, uint _networkId, NodeMode _m = NodeMode::Full);
~PeerServer();
/// Connect to a peer explicitly.
@ -172,7 +187,7 @@ private:
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting();
std::vector<bi::tcp::endpoint> potentialPeers();
std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full;
@ -186,13 +201,14 @@ private:
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
KeyPair m_key;
uint m_requiredNetworkId;
std::vector<std::weak_ptr<PeerSession>> m_peers;
std::map<Public, std::weak_ptr<PeerSession>> m_peers;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
std::vector<bi::tcp::endpoint> m_incomingPeers;
std::multimap<Public, bi::tcp::endpoint> m_incomingPeers;
h256 m_latestBlockSent;
std::set<h256> m_transactionsSent;

3
libethereum/RLP.h

@ -278,8 +278,7 @@ public:
RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); }
RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); }
RLPStream& append(char const* _s) { return append(std::string(_s)); }
RLPStream& append(h160 _s, bool _compact = false) { return append(_s.ref(), _compact); }
RLPStream& append(h256 _s, bool _compact = false) { return append(_s.ref(), _compact); }
template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false) { return append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item.
RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }

125
libethereum/State.cpp

@ -46,20 +46,15 @@
using namespace std;
using namespace eth;
u256 const State::c_stepFee = 10000;
u256 const State::c_dataFee = 20000;
u256 const State::c_memoryFee = 30000;
u256 const State::c_extroFee = 40000;
u256 const State::c_cryptoFee = 50000;
u256 const State::c_newContractFee = 60000;
u256 const State::c_txFee = 0;
u256 const State::c_blockReward = 1000000000000;
#if NDEBUG
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#else
u256 const c_stepFee = 1;
u256 const c_dataFee = 20;
u256 const c_memoryFee = 5;
u256 const c_extroFee = 40;
u256 const c_cryptoFee = 20;
u256 const c_newContractFee = 100;
u256 const c_txFee = 100;
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#endif
std::map<Address, AddressState> const& eth::genesisState()
{
@ -90,8 +85,14 @@ Overlay State::openDB(std::string _path, bool _killExisting)
return Overlay(db);
}
State::State(Address _coinbaseAddress, Overlay const& _db): m_db(_db), m_state(&m_db), m_ourAddress(_coinbaseAddress)
State::State(Address _coinbaseAddress, Overlay const& _db):
m_db(_db),
m_state(&m_db),
m_ourAddress(_coinbaseAddress)
{
m_blockReward = u256(15000000000) * 100000000;
m_fees.setMultiplier(u256(100000) * 1000000000);
secp256k1_start();
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
@ -106,6 +107,46 @@ State::State(Address _coinbaseAddress, Overlay const& _db): m_db(_db), m_state(&
assert(m_state.root() == m_previousBlock.stateRoot);
}
State::State(State const& _s):
m_db(_s.m_db),
m_state(&m_db, _s.m_state.root()),
m_transactions(_s.m_transactions),
m_cache(_s.m_cache),
m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock),
m_currentNumber(_s.m_currentNumber),
m_ourAddress(_s.m_ourAddress),
m_fees(_s.m_fees),
m_blockReward(_s.m_blockReward)
{
}
State& State::operator=(State const& _s)
{
m_db = _s.m_db;
m_state.open(&m_db, _s.m_state.root());
m_transactions = _s.m_transactions;
m_cache = _s.m_cache;
m_previousBlock = _s.m_previousBlock;
m_currentBlock = _s.m_currentBlock;
m_currentNumber = _s.m_currentNumber;
m_ourAddress = _s.m_ourAddress;
m_fees = _s.m_fees;
m_blockReward = _s.m_blockReward;
return *this;
}
void FeeStructure::setMultiplier(u256 _x)
{
m_stepFee = c_stepFee * _x;
m_dataFee = c_dataFee * _x;
m_memoryFee = c_memoryFee * _x;
m_extroFee = c_extroFee * _x;
m_cryptoFee = c_cryptoFee * _x;
m_newContractFee = c_newContractFee * _x;
m_txFee = c_txFee * _x;
}
void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{
auto it = m_cache.find(_a);
@ -525,11 +566,11 @@ void State::execute(bytesConstRef _rlp)
void State::applyRewards(Addresses const& _uncleAddresses)
{
u256 r = c_blockReward;
u256 r = m_blockReward;
for (auto const& i: _uncleAddresses)
{
addBalance(i, c_blockReward * 4 / 3);
r += c_blockReward / 8;
addBalance(i, m_blockReward * 4 / 3);
r += m_blockReward / 8;
}
addBalance(m_currentBlock.coinbaseAddress, r);
}
@ -544,31 +585,32 @@ void State::executeBare(Transaction const& _t, Address _sender)
throw InvalidNonce(nonceReq, _t.nonce);
// Not considered invalid - just pointless.
if (balance(_sender) < _t.value + _t.fee)
u256 fee = _t.receiveAddress ? m_fees.m_txFee : (_t.data.size() * m_fees.m_memoryFee + m_fees.m_newContractFee);
if (balance(_sender) < _t.value + fee)
throw NotEnoughCash();
// TODO: check fee is sufficient?
// Increment associated nonce for sender.
noteSending(_sender);
if (_t.receiveAddress)
{
subBalance(_sender, _t.value + _t.fee);
subBalance(_sender, _t.value + fee);
addBalance(_t.receiveAddress, _t.value);
addBalance(m_currentBlock.coinbaseAddress, _t.fee);
if (isContractAddress(_t.receiveAddress))
{
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction.
execute(_t.receiveAddress, _sender, _t.value, _t.fee, _t.data, &feeAdder.fee);
execute(_t.receiveAddress, _sender, _t.value, _t.data, &feeAdder.fee);
}
}
else
{
// Try to make a new contract
if (_t.fee < _t.data.size() * c_memoryFee + c_newContractFee)
throw FeeTooSmall();
#if ETH_SENDER_PAYS_SETUP
if (balance(_sender) < _t.value + fee)
#else
if (_t.value < fee)
#endif
throw NotEnoughCash();
Address newAddress = low160(_t.sha3());
@ -584,9 +626,13 @@ void State::executeBare(Transaction const& _t, Address _sender)
else
mem.at(i) = _t.data[i];
subBalance(_sender, _t.value + _t.fee);
#if ETH_SENDER_PAYS_SETUP
subBalance(_sender, _t.value + fee);
addBalance(newAddress, _t.value);
addBalance(m_currentBlock.coinbaseAddress, _t.fee);
#else
subBalance(_sender, _t.value);
addBalance(newAddress, _t.value - fee);
#endif
}
}
@ -598,7 +644,7 @@ inline Address asAddress(u256 _item)
return left160(h256(_item));
}
void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* _totalFee)
void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* _totalFee)
{
std::vector<u256> stack;
@ -637,7 +683,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
{
stepCount++;
bigint minerFee = stepCount > 16 ? c_stepFee : 0;
bigint minerFee = stepCount > 16 ? m_fees.m_stepFee : 0;
bigint voidFee = 0;
auto rawInst = mem(curPC);
@ -650,21 +696,21 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::STORE:
require(2);
if (!mem(stack.back()) && stack[stack.size() - 2])
voidFee += c_memoryFee;
voidFee += m_fees.m_memoryFee;
if (mem(stack.back()) && !stack[stack.size() - 2])
voidFee -= c_memoryFee;
voidFee -= m_fees.m_memoryFee;
// continue on to...
case Instruction::LOAD:
minerFee += c_dataFee;
minerFee += m_fees.m_dataFee;
break;
case Instruction::EXTRO:
case Instruction::BALANCE:
minerFee += c_extroFee;
minerFee += m_fees.m_extroFee;
break;
case Instruction::MKTX:
minerFee += c_txFee;
minerFee += m_fees.m_txFee;
break;
case Instruction::SHA256:
@ -674,7 +720,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::ECSIGN:
case Instruction::ECRECOVER:
case Instruction::ECVALID:
minerFee += c_cryptoFee;
minerFee += m_fees.m_cryptoFee;
break;
default:
break;
@ -779,9 +825,6 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::TXVALUE:
stack.push_back(_txValue);
break;
case Instruction::TXFEE:
stack.push_back(_txFee);
break;
case Instruction::TXDATAN:
stack.push_back(_txData.size());
break;
@ -1069,8 +1112,6 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
stack.pop_back();
t.value = stack.back();
stack.pop_back();
t.fee = stack.back();
stack.pop_back();
auto itemCount = stack.back();
stack.pop_back();
@ -1092,7 +1133,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
{
require(1);
Address dest = asAddress(stack.back());
u256 minusVoidFee = myMemory.size() * c_memoryFee;
u256 minusVoidFee = myMemory.size() * m_fees.m_memoryFee;
addBalance(dest, balance(_myAddress) + minusVoidFee);
m_cache[_myAddress].kill();
// ...follow through to...

42
libethereum/State.h

@ -42,6 +42,21 @@ class BlockChain;
extern const u256 c_genesisDifficulty;
std::map<Address, AddressState> const& genesisState();
#define ETH_SENDER_PAYS_SETUP 1
struct FeeStructure
{
/// The fee structure. Values yet to be agreed on...
void setMultiplier(u256 _x); ///< The current block multiplier.
u256 m_stepFee;
u256 m_dataFee;
u256 m_memoryFee;
u256 m_extroFee;
u256 m_cryptoFee;
u256 m_newContractFee;
u256 m_txFee;
};
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -53,6 +68,12 @@ public:
/// Construct state object.
State(Address _coinbaseAddress, Overlay const& _db);
/// Copy state object.
State(State const& _s);
/// Copy state object.
State& operator=(State const& _s);
/// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }
@ -146,6 +167,12 @@ public:
/// This might throw.
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit);
/// Get the fee associated for a contract created with the given data.
u256 fee(uint _dataCount) const { return m_fees.m_memoryFee * _dataCount + m_fees.m_newContractFee; }
/// Get the fee associated for a normal transaction.
u256 fee() const { return m_fees.m_txFee; }
private:
/// Fee-adder on destruction RAII class.
struct MinerFeeAdder
@ -177,7 +204,7 @@ private:
void executeBare(Transaction const& _t, Address _sender);
/// Execute a contract transaction.
void execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _txFee, u256s const& _txData, u256* o_totalFee);
void execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* o_totalFee);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
@ -199,16 +226,9 @@ private:
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
Dagger m_dagger;
/// The fee structure. Values yet to be agreed on...
static const u256 c_stepFee;
static const u256 c_dataFee;
static const u256 c_memoryFee;
static const u256 c_extroFee;
static const u256 c_cryptoFee;
static const u256 c_newContractFee;
static const u256 c_txFee;
static const u256 c_blockReward;
FeeStructure m_fees;
u256 m_blockReward;
static std::string c_defaultPath;

5
libethereum/Transaction.cpp

@ -32,8 +32,7 @@ Transaction::Transaction(bytesConstRef _rlpData)
nonce = rlp[0].toInt<u256>();
receiveAddress = rlp[1].toHash<Address>();
value = rlp[2].toInt<u256>();
fee = rlp[3].toInt<u256>();
data.reserve(rlp[4].itemCountStrict());
data.reserve(rlp[3].itemCountStrict());
for (auto const& i: rlp[4])
data.push_back(i.toInt<u256>());
vrs = Signature{ rlp[5].toInt<byte>(), rlp[6].toInt<u256>(), rlp[7].toInt<u256>() };
@ -92,7 +91,7 @@ void Transaction::sign(Secret _priv)
void Transaction::fillStream(RLPStream& _s, bool _sig) const
{
_s.appendList(_sig ? 8 : 5);
_s << nonce << receiveAddress << value << fee << data;
_s << nonce << receiveAddress << value << data;
if (_sig)
_s << vrs.v << vrs.r << vrs.s;
}

3
libethereum/Transaction.h

@ -34,7 +34,7 @@ struct Signature
u256 s;
};
// [ nonce, receiving_address, value, fee, [ data item 0, data item 1 ... data item n ], v, r, s ]
// [ nonce, receiving_address, value, [ data item 0, data item 1 ... data item n ], v, r, s ]
struct Transaction
{
Transaction() {}
@ -44,7 +44,6 @@ struct Transaction
u256 nonce;
Address receiveAddress;
u256 value;
u256 fee;
u256s data;
Signature vrs;

1
test/crypto.cpp

@ -41,7 +41,6 @@ int cryptoTest()
Transaction t;
t.nonce = 0;
t.fee = 0;
t.value = 1; // 1 wei.
t.receiveAddress = toAddress(sha3("123"));

1
test/state.cpp

@ -62,7 +62,6 @@ int stateTest()
{
Transaction t;
t.nonce = s.transactionsFrom(myMiner.address());
t.fee = 0;
t.value = 1000; // 1e3 wei.
t.receiveAddress = me.address();
t.sign(myMiner.secret());

Loading…
Cancel
Save