diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b43ad4aa2..65cafa6f2 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -390,45 +390,22 @@ - - + + - + 0 0 - &To - - - destination - - - - - - - - 1 - 0 - - - - (Create Contract) - - - - - - - false + &Data - - true + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - + + data @@ -442,7 +419,10 @@ - + + + + @@ -455,21 +435,43 @@ - - - - - + + + + + 0 + 0 + + - &Gas + &To - gas + destination - - + + + + Qt::Vertical + + + + + Qt::NoFocus + + + true + + + + + + + + @ + 1 @@ -478,21 +480,11 @@ - - - - - 1 - 0 - - - - at + + + + gas - - - - 1 @@ -501,29 +493,20 @@ - - + + - - - - - 0 - 0 - - + + - &Data - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + &Gas - data + gas - + @@ -539,23 +522,14 @@ - - - - Qt::Vertical + + + + &Send - - - - Qt::NoFocus - - - true - - - + @@ -568,10 +542,29 @@ - - - - &Send + + + + false + + + true + + + + + + + + + + + 1 + 0 + + + + (Create Contract) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 7632b5303..5e3fb4cf6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -81,6 +81,8 @@ Main::Main(QWidget *parent) : int pocnumber = QString(ETH_QUOTED(ETH_VERSION)).section('.', 1, 1).toInt(); if (pocnumber == 3) m_servers.push_back("54.201.28.117:30303"); + else if (pocnumber == 4) + m_servers.push_back("54.72.31.55:30303"); else { connect(&m_webCtrl, &QNetworkAccessManager::finished, [&](QNetworkReply* _r) @@ -393,23 +395,21 @@ void Main::on_blocks_currentItemChanged() s << "

" << h << "[" << txi << "]

"; auto ss = tx.safeSender(); s << "
From: " << pretty(ss).toStdString() << " " << ss; - if (tx.receiveAddress) - s << "
To: " << pretty(tx.receiveAddress).toStdString() << " " << tx.receiveAddress; - else + if (tx.isCreation) s << "
Creates: " << pretty(right160(th)).toStdString() << " " << right160(th); + else + s << "
To: " << pretty(tx.receiveAddress).toStdString() << " " << tx.receiveAddress; s << "
Value: " << formatBalance(tx.value) << ""; - s << "
Gas: " << tx.gas << ""; - s << "
Gas price: " << tx.gasPrice << ""; s << "   #" << tx.nonce << ""; - if (tx.storage.size() && tx.isCreation) + s << "
Gas price: " << formatBalance(tx.gasPrice) << ""; + if (tx.isCreation) { s << "
Storage:   "; -// for (auto i: tx.data) -// s << "0x" << hex << i << " "; s << "
" << disassemble(tx.storage); } - else if (tx.data.size() && !tx.isCreation) + else { + s << "
Gas: " << tx.gas << ""; s << "
Data:    0x..." << setw(2) << setfill('0') << hex; unsigned c = 0; for (auto i: tx.data) @@ -438,7 +438,7 @@ void Main::on_contracts_currentItemChanged() u256 next = 0; unsigned numerics = 0; bool unexpectedNumeric = false; - for (auto i: mem) + for (auto const& i: mem) { if (next < i.first) { @@ -451,9 +451,7 @@ void Main::on_contracts_currentItemChanged() s << " ...
@" << showbase << hex << i.first << "    "; } else if (!next) - { s << "@" << showbase << hex << i.first << "    "; - } auto iit = c_instructionInfo.find((Instruction)(unsigned)i.second); if (numerics || iit == c_instructionInfo.end() || (u256)(unsigned)iit->first != i.second) // not an instruction or expecting an argument... { @@ -534,21 +532,35 @@ void Main::on_data_textChanged() else { string code = ui->data->toPlainText().replace(" ", "").toStdString(); - m_data = fromHex(code); + try + { + m_data = fromHex(code); + } + catch (...) + {} ui->code->setPlainText(QString::fromStdString(toHex(m_data))); - ui->gas->setEnabled(true); + if (m_client->postState().isContractAddress(fromString(ui->destination->text()))) + { + ui->gas->setMinimum((qint64)state().callGas(m_data.size(), 1)); + ui->gas->setEnabled(true); + } + else + { + ui->gas->setValue((qint64)state().callGas(m_data.size())); + ui->gas->setEnabled(false); + } } updateFee(); } bool Main::isCreation() const { - return !(ui->destination->text().isEmpty() || !ui->destination->text().toInt()); + return ui->destination->text().isEmpty()/* || !ui->destination->text().toInt()*/; } u256 Main::fee() const { - return (isCreation() ? state().createGas(m_storage.size()) : state().callGas(m_data.size(), ui->gas->value())) * gasPrice(); + return ui->gas->value() * gasPrice(); } u256 Main::value() const @@ -568,7 +580,7 @@ u256 Main::total() const void Main::updateFee() { - ui->fee->setText(QString("(fee: %1)").arg(formatBalance(fee()).c_str())); + ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); auto totalReq = total(); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); diff --git a/libethereum/CommonData.cpp b/libethereum/CommonData.cpp index 2e3259a4b..a5ff8e715 100644 --- a/libethereum/CommonData.cpp +++ b/libethereum/CommonData.cpp @@ -72,8 +72,7 @@ int eth::fromHex(char _i) bytes eth::fromHex(std::string const& _s) { - assert(_s.size() % 2 == 0); - if (_s.size() < 2) + if (_s.size() % 2 || _s.size() < 2) return bytes(); uint s = (_s[0] == '0' && _s[1] == 'x') ? 2 : 0; std::vector ret; diff --git a/libethereum/Exceptions.h b/libethereum/Exceptions.h index 50e66590f..49505b247 100644 --- a/libethereum/Exceptions.h +++ b/libethereum/Exceptions.h @@ -30,6 +30,7 @@ class OutOfGas: public VMException {}; class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; }; +class GasPriceTooLow: public Exception {}; class NoSuchContract: public Exception {}; class ContractAddressCollision: public Exception {}; class FeeTooSmall: public Exception {}; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 115a44c61..ebf077b92 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -608,6 +608,13 @@ void State::execute(bytesConstRef _rlp) throw InvalidNonce(nonceReq, t.nonce); } + // Don't like transactions whose gas price is too low. + if (t.gasPrice < 10 * szabo) + { + clog(StateChat) << "Offered gas-price is too low."; + throw GasPriceTooLow(); + } + // Entry point for a contract-originated transaction. u256 gasCost; if (t.isCreation) @@ -617,10 +624,19 @@ void State::execute(bytesConstRef _rlp) if (i) nonZero++; gasCost = nonZero * c_sstoreGas + c_createGas; + t.gas = gasCost; } else - gasCost = t.data.size() * c_txDataGas + c_callGas + t.gas; - u256 cost = t.value + gasCost * t.gasPrice; + { + 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) @@ -629,42 +645,40 @@ void State::execute(bytesConstRef _rlp) 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) { Address newAddress = right160(t.sha3()); - while (isContractAddress(newAddress) || isNormalAddress(newAddress)) newAddress = (u160)newAddress + 1; - // Increment associated nonce for sender. - noteSending(sender); - - // Pay out of sender... - subBalance(sender, cost); - // Set up new account... m_cache[newAddress] = AddressState(t.value, 0, AddressType::Contract); auto& mem = m_cache[newAddress].memory(); - for (uint i = 0; i < t.data.size(); ++i) + for (uint i = 0; i < t.storage.size(); ++i) mem[i] = t.storage[i]; } else { - // Increment associated nonce for sender. - noteSending(sender); - - // Pay... - subBalance(sender, cost); + cnote << "Giving" << formatBalance(t.value) << "to receiver"; addBalance(t.receiveAddress, t.value); - u256 gas = t.gas; if (isContractAddress(t.receiveAddress)) // Once we get here, there's no going back. call(t.receiveAddress, sender, t.value, t.gasPrice, bytesConstRef(&t.data), &gas, bytesRef()); - - addBalance(t.receiveAddress, gas * t.gasPrice); } + cnote << "Refunding" << formatBalance(gas * t.gasPrice) << "to sender (=" << gas << "*" << formatBalance(t.gasPrice) << ")"; + addBalance(sender, gas * t.gasPrice); + // Add to the user-originated transactions that we've executed. // NOTE: Here, contract-originated transactions will not get added to the transaction list. // If this is wrong, move this line into execute(Transaction const& _t, Address _sender) and diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index fedde6d4d..f694a7a36 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -44,6 +44,7 @@ Transaction::Transaction(bytesConstRef _rlpData) storage.reserve(rlp[field = 3].itemCountStrict()); for (auto const& i: rlp[3]) storage.push_back(i.toInt()); + vrs = Signature{ rlp[field = 4].toInt(), rlp[field = 5].toInt(), rlp[field = 6].toInt() }; } else { @@ -52,8 +53,8 @@ Transaction::Transaction(bytesConstRef _rlpData) data.reserve(rlp[field = 5].itemCountStrict()); for (auto const& i: rlp[5]) data.push_back(i.toInt()); + 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&) {