From f68a73b2a04c1bb946f42d84342978aaec5f64cf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 23 Apr 2014 20:37:16 +0100 Subject: [PATCH] CALLDATACOPY instruction. Contract body gets created from init code. --- alethzero/MainWin.cpp | 60 ++++++++++-------- alethzero/MainWin.h | 1 - libethereum/AddressState.h | 1 + libethereum/Client.cpp | 5 +- libethereum/Client.h | 2 +- libethereum/FeeStructure.cpp | 1 + libethereum/FeeStructure.h | 3 +- libethereum/Instruction.cpp | 4 +- libethereum/Instruction.h | 3 + libethereum/PeerServer.cpp | 2 +- libethereum/State.cpp | 115 +++++++++-------------------------- libethereum/State.h | 10 +-- libethereum/Transaction.cpp | 22 +++---- libethereum/Transaction.h | 3 +- libethereum/VM.h | 35 ++++++----- libqethereum/QEthereum.cpp | 8 +-- libqethereum/QEthereum.h | 4 +- neth/main.cpp | 5 +- test/vm.cpp | 5 +- 19 files changed, 121 insertions(+), 168 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b6c2b00de..913a6e2e7 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -45,6 +45,7 @@ using eth::Executive; // functions using eth::toHex; using eth::assemble; +using eth::pushLiteral; using eth::compileLisp; using eth::disassemble; using eth::formatBalance; @@ -581,10 +582,8 @@ void Main::on_blocks_currentItemChanged() s << "
Gas: " << tx.gas << ""; if (tx.isCreation()) { - if (tx.init.size()) - s << "

Init

" << disassemble(tx.init); if (tx.data.size()) - s << "

Body

" << disassemble(tx.data); + s << "

Code

" << disassemble(tx.data); } else { @@ -669,14 +668,15 @@ void Main::on_data_textChanged() if (isCreation()) { QString code = ui->data->toPlainText(); - m_init.clear(); + bytes initBytes; + bytes bodyBytes; auto init = code.indexOf("init:"); auto body = code.indexOf("body:"); if (body == -1) body = code.indexOf("code:"); if (body == -1 && init == -1) - m_data = compileLisp(code.toStdString(), true, m_init); + bodyBytes = compileLisp(code.toStdString(), true, initBytes); else { init = (init == -1 ? 0 : (init + 5)); @@ -685,16 +685,37 @@ void Main::on_data_textChanged() auto initCode = code.mid(init, initSize).trimmed(); auto bodyCode = code.mid(body).trimmed(); if (QRegExp("[^0-9a-fA-F]").indexIn(initCode) == -1) - m_init = fromHex(initCode.toStdString()); + initBytes = fromHex(initCode.toStdString()); else - m_init = compileSerpent(initCode.toStdString()); + initBytes = compileSerpent(initCode.toStdString()); if (QRegExp("[^0-9a-zA-Z]").indexIn(bodyCode) == -1) - m_data = fromHex(bodyCode.toStdString()); + bodyBytes = fromHex(bodyCode.toStdString()); else - m_data = compileSerpent(bodyCode.toStdString()); + bodyBytes = compileSerpent(bodyCode.toStdString()); } - ui->code->setHtml((m_init.size() ? "

Init

" + QString::fromStdString(disassemble(m_init)).toHtmlEscaped() : "") + "

Body

" + 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("

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); + ui->gas->setMinimum((qint64)state().createGas(m_data.size(), 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -861,7 +882,7 @@ void Main::on_send_clicked() m_client->unlock(); Secret s = i.secret(); 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 m_client->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); refresh(); @@ -891,16 +912,7 @@ void Main::on_debug_clicked() t.gasPrice = gasPrice(); t.gas = ui->gas->value(); t.data = m_data; - if (isCreation()) - { - t.receiveAddress = Address(); - t.init = m_init; - } - else - { - t.receiveAddress = fromString(ui->destination->currentText()); - t.data = m_data; - } + t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.sign(s); auto r = t.rlp(); m_currentExecution->setup(&r); @@ -942,14 +954,14 @@ void Main::debugFinished() ui->debugMemory->setHtml(""); ui->debugStorage->setHtml(""); ui->debugStateInfo->setText(""); - ui->send->setEnabled(true); +// ui->send->setEnabled(true); ui->debugStep->setEnabled(false); ui->debugPanel->setEnabled(false); } void Main::initDebugger() { - ui->send->setEnabled(false); +// ui->send->setEnabled(false); ui->debugStep->setEnabled(true); ui->debugPanel->setEnabled(true); ui->debugCode->setEnabled(false); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 7e281c8c8..b61390416 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -113,7 +113,6 @@ private: QList m_myKeys; bool m_keysChanged = false; eth::bytes m_data; - eth::bytes m_init; eth::Address m_nameReg; unsigned m_backupGas; diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h index 154858e07..9adbbb32c 100644 --- a/libethereum/AddressState.h +++ b/libethereum/AddressState.h @@ -59,6 +59,7 @@ public: std::map 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; } bool freshCode() const { return !m_codeHash && m_isComplete; } + void setCode(bytesConstRef _code) { assert(freshCode()); m_code = _code.toBytes(); } private: AddressType m_type; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index c19efbe8d..7007ae91a 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -157,7 +157,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ 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 l(m_lock); Transaction t; @@ -166,8 +166,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _code, by t.gasPrice = _gasPrice; t.gas = _gas; t.receiveAddress = Address(); - t.data = _code; - t.init = _init; + t.data = _init; t.sign(_secret); cnote << "New transaction " << t; m_tq.attemptImport(t.rlp()); diff --git a/libethereum/Client.h b/libethereum/Client.h index 0089b8a23..6075b0224 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -88,7 +88,7 @@ public: /// Submits a new contract-creation transaction. /// @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 // bytes call(Secret _secret, u256 _amount, u256 _gasPrice, Address _dest, u256 _gas, bytes _data = bytes()); diff --git a/libethereum/FeeStructure.cpp b/libethereum/FeeStructure.cpp index c75835b49..f7dbbfbf8 100644 --- a/libethereum/FeeStructure.cpp +++ b/libethereum/FeeStructure.cpp @@ -33,3 +33,4 @@ u256 const eth::c_createGas = 100; u256 const eth::c_callGas = 20; u256 const eth::c_memoryGas = 1; u256 const eth::c_txDataGas = 5; +u256 const eth::c_txGas = 500; diff --git a/libethereum/FeeStructure.h b/libethereum/FeeStructure.h index c4f493954..42d6967aa 100644 --- a/libethereum/FeeStructure.h +++ b/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_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_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. } diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 3d7db5c9e..1af9511ac 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -56,6 +56,7 @@ const std::map eth::c_instructions = { "CALLVALUE", Instruction::CALLVALUE }, { "CALLDATALOAD", Instruction::CALLDATALOAD }, { "CALLDATASIZE", Instruction::CALLDATASIZE }, + { "CALLDATACOPY", Instruction::CALLDATACOPY }, { "BASEFEE", Instruction::GASPRICE }, { "PREVHASH", Instruction::PREVHASH }, { "COINBASE", Instruction::COINBASE }, @@ -142,6 +143,7 @@ const std::map eth::c_instructionInfo = { Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } }, { Instruction::CALLDATALOAD, { "CALLDATALOAD", 0, 1, 1 } }, { Instruction::CALLDATASIZE, { "CALLDATASIZE", 0, 0, 1 } }, + { Instruction::CALLDATACOPY, { "CALLDATACOPY", 0, 3, 0 } }, { Instruction::GASPRICE, { "BASEFEE", 0, 0, 1 } }, { Instruction::PREVHASH, { "PREVHASH", 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); } -static unsigned pushLiteral(bytes& o_code, u256 _literalValue) +unsigned eth::pushLiteral(bytes& o_code, u256 _literalValue) { unsigned br = max(1, bytesRequired(_literalValue)); o_code.push_back((byte)Instruction::PUSH1 + br - 1); diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h index 7fddec181..342076399 100644 --- a/libethereum/Instruction.h +++ b/libethereum/Instruction.h @@ -60,6 +60,7 @@ enum class Instruction: uint8_t CALLVALUE, CALLDATALOAD, CALLDATASIZE, + CALLDATACOPY, GASPRICE, PREVHASH = 0x40, @@ -146,4 +147,6 @@ std::string disassemble(bytes const& _mem); /// Compile a Low-level Lisp-like Language program into EVM-code. bytes compileLisp(std::string const& _code, bool _quiet, bytes& _init); +unsigned pushLiteral(bytes& o_code, u256 _literalValue); + } diff --git a/libethereum/PeerServer.cpp b/libethereum/PeerServer.cpp index 1784ef49a..e86289d2c 100644 --- a/libethereum/PeerServer.cpp +++ b/libethereum/PeerServer.cpp @@ -115,7 +115,7 @@ PeerServer::~PeerServer() unsigned PeerServer::protocolVersion() { - return 12; + return 13; } void PeerServer::determinePublic(string const& _publicAddress, bool _upnp) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 9a587915b..73cd4684c 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -631,11 +631,7 @@ void Executive::setup(bytesConstRef _rlp) } // Check gas cost is enough. - u256 gasCost; - 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; + u256 gasCost = m_t.data.size() * c_txDataGas + c_txGas; if (m_t.gas < gasCost) { @@ -662,7 +658,7 @@ void Executive::setup(bytesConstRef _rlp) m_s.subBalance(sender, cost); 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 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; } -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))); while (m_s.isContractAddress(m_newAddress) || m_s.isNormalAddress(m_newAddress)) m_newAddress = (u160)m_newAddress + 1; // 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. 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) @@ -702,7 +698,7 @@ bool Executive::go(uint64_t _steps) bool revert = false; try { - m_vm->go(*m_ext, _steps); + m_out = m_vm->go(*m_ext, _steps); m_endGas = m_vm->gas(); } 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) << ")"; 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; /* unsigned c_feesKept = 8; u256 feesEarned = gasSpent - (gasSpent / c_feesKept); @@ -763,78 +763,16 @@ void Executive::finalize() void State::execute(bytesConstRef _rlp) { - // Entry point for a user-executed transaction. - Transaction t(_rlp); - - auto sender = t.sender(); - - // Avoid invalid transactions. - auto nonceReq = transactionsFrom(sender); - if (t.nonce != nonceReq) + Executive e(*this); { - clog(StateChat) << "Invalid Nonce."; - throw InvalidNonce(nonceReq, t.nonce); + e.setup(_rlp); + e.go(); + e.finalize(); } - // 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."; - throw NotEnoughCash(); - } - - 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. - m_transactions.push_back(t); - m_transactionSet.insert(t.sha3()); + m_transactions.push_back(e.t()); + 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) @@ -885,7 +823,7 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u 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) _origin = _sender; @@ -895,18 +833,17 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, newAddress = (u160)newAddress + 1; // Set up new account... - m_cache[newAddress] = AddressState(0, 0, _code); + m_cache[newAddress] = AddressState(0, 0, {}); // Execute _init. 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; + bytesConstRef out; try { - /*auto out =*/ vm.go(evm); - // Don't do anything with the output (yet). - //memcpy(_out.data(), out.data(), std::min(out.size(), _out.size())); + out = vm.go(evm); } 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(); } - // 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) - { evm.revert(); + + // Kill contract if there's no code. + if (out.empty()) + { m_cache.erase(newAddress); newAddress = Address(); } + else + m_cache[newAddress].setCode(out); + *_gas = vm.gas(); diff --git a/libethereum/State.h b/libethereum/State.h index e0dc6dae2..1895a6684 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -61,11 +61,13 @@ public: ~Executive(); 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); bool go(uint64_t _steps = (unsigned)-1); void finalize(); + Transaction const& t() const { return m_t; } + u256 gas() const; bytesConstRef out() const { return m_out; } @@ -244,7 +246,7 @@ private: // We assume all instrinsic fees are paid up before this point. /// 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. /// @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); } - h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) + h160 create(u256 _endowment, u256* _gas, bytesConstRef _code) { // Increment associated nonce for sender. 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) diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 21b162ed4..828d85846 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -36,18 +36,12 @@ Transaction::Transaction(bytesConstRef _rlpData) try { nonce = rlp[field = 0].toInt(); - value = rlp[field = 1].toInt(); - receiveAddress = rlp[field = 2].toHash
(); - gasPrice = rlp[field = 3].toInt(); - gas = rlp[field = 4].toInt(); + gasPrice = rlp[field = 1].toInt(); + gas = rlp[field = 2].toInt(); + receiveAddress = rlp[field = 3].toHash
(); + value = rlp[field = 4].toInt(); data = rlp[field = 5].toBytes(); - if (isCreation()) - { - init = rlp[field = 6].toBytes(); - vrs = Signature{ rlp[field = 7].toInt(), rlp[field = 8].toInt(), rlp[field = 9].toInt() }; - } - else - vrs = Signature{ rlp[field = 6].toInt(), rlp[field = 7].toInt(), rlp[field = 8].toInt() }; + vrs = Signature{ rlp[field = 6].toInt(), rlp[field = 7].toInt(), rlp[field = 8].toInt() }; } catch (RLPException const&) { @@ -119,10 +113,8 @@ void Transaction::sign(Secret _priv) void Transaction::fillStream(RLPStream& _s, bool _sig) const { - _s.appendList((_sig ? 3 : 0) + (isCreation() ? 7 : 6)); - _s << nonce << value << receiveAddress << gasPrice << gas << data; - if (isCreation()) - _s << init; + _s.appendList((_sig ? 3 : 0) + 6); + _s << nonce << gasPrice << gas << receiveAddress << value << data; if (_sig) _s << vrs.v << vrs.r << vrs.s; } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 7d557b6fa..fe37f2ee8 100644 --- a/libethereum/Transaction.h +++ b/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 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 init; ///< The initialisation associated with the transaction. + bytes data; ///< The data associated with the transaction, or the initialiser if it's a creation transaction. Signature vrs; ///< The signature of the transaction. Encodes the sender. diff --git a/libethereum/VM.h b/libethereum/VM.h index 64095725b..da2a7aef8 100644 --- a/libethereum/VM.h +++ b/libethereum/VM.h @@ -133,6 +133,10 @@ template 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::CALLDATACOPY: + require(3); + newTempSize = (unsigned)m_stack.back() + (unsigned)m_stack[m_stack.size() - 3]; + break; case Instruction::BALANCE: runGas = c_balanceGas; @@ -147,19 +151,10 @@ template eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps) case Instruction::CREATE: { require(3); - - u256 gas = (unsigned)m_stack[m_stack.size() - 1]; unsigned inOff = (unsigned)m_stack[m_stack.size() - 2]; unsigned inSize = (unsigned)m_stack[m_stack.size() - 3]; newTempSize = inOff + inSize; - - 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; + runGas += c_createGas; break; } @@ -324,6 +319,18 @@ template eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps) case Instruction::CALLDATASIZE: m_stack.push_back(_ext.data.size()); 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: m_stack.push_back(_ext.gasPrice); break; @@ -477,14 +484,10 @@ template eth::bytesConstRef eth::VM::go(Ext& _ext, uint64_t _steps) break; case Instruction::CREATE: { - require(5); + require(3); u256 endowment = m_stack.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(); m_stack.pop_back(); unsigned initSize = (unsigned)m_stack.back(); @@ -493,7 +496,7 @@ template 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(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 m_stack.push_back(0); diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 54ae9e9f1..e2c7f12c1 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -166,9 +166,9 @@ unsigned QmlEthereum::peerCount() const 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) @@ -307,9 +307,9 @@ unsigned QEthereum::peerCount() const 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), to(_amount), bytes(_code.data(), _code.data() + _code.size()), bytes(_init.data(), _init.data() + _init.size()), to(_gas), to(_gasPrice))); + return toQJS(client()->transact(to(_secret), to(_amount), bytes(_init.data(), _init.data() + _init.size()), to(_gas), to(_gasPrice))); } void QEthereum::transact(QVariant _secret, QVariant _amount, QVariant _dest, QByteArray _data, QVariant _gas, QVariant _gasPrice) diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index de35aaaa8..23dc0c248 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -140,7 +140,7 @@ public: 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::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 setMining(bool _l); @@ -314,7 +314,7 @@ public: 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); eth::u256 balanceAt(eth::Address _a) const; diff --git a/neth/main.cpp b/neth/main.cpp index 2c1a00914..73612e203 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -707,17 +707,14 @@ int main(int argc, char** argv) cwarn << "No code submitted"; else { - bytes code = fromHex(scode); cnote << "Assembled:"; stringstream ssc; - ssc << disassemble(code); - cnote << ssc.str(); bytes init = fromHex(sinit); ssc.str(string()); ssc << disassemble(init); cnote << "Init:"; cnote << ssc.str(); - c.transact(us.secret(), endowment, code, init, gas, gasPrice); + c.transact(us.secret(), endowment, init, gas, gasPrice); } } } diff --git a/test/vm.cpp b/test/vm.cpp index 7d8501d35..abed42f77 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -70,14 +70,13 @@ public: txs.push_back(_t); } } - h160 create(u256 _endowment, u256* _gas, bytesConstRef _code, bytesConstRef _init) + h160 create(u256 _endowment, u256* _gas, bytesConstRef _init) { Transaction t; t.value = _endowment; t.gasPrice = gasPrice; t.gas = *_gas; - t.data = _code.toBytes(); - t.init = _init.toBytes(); + t.data = _init.toBytes(); txs.push_back(t); return right160(t.sha3(false)); }