/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ /** @file ClientModel.h * @author Yann yann@ethdev.com * @author Arkadiy Paronyan arkadiy@ethdev.com * @date 2015 * Ethereum IDE client. */ #pragma once #include #include #include #include #include #include #include #include #include "MachineStates.h" #include "QEther.h" namespace dev { namespace eth { class FixedAccountHolder; } namespace mix { class Web3Server; class RpcConnector; class QEther; class QDebugData; class MixClient; class QVariableDefinition; class CodeModel; struct SolidityType; /// Backend transaction config class struct TransactionSettings { TransactionSettings() {} TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, bool _gasAuto, u256 _gasPrice, Secret _sender, bool _isContractCreation, bool _isFunctionCall): contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasAuto(_gasAuto), gasPrice(_gasPrice), sender(_sender), isContractCreation(_isContractCreation), isFunctionCall(_isFunctionCall) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): contractId(_stdContractName), gasAuto(true), stdContractUrl(_stdContractUrl), isContractCreation(true), isFunctionCall(true) {} /// Contract name QString contractId; /// Contract function name QString functionId; /// Transaction value u256 value; /// Gas u256 gas; /// Calculate gas automatically bool gasAuto = true; /// Gas price u256 gasPrice; /// Mapping from contract function parameter name to value QVariantMap parameterValues; /// Standard contract url QString stdContractUrl; /// Sender Secret sender; /// Tr deploys a contract bool isContractCreation; /// Tr call a ctr function bool isFunctionCall; }; /// UI Transaction log record class RecordLogEntry: public QObject { Q_OBJECT Q_ENUMS(RecordType) /// Recording index Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT) /// Human readable transaction bloack and transaction index Q_PROPERTY(QString transactionIndex MEMBER m_transactionIndex CONSTANT) /// Contract name if any Q_PROPERTY(QString contract MEMBER m_contract CONSTANT) /// Function name if any Q_PROPERTY(QString function MEMBER m_function CONSTANT) /// Transaction value Q_PROPERTY(QString value MEMBER m_value CONSTANT) /// Receiving address Q_PROPERTY(QString address MEMBER m_address CONSTANT) /// Returned value or transaction address in case of creation Q_PROPERTY(QString returned MEMBER m_returned CONSTANT) /// true if call, false if transaction Q_PROPERTY(bool call MEMBER m_call CONSTANT) /// @returns record type Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) /// Gas used Q_PROPERTY(QString gasUsed MEMBER m_gasUsed CONSTANT) /// Sender Q_PROPERTY(QString sender MEMBER m_sender CONSTANT) /// label Q_PROPERTY(QString label MEMBER m_label CONSTANT) /// input parameters Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) /// return parameters Q_PROPERTY(QVariantMap returnParameters MEMBER m_returnParameters CONSTANT) /// logs Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) public: enum RecordType { Transaction, Block }; RecordLogEntry(): 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, QString _gasUsed, QString _sender, QString _label, QVariantMap _inputParameters, QVariantMap _returnParameters, QVariantList _logs): 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), m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_returnParameters(_returnParameters), m_logs(_logs) {} private: unsigned m_recordIndex; QString m_transactionIndex; QString m_contract; QString m_function; QString m_value; QString m_address; QString m_returned; bool m_call; RecordType m_type; QString m_gasUsed; QString m_sender; QString m_label; QVariantMap m_inputParameters; QVariantMap m_returnParameters; QVariantList m_logs; }; /** * @brief Ethereum state control */ class ClientModel: public QObject { Q_OBJECT public: ClientModel(); ~ClientModel(); /// @returns true if currently executing contract code Q_PROPERTY(bool running MEMBER m_running NOTIFY runStateChanged) /// @returns true if currently mining Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) /// @returns deployed contracts addresses Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) /// @returns deployed contracts gas costs Q_PROPERTY(QVariantList gasCosts READ gasCosts NOTIFY gasCostsChanged) /// @returns the last block Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT) /// ethereum.js RPC request entry point /// @param _message RPC request in Json format /// @returns RPC response in Json format Q_INVOKABLE QString apiCall(QString const& _message); /// Simulate mining. Creates a new block Q_INVOKABLE void mine(); /// Get/set code model. Should be set from qml Q_PROPERTY(CodeModel* codeModel MEMBER m_codeModel) /// Encode parameters Q_INVOKABLE QStringList encodeParams(QVariant const& _param, QString const& _contract, QString const& _function); /// Encode parameter Q_INVOKABLE QString encodeStringParam(QString const& _param); /// To Hex number Q_INVOKABLE QString toHex(QString const& _int); /// Add new account to the model Q_INVOKABLE void addAccount(QString const& _secret); /// Return the address associated with the current secret Q_INVOKABLE QString resolveAddress(QString const& _secret); /// Compute required gas for a list of transactions @arg _tr QBigInt computeRequiredGas(QVariantList _tr); /// init eth client Q_INVOKABLE void init(QString _dbpath); public slots: /// Setup scenario, run transaction sequence, show debugger for the last transaction /// @param _state JS object with state configuration void setupScenario(QVariantMap _scenario); /// Execute the given @param _tr on the current state void executeTr(QVariantMap _tr); /// Show the debugger for a specified record Q_INVOKABLE void debugRecord(unsigned _index); /// Show the debugger for an empty record Q_INVOKABLE void emptyRecord(); /// Generate new secret Q_INVOKABLE QString newSecret(); /// retrieve the address of @arg _secret Q_INVOKABLE QString address(QString const& _secret); /// Encode a string to ABI parameter. Returns a hex string Q_INVOKABLE QString encodeAbiString(QString _string); private slots: /// Update UI with machine states result. Display a modal dialog. void showDebugger(); signals: /// Transaction execution started void runStarted(); /// Transaction execution completed successfully void runComplete(); /// Mining has started void miningStarted(); /// Mined a new block void miningComplete(); /// Mining stopped or started void miningStateChanged(); /// Transaction execution completed with error /// @param _message Error message void runFailed(QString const& _message); /// Contract address changed void contractAddressesChanged(); /// Gas costs updated void gasCostsChanged(); /// Execution state changed void newBlock(); /// Execution state changed void runStateChanged(); /// Show debugger window request void debugDataReady(QObject* _debugData); /// ethereum.js RPC response ready /// @param _message RPC response in Json format void apiResponse(QString const& _message); /// New transaction log entry void newRecord(RecordLogEntry* _r); /// State (transaction log) cleared void stateCleared(); /// new state has been processed void newState(unsigned _record, QVariantMap _accounts); private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantList gasCosts() const; void executeSequence(std::vector const& _sequence); Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); QString resolveToken(std::pair const& _value); std::pair retrieveToken(QString const& _value); std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); void processNextTransactions(); void finalizeBlock(); void stopExecution(); void setupExecutionChain(); TransactionSettings transaction(QVariant const& _tr) const; std::atomic m_running; std::atomic m_mining; QFuture m_runFuture; std::unique_ptr m_client; std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; std::shared_ptr m_ethAccounts; std::unordered_map m_accounts; std::vector m_accountsSecret; QList m_gasCosts; std::map, Address> m_contractAddresses; std::map m_contractNames; std::map m_stdContractAddresses; std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; QList m_queueTransactions; mutable boost::shared_mutex x_queueTransactions; QString m_dbpath; }; } } Q_DECLARE_METATYPE(dev::mix::RecordLogEntry*)