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. 22
      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
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 << "<br/>Gas: <b>" << tx.gas << "</b>";
if (tx.isCreation())
{
if (tx.init.size())
s << "<h4>Init</h4>" << disassemble(tx.init);
if (tx.data.size())
s << "<h4>Body</h4>" << disassemble(tx.data);
s << "<h4>Code</h4>" << 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() ? "<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())
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);

1
alethzero/MainWin.h

@ -113,7 +113,6 @@ private:
QList<eth::KeyPair> m_myKeys;
bool m_keysChanged = false;
eth::bytes m_data;
eth::bytes m_init;
eth::Address m_nameReg;
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; }
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;

5
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<recursive_mutex> 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());

2
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());

1
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;

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_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.
}

4
libethereum/Instruction.cpp

@ -56,6 +56,7 @@ const std::map<std::string, Instruction> 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<Instruction, InstructionInfo> 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<unsigned>(1, bytesRequired(_literalValue));
o_code.push_back((byte)Instruction::PUSH1 + br - 1);

3
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);
}

2
libethereum/PeerServer.cpp

@ -115,7 +115,7 @@ PeerServer::~PeerServer()
unsigned PeerServer::protocolVersion()
{
return 12;
return 13;
}
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.
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();

10
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)

22
libethereum/Transaction.cpp

@ -36,18 +36,12 @@ Transaction::Transaction(bytesConstRef _rlpData)
try
{
nonce = rlp[field = 0].toInt<u256>();
value = rlp[field = 1].toInt<u256>();
receiveAddress = rlp[field = 2].toHash<Address>();
gasPrice = rlp[field = 3].toInt<u256>();
gas = rlp[field = 4].toInt<u256>();
gasPrice = rlp[field = 1].toInt<u256>();
gas = rlp[field = 2].toInt<u256>();
receiveAddress = rlp[field = 3].toHash<Address>();
value = rlp[field = 4].toInt<u256>();
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&)
{
@ -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;
}

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 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.

35
libethereum/VM.h

@ -133,6 +133,10 @@ 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::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 <class Ext> 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 <class Ext> 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 <class Ext> 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 <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(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);

8
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>(_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)

4
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;

5
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);
}
}
}

5
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));
}

Loading…
Cancel
Save