Browse Source

PoC 3.5 functionality. Still buggy though.

cl-refactor
Gav Wood 11 years ago
parent
commit
b3093e6447
  1. 176
      alethzero/Main.ui
  2. 63
      alethzero/MainWin.cpp
  3. 5
      alethzero/MainWin.h
  4. 13
      eth/main.cpp
  5. 9
      libethereum/Client.cpp
  6. 10
      libethereum/Client.h
  7. 7
      libethereum/ExtVMFace.h
  8. 17
      libethereum/FeeStructure.cpp
  9. 50
      libethereum/Instruction.cpp
  10. 51
      libethereum/Instruction.h
  11. 8
      libethereum/State.h
  12. 78
      libethereum/VM.h
  13. 5
      libethereum/vector_ref.h
  14. 1
      test/crypto.cpp
  15. 107
      test/vm.cpp
  16. 11
      walleth/MainWin.cpp
  17. 3
      walleth/MainWin.h

176
alethzero/Main.ui

@ -406,6 +406,32 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<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="1" column="1" colspan="4">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label5_2">
<property name="text">
@ -416,7 +442,69 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="3">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gas</string>
</property>
<property name="buddy">
<cstring>gas</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="gas">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>at</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QSpinBox" name="gasPrice">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>430000000</number>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QComboBox" name="gasPriceUnits"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
@ -435,7 +523,23 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="4">
<item row="4" column="1" colspan="4">
<widget class="QLabel" name="fee">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="0" colspan="5">
<widget class="QSplitter" name="splitter_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -451,69 +555,23 @@
</widget>
</widget>
</item>
<item row="5" column="3">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Send</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<item row="6" column="0" colspan="4">
<widget class="QLabel" name="total">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="destination">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>(Create Contract)</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="calculatedName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QComboBox" name="valueUnits"/>
</item>
<item row="3" column="1" colspan="3">
<widget class="QLabel" name="fee">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="value">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<number>430000000</number>
</property>
<property name="value">
<number>1000</number>
<item row="6" column="4">
<widget class="QPushButton" name="send">
<property name="text">
<string>&amp;Send</string>
</property>
</widget>
</item>
@ -803,18 +861,16 @@
<tabstop>calculatedName</tabstop>
<tabstop>value</tabstop>
<tabstop>valueUnits</tabstop>
<tabstop>gas</tabstop>
<tabstop>gasPrice</tabstop>
<tabstop>gasPriceUnits</tabstop>
<tabstop>data</tabstop>
<tabstop>code</tabstop>
<tabstop>send</tabstop>
<tabstop>idealPeers</tabstop>
<tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>nameReg</tabstop>
<tabstop>verbosity</tabstop>
<tabstop>transactionQueue</tabstop>
<tabstop>accounts</tabstop>
<tabstop>peers</tabstop>
<tabstop>log</tabstop>
<tabstop>ourAccounts</tabstop>
</tabstops>
<resources/>
<connections/>

63
alethzero/MainWin.cpp

@ -97,6 +97,7 @@ Main::Main(QWidget *parent) :
on_verbosity_sliderMoved();
initUnits(ui->valueUnits);
initUnits(ui->gasPriceUnits);
on_destination_textChanged();
statusBar()->addPermanentWidget(ui->balance);
@ -395,13 +396,22 @@ void Main::on_blocks_currentItemChanged()
else
s << "<br/>Creates: <b>" << pretty(right160(th)).toStdString() << "</b> " << right160(th);
s << "<br/>Value: <b>" << formatBalance(tx.value) << "</b>";
s << "<br/>Gas: <b>" << tx.gas << "</b>";
s << "<br/>Gas price: <b>" << tx.gasPrice << "</b>";
s << "&nbsp;&emsp;&nbsp;#<b>" << tx.nonce << "</b>";
if (tx.data.size())
if (tx.storage.size() && tx.isCreation)
{
s << "<br/>Data:&nbsp;&emsp;&nbsp;";
s << "<br/>Storage:&nbsp;&emsp;&nbsp;";
// for (auto i: tx.data)
// s << "0x<b>" << hex << i << "</b>&emsp;";
s << "</br>" << disassemble(tx.data);
s << "</br>" << disassemble(tx.storage);
}
else if (tx.data.size() && !tx.isCreation)
{
s << "<br/>Data:&nbsp;&emsp;&nbsp; 0x..." << setw(2) << setfill('0') << hex;
unsigned c = 0;
for (auto i: tx.data)
s << i << (c % 8 ? "" : " ");
}
}
@ -505,20 +515,44 @@ void Main::on_destination_textChanged()
ui->calculatedName->setText("Unknown Address");
else
ui->calculatedName->setText("Create Contract");
updateFee();
on_data_textChanged();
// updateFee();
}
void Main::on_data_textChanged()
{
string code = ui->data->toPlainText().toStdString();
m_data = code[0] == '(' ? compileLisp(code, true) : assemble(code, true);
ui->code->setPlainText(QString::fromStdString(disassemble(m_data)));
if (isCreation())
{
string code = ui->data->toPlainText().toStdString();
m_storage = code[0] == '(' ? compileLisp(code, true) : assemble(code, true);
ui->code->setPlainText(QString::fromStdString(disassemble(m_storage)));
ui->gas->setValue((qint64)state().createGas(m_storage.size()));
ui->gas->setEnabled(false);
}
else
{
string code = ui->data->toPlainText().replace(" ", "").toStdString();
m_data = fromHex(code);
ui->code->setPlainText(QString::fromStdString(toHex(m_data)));
ui->gas->setEnabled(true);
}
updateFee();
}
bool Main::isCreation() const
{
return (ui->destination->text().isEmpty() || !ui->destination->text().toInt());
}
u256 Main::fee() const
{
return (ui->destination->text().isEmpty() || !ui->destination->text().toInt()) ? state().fee(m_data.size()) : state().fee();
cnote << gasPrice();
cnote << isCreation();
cnote << ui->gas->value();
cnote << m_data.size();
cnote << m_storage.size();
return (isCreation() ? state().createGas(m_storage.size()) : state().callGas(m_data.size(), ui->gas->value())) * gasPrice();
}
u256 Main::value() const
@ -526,6 +560,11 @@ u256 Main::value() const
return ui->value->value() * units()[units().size() - 1 - ui->valueUnits->currentIndex()].first;
}
u256 Main::gasPrice() const
{
return ui->gasPrice->value() * units()[units().size() - 1 - ui->gasPriceUnits->currentIndex()].first;
}
u256 Main::total() const
{
return value() + fee();
@ -607,12 +646,14 @@ void Main::on_send_clicked()
u256 totalReq = value() + fee();
m_client->lock();
for (auto i: m_myKeys)
if (m_client->state().balance(i.address()) >= totalReq )
if (m_client->state().balance(i.address()) >= totalReq)
{
m_client->unlock();
Secret s = i.secret();
Address r = fromString(ui->destination->text());
m_client->transact(s, r, value(), m_data);
if (isCreation())
m_client->transact(s, value(), gasPrice(), m_storage);
else
m_client->transact(s, value(), gasPrice(), fromString(ui->destination->text()), ui->gas->value(), m_data);
refresh();
return;
}

5
alethzero/MainWin.h

@ -63,9 +63,11 @@ private:
void readSettings();
void writeSettings();
bool isCreation() const;
eth::u256 fee() const;
eth::u256 total() const;
eth::u256 value() const;
eth::u256 gasPrice() const;
std::unique_ptr<Ui::Main> ui;
@ -78,7 +80,8 @@ private:
QStringList m_servers;
QVector<eth::KeyPair> m_myKeys;
bool m_keysChanged = false;
eth::u256s m_data;
eth::u256s m_storage;
eth::bytes m_data;
eth::Address m_nameReg;
QNetworkAccessManager m_webCtrl;

13
eth/main.cpp

@ -282,19 +282,24 @@ int main(int argc, char** argv)
string sechex;
string rechex;
u256 amount;
cin >> sechex >> rechex >> amount;
u256 gasPrice;
u256 gas;
cin >> sechex >> rechex >> amount >> gasPrice >> gas;
Secret secret = h256(fromHex(sechex));
Address dest = h160(fromHex(rechex));
c.transact(secret, dest, amount);
bytes data;
c.transact(secret, amount, gasPrice, dest, gas, data);
}
else if (cmd == "send")
{
string rechex;
u256 amount;
cin >> rechex >> amount;
u256 gasPrice;
u256 gas;
cin >> rechex >> amount >> gasPrice >> gas;
Address dest = h160(fromHex(rechex));
c.transact(us.secret(), dest, amount);
c.transact(us.secret(), amount, gasPrice, dest, gas, bytes());
}
else if (cmd == "inspect")
{

9
libethereum/Client.cpp

@ -131,13 +131,14 @@ void Client::stopMining()
m_doMine = false;
}
void Client::call(Secret _secret, u256 _amount, u256 _baseFee, Address _dest, u256 _gas, bytes _data)
void Client::transact(Secret _secret, u256 _value, u256 _gasPrice, Address _dest, u256 _gas, bytes _data)
{
lock_guard<recursive_mutex> l(m_lock);
Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.receiveAddress = _dest;
t.value = _amount;
t.value = _value;
t.gasPrice = _gasPrice;
t.gas = _gas;
t.data = _data;
t.sign(_secret);
@ -146,13 +147,13 @@ void Client::call(Secret _secret, u256 _amount, u256 _baseFee, Address _dest, u2
m_changed = true;
}
void Client::create(Secret _secret, u256 _endowment, u256 _baseFee, u256s _storage)
void Client::transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256s _storage)
{
lock_guard<recursive_mutex> l(m_lock);
Transaction t;
t.nonce = m_postMine.transactionsFrom(toAddress(_secret));
t.value = _endowment;
t.gasPrice = _baseFee;
t.gasPrice = _gasPrice;
t.storage = _storage;
t.sign(_secret);
cnote << "New transaction " << t;

10
libethereum/Client.h

@ -84,13 +84,13 @@ public:
~Client();
/// Submits the given transaction.
void transact(Secret _secret, u256 _amount, u256 _baseFee, Address _dest, u256 _gas, bytes _data = bytes());
/// Makes the given call. Nothing is recorded into the state. TODO
// bytes call(Secret _secret, u256 _amount, u256 _baseFee, Address _dest, u256 _gas, bytes _data = bytes());
void transact(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());
/// Submits a new contract.
void create(Secret _secret, u256 _endowment, u256 _baseFee, u256s _storage = u256s());
void transact(Secret _secret, u256 _endowment, u256 _gasPrice, u256s _storage = u256s());
/// Makes the given call. Nothing is recorded into the state. TODO
// bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());
/// Requires transactions involving this address be queued for inspection.
void setInterest(Address _dest);

7
libethereum/ExtVMFace.h

@ -52,7 +52,6 @@ public:
currentNumber(_currentNumber)
{}
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma GCC diagnostic push
@ -64,8 +63,8 @@ public:
void subBalance(u256 _a) {}
u256 txCount(Address _a) { return 0; }
void suicide(Address _a) {}
h160 create(Address _txSender, u256 _endowment, vector_ref<h256 const> _storage) { return h160(); }
bool call(Address _myAddress, Address _txSender, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _tx) { return false; }
h160 create(u256 _endowment, vector_ref<h256 const> _storage) { return h160(); }
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _tx) { return false; }
#pragma GCC diagnostic pop
#pragma warning(pop)
@ -76,7 +75,7 @@ public:
u256 gasPrice;
bytesConstRef txData;
BlockInfo previousBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information.
BlockInfo currentBlock; ///< The current block's information.
uint currentNumber;
};

17
libethereum/FeeStructure.cpp

@ -24,11 +24,12 @@
using namespace std;
using namespace eth;
u256 const c_stepGas = 1;
u256 const c_ioGas = 20;
u256 const c_memoryGas = 5;
u256 const c_newMemoryFee = 5;
u256 const c_extroFee = 40;
u256 const c_balanceGas = 40;
u256 const c_createGas = 100;
u256 const c_callGas = 100;
u256 const eth::c_stepGas = 1;
u256 const eth::c_balanceGas = 20;
u256 const eth::c_sha3Gas = 20;
u256 const eth::c_sloadGas = 20;
u256 const eth::c_sstoreGas = 100;
u256 const eth::c_createGas = 100;
u256 const eth::c_callGas = 20;
u256 const eth::c_memoryGas = 1;
u256 const eth::c_txDataGas = 5;

50
libethereum/Instruction.cpp

@ -44,25 +44,25 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "GT", Instruction::GT },
{ "EQ", Instruction::EQ },
{ "NOT", Instruction::NOT },
{ "ROTATE", Instruction::ROTATE },
{ "AND", Instruction::AND },
{ "OR", Instruction::OR },
{ "XOR", Instruction::XOR },
{ "BYTE", Instruction::BYTE },
{ "SHA3", Instruction::SHA3 },
{ "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE },
{ "ORIGIN", Instruction::ORIGIN },
{ "CALLER", Instruction::CALLER },
{ "CALLVALUE", Instruction::CALLVALUE },
{ "CALLDATA", Instruction::CALLDATA },
{ "CALLDATALOAD", Instruction::CALLDATALOAD },
{ "CALLDATASIZE", Instruction::CALLDATASIZE },
{ "BASEFEE", Instruction::GASPRICE },
{ "PREVHASH", Instruction::PREVHASH },
{ "PREVNONCE", Instruction::PREVNONCE },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY },
{ "GASLIMIT", Instruction::GASLIMIT },
{ "PUSH", Instruction::PUSH },
{ "POP", Instruction::POP },
{ "DUP", Instruction::DUP },
@ -75,6 +75,8 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "JUMP", Instruction::JUMP },
{ "JUMPI", Instruction::JUMPI },
{ "PC", Instruction::PC },
{ "MEMSIZE", Instruction::MEMSIZE },
{ "GAS", Instruction::GAS },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "RETURN", Instruction::RETURN },
@ -97,25 +99,25 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::GT, { "GT", 0, 2, 1 } },
{ Instruction::EQ, { "EQ", 0, 2, 1 } },
{ Instruction::NOT, { "NOT", 0, 1, 1 } },
{ Instruction::ROTATE, { "ROTATE", 0, 2, 1 } },
{ Instruction::ADD, { "ADD", 0, 2, 1 } },
{ Instruction::OR, { "OR", 0, 2, 1 } },
{ Instruction::XOR, { "XOR", 0, 2, 1 } },
{ Instruction::BYTE, { "BYTE", 0, 2, 1 } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1 } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1 } },
{ Instruction::ORIGIN, { "ORIGIN", 0, 1, 1 } },
{ Instruction::CALLER, { "CALLER", 0, 0, 1 } },
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } },
{ Instruction::CALLDATA, { "CALLDATA", 0, 0, 1 } },
{ Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } },
{ Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 1, 1 } },
{ Instruction::GASPRICE, { "BASEFEE", 0, 0, 1 } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } },
{ Instruction::PREVNONCE, { "PREVNONCE", 0, 0, 1 } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1 } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1 } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1 } },
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1 } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1 } },
{ Instruction::PUSH, { "PUSH", 1, 0, 1 } },
{ Instruction::POP, { "POP", 0, 1, 0 } },
{ Instruction::DUP, { "DUP", 0, 1, 2 } },
@ -128,7 +130,9 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::JUMP, { "JUMP", 0, 1, 0 } },
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0 } },
{ Instruction::PC, { "PC", 0, 0, 1 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } }, // endowment, first word in memory, data words
{ Instruction::MEMSIZE, { "MEMSIZE", 0, 0, 1 } },
{ Instruction::GAS, { "GAS", 0, 0, 1 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } },
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} }
@ -352,16 +356,16 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (compileLispFragment(d, e, _quiet, codes[3], locs[3]) != -1)
return false;
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned posLocation = (unsigned)o_code.size();
o_locs.push_back(posLocation);
o_code.push_back(0);
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Jump to positive if true.
// Jump to negative if false.
o_code.push_back(Instruction::JUMPI);
// Second fragment - negative.
@ -399,15 +403,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
if (compileLispFragment(d, e, _quiet, codes[2], locs[2]) != -1)
return false;
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned endLocation = (unsigned)o_code.size();
o_locs.push_back(endLocation);
o_code.push_back(0);
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Jump to end...
if (t == "WHEN")
o_code.push_back(Instruction::NOT);
@ -439,15 +443,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
unsigned startLocation = (unsigned)o_code.size();
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Push the positive location.
o_code.push_back(Instruction::PUSH);
unsigned endInsertion = (unsigned)o_code.size();
o_locs.push_back(endInsertion);
o_code.push_back(0);
// First fragment - predicate
appendCode(o_code, o_locs, codes[0], locs[0]);
// Jump to positive if true.
o_code.push_back(Instruction::NOT);
o_code.push_back(Instruction::JUMPI);
@ -568,15 +572,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
for (unsigned i = 1; i < codes.size(); ++i)
{
// Check if true - predicate
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Push the false location.
o_code.push_back(Instruction::PUSH);
ends.push_back((unsigned)o_code.size());
o_locs.push_back(ends.back());
o_code.push_back(0);
// Check if true - predicate
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Jump to end...
o_code.push_back(Instruction::NOT);
o_code.push_back(Instruction::JUMPI);
@ -622,15 +626,15 @@ static int compileLispFragment(char const*& d, char const* e, bool _quiet, u256s
for (unsigned i = 1; i < codes.size(); ++i)
{
// Check if true - predicate
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Push the false location.
o_code.push_back(Instruction::PUSH);
ends.push_back((unsigned)o_code.size());
o_locs.push_back(ends.back());
o_code.push_back(0);
// Check if true - predicate
appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]);
// Jump to end...
o_code.push_back(Instruction::JUMPI);
}

51
libethereum/Instruction.h

@ -45,12 +45,31 @@ enum class Instruction: uint8_t
GT,
EQ,
NOT,
ROTATE,
AND,
AND = 0x10,
OR,
XOR,
SHA3,
PUSH,
BYTE,
SHA3 = 0x20,
ADDRESS = 0x30,
BALANCE,
ORIGIN,
CALLER,
CALLVALUE,
CALLDATALOAD,
CALLDATASIZE,
GASPRICE,
PREVHASH = 0x40,
COINBASE,
TIMESTAMP,
NUMBER,
DIFFICULTY,
GASLIMIT,
PUSH = 0x50,
POP,
DUP,
SWAP,
@ -60,27 +79,15 @@ enum class Instruction: uint8_t
SLOAD,
SSTORE,
JUMP,
JUMPI, //0x1d
ADDRESS = 0x20, ///< pushes the transaction sender
BALANCE,
ORIGIN, ///< pushes the transaction sender
CALLER, ///< pushes the transaction sender
CALLVALUE, ///< pushes the transaction value
CALLDATA, ///< pushes the transaction value
CALLDATASIZE, ///< pushes the transaction value
GASPRICE,
MEMSIZE,
PREVHASH, ///< pushes the hash of the previous block (NOT the current one since that's impossible!)
PREVNONCE,
COINBASE, ///< pushes the coinbase of the current block
TIMESTAMP, ///< pushes the timestamp of the current block
NUMBER, ///< pushes the current block number
DIFFICULTY, ///< pushes the difficulty of the current block
JUMPI,
PC,
CREATE = 0x30,
MEMSIZE,
GAS,
CREATE = 0x60,
CALL,
RETURN,
SUICIDE = 0x3f
SUICIDE = 0x7f
};
/// Information structure for a particular instruction.

8
libethereum/State.h

@ -266,14 +266,14 @@ public:
m_store->erase(_n);
}
h160 create(Address _txSender, u256 _endowment, vector_ref<h256 const> _storage)
h160 create(u256 _endowment, vector_ref<h256 const> _storage)
{
return m_s.create(_txSender, _endowment, gasPrice, _storage);
return m_s.create(myAddress, _endowment, gasPrice, _storage);
}
bool call(Address _myAddress, Address _txSender, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)
{
return m_s.call(_myAddress, _txSender, _txValue, gasPrice, _txData, _gas, _out);
return m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out);
}
u256 balance(Address _a) { return m_s.balance(_a); }

78
libethereum/VM.h

@ -130,10 +130,6 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
runGas = c_sha3Gas;
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2];
break;
case Instruction::CALLDATA:
require(2);
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2];
break;
case Instruction::BALANCE:
runGas = c_balanceGas;
@ -266,6 +262,26 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
require(1);
m_stack.back() = m_stack.back() ? 0 : 1;
break;
case Instruction::AND:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() & m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::OR:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() | m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::XOR:
require(2);
m_stack[m_stack.size() - 2] = m_stack.back() ^ m_stack[m_stack.size() - 2];
m_stack.pop_back();
break;
case Instruction::BYTE:
require(2);
m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] < 32 ? (m_stack[m_stack.size() - 2] >> (uint)(31 - m_stack.back())) & 0xff : 0;
m_stack.pop_back();
break;
case Instruction::SHA3:
{
require(2);
@ -295,13 +311,18 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::CALLVALUE:
m_stack.push_back(_ext.txValue);
break;
case Instruction::CALLDATA:
case Instruction::CALLDATALOAD:
{
unsigned inOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned inSize = (unsigned)m_stack.back();
m_stack.pop_back();
memcpy(m_temp.data() + inOff, _ext.txData.data(), std::min<unsigned>(_ext.txData.size(), inSize));
require(1);
if ((unsigned)m_stack.back() < _ext.txData.size() + 32)
m_stack.back() = (u256)*(h256 const*)(_ext.txData.data() + (unsigned)m_stack.back());
else
{
h256 r;
for (unsigned i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + 32, j = 0; i < e; ++i, ++j)
r[j] = i < _ext.txData.size() ? _ext.txData[i] : 0;
m_stack.back() = (u256)r;
}
break;
}
case Instruction::CALLDATASIZE:
@ -313,9 +334,6 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::PREVHASH:
m_stack.push_back(_ext.previousBlock.hash);
break;
case Instruction::PREVNONCE:
m_stack.push_back(_ext.previousBlock.nonce);
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
break;
@ -328,6 +346,9 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::DIFFICULTY:
m_stack.push_back(_ext.currentBlock.difficulty);
break;
case Instruction::GASLIMIT:
m_stack.push_back(1000000);
break;
case Instruction::PUSH:
{
m_stack.push_back(_ext.store(m_curPC + 1));
@ -410,14 +431,20 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
break;
case Instruction::JUMPI:
require(2);
if (m_stack.back())
m_nextPC = m_stack[m_stack.size() - 2];
if (m_stack[m_stack.size() - 2])
m_nextPC = m_stack.back();
m_stack.pop_back();
m_stack.pop_back();
break;
case Instruction::PC:
m_stack.push_back(m_curPC);
break;
case Instruction::MEMSIZE:
m_stack.push_back(m_temp.size());
break;
case Instruction::GAS:
m_stack.push_back(m_gas);
break;
case Instruction::CREATE:
{
require(3);
@ -432,7 +459,7 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
if (_ext.balance(_ext.myAddress) >= endowment)
{
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(_ext.myAddress, endowment, vector_ref<h256 const>((h256 const*)(m_temp.data() + inOff), inSize / 32)));
m_stack.push_back((u160)_ext.create(endowment, vector_ref<h256 const>((h256 const*)(m_temp.data() + inOff), inSize / 32)));
}
else
m_stack.push_back(0);
@ -442,18 +469,12 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
{
require(7);
u256 gas = m_stack.back();
if (!gas)
{
gas = m_gas;
m_gas = 0;
}
m_stack.pop_back();
u160 receiveAddress = asAddress(m_stack.back());
m_stack.pop_back();
u256 value = m_stack.back();
m_stack.pop_back();
u256 gas = m_stack.back();
m_stack.pop_back();
unsigned inOff = (unsigned)m_stack.back();
m_stack.pop_back();
@ -464,10 +485,15 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
unsigned outSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (!gas)
{
gas = m_gas;
m_gas = 0;
}
if (_ext.balance(_ext.myAddress) >= value)
{
_ext.subBalance(value);
m_stack.push_back(_ext.call(receiveAddress, _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), &gas, bytesRef(m_temp.data() + outOff, outSize)));
m_stack.push_back(_ext.call(receiveAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), &gas, bytesRef(m_temp.data() + outOff, outSize)));
}
m_gas += gas;
@ -499,6 +525,6 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
}
if (_steps == (unsigned)-1)
throw StepsDone();
return true;
return bytesConstRef();
}

5
libethereum/vector_ref.h

@ -19,6 +19,7 @@ class vector_ref
public:
typedef _T value_type;
typedef _T element_type;
typedef typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type mutable_value_type;
vector_ref(): m_data(nullptr), m_count(0) {}
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
@ -29,8 +30,8 @@ public:
explicit operator bool() const { return m_data && m_count; }
bool contentsEqual(std::vector<_T> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
std::vector<_T> toVector() const { return std::vector<_T>(m_data, m_data + m_count); }
bool contentsEqual(std::vector<mutable_value_type> const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
std::vector<mutable_value_type> toVector() const { return std::vector<mutable_value_type>(m_data, m_data + m_count); }
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>((unsigned char const*)m_data, m_data + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count); }
template <class _T2> operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); }

1
test/crypto.cpp

@ -42,7 +42,6 @@ int cryptoTest()
t.nonce = 0;
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b"));
t.value = 1000;
t.data = u256s();
cnote << RLP(t.rlp(false));
cnote << toHex(t.rlp(false));
cnote << t.sha3(false);

107
test/vm.cpp

@ -40,7 +40,7 @@ public:
FakeExtVM()
{}
FakeExtVM(BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, uint _currentNumber):
ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber)
ExtVMFace(Address(), Address(), 0, 1, bytesConstRef(), _previousBlock, _currentBlock, _currentNumber)
{}
u256 store(u256 _n)
@ -51,6 +51,14 @@ public:
{
get<3>(addresses[myAddress])[_n] = _v;
}
u256 balance(Address _a) { return get<0>(addresses[_a]); }
void subBalance(u256 _a) { get<0>(addresses[myAddress]) -= _a; }
u256 txCount(Address _a) { return get<1>(addresses[_a]); }
void suicide(Address _a)
{
get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
addresses.erase(myAddress);
}
void transact(Transaction& _t)
{
if (get<0>(addresses[myAddress]) >= _t.value)
@ -61,41 +69,52 @@ public:
txs.push_back(_t);
}
}
u256 balance(Address _a) { return get<0>(addresses[_a]); }
void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); }
u256 txCount(Address _a) { return get<1>(addresses[_a]); }
u256 extro(Address _a, u256 _pos)
h160 create(u256 _endowment, vector_ref<h256 const> _storage)
{
return get<3>(addresses[_a])[_pos];
Transaction t;
t.value = _endowment;
t.isCreation = true;
t.storage.reserve(_storage.size());
for (auto i: _storage)
t.storage.push_back(i);
t.gasPrice = gasPrice;
txs.push_back(t);
return right160(t.sha3(false));
}
u256 extroPrice(Address _a) { return get<2>(addresses[_a]); }
void suicide(Address _a)
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _txOut)
{
for (auto const& i: get<3>(addresses[myAddress]))
if (i.second)
get<0>(addresses[_a]) += fees.m_memoryFee;
get<0>(addresses[_a]) += get<0>(addresses[myAddress]);
addresses.erase(myAddress);
Transaction t;
t.isCreation = false;
t.value = _txValue;
t.data = _txData.toVector();
t.gas = *_gas;
t.gasPrice = gasPrice;
t.receiveAddress = _receiveAddress;
txs.push_back(t);
(void)_txOut;
return true;
}
void setTransaction(Address _txSender, u256 _txValue, u256s const& _txData)
void setTransaction(Address _txSender, u256 _txValue, u256 _gasPrice, bytes const& _txData)
{
txSender = _txSender;
txValue = _txValue;
txData = _txData;
txData = &_txData;
gasPrice = _gasPrice;
}
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s _myData)
void setContract(Address _myAddress, u256 _myBalance, u256 _myNonce, u256s const& _storage)
{
myAddress = _myAddress;
set(myAddress, _myBalance, _myNonce, _myData);
set(myAddress, _myBalance, _myNonce, _storage);
}
void set(Address _a, u256 _myBalance, u256 _myNonce, u256s _myData)
void set(Address _a, u256 _myBalance, u256 _myNonce, u256s const& _storage)
{
get<0>(addresses[_a]) = _myBalance;
get<1>(addresses[_a]) = _myNonce;
get<2>(addresses[_a]) = 0;
for (unsigned i = 0; i < _myData.size(); ++i)
get<3>(addresses[_a])[i] = _myData[i];
for (unsigned i = 0; i < _storage.size(); ++i)
get<3>(addresses[_a])[i] = _storage[i];
}
mObject exportEnv()
@ -106,7 +125,6 @@ public:
push(ret, "currentDifficulty", currentBlock.difficulty);
push(ret, "currentTimestamp", currentBlock.timestamp);
ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress);
push(ret, "feeMultiplier", fees.multiplier());
return ret;
}
@ -117,7 +135,6 @@ public:
currentBlock.difficulty = toInt(_o["currentDifficulty"]);
currentBlock.timestamp = toInt(_o["currentTimestamp"]);
currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str());
fees.setMultiplier(toInt(_o["feeMultiplier"]));
}
static u256 toInt(mValue const& _v)
@ -133,6 +150,19 @@ public:
return 0;
}
static byte toByte(mValue const& _v)
{
switch (_v.type())
{
case str_type: return (byte)stoi(_v.get_str());
case int_type: return (byte)_v.get_uint64();
case bool_type: return (byte)_v.get_bool();
case real_type: return (byte)_v.get_real();
default: cwarn << "Bad type for scalar: " << _v.type();
}
return 0;
}
static void push(mObject& o, string const& _n, u256 _v)
{
if (_v < (u256)1 << 64)
@ -157,7 +187,6 @@ public:
mObject o;
push(o, "balance", get<0>(a.second));
push(o, "nonce", get<1>(a.second));
push(o, "extroPrice", get<2>(a.second));
mObject store;
string curKey;
@ -197,7 +226,6 @@ public:
auto& a = addresses[Address(i.first)];
get<0>(a) = toInt(o["balance"]);
get<1>(a) = toInt(o["nonce"]);
get<2>(a) = toInt(o["extroPrice"]);
if (o.count("store"))
for (auto const& j: o["store"].get_obj())
{
@ -220,6 +248,7 @@ public:
ret["address"] = toString(myAddress);
ret["sender"] = toString(txSender);
push(ret, "value", txValue);
push(ret, "gasPrice", gasPrice);
mArray d;
for (auto const& i: txData)
push(d, i);
@ -232,8 +261,11 @@ public:
myAddress = Address(_o["address"].get_str());
txSender = Address(_o["sender"].get_str());
txValue = toInt(_o["value"]);
gasPrice = toInt(_o["gasPrice"]);
thisTxData.clear();
for (auto const& j: _o["data"].get_array())
txData.push_back(toInt(j));
thisTxData.push_back(toByte(j));
txData = &thisTxData;
}
mArray exportTxs()
@ -262,7 +294,7 @@ public:
t.receiveAddress = Address(tx["destination"].get_str());
t.value = toInt(tx["value"]);
for (auto const& j: tx["data"].get_array())
t.data.push_back(toInt(j));
t.data.push_back(toByte(j));
txs.push_back(t);
}
}
@ -276,6 +308,7 @@ public:
map<Address, tuple<u256, u256, u256, map<u256, u256>>> addresses;
Transactions txs;
bytes thisTxData;
};
#define CREATE_TESTS 0
@ -315,21 +348,37 @@ public:
if (_fillin)
o["pre"] = mValue(fev.exportState());
bytes output;
for (auto i: o["exec"].get_array())
{
fev.importExec(i.get_obj());
vm.go(fev);
output = vm.go(fev).toBytes();
}
if (_fillin)
{
o["post"] = mValue(fev.exportState());
o["txs"] = fev.exportTxs();
mArray df;
for (auto const& i: output)
FakeExtVM::push(df, i);
o["out"] = df;
}
else
{
FakeExtVM test;
test.importState(o["post"].get_obj());
test.importTxs(o["txs"].get_array());
int i = 0;
for (auto const& d: o["out"].get_array())
{
if (output[i] != FakeExtVM::toInt(d))
{
cwarn << "Test failed: output byte" << i << "different.";
passed = false;
}
++i;
}
if (test.addresses != fev.addresses)
{
cwarn << "Test failed: state different.";
@ -359,11 +408,11 @@ public:
cb.difficulty = 256;
cb.timestamp = 1;
cb.coinbaseAddress = toAddress(sha3("coinbase"));
FakeExtVM fev(fees, pb, cb, 0);
FakeExtVM fev(pb, cb, 0);
fev.setContract(toAddress(sha3("contract")), ether, 0, compileLisp("(suicide (txsender))"));
o["env"] = fev.exportEnv();
o["pre"] = fev.exportState();
fev.setTransaction(toAddress(sha3("sender")), ether, u256s());
fev.setTransaction(toAddress(sha3("sender")), ether, finney, bytes());
mArray execs;
execs.push_back(fev.exportExec());
o["exec"] = execs;

11
walleth/MainWin.cpp

@ -24,6 +24,7 @@ using eth::h160;
using eth::h256;
using eth::u160;
using eth::u256;
using eth::u256s;
using eth::Address;
using eth::BlockInfo;
using eth::Client;
@ -173,9 +174,14 @@ unsigned QEthereum::peerCount() const
return (unsigned)client()->peerCount();
}
void QEthereum::transact(Secret _secret, Address _dest, u256 _amount)
void QEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, QVector<u256> _storage)
{
client()->transact(_secret, _dest, _amount);
return client()->transact(_secret, _amount, _gasPrice, _storage.toStdVector());
}
void QEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _data)
{
client()->transact(_secret, _amount, _gasPrice, _dest, _gas, bytes(_data.data(), _data.data() + _data.size()));
}
Main::Main(QWidget *parent) :
@ -304,7 +310,6 @@ void Main::readSettings()
restoreGeometry(s.value("geometry").toByteArray());
restoreState(s.value("windowState").toByteArray());
QByteArray b = s.value("address").toByteArray();
if (b.isEmpty())
m_myKeys.append(KeyPair::create());

3
walleth/MainWin.h

@ -140,7 +140,8 @@ public:
Q_INVOKABLE QEthereum* self() { return this; }
public slots:
void transact(eth::Secret _secret, eth::Address _dest, eth::u256 _amount);
void transact(eth::Secret _secret, eth::Address _dest, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _data);
void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, QVector<eth::u256> _storage);
void setCoinbase(eth::Address);
void setMining(bool _l);

Loading…
Cancel
Save