Browse Source

Merge pull request #1550 from arkpar/mix_auto_gas

Mix: Auto gas estimation
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
2cd3baa9ec
  1. 31
      mix/ClientModel.cpp
  2. 21
      mix/ClientModel.h
  3. 1
      mix/MachineStates.h
  4. 7
      mix/MixApplication.cpp
  5. 80
      mix/MixClient.cpp
  6. 7
      mix/MixClient.h
  7. 8
      mix/qml/DeploymentDialog.qml
  8. 2
      mix/qml/StateListModel.qml
  9. 11
      mix/qml/TransactionDialog.qml
  10. 5
      mix/qml/TransactionLog.qml
  11. 1
      mix/qml/js/TransactionHelper.js
  12. 1
      mix/test/TestService.cpp

31
mix/ClientModel.cpp

@ -154,6 +154,14 @@ QVariantMap ClientModel::contractAddresses() const
return res; return res;
} }
QVariantMap ClientModel::gasCosts() const
{
QVariantMap res;
for (auto const& c: m_gasCosts)
res.insert(c.first, QVariant::fromValue(static_cast<int>(c.second)));
return res;
}
void ClientModel::setupState(QVariantMap _state) void ClientModel::setupState(QVariantMap _state)
{ {
QVariantList balances = _state.value("accounts").toList(); QVariantList balances = _state.value("accounts").toList();
@ -173,6 +181,7 @@ void ClientModel::setupState(QVariantMap _state)
QString contractId = transaction.value("contractId").toString(); QString contractId = transaction.value("contractId").toString();
QString functionId = transaction.value("functionId").toString(); QString functionId = transaction.value("functionId").toString();
u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue()); u256 gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
bool gasAuto = transaction.value("gasAuto").toBool();
u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei(); u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei(); u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei();
QString sender = transaction.value("sender").toString(); QString sender = transaction.value("sender").toString();
@ -183,7 +192,7 @@ void ClientModel::setupState(QVariantMap _state)
contractId = functionId; contractId = functionId;
TransactionSettings transactionSettings(contractId, transaction.value("url").toString()); TransactionSettings transactionSettings(contractId, transaction.value("url").toString());
transactionSettings.gasPrice = 10000000000000; transactionSettings.gasPrice = 10000000000000;
transactionSettings.gas = 125000; transactionSettings.gasAuto = true;
transactionSettings.value = 0; transactionSettings.value = 0;
transactionSettings.sender = Secret(sender.toStdString()); transactionSettings.sender = Secret(sender.toStdString());
transactionSequence.push_back(transactionSettings); transactionSequence.push_back(transactionSettings);
@ -192,7 +201,7 @@ void ClientModel::setupState(QVariantMap _state)
{ {
if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later
contractId = m_codeModel->contracts().keys()[0]; contractId = m_codeModel->contracts().keys()[0];
TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice, Secret(sender.toStdString())); TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()));
transactionSettings.parameterValues = transaction.value("parameters").toMap(); transactionSettings.parameterValues = transaction.value("parameters").toMap();
if (contractId == functionId || functionId == "Constructor") if (contractId == functionId || functionId == "Constructor")
@ -228,7 +237,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
//std contract //std contract
bytes const& stdContractCode = m_codeModel->getStdContractCode(transaction.contractId, transaction.stdContractUrl); bytes const& stdContractCode = m_codeModel->getStdContractCode(transaction.contractId, transaction.stdContractUrl);
TransactionSettings stdTransaction = transaction; TransactionSettings stdTransaction = transaction;
stdTransaction.gas = 500000;// TODO: get this from std contracts library stdTransaction.gasAuto = true;
Address address = deployContract(stdContractCode, stdTransaction); Address address = deployContract(stdContractCode, stdTransaction);
m_stdContractAddresses[stdTransaction.contractId] = address; m_stdContractAddresses[stdTransaction.contractId] = address;
m_stdContractNames[address] = stdTransaction.contractId; m_stdContractNames[address] = stdTransaction.contractId;
@ -277,6 +286,8 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
m_contractNames[newAddress] = transaction.contractId; m_contractNames[newAddress] = transaction.contractId;
contractAddressesChanged(); contractAddressesChanged();
} }
gasCostsChanged();
m_gasCosts[transaction.contractId] = m_client->lastExecution().gasUsed;
} }
else else
{ {
@ -507,13 +518,13 @@ void ClientModel::debugRecord(unsigned _index)
Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction)
{ {
Address newAddress = m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice); Address newAddress = m_client->submitTransaction(_ctrTransaction.sender, _ctrTransaction.value, _code, _ctrTransaction.gas, _ctrTransaction.gasPrice, _ctrTransaction.gasAuto);
return newAddress; return newAddress;
} }
void ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) void ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{ {
m_client->submitTransaction(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); m_client->submitTransaction(_tr.sender, _tr.value, _contract, _data, _tr.gas, _tr.gasPrice, _tr.gasAuto);
} }
RecordLogEntry* ClientModel::lastBlock() const RecordLogEntry* ClientModel::lastBlock() const
@ -523,7 +534,7 @@ RecordLogEntry* ClientModel::lastBlock() const
strGas << blockInfo.gasUsed; strGas << blockInfo.gasUsed;
stringstream strNumber; stringstream strNumber;
strNumber << blockInfo.number; strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash().ref()))), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false, RecordLogEntry::RecordType::Block); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()));
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record; return record;
} }
@ -544,13 +555,17 @@ void ClientModel::onNewTransaction()
unsigned recordIndex = tr.executonIndex; unsigned recordIndex = tr.executonIndex;
QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex); QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex);
QString address = QString::fromStdString(toJS(tr.address)); QString address = QString::fromStdString(toJS(tr.address));
QString value = QString::fromStdString(toString(tr.value)); QString value = QString::fromStdString(toString(tr.value));
QString contract = address; QString contract = address;
QString function; QString function;
QString returned; QString returned;
QString gasUsed;
bool creation = (bool)tr.contractAddress; bool creation = (bool)tr.contractAddress;
if (!tr.isCall())
gasUsed = QString::fromStdString(toString(tr.gasUsed));
//TODO: handle value transfer //TODO: handle value transfer
FixedHash<4> functionHash; FixedHash<4> functionHash;
bool abi = false; bool abi = false;
@ -605,7 +620,7 @@ void ClientModel::onNewTransaction()
} }
} }
RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction); RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, gasUsed);
QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);
emit newRecord(log); emit newRecord(log);
} }

21
mix/ClientModel.h

@ -48,10 +48,10 @@ struct SolidityType;
struct TransactionSettings struct TransactionSettings
{ {
TransactionSettings() {} TransactionSettings() {}
TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice, Secret _sender): TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender):
contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice), sender(_sender) {} contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender) {}
TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl):
contractId(_stdContractName), stdContractUrl(_stdContractUrl) {} contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl) {}
/// Contract name /// Contract name
QString contractId; QString contractId;
@ -61,6 +61,8 @@ struct TransactionSettings
u256 value; u256 value;
/// Gas /// Gas
u256 gas; u256 gas;
/// Calculate gas automatically
bool gasAuto = true;
/// Gas price /// Gas price
u256 gasPrice; u256 gasPrice;
/// Mapping from contract function parameter name to value /// Mapping from contract function parameter name to value
@ -95,6 +97,8 @@ class RecordLogEntry: public QObject
Q_PROPERTY(bool call MEMBER m_call CONSTANT) Q_PROPERTY(bool call MEMBER m_call CONSTANT)
/// @returns record type /// @returns record type
Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) Q_PROPERTY(RecordType type MEMBER m_type CONSTANT)
/// Gas used
Q_PROPERTY(QString gasUsed MEMBER m_gasUsed CONSTANT)
public: public:
enum RecordType enum RecordType
@ -105,8 +109,8 @@ public:
RecordLogEntry(): RecordLogEntry():
m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {}
RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type): RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed):
m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type) {} m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed) {}
private: private:
unsigned m_recordIndex; unsigned m_recordIndex;
@ -118,6 +122,7 @@ private:
QString m_returned; QString m_returned;
bool m_call; bool m_call;
RecordType m_type; RecordType m_type;
QString m_gasUsed;
}; };
/** /**
@ -136,6 +141,8 @@ public:
Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged)
/// @returns deployed contracts addresses /// @returns deployed contracts addresses
Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
/// @returns deployed contracts gas costs
Q_PROPERTY(QVariantMap gasCosts READ gasCosts NOTIFY gasCostsChanged)
// @returns the last block // @returns the last block
Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT) Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT)
/// ethereum.js RPC request entry point /// ethereum.js RPC request entry point
@ -180,6 +187,8 @@ signals:
void runFailed(QString const& _message); void runFailed(QString const& _message);
/// Contract address changed /// Contract address changed
void contractAddressesChanged(); void contractAddressesChanged();
/// Gas costs updated
void gasCostsChanged();
/// Execution state changed /// Execution state changed
void newBlock(); void newBlock();
/// Execution state changed /// Execution state changed
@ -197,6 +206,7 @@ signals:
private: private:
RecordLogEntry* lastBlock() const; RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const; QVariantMap contractAddresses() const;
QVariantMap gasCosts() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Secret, u256> const& _balances); void executeSequence(std::vector<TransactionSettings> const& _sequence, std::map<Secret, u256> const& _balances);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
@ -212,6 +222,7 @@ private:
std::unique_ptr<MixClient> m_client; std::unique_ptr<MixClient> m_client;
std::unique_ptr<RpcConnector> m_rpcConnector; std::unique_ptr<RpcConnector> m_rpcConnector;
std::unique_ptr<Web3Server> m_web3Server; std::unique_ptr<Web3Server> m_web3Server;
std::map<QString, u256> m_gasCosts;
std::map<QString, Address> m_contractAddresses; std::map<QString, Address> m_contractAddresses;
std::map<Address, QString> m_contractNames; std::map<Address, QString> m_contractNames;
std::map<QString, Address> m_stdContractAddresses; std::map<QString, Address> m_stdContractAddresses;

1
mix/MachineStates.h

@ -80,6 +80,7 @@ namespace mix
dev::Address sender; dev::Address sender;
dev::Address contractAddress; dev::Address contractAddress;
dev::u256 value; dev::u256 value;
dev::u256 gasUsed;
unsigned transactionIndex; unsigned transactionIndex;
unsigned executonIndex = 0; unsigned executonIndex = 0;

7
mix/MixApplication.cpp

@ -52,13 +52,8 @@ ApplicationService::ApplicationService()
MixApplication::MixApplication(int& _argc, char* _argv[]): MixApplication::MixApplication(int& _argc, char* _argv[]):
QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine()) QApplication(_argc, _argv), m_engine(new QQmlApplicationEngine())
{ {
setWindowIcon(QIcon(":/res/mix_256x256x32.png"));
m_engine->load(QUrl("qrc:/qml/Application.qml")); m_engine->load(QUrl("qrc:/qml/Application.qml"));
if (!m_engine->rootObjects().empty())
{
QWindow *window = qobject_cast<QWindow*>(m_engine->rootObjects().at(0));
if (window)
window->setIcon(QIcon(":/res/mix_256x256x32.png"));
}
} }
void MixApplication::initialize() void MixApplication::initialize()

80
mix/MixClient.cpp

@ -40,10 +40,8 @@ namespace dev
namespace mix namespace mix
{ {
// TODO: merge as much as possible with the Client.cpp into a mutually inherited base class. Secret const c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
u256 const c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow
const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow
bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{ {
@ -100,9 +98,18 @@ void MixClient::resetState(std::map<Secret, u256> _accounts)
m_executions.clear(); m_executions.clear();
} }
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call) Transaction MixClient::replaceGas(Transaction const& _t, Secret const& _secret, u256 const& _gas)
{
if (_t.isCreation())
return Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret);
else
return Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret);
}
void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret)
{ {
bytes rlp = _t.rlp(); Transaction t = _gasAuto ? replaceGas(_t, _secret, m_state.gasLimitRemaining()) : _t;
bytes rlp = t.rlp();
// do debugging run first // do debugging run first
LastHashes lastHashes(256); LastHashes lastHashes(256);
@ -167,6 +174,31 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
execution.go(onOp); execution.go(onOp);
execution.finalize(); execution.finalize();
dev::eth::ExecutionResult er = execution.executionResult();
switch (er.excepted)
{
case TransactionException::None:
break;
case TransactionException::NotEnoughCash:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment"));
case TransactionException::OutOfGasBase:
case TransactionException::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
case TransactionException::BlockGasLimitReached:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached"));
case TransactionException::OutOfStack:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
case TransactionException::StackUnderflow:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow"));
//these should not happen in mix
case TransactionException::Unknown:
case TransactionException::BadInstruction:
case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error"));
};
ExecutionResult d; ExecutionResult d;
d.result = execution.executionResult(); d.result = execution.executionResult();
@ -176,6 +208,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
d.address = _t.receiveAddress(); d.address = _t.receiveAddress();
d.sender = _t.sender(); d.sender = _t.sender();
d.value = _t.value(); d.value = _t.value();
d.gasUsed = er.gasUsed + er.gasRefunded;
if (_t.isCreation()) if (_t.isCreation())
d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
if (!_call) if (!_call)
@ -185,9 +218,11 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
// execute on a state // execute on a state
if (!_call) if (!_call)
{ {
dev::eth::ExecutionResult er =_state.execute(lastHashes, _t); t = _gasAuto ? replaceGas(_t, _secret, d.gasUsed) : _t;
if (_t.isCreation() && _state.code(d.contractAddress).empty()) er =_state.execute(lastHashes, t);
if (t.isCreation() && _state.code(d.contractAddress).empty())
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit;
// collect watches // collect watches
h256Set changed; h256Set changed;
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
@ -242,25 +277,25 @@ State MixClient::asOf(h256 const& _block) const
return State(m_stateDB, bc(), _block); return State(m_stateDB, bc(), _block);
} }
void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret)); u256 n = m_state.transactionsFrom(toAddress(_secret));
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
executeTransaction(t, m_state, false); executeTransaction(t, m_state, false, _gasAuto, _secret);
} }
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto)
{ {
WriteGuard l(x_state); WriteGuard l(x_state);
u256 n = m_state.transactionsFrom(toAddress(_secret)); u256 n = m_state.transactionsFrom(toAddress(_secret));
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret);
executeTransaction(t, m_state, false); executeTransaction(t, m_state, false, _gasAuto, _secret);
Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); Address address = right160(sha3(rlpList(t.sender(), t.nonce())));
return address; return address;
} }
dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto)
{ {
(void)_blockNumber; (void)_blockNumber;
State temp = asOf(eth::PendingBlock); State temp = asOf(eth::PendingBlock);
@ -268,10 +303,25 @@ dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret);
bytes rlp = t.rlp(); bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true); executeTransaction(t, temp, true, _gasAuto, _secret);
return lastExecution().result; return lastExecution().result;
} }
void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice)
{
submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, false);
}
Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice)
{
return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false);
}
dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{
return call(_secret, _value, _dest, _data, _gas, _gasPrice, _blockNumber,false);
}
dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber)
{ {
(void)_blockNumber; (void)_blockNumber;
@ -285,7 +335,7 @@ dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes c
Transaction t(_value, _gasPrice, _gas, _data, n, _secret); Transaction t(_value, _gasPrice, _gas, _data, n, _secret);
bytes rlp = t.rlp(); bytes rlp = t.rlp();
WriteGuard lw(x_state); //TODO: lock is required only for last execution state WriteGuard lw(x_state); //TODO: lock is required only for last execution state
executeTransaction(t, temp, true); executeTransaction(t, temp, true, false, _secret);
return lastExecution().result; return lastExecution().result;
} }

7
mix/MixClient.h

@ -58,6 +58,10 @@ public:
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock) override; dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock) override;
dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock) override; dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock) override;
void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto);
Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto);
dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber, bool _gasAuto);
void setAddress(Address _us) override; void setAddress(Address _us) override;
void setMiningThreads(unsigned _threads) override; void setMiningThreads(unsigned _threads) override;
unsigned miningThreads() const override; unsigned miningThreads() const override;
@ -86,8 +90,9 @@ protected:
virtual void prepareForTransaction() override {} virtual void prepareForTransaction() override {}
private: private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret);
void noteChanged(h256Set const& _filters); void noteChanged(h256Set const& _filters);
dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::Secret const& _secret, dev::u256 const& _gas);
std::vector<KeyPair> m_userAccounts; std::vector<KeyPair> m_userAccounts;
eth::State m_state; eth::State m_state;

8
mix/qml/DeploymentDialog.qml

@ -73,6 +73,12 @@ Dialog {
balance.text = comboAccounts.balances[0]; balance.text = comboAccounts.balances[0];
}); });
}); });
var gas = 0;
var gasCosts = clientModel.gasCosts;
for (var g in gasCosts)
gas += gasCosts[g];
gasToUse = gas;
} }
function stopForInputError(inError) function stopForInputError(inError)
@ -421,7 +427,7 @@ Dialog {
Layout.preferredWidth: 350 Layout.preferredWidth: 350
id: localPackageUrl id: localPackageUrl
readOnly: true readOnly: true
enabled: rowRegister.isOkToRegister()
} }
DefaultLabel DefaultLabel

2
mix/qml/StateListModel.qml

@ -44,6 +44,7 @@ Item {
value: QEtherHelper.createEther(t.value.value, t.value.unit), value: QEtherHelper.createEther(t.value.value, t.value.unit),
gas: QEtherHelper.createBigInt(t.gas.value), gas: QEtherHelper.createBigInt(t.gas.value),
gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit), gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit),
gasAuto: t.gasAuto,
stdContract: t.stdContract ? true : false, stdContract: t.stdContract ? true : false,
parameters: {}, parameters: {},
sender: t.sender sender: t.sender
@ -91,6 +92,7 @@ Item {
url: t.url, url: t.url,
value: { value: t.value.value, unit: t.value.unit }, value: { value: t.value.value, unit: t.value.unit },
gas: { value: t.gas.value() }, gas: { value: t.gas.value() },
gasAuto: t.gasAuto,
gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit }, gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit },
stdContract: t.stdContract, stdContract: t.stdContract,
parameters: {} parameters: {}

11
mix/qml/TransactionDialog.qml

@ -17,6 +17,7 @@ Dialog {
title: qsTr("Edit Transaction") title: qsTr("Edit Transaction")
property int transactionIndex property int transactionIndex
property alias gas: gasValueEdit.gasValue; property alias gas: gasValueEdit.gasValue;
property alias gasAuto: gasAutoCheck.checked;
property alias gasPrice: gasPriceField.value; property alias gasPrice: gasPriceField.value;
property alias transactionValue: valueField.value; property alias transactionValue: valueField.value;
property string contractId: contractComboBox.currentValue(); property string contractId: contractComboBox.currentValue();
@ -39,6 +40,7 @@ Dialog {
transactionIndex = index; transactionIndex = index;
gasValueEdit.gasValue = item.gas; gasValueEdit.gasValue = item.gas;
gasAutoCheck.checked = item.gasAuto ? true : false;
gasPriceField.value = item.gasPrice; gasPriceField.value = item.gasPrice;
valueField.value = item.value; valueField.value = item.value;
var contractId = item.contractId; var contractId = item.contractId;
@ -164,6 +166,7 @@ Dialog {
contractId: transactionDialog.contractId, contractId: transactionDialog.contractId,
functionId: transactionDialog.functionId, functionId: transactionDialog.functionId,
gas: transactionDialog.gas, gas: transactionDialog.gas,
gasAuto: transactionDialog.gasAuto,
gasPrice: transactionDialog.gasPrice, gasPrice: transactionDialog.gasPrice,
value: transactionDialog.transactionValue, value: transactionDialog.transactionValue,
parameters: {}, parameters: {},
@ -314,8 +317,16 @@ Dialog {
onGasValueChanged: text = gasValue.value(); onGasValueChanged: text = gasValue.value();
onTextChanged: gasValue.setValue(text); onTextChanged: gasValue.setValue(text);
implicitWidth: 200 implicitWidth: 200
enabled: !gasAutoCheck.checked
id: gasValueEdit; id: gasValueEdit;
} }
CheckBox
{
id: gasAutoCheck
checked: true
text: qsTr("Auto");
}
} }
CommonSeparator CommonSeparator

5
mix/qml/TransactionLog.qml

@ -127,6 +127,11 @@ Item {
title: qsTr("Returned") title: qsTr("Returned")
width: 120 width: 120
} }
TableViewColumn {
role: "gasUsed"
title: qsTr("Gas Used")
width: 120
}
onActivated: { onActivated: {
var item = logTable.model.get(row); var item = logTable.model.get(row);
if (item.type === RecordLogEntry.Transaction) if (item.type === RecordLogEntry.Transaction)

1
mix/qml/js/TransactionHelper.js

@ -6,6 +6,7 @@ function defaultTransaction()
value: createEther("0", QEther.Wei), value: createEther("0", QEther.Wei),
functionId: "", functionId: "",
gas: createBigInt("250000"), gas: createBigInt("250000"),
gasAuto: true,
gasPrice: createEther("100000", QEther.Wei), gasPrice: createEther("100000", QEther.Wei),
parameters: {}, parameters: {},
stdContract: false stdContract: false

1
mix/test/TestService.cpp

@ -163,7 +163,6 @@ bool TestService::keyClickChar(QObject* _item, QString const& _character, int _m
bool TestService::mouseClick(QObject* _item, qreal _x, qreal _y, int _button, int _modifiers, int _delay) bool TestService::mouseClick(QObject* _item, qreal _x, qreal _y, int _button, int _modifiers, int _delay)
{ {
QWindow* window = qobject_cast<QWindow*>(_item); QWindow* window = qobject_cast<QWindow*>(_item);
QMetaObject const* mo = _item->metaObject();
if (!window) if (!window)
window = eventWindow(_item); window = eventWindow(_item);
mouseEvent(MouseClick, window, _item, Qt::MouseButton(_button), Qt::KeyboardModifiers(_modifiers), QPointF(_x, _y), _delay); mouseEvent(MouseClick, window, _item, Qt::MouseButton(_button), Qt::KeyboardModifiers(_modifiers), QPointF(_x, _y), _delay);

Loading…
Cancel
Save