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

65
alethzero/MainWin.cpp

@ -24,8 +24,6 @@ Main::Main(QWidget *parent) :
{ {
setWindowFlags(Qt::Window); setWindowFlags(Qt::Window);
ui->setupUi(this); ui->setupUi(this);
initUnits(ui->valueUnits);
initUnits(ui->feeUnits);
g_logPost = [=](std::string const& s, char const*) { ui->log->addItem(QString::fromStdString(s)); }; 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)); 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(); on_verbosity_sliderMoved();
initUnits(ui->valueUnits);
statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount); statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->blockChain); statusBar()->addPermanentWidget(ui->blockChain);
@ -137,9 +136,8 @@ void Main::refresh()
for (pair<h256, bytes> const& i: m_client->transactionQueue().transactions()) for (pair<h256, bytes> const& i: m_client->transactionQueue().transactions())
{ {
Transaction t(i.second); 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.value).c_str())
.arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str()) .arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().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]) for (auto const& i: RLP(bc.block(h))[1])
{ {
Transaction t(i.data()); 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.value).c_str())
.arg(formatBalance(t.fee).c_str())
.arg(asHex(t.receiveAddress.asArray()).c_str()) .arg(asHex(t.receiveAddress.asArray()).c_str())
.arg(asHex(t.sender().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)); 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() void Main::on_net_triggered()
{ {
ui->port->setEnabled(!ui->net->isChecked()); ui->port->setEnabled(!ui->net->isChecked());
@ -233,9 +275,7 @@ void Main::on_mine_triggered()
void Main::on_send_clicked() void Main::on_send_clicked()
{ {
u256 value = ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first; u256 totalReq = value() + fee();
u256 fee = ui->fee->value() * units()[units().size() - 1 - ui->feeUnits->currentIndex()].first;
u256 totalReq = value + fee;
m_client->lock(); m_client->lock();
for (auto i: m_myKeys) for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq) if (m_client->state().balance(i.address()) >= totalReq)
@ -243,12 +283,11 @@ void Main::on_send_clicked()
m_client->unlock(); m_client->unlock();
Secret s = m_myKeys.front().secret(); Secret s = m_myKeys.front().secret();
Address r = Address(fromUserHex(ui->destination->text().toStdString())); Address r = Address(fromUserHex(ui->destination->text().toStdString()));
auto ds = ui->data->toPlainText().split(QRegExp("[^0-9a-fA-Fx]+"));
u256s data; u256s data;
data.reserve(ds.size()); data.reserve(m_data.size());
for (QString const& i: ds) for (QString const& i: m_data)
data.push_back(u256(i.toStdString())); data.push_back(u256(i.toStdString()));
m_client->transact(s, r, value, fee, data); m_client->transact(s, r, value(), data);
refresh(); refresh();
return; return;
} }

10
alethzero/MainWin.h

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

10
eth/main.cpp

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

4
libethereum/Client.h

@ -62,7 +62,7 @@ public:
~Client(); ~Client();
/// Executes the given transaction. /// 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. /// Requires transactions involving this address be queued for inspection.
void setInterest(Address _dest); void setInterest(Address _dest);
@ -131,6 +131,7 @@ private:
TransactionQueue m_tq; ///< Maintains list of incoming transactions not yet on the block chain. 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. 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_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. 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__) #if defined(__APPLE__)
@ -143,6 +144,7 @@ private:
enum { Active = 0, Deleting, Deleted } m_workState = Active; enum { Active = 0, Deleting, Deleted } m_workState = Active;
bool m_doMine = false; ///< Are we supposed to be mining? bool m_doMine = false; ///< Are we supposed to be mining?
MineProgress m_mineProgress; MineProgress m_mineProgress;
mutable bool m_miningStarted = false;
mutable bool m_changed; mutable bool m_changed;
}; };

47
libethereum/Common.cpp

@ -190,13 +190,50 @@ Address eth::toAddress(Secret _private)
KeyPair KeyPair::create() KeyPair KeyPair::create()
{ {
secp256k1_start();
static std::mt19937_64 s_eng(time(0)); static std::mt19937_64 s_eng(time(0));
std::uniform_int_distribution<byte> d(0, 255); std::uniform_int_distribution<byte> d(0, 255);
KeyPair ret;
for (uint i = 0; i < 32; ++i) for (int i = 0; i < 100; ++i)
ret.m_secret[i] = d(s_eng); {
ret.m_address = toAddress(ret.m_secret); h256 sec;
return ret; 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 = 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; return _out;
} }
using h512 = FixedHash<64>;
using h256 = FixedHash<32>; using h256 = FixedHash<32>;
using h160 = FixedHash<20>; using h160 = FixedHash<20>;
using h256s = std::vector<h256>; using h256s = std::vector<h256>;
@ -135,6 +136,7 @@ using h256Set = std::set<h256>;
using h160Set = std::set<h160>; using h160Set = std::set<h160>;
using Secret = h256; using Secret = h256;
using Public = h512;
using Address = h160; using Address = h160;
using Addresses = h160s; using Addresses = h160s;
@ -434,15 +436,19 @@ class KeyPair
{ {
public: public:
KeyPair() {} KeyPair() {}
KeyPair(Secret _k): m_secret(_k), m_address(toAddress(_k)) {} KeyPair(Secret _k);
static KeyPair create(); static KeyPair create();
Secret const& secret() const { return m_secret; } 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; } Address const& address() const { return m_address; }
private: private:
Secret m_secret; Secret m_secret;
Public m_public;
Address m_address; Address m_address;
}; };

122
libethereum/PeerNetwork.cpp

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

26
libethereum/PeerNetwork.h

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <map>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <boost/asio.hpp> #include <boost/asio.hpp>
@ -60,6 +61,19 @@ enum PacketType
GetTransactionsPacket GetTransactionsPacket
}; };
enum DisconnectReason
{
DisconnectRequested = 0,
TCPError,
BadProtocol,
UselessPeer,
TooManyPeers,
DuplicatePeer,
WrongGenesis,
IncompatibleProtocol,
ClientQuit
};
class PeerServer; class PeerServer;
struct PeerInfo struct PeerInfo
@ -79,7 +93,7 @@ public:
~PeerSession(); ~PeerSession();
void start(); void start();
void disconnect(); void disconnect(int _reason);
void ping(); void ping();
@ -102,6 +116,7 @@ private:
bi::tcp::socket m_socket; bi::tcp::socket m_socket;
std::array<byte, 65536> m_data; std::array<byte, 65536> m_data;
PeerInfo m_info; PeerInfo m_info;
Public m_id;
bytes m_incoming; bytes m_incoming;
uint m_protocolVersion; uint m_protocolVersion;
@ -137,7 +152,7 @@ public:
/// Start server, listening for connections on the given port. /// 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); 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. /// 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(); ~PeerServer();
/// Connect to a peer explicitly. /// Connect to a peer explicitly.
@ -172,7 +187,7 @@ private:
void populateAddresses(); void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp); void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting(); void ensureAccepting();
std::vector<bi::tcp::endpoint> potentialPeers(); std::map<Public, bi::tcp::endpoint> potentialPeers();
std::string m_clientVersion; std::string m_clientVersion;
NodeMode m_mode = NodeMode::Full; NodeMode m_mode = NodeMode::Full;
@ -186,13 +201,14 @@ private:
UPnP* m_upnp = nullptr; UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public; bi::tcp::endpoint m_public;
KeyPair m_key;
uint m_requiredNetworkId; 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_incomingTransactions;
std::vector<bytes> m_incomingBlocks; std::vector<bytes> m_incomingBlocks;
std::vector<bi::tcp::endpoint> m_incomingPeers; std::multimap<Public, bi::tcp::endpoint> m_incomingPeers;
h256 m_latestBlockSent; h256 m_latestBlockSent;
std::set<h256> m_transactionsSent; 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(bytes const& _s) { return append(bytesConstRef(&_s)); }
RLPStream& append(std::string 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(char const* _s) { return append(std::string(_s)); }
RLPStream& append(h160 _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); }
RLPStream& append(h256 _s, bool _compact = false) { return append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item. /// Appends an arbitrary RLP fragment - this *must* be a single item.
RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } 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 std;
using namespace eth; using namespace eth;
u256 const State::c_stepFee = 10000; u256 const c_stepFee = 1;
u256 const State::c_dataFee = 20000; u256 const c_dataFee = 20;
u256 const State::c_memoryFee = 30000; u256 const c_memoryFee = 5;
u256 const State::c_extroFee = 40000; u256 const c_extroFee = 40;
u256 const State::c_cryptoFee = 50000; u256 const c_cryptoFee = 20;
u256 const State::c_newContractFee = 60000; u256 const c_newContractFee = 100;
u256 const State::c_txFee = 0; u256 const c_txFee = 100;
u256 const State::c_blockReward = 1000000000000;
#if NDEBUG
u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#else
u256 const eth::c_genesisDifficulty = (u256)1 << 22; u256 const eth::c_genesisDifficulty = (u256)1 << 22;
#endif
std::map<Address, AddressState> const& eth::genesisState() std::map<Address, AddressState> const& eth::genesisState()
{ {
@ -90,8 +85,14 @@ Overlay State::openDB(std::string _path, bool _killExisting)
return Overlay(db); 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(); secp256k1_start();
// Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. // 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); 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 void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
{ {
auto it = m_cache.find(_a); auto it = m_cache.find(_a);
@ -525,11 +566,11 @@ void State::execute(bytesConstRef _rlp)
void State::applyRewards(Addresses const& _uncleAddresses) void State::applyRewards(Addresses const& _uncleAddresses)
{ {
u256 r = c_blockReward; u256 r = m_blockReward;
for (auto const& i: _uncleAddresses) for (auto const& i: _uncleAddresses)
{ {
addBalance(i, c_blockReward * 4 / 3); addBalance(i, m_blockReward * 4 / 3);
r += c_blockReward / 8; r += m_blockReward / 8;
} }
addBalance(m_currentBlock.coinbaseAddress, r); addBalance(m_currentBlock.coinbaseAddress, r);
} }
@ -544,31 +585,32 @@ void State::executeBare(Transaction const& _t, Address _sender)
throw InvalidNonce(nonceReq, _t.nonce); throw InvalidNonce(nonceReq, _t.nonce);
// Not considered invalid - just pointless. // 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(); throw NotEnoughCash();
// TODO: check fee is sufficient?
// Increment associated nonce for sender. // Increment associated nonce for sender.
noteSending(_sender); noteSending(_sender);
if (_t.receiveAddress) if (_t.receiveAddress)
{ {
subBalance(_sender, _t.value + _t.fee); subBalance(_sender, _t.value + fee);
addBalance(_t.receiveAddress, _t.value); addBalance(_t.receiveAddress, _t.value);
addBalance(m_currentBlock.coinbaseAddress, _t.fee);
if (isContractAddress(_t.receiveAddress)) if (isContractAddress(_t.receiveAddress))
{ {
MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction. 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 else
{ {
// Try to make a new contract #if ETH_SENDER_PAYS_SETUP
if (_t.fee < _t.data.size() * c_memoryFee + c_newContractFee) if (balance(_sender) < _t.value + fee)
throw FeeTooSmall(); #else
if (_t.value < fee)
#endif
throw NotEnoughCash();
Address newAddress = low160(_t.sha3()); Address newAddress = low160(_t.sha3());
@ -584,9 +626,13 @@ void State::executeBare(Transaction const& _t, Address _sender)
else else
mem.at(i) = _t.data[i]; 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(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)); 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; std::vector<u256> stack;
@ -637,7 +683,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
{ {
stepCount++; stepCount++;
bigint minerFee = stepCount > 16 ? c_stepFee : 0; bigint minerFee = stepCount > 16 ? m_fees.m_stepFee : 0;
bigint voidFee = 0; bigint voidFee = 0;
auto rawInst = mem(curPC); auto rawInst = mem(curPC);
@ -650,21 +696,21 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::STORE: case Instruction::STORE:
require(2); require(2);
if (!mem(stack.back()) && stack[stack.size() - 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]) if (mem(stack.back()) && !stack[stack.size() - 2])
voidFee -= c_memoryFee; voidFee -= m_fees.m_memoryFee;
// continue on to... // continue on to...
case Instruction::LOAD: case Instruction::LOAD:
minerFee += c_dataFee; minerFee += m_fees.m_dataFee;
break; break;
case Instruction::EXTRO: case Instruction::EXTRO:
case Instruction::BALANCE: case Instruction::BALANCE:
minerFee += c_extroFee; minerFee += m_fees.m_extroFee;
break; break;
case Instruction::MKTX: case Instruction::MKTX:
minerFee += c_txFee; minerFee += m_fees.m_txFee;
break; break;
case Instruction::SHA256: case Instruction::SHA256:
@ -674,7 +720,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::ECSIGN: case Instruction::ECSIGN:
case Instruction::ECRECOVER: case Instruction::ECRECOVER:
case Instruction::ECVALID: case Instruction::ECVALID:
minerFee += c_cryptoFee; minerFee += m_fees.m_cryptoFee;
break; break;
default: default:
break; break;
@ -779,9 +825,6 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
case Instruction::TXVALUE: case Instruction::TXVALUE:
stack.push_back(_txValue); stack.push_back(_txValue);
break; break;
case Instruction::TXFEE:
stack.push_back(_txFee);
break;
case Instruction::TXDATAN: case Instruction::TXDATAN:
stack.push_back(_txData.size()); stack.push_back(_txData.size());
break; break;
@ -1069,8 +1112,6 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
stack.pop_back(); stack.pop_back();
t.value = stack.back(); t.value = stack.back();
stack.pop_back(); stack.pop_back();
t.fee = stack.back();
stack.pop_back();
auto itemCount = stack.back(); auto itemCount = stack.back();
stack.pop_back(); stack.pop_back();
@ -1092,7 +1133,7 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _
{ {
require(1); require(1);
Address dest = asAddress(stack.back()); Address dest = asAddress(stack.back());
u256 minusVoidFee = myMemory.size() * c_memoryFee; u256 minusVoidFee = myMemory.size() * m_fees.m_memoryFee;
addBalance(dest, balance(_myAddress) + minusVoidFee); addBalance(dest, balance(_myAddress) + minusVoidFee);
m_cache[_myAddress].kill(); m_cache[_myAddress].kill();
// ...follow through to... // ...follow through to...

42
libethereum/State.h

@ -42,6 +42,21 @@ class BlockChain;
extern const u256 c_genesisDifficulty; extern const u256 c_genesisDifficulty;
std::map<Address, AddressState> const& genesisState(); 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. * @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). * 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. /// Construct state object.
State(Address _coinbaseAddress, Overlay const& _db); 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. /// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block. /// This causes a complete reset of current block.
void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); } void setAddress(Address _coinbaseAddress) { m_ourAddress = _coinbaseAddress; resetCurrent(); }
@ -146,6 +167,12 @@ public:
/// This might throw. /// This might throw.
u256 playback(bytesConstRef _block, BlockInfo const& _bi, BlockInfo const& _parent, BlockInfo const& _grandParent, bool _fullCommit); 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: private:
/// Fee-adder on destruction RAII class. /// Fee-adder on destruction RAII class.
struct MinerFeeAdder struct MinerFeeAdder
@ -177,7 +204,7 @@ private:
void executeBare(Transaction const& _t, Address _sender); void executeBare(Transaction const& _t, Address _sender);
/// Execute a contract transaction. /// 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). /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent(); void resetCurrent();
@ -199,16 +226,9 @@ private:
Address m_ourAddress; ///< Our address (i.e. the address to which fees go). Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
Dagger m_dagger; Dagger m_dagger;
/// The fee structure. Values yet to be agreed on... FeeStructure m_fees;
static const u256 c_stepFee; u256 m_blockReward;
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;
static std::string c_defaultPath; static std::string c_defaultPath;

5
libethereum/Transaction.cpp

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

3
libethereum/Transaction.h

@ -34,7 +34,7 @@ struct Signature
u256 s; 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 struct Transaction
{ {
Transaction() {} Transaction() {}
@ -44,7 +44,6 @@ struct Transaction
u256 nonce; u256 nonce;
Address receiveAddress; Address receiveAddress;
u256 value; u256 value;
u256 fee;
u256s data; u256s data;
Signature vrs; Signature vrs;

1
test/crypto.cpp

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

1
test/state.cpp

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

Loading…
Cancel
Save