Browse Source

CALLDATACOPY instruction.

Contract body gets created from init code.
cl-refactor
Gav Wood 11 years ago
parent
commit
f68a73b2a0
  1. 60
      alethzero/MainWin.cpp
  2. 1
      alethzero/MainWin.h
  3. 1
      libethereum/AddressState.h
  4. 5
      libethereum/Client.cpp
  5. 2
      libethereum/Client.h
  6. 1
      libethereum/FeeStructure.cpp
  7. 3
      libethereum/FeeStructure.h
  8. 4
      libethereum/Instruction.cpp
  9. 3
      libethereum/Instruction.h
  10. 2
      libethereum/PeerServer.cpp
  11. 115
      libethereum/State.cpp
  12. 10
      libethereum/State.h
  13. 20
      libethereum/Transaction.cpp
  14. 3
      libethereum/Transaction.h
  15. 35
      libethereum/VM.h
  16. 8
      libqethereum/QEthereum.cpp
  17. 4
      libqethereum/QEthereum.h
  18. 5
      neth/main.cpp
  19. 5
      test/vm.cpp

60
alethzero/MainWin.cpp

@ -45,6 +45,7 @@ using eth::Executive;
// functions // functions
using eth::toHex; using eth::toHex;
using eth::assemble; using eth::assemble;
using eth::pushLiteral;
using eth::compileLisp; using eth::compileLisp;
using eth::disassemble; using eth::disassemble;
using eth::formatBalance; using eth::formatBalance;
@ -581,10 +582,8 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Gas: <b>" << tx.gas << "</b>"; s << "<br/>Gas: <b>" << tx.gas << "</b>";
if (tx.isCreation()) if (tx.isCreation())
{ {
if (tx.init.size())
s << "<h4>Init</h4>" << disassemble(tx.init);
if (tx.data.size()) if (tx.data.size())
s << "<h4>Body</h4>" << disassemble(tx.data); s << "<h4>Code</h4>" << disassemble(tx.data);
} }
else else
{ {
@ -669,14 +668,15 @@ void Main::on_data_textChanged()
if (isCreation()) if (isCreation())
{ {
QString code = ui->data->toPlainText(); QString code = ui->data->toPlainText();
m_init.clear(); bytes initBytes;
bytes bodyBytes;
auto init = code.indexOf("init:"); auto init = code.indexOf("init:");
auto body = code.indexOf("body:"); auto body = code.indexOf("body:");
if (body == -1) if (body == -1)
body = code.indexOf("code:"); body = code.indexOf("code:");
if (body == -1 && init == -1) if (body == -1 && init == -1)
m_data = compileLisp(code.toStdString(), true, m_init); bodyBytes = compileLisp(code.toStdString(), true, initBytes);
else else
{ {
init = (init == -1 ? 0 : (init + 5)); init = (init == -1 ? 0 : (init + 5));
@ -685,16 +685,37 @@ void Main::on_data_textChanged()
auto initCode = code.mid(init, initSize).trimmed(); auto initCode = code.mid(init, initSize).trimmed();
auto bodyCode = code.mid(body).trimmed(); auto bodyCode = code.mid(body).trimmed();
if (QRegExp("[^0-9a-fA-F]").indexIn(initCode) == -1) if (QRegExp("[^0-9a-fA-F]").indexIn(initCode) == -1)
m_init = fromHex(initCode.toStdString()); initBytes = fromHex(initCode.toStdString());
else else
m_init = compileSerpent(initCode.toStdString()); initBytes = compileSerpent(initCode.toStdString());
if (QRegExp("[^0-9a-zA-Z]").indexIn(bodyCode) == -1) if (QRegExp("[^0-9a-zA-Z]").indexIn(bodyCode) == -1)
m_data = fromHex(bodyCode.toStdString()); bodyBytes = fromHex(bodyCode.toStdString());
else else
m_data = compileSerpent(bodyCode.toStdString()); bodyBytes = compileSerpent(bodyCode.toStdString());
} }
ui->code->setHtml((m_init.size() ? "<h4>Init</h4>" + QString::fromStdString(disassemble(m_init)).toHtmlEscaped() : "") + "<h4>Body</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped());
ui->gas->setMinimum((qint64)state().createGas(m_data.size() + m_init.size(), 0)); m_data.clear();
if (initBytes.size())
m_data = initBytes;
if (bodyBytes.size())
{
unsigned s = bodyBytes.size();
auto ss = pushLiteral(m_data, s);
unsigned p = m_data.size() + 4 + 2 + 1 + ss + 2 + 1;
pushLiteral(m_data, p);
pushLiteral(m_data, 0);
m_data.push_back((byte)Instruction::CALLDATACOPY);
pushLiteral(m_data, s);
pushLiteral(m_data, 0);
m_data.push_back((byte)Instruction::RETURN);
while (m_data.size() < p)
m_data.push_back(0);
for (auto b: bodyBytes)
m_data.push_back(b);
}
ui->code->setHtml("<h4>Code</h4>" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped());
ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0));
if (!ui->gas->isEnabled()) if (!ui->gas->isEnabled())
ui->gas->setValue(m_backupGas); ui->gas->setValue(m_backupGas);
ui->gas->setEnabled(true); ui->gas->setEnabled(true);
@ -861,7 +882,7 @@ void Main::on_send_clicked()
m_client->unlock(); m_client->unlock();
Secret s = i.secret(); Secret s = i.secret();
if (isCreation()) if (isCreation())
m_client->transact(s, value(), m_data, m_init, ui->gas->value(), gasPrice()); m_client->transact(s, value(), m_data, ui->gas->value(), gasPrice());
else else
m_client->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); m_client->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
refresh(); refresh();
@ -891,16 +912,7 @@ void Main::on_debug_clicked()
t.gasPrice = gasPrice(); t.gasPrice = gasPrice();
t.gas = ui->gas->value(); t.gas = ui->gas->value();
t.data = m_data; t.data = m_data;
if (isCreation()) t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText());
{
t.receiveAddress = Address();
t.init = m_init;
}
else
{
t.receiveAddress = fromString(ui->destination->currentText());
t.data = m_data;
}
t.sign(s); t.sign(s);
auto r = t.rlp(); auto r = t.rlp();
m_currentExecution->setup(&r); m_currentExecution->setup(&r);
@ -942,14 +954,14 @@ void Main::debugFinished()
ui->debugMemory->setHtml(""); ui->debugMemory->setHtml("");
ui->debugStorage->setHtml(""); ui->debugStorage->setHtml("");
ui->debugStateInfo->setText(""); ui->debugStateInfo->setText("");
ui->send->setEnabled(true); // ui->send->setEnabled(true);
ui->debugStep->setEnabled(false); ui->debugStep->setEnabled(false);
ui->debugPanel->setEnabled(false); ui->debugPanel->setEnabled(false);
} }
void Main::initDebugger() void Main::initDebugger()
{ {
ui->send->setEnabled(false); // ui->send->setEnabled(false);
ui->debugStep->setEnabled(true); ui->debugStep->setEnabled(true);
ui->debugPanel->setEnabled(true); ui->debugPanel->setEnabled(true);
ui->debugCode->setEnabled(false); ui->debugCode->setEnabled(false);

1
alethzero/MainWin.h

@ -113,7 +113,6 @@ private:
QList<eth::KeyPair> m_myKeys; QList<eth::KeyPair> m_myKeys;
bool m_keysChanged = false; bool m_keysChanged = false;
eth::bytes m_data; eth::bytes m_data;
eth::bytes m_init;
eth::Address m_nameReg; eth::Address m_nameReg;
unsigned m_backupGas; unsigned m_backupGas;

1
libethereum/AddressState.h

@ -59,6 +59,7 @@ public:
std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && isComplete()); return m_memory; } std::map<u256, u256> const& memory() const { assert(m_type == AddressType::Contract && isComplete()); return m_memory; }
bytes const& code() const { assert(m_type == AddressType::Contract && isComplete()); return m_code; } bytes const& code() const { assert(m_type == AddressType::Contract && isComplete()); return m_code; }
bool freshCode() const { return !m_codeHash && m_isComplete; } bool freshCode() const { return !m_codeHash && m_isComplete; }
void setCode(bytesConstRef _code) { assert(freshCode()); m_code = _code.toBytes(); }
private: private:
AddressType m_type; AddressType m_type;

5
libethereum/Client.cpp

@ -157,7 +157,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _
m_changed = true; m_changed = true;
} }
Address Client::transact(Secret _secret, u256 _endowment, bytes const& _code, bytes const& _init, u256 _gas, u256 _gasPrice) Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{ {
lock_guard<recursive_mutex> l(m_lock); lock_guard<recursive_mutex> l(m_lock);
Transaction t; Transaction t;
@ -166,8 +166,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _code, by
t.gasPrice = _gasPrice; t.gasPrice = _gasPrice;
t.gas = _gas; t.gas = _gas;
t.receiveAddress = Address(); t.receiveAddress = Address();
t.data = _code; t.data = _init;
t.init = _init;
t.sign(_secret); t.sign(_secret);
cnote << "New transaction " << t; cnote << "New transaction " << t;
m_tq.attemptImport(t.rlp()); m_tq.attemptImport(t.rlp());

2
libethereum/Client.h

@ -88,7 +88,7 @@ public:
/// Submits a new contract-creation transaction. /// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through). /// @returns the new contract's address (assuming it all goes through).
Address transact(Secret _secret, u256 _endowment, bytes const& _code, bytes const& _init = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo); Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Makes the given call. Nothing is recorded into the state. TODO /// 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()); // bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes());

1
libethereum/FeeStructure.cpp

@ -33,3 +33,4 @@ u256 const eth::c_createGas = 100;
u256 const eth::c_callGas = 20; u256 const eth::c_callGas = 20;
u256 const eth::c_memoryGas = 1; u256 const eth::c_memoryGas = 1;
u256 const eth::c_txDataGas = 5; u256 const eth::c_txDataGas = 5;
u256 const eth::c_txGas = 500;

3
libethereum/FeeStructure.h

@ -34,6 +34,7 @@ extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CRE
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
extern u256 const c_txDataGas; ///< Per byte of data attached to a message-call transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
} }

4
libethereum/Instruction.cpp

@ -56,6 +56,7 @@ const std::map<std::string, Instruction> eth::c_instructions =
{ "CALLVALUE", Instruction::CALLVALUE }, { "CALLVALUE", Instruction::CALLVALUE },
{ "CALLDATALOAD", Instruction::CALLDATALOAD }, { "CALLDATALOAD", Instruction::CALLDATALOAD },
{ "CALLDATASIZE", Instruction::CALLDATASIZE }, { "CALLDATASIZE", Instruction::CALLDATASIZE },
{ "CALLDATACOPY", Instruction::CALLDATACOPY },
{ "BASEFEE", Instruction::GASPRICE }, { "BASEFEE", Instruction::GASPRICE },
{ "PREVHASH", Instruction::PREVHASH }, { "PREVHASH", Instruction::PREVHASH },
{ "COINBASE", Instruction::COINBASE }, { "COINBASE", Instruction::COINBASE },
@ -142,6 +143,7 @@ const std::map<Instruction, InstructionInfo> eth::c_instructionInfo =
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } }, { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } },
{ Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } }, { Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } },
{ Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 0, 1 } }, { Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 0, 1 } },
{ Instruction::CALLDATACOPY, { "CALLDATACOPY", 0, 3, 0 } },
{ Instruction::GASPRICE, { "BASEFEE", 0, 0, 1 } }, { Instruction::GASPRICE, { "BASEFEE", 0, 0, 1 } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } }, { Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1 } }, { Instruction::COINBASE, { "COINBASE", 0, 0, 1 } },
@ -313,7 +315,7 @@ static void pushLocation(bytes& o_code, uint32_t _locationValue)
toBigEndian(_locationValue, r); toBigEndian(_locationValue, r);
} }
static unsigned pushLiteral(bytes& o_code, u256 _literalValue) unsigned eth::pushLiteral(bytes& o_code, u256 _literalValue)
{ {
unsigned br = max<unsigned>(1, bytesRequired(_literalValue)); unsigned br = max<unsigned>(1, bytesRequired(_literalValue));
o_code.push_back((byte)Instruction::PUSH1 + br - 1); o_code.push_back((byte)Instruction::PUSH1 + br - 1);

3
libethereum/Instruction.h

@ -60,6 +60,7 @@ enum class Instruction: uint8_t
CALLVALUE, CALLVALUE,
CALLDATALOAD, CALLDATALOAD,
CALLDATASIZE, CALLDATASIZE,
CALLDATACOPY,
GASPRICE, GASPRICE,
PREVHASH = 0x40, PREVHASH = 0x40,
@ -146,4 +147,6 @@ std::string disassemble(bytes const& _mem);
/// Compile a Low-level Lisp-like Language program into EVM-code. /// Compile a Low-level Lisp-like Language program into EVM-code.
bytes compileLisp(std::string const& _code, bool _quiet, bytes& _init); bytes compileLisp(std::string const& _code, bool _quiet, bytes& _init);
unsigned pushLiteral(bytes& o_code, u256 _literalValue);
} }

2
libethereum/PeerServer.cpp

@ -115,7 +115,7 @@ PeerServer::~PeerServer()
unsigned PeerServer::protocolVersion() unsigned PeerServer::protocolVersion()
{ {
return 12; return 13;
} }
void PeerServer::determinePublic(string const& _publicAddress, bool _upnp) void PeerServer::determinePublic(string const& _publicAddress, bool _upnp)

115
libethereum/State.cpp

@ -631,11 +631,7 @@ void Executive::setup(bytesConstRef _rlp)
} }
// Check gas cost is enough. // Check gas cost is enough.
u256 gasCost; u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas;
if (m_t.isCreation())
gasCost = (m_t.init.size() + m_t.data.size()) * c_txDataGas + c_createGas;
else
gasCost = m_t.data.size() * c_txDataGas + c_callGas;
if (m_t.gas < gasCost) if (m_t.gas < gasCost)
{ {
@ -662,7 +658,7 @@ void Executive::setup(bytesConstRef _rlp)
m_s.subBalance(sender, cost); m_s.subBalance(sender, cost);
if (m_t.isCreation()) if (m_t.isCreation())
create(sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, &m_t.init, sender); create(sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, sender);
else else
call(m_t.receiveAddress, sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, sender); call(m_t.receiveAddress, sender, m_t.value, m_t.gasPrice, bytesConstRef(&m_t.data), m_t.gas - gasCost, sender);
} }
@ -681,18 +677,18 @@ void Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
m_endGas = _gas; m_endGas = _gas;
} }
void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, bytesConstRef _init, Address _origin) void Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _init, Address _origin)
{ {
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1))); m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
while (m_s.isContractAddress(m_newAddress) || m_s.isNormalAddress(m_newAddress)) while (m_s.isContractAddress(m_newAddress) || m_s.isNormalAddress(m_newAddress))
m_newAddress = (u160)m_newAddress + 1; m_newAddress = (u160)m_newAddress + 1;
// Set up new account... // Set up new account...
m_s.m_cache[m_newAddress] = AddressState(0, 0, _code); m_s.m_cache[m_newAddress] = AddressState(0, 0, bytesConstRef());
// Execute _init. // Execute _init.
m_vm = new VM(_gas); m_vm = new VM(_gas);
m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init); m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, _init, _init);
} }
bool Executive::go(uint64_t _steps) bool Executive::go(uint64_t _steps)
@ -702,7 +698,7 @@ bool Executive::go(uint64_t _steps)
bool revert = false; bool revert = false;
try try
{ {
m_vm->go(*m_ext, _steps); m_out = m_vm->go(*m_ext, _steps);
m_endGas = m_vm->gas(); m_endGas = m_vm->gas();
} }
catch (StepsDone const&) catch (StepsDone const&)
@ -751,6 +747,10 @@ void Executive::finalize()
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_ext->origin, m_endGas * m_ext->gasPrice); m_s.addBalance(m_ext->origin, m_endGas * m_ext->gasPrice);
if (m_t.isCreation() && m_newAddress && m_out.size())
// non-reverted creation - put code in place.
m_s.m_cache[m_newAddress].setCode(m_out);
u256 gasSpent = (m_startGas - m_endGas) * m_ext->gasPrice; u256 gasSpent = (m_startGas - m_endGas) * m_ext->gasPrice;
/* unsigned c_feesKept = 8; /* unsigned c_feesKept = 8;
u256 feesEarned = gasSpent - (gasSpent / c_feesKept); u256 feesEarned = gasSpent - (gasSpent / c_feesKept);
@ -763,78 +763,16 @@ void Executive::finalize()
void State::execute(bytesConstRef _rlp) void State::execute(bytesConstRef _rlp)
{ {
// Entry point for a user-executed transaction. Executive e(*this);
Transaction t(_rlp);
auto sender = t.sender();
// Avoid invalid transactions.
auto nonceReq = transactionsFrom(sender);
if (t.nonce != nonceReq)
{
clog(StateChat) << "Invalid Nonce.";
throw InvalidNonce(nonceReq, t.nonce);
}
// Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going.
if (t.gasPrice < 10 * szabo)
{
clog(StateChat) << "Offered gas-price is too low.";
throw GasPriceTooLow();
}
// Check gas cost is enough.
u256 gasCost;
if (t.isCreation())
gasCost = (t.init.size() + t.data.size()) * c_txDataGas + c_createGas;
else
gasCost = t.data.size() * c_txDataGas + c_callGas;
if (t.gas < gasCost)
{
clog(StateChat) << "Not enough gas to pay for the transaction.";
throw OutOfGas();
}
u256 cost = t.value + t.gas * t.gasPrice;
// Avoid unaffordable transactions.
if (balance(sender) < cost)
{ {
clog(StateChat) << "Not enough cash."; e.setup(_rlp);
throw NotEnoughCash(); e.go();
e.finalize();
} }
u256 gas = t.gas - gasCost;
// Increment associated nonce for sender.
noteSending(sender);
// Pay...
// cnote << "Paying" << formatBalance(cost) << "from sender (includes" << t.gas << "gas at" << formatBalance(t.gasPrice) << ")";
subBalance(sender, cost);
if (t.isCreation())
create(sender, t.value, t.gasPrice, &gas, &t.data, &t.init);
else
call(t.receiveAddress, sender, t.value, t.gasPrice, bytesConstRef(&t.data), &gas, bytesRef());
// cnote << "Refunding" << formatBalance(gas * t.gasPrice) << "to sender (=" << gas << "*" << formatBalance(t.gasPrice) << ")";
addBalance(sender, gas * t.gasPrice);
u256 gasSpent = (t.gas - gas) * t.gasPrice;
/* unsigned c_feesKept = 8;
u256 feesEarned = gasSpent - (gasSpent / c_feesKept);
cnote << "Transferring" << (100.0 - 100.0 / c_feesKept) << "% of" << formatBalance(gasSpent) << "=" << formatBalance(feesEarned) << "to miner (" << formatBalance(gasSpent - feesEarned) << "is burnt).";
*/
u256 feesEarned = gasSpent;
// cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
addBalance(m_currentBlock.coinbaseAddress, feesEarned);
// !!!!!!!!!!!!!!!!!!!!! If moving to use Executive, this still needs to be done - Executive won't do it.
// Add to the user-originated transactions that we've executed. // Add to the user-originated transactions that we've executed.
m_transactions.push_back(t); m_transactions.push_back(e.t());
m_transactionSet.insert(t.sha3()); m_transactionSet.insert(e.t().sha3());
} }
bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress) bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress)
@ -885,7 +823,7 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
return true; return true;
} }
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init, Address _origin) h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin)
{ {
if (!_origin) if (!_origin)
_origin = _sender; _origin = _sender;
@ -895,18 +833,17 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
newAddress = (u160)newAddress + 1; newAddress = (u160)newAddress + 1;
// Set up new account... // Set up new account...
m_cache[newAddress] = AddressState(0, 0, _code); m_cache[newAddress] = AddressState(0, 0, {});
// Execute _init. // Execute _init.
VM vm(*_gas); VM vm(*_gas);
ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init); ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code);
bool revert = false; bool revert = false;
bytesConstRef out;
try try
{ {
/*auto out =*/ vm.go(evm); out = vm.go(evm);
// Don't do anything with the output (yet).
//memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {
@ -926,13 +863,19 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
clog(StateChat) << "std::exception in VM: " << _e.what(); clog(StateChat) << "std::exception in VM: " << _e.what();
} }
// Write state out only in the case of a non-excepted transaction. // Write state out only in the case of a non-out-of-gas transaction.
if (revert) if (revert)
{
evm.revert(); evm.revert();
// Kill contract if there's no code.
if (out.empty())
{
m_cache.erase(newAddress); m_cache.erase(newAddress);
newAddress = Address(); newAddress = Address();
} }
else
m_cache[newAddress].setCode(out);
*_gas = vm.gas(); *_gas = vm.gas();

10
libethereum/State.h

@ -61,11 +61,13 @@ public:
~Executive(); ~Executive();
void setup(bytesConstRef _transaction); void setup(bytesConstRef _transaction);
void create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, bytesConstRef _init, Address _originAddress); void create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress);
void call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); void call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress);
bool go(uint64_t _steps = (unsigned)-1); bool go(uint64_t _steps = (unsigned)-1);
void finalize(); void finalize();
Transaction const& t() const { return m_t; }
u256 gas() const; u256 gas() const;
bytesConstRef out() const { return m_out; } bytesConstRef out() const { return m_out; }
@ -244,7 +246,7 @@ private:
// We assume all instrinsic fees are paid up before this point. // We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction. /// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, bytesConstRef _init, Address _originAddress = Address()); h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address());
/// Execute a call. /// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly. /// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
@ -309,12 +311,12 @@ public:
m_store->erase(_n); m_store->erase(_n);
} }
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) h160 create(u256 _endowment, u256* _gas, bytesConstRef _code)
{ {
// Increment associated nonce for sender. // Increment associated nonce for sender.
m_s.noteSending(myAddress); m_s.noteSending(myAddress);
return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, _init, origin); return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin);
} }
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out) bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)

20
libethereum/Transaction.cpp

@ -36,17 +36,11 @@ Transaction::Transaction(bytesConstRef _rlpData)
try try
{ {
nonce = rlp[field = 0].toInt<u256>(); nonce = rlp[field = 0].toInt<u256>();
value = rlp[field = 1].toInt<u256>(); gasPrice = rlp[field = 1].toInt<u256>();
receiveAddress = rlp[field = 2].toHash<Address>(); gas = rlp[field = 2].toInt<u256>();
gasPrice = rlp[field = 3].toInt<u256>(); receiveAddress = rlp[field = 3].toHash<Address>();
gas = rlp[field = 4].toInt<u256>(); value = rlp[field = 4].toInt<u256>();
data = rlp[field = 5].toBytes(); data = rlp[field = 5].toBytes();
if (isCreation())
{
init = rlp[field = 6].toBytes();
vrs = Signature{ rlp[field = 7].toInt<byte>(), rlp[field = 8].toInt<u256>(), rlp[field = 9].toInt<u256>() };
}
else
vrs = Signature{ rlp[field = 6].toInt<byte>(), rlp[field = 7].toInt<u256>(), rlp[field = 8].toInt<u256>() }; vrs = Signature{ rlp[field = 6].toInt<byte>(), rlp[field = 7].toInt<u256>(), rlp[field = 8].toInt<u256>() };
} }
catch (RLPException const&) catch (RLPException const&)
@ -119,10 +113,8 @@ void Transaction::sign(Secret _priv)
void Transaction::fillStream(RLPStream& _s, bool _sig) const void Transaction::fillStream(RLPStream& _s, bool _sig) const
{ {
_s.appendList((_sig ? 3 : 0) + (isCreation() ? 7 : 6)); _s.appendList((_sig ? 3 : 0) + 6);
_s << nonce << value << receiveAddress << gasPrice << gas << data; _s << nonce << gasPrice << gas << receiveAddress << value << data;
if (isCreation())
_s << init;
if (_sig) if (_sig)
_s << vrs.v << vrs.r << vrs.s; _s << vrs.v << vrs.r << vrs.s;
} }

3
libethereum/Transaction.h

@ -52,8 +52,7 @@ struct Transaction
u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS. u256 gasPrice; ///< The base fee and thus the implied exchange rate of ETH to GAS.
u256 gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended. u256 gas; ///< The total gas to convert, paid for from sender's account. Any unused gas gets refunded once the contract is ended.
bytes data; ///< The data associated with the transaction, or the main body if it's a creation transaction. bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction.
bytes init; ///< The initialisation associated with the transaction.
Signature vrs; ///< The signature of the transaction. Encodes the sender. Signature vrs; ///< The signature of the transaction. Encodes the sender.

35
libethereum/VM.h

@ -133,6 +133,10 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
runGas = c_sha3Gas; runGas = c_sha3Gas;
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2]; newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 2];
break; break;
case Instruction::CALLDATACOPY:
require(3);
newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 3];
break;
case Instruction::BALANCE: case Instruction::BALANCE:
runGas = c_balanceGas; runGas = c_balanceGas;
@ -147,19 +151,10 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::CREATE: case Instruction::CREATE:
{ {
require(3); require(3);
u256 gas = (unsigned)m_stack[m_stack.size() - 1];
unsigned inOff = (unsigned)m_stack[m_stack.size() - 2]; unsigned inOff = (unsigned)m_stack[m_stack.size() - 2];
unsigned inSize = (unsigned)m_stack[m_stack.size() - 3]; unsigned inSize = (unsigned)m_stack[m_stack.size() - 3];
newTempSize = inOff + inSize; newTempSize = inOff + inSize;
runGas += c_createGas;
unsigned wc = std::min(inSize / 32 * 32 + inOff, (unsigned)m_temp.size());
unsigned nonZero = 0;
for (unsigned i = inOff; i < wc; i += 32)
if (!!*(h256*)(m_temp.data() + inOff))
nonZero++;
runGas += c_createGas + nonZero * c_sstoreGas + gas;
break; break;
} }
@ -324,6 +319,18 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
case Instruction::CALLDATASIZE: case Instruction::CALLDATASIZE:
m_stack.push_back(_ext.data.size()); m_stack.push_back(_ext.data.size());
break; break;
case Instruction::CALLDATACOPY:
{
require(3);
unsigned mf = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned cf = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned l = (unsigned)m_stack.back();
m_stack.pop_back();
memcpy(m_temp.data() + mf, _ext.data.data() + cf, l);
break;
}
case Instruction::GASPRICE: case Instruction::GASPRICE:
m_stack.push_back(_ext.gasPrice); m_stack.push_back(_ext.gasPrice);
break; break;
@ -477,14 +484,10 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
break; break;
case Instruction::CREATE: case Instruction::CREATE:
{ {
require(5); require(3);
u256 endowment = m_stack.back(); u256 endowment = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned codeOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned codeSize = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned initOff = (unsigned)m_stack.back(); unsigned initOff = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned initSize = (unsigned)m_stack.back(); unsigned initSize = (unsigned)m_stack.back();
@ -493,7 +496,7 @@ template <class Ext> eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps)
if (_ext.balance(_ext.myAddress) >= endowment) if (_ext.balance(_ext.myAddress) >= endowment)
{ {
_ext.subBalance(endowment); _ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + codeOff, codeSize), bytesConstRef(m_temp.data() + initOff, initSize))); m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + initOff, initSize)));
} }
else else
m_stack.push_back(0); m_stack.push_back(0);

8
libqethereum/QEthereum.cpp

@ -166,9 +166,9 @@ unsigned QmlEthereum::peerCount() const
return (unsigned)client()->peerCount(); return (unsigned)client()->peerCount();
} }
void QmlEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _code, QByteArray _init) void QmlEthereum::transact(Secret _secret, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _init)
{ {
client()->transact(_secret, _amount, bytes(_code.data(), _code.data() + _code.size()), bytes(_init.data(), _init.data() + _init.size()), _gas, _gasPrice); client()->transact(_secret, _amount, bytes(_init.data(), _init.data() + _init.size()), _gas, _gasPrice);
} }
void QmlEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _data) void QmlEthereum::transact(Secret _secret, Address _dest, u256 _amount, u256 _gasPrice, u256 _gas, QByteArray _data)
@ -307,9 +307,9 @@ unsigned QEthereum::peerCount() const
return (unsigned)client()->peerCount(); return (unsigned)client()->peerCount();
} }
QVariant QEthereum::create(QVariant _secret, QVariant _amount, QByteArray _code, QByteArray _init, QVariant _gas, QVariant _gasPrice) QVariant QEthereum::create(QVariant _secret, QVariant _amount, QByteArray _init, QVariant _gas, QVariant _gasPrice)
{ {
return toQJS(client()->transact(to<Secret>(_secret), to<u256>(_amount), bytes(_code.data(), _code.data() + _code.size()), bytes(_init.data(), _init.data() + _init.size()), to<u256>(_gas), to<u256>(_gasPrice))); return toQJS(client()->transact(to<Secret>(_secret), to<u256>(_amount), bytes(_init.data(), _init.data() + _init.size()), to<u256>(_gas), to<u256>(_gasPrice)));
} }
void QEthereum::transact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice) void QEthereum::transact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice)

4
libqethereum/QEthereum.h

@ -140,7 +140,7 @@ public:
public slots: public slots:
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::Address _dest, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _data);
void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _code, QByteArray _init); void transact(eth::Secret _secret, eth::u256 _amount, eth::u256 _gasPrice, eth::u256 _gas, QByteArray _init);
void setCoinbase(eth::Address); void setCoinbase(eth::Address);
void setMining(bool _l); void setMining(bool _l);
@ -314,7 +314,7 @@ public:
Q_INVOKABLE QEthereum* self() { return this; } Q_INVOKABLE QEthereum* self() { return this; }
Q_INVOKABLE QVariant create(QVariant _secret, QVariant _amount, QByteArray _code, QByteArray _init, QVariant _gas, QVariant _gasPrice); Q_INVOKABLE QVariant create(QVariant _secret, QVariant _amount, QByteArray _init, QVariant _gas, QVariant _gasPrice);
Q_INVOKABLE void transact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice); Q_INVOKABLE void transact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice);
eth::u256 balanceAt(eth::Address _a) const; eth::u256 balanceAt(eth::Address _a) const;

5
neth/main.cpp

@ -707,17 +707,14 @@ int main(int argc, char** argv)
cwarn << "No code submitted"; cwarn << "No code submitted";
else else
{ {
bytes code = fromHex(scode);
cnote << "Assembled:"; cnote << "Assembled:";
stringstream ssc; stringstream ssc;
ssc << disassemble(code);
cnote << ssc.str();
bytes init = fromHex(sinit); bytes init = fromHex(sinit);
ssc.str(string()); ssc.str(string());
ssc << disassemble(init); ssc << disassemble(init);
cnote << "Init:"; cnote << "Init:";
cnote << ssc.str(); cnote << ssc.str();
c.transact(us.secret(), endowment, code, init, gas, gasPrice); c.transact(us.secret(), endowment, init, gas, gasPrice);
} }
} }
} }

5
test/vm.cpp

@ -70,14 +70,13 @@ public:
txs.push_back(_t); txs.push_back(_t);
} }
} }
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) h160 create(u256 _endowment, u256* _gas, bytesConstRef _init)
{ {
Transaction t; Transaction t;
t.value = _endowment; t.value = _endowment;
t.gasPrice = gasPrice; t.gasPrice = gasPrice;
t.gas = *_gas; t.gas = *_gas;
t.data = _code.toBytes(); t.data = _init.toBytes();
t.init = _init.toBytes();
txs.push_back(t); txs.push_back(t);
return right160(t.sha3(false)); return right160(t.sha3(false));
} }

Loading…
Cancel
Save