diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt
index d9e8dff6f..9abb3f1a4 100644
--- a/alethzero/CMakeLists.txt
+++ b/alethzero/CMakeLists.txt
@@ -22,6 +22,7 @@ qt5_wrap_ui(ui_Main.h Main.ui)
qt5_wrap_ui(ui_Connect.h Connect.ui)
qt5_wrap_ui(ui_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui)
+qt5_wrap_ui(ui_ExportState.h ExportState.ui)
file(GLOB HEADERS "*.h")
@@ -34,7 +35,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON alethzero
- UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui
+ UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui ExportState.ui
WIN_RESOURCES alethzero.rc
)
diff --git a/alethzero/ExportState.cpp b/alethzero/ExportState.cpp
new file mode 100644
index 000000000..e39b74b76
--- /dev/null
+++ b/alethzero/ExportState.cpp
@@ -0,0 +1,183 @@
+/*
+ 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 ExportState.cpp
+ * @author Arkadiy Paronyan
+ * @date 2015
+ */
+
+#include "ExportState.h"
+#include
+#include
+#include
+#include "MainWin.h"
+#include "ui_ExportState.h"
+
+using namespace std;
+using namespace dev;
+using namespace dev::eth;
+
+ExportStateDialog::ExportStateDialog(Main* _parent):
+ QDialog(_parent),
+ ui(new Ui::ExportState),
+ m_main(_parent)
+{
+ ui->setupUi(this);
+ connect(ui->close, &QPushButton::clicked, this, &ExportStateDialog::close);
+ connect(ui->accounts, &QListWidget::itemSelectionChanged, this, &ExportStateDialog::generateJSON);
+ connect(ui->contracts, &QListWidget::itemSelectionChanged, this, &ExportStateDialog::generateJSON);
+ fillBlocks();
+}
+
+ExportStateDialog::~ExportStateDialog()
+{
+}
+
+dev::eth::Client* ExportStateDialog::ethereum() const
+{
+ return m_main->ethereum();
+}
+
+void ExportStateDialog::on_block_editTextChanged()
+{
+ QString text = ui->block->currentText();
+ int i = ui->block->count();
+ while (i-- >= 0)
+ if (ui->block->itemText(i) == text)
+ return;
+ fillBlocks();
+}
+
+void ExportStateDialog::on_block_currentIndexChanged(int _index)
+{
+ m_block = ui->block->itemData(_index).toUInt();
+ fillContracts();
+}
+
+void ExportStateDialog::fillBlocks()
+{
+ BlockChain const& bc = ethereum()->blockChain();
+ QStringList filters = ui->block->currentText().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
+ const unsigned numLastBlocks = 10;
+ if (ui->block->count() == 0)
+ {
+ unsigned i = numLastBlocks;
+ for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
+ {
+ auto d = bc.details(h);
+ ui->block->addItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), d.number);
+ if (h == bc.genesisHash())
+ break;
+ }
+ if (ui->block->currentIndex() < 0)
+ ui->block->setCurrentIndex(0);
+ m_recentBlocks = numLastBlocks - i;
+ }
+
+ int i = ui->block->count();
+ while (i > 0 && i >= m_recentBlocks)
+ ui->block->removeItem(i--);
+
+ h256Set blocks;
+ for (QString f: filters)
+ {
+ if (f.startsWith("#"))
+ f = f.remove(0, 1);
+ if (f.size() == 64)
+ {
+ h256 h(f.toStdString());
+ if (bc.isKnown(h))
+ blocks.insert(h);
+ for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
+ blocks.insert(bc.numberHash(b));
+ }
+ else if (f.toLongLong() <= bc.number())
+ blocks.insert(bc.numberHash((unsigned)f.toLongLong()));
+ else if (f.size() == 40)
+ {
+ Address h(f.toStdString());
+ for (auto const& b: bc.withBlockBloom(LogBloom().shiftBloom<3>(sha3(h)), 0, -1))
+ blocks.insert(bc.numberHash(b));
+ }
+ }
+
+ for (auto const& h: blocks)
+ {
+ auto d = bc.details(h);
+ ui->block->addItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), d.number);
+ }
+}
+
+void ExportStateDialog::fillContracts()
+{
+ ui->accounts->clear();
+ ui->contracts->clear();
+ ui->accounts->setEnabled(true);
+ ui->contracts->setEnabled(true);
+ for (auto i: ethereum()->addresses(m_block))
+ {
+ QString r = m_main->render(i);
+ (new QListWidgetItem(QString("%2: %1 [%3]").arg(formatBalance(ethereum()->balanceAt(i)).c_str()).arg(r).arg((unsigned)ethereum()->countAt(i)), ethereum()->codeAt(i).empty() ? ui->accounts : ui->contracts))
+ ->setData(Qt::UserRole, QByteArray((char const*)i.data(), Address::size));
+ }
+}
+
+void ExportStateDialog::generateJSON()
+{
+ std::stringstream json;
+ json << "{\n";
+ std::string prefix;
+ for(QListWidgetItem* item: ui->accounts->selectedItems())
+ {
+ auto hba = item->data(Qt::UserRole).toByteArray();
+ auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
+ json << prefix << "\t\"" << toHex(address.ref()) << "\": { \"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\" }";
+ prefix = ",\n";
+ }
+ for(QListWidgetItem* item: ui->contracts->selectedItems())
+ {
+ auto hba = item->data(Qt::UserRole).toByteArray();
+ auto address = Address((byte const*)hba.data(), Address::ConstructFromPointer);
+ json << prefix << "\t\"" << toHex(address.ref()) << "\":\n\t{\n\t\t\"wei\": \"" << ethereum()->balanceAt(address, m_block) << "\",\n";
+ json << "\t\t\"code\": \"" << toHex(ethereum()->codeAt(address, m_block)) << "\",\n";
+ std::map storage = ethereum()->storageAt(address, m_block);
+ if (!storage.empty())
+ {
+ json << "\t\t\"storage\":\n\t\t{\n";
+ for (auto s: storage)
+ json << "\t\t\t\"" << toHex(s.first) << "\": \"" << toHex(s.second) << "\"" << (s.first == storage.rbegin()->first ? "" : ",") <<"\n";
+ json << "\t\t}\n";
+ }
+ json << "\t}";
+ prefix = ",\n";
+ }
+ json << "\n}";
+ json.flush();
+
+ ui->json->setEnabled(true);
+ ui->json->setText(QString::fromStdString(json.str()));
+ ui->saveButton->setEnabled(true);
+}
+
+void ExportStateDialog::on_saveButton_clicked()
+{
+ QString fn = QFileDialog::getSaveFileName(this, "Save state", QString(), "JSON Files (*.json)");
+ if (!fn.endsWith(".json"))
+ fn = fn.append(".json");
+ ofstream file(fn.toStdString());
+ if (file.is_open())
+ file << ui->json->toPlainText().toStdString();
+}
diff --git a/alethzero/ExportState.h b/alethzero/ExportState.h
new file mode 100644
index 000000000..e8e045855
--- /dev/null
+++ b/alethzero/ExportState.h
@@ -0,0 +1,57 @@
+/*
+ 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 ExportState.h
+ * @author Arkadiy Paronyan
+ * @date 2015
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace Ui { class ExportState; }
+namespace dev { namespace eth { class Client; } }
+
+class Main;
+
+class ExportStateDialog: public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ExportStateDialog(Main* _parent = 0);
+ virtual ~ExportStateDialog();
+
+private slots:
+ void on_block_editTextChanged();
+ void on_block_currentIndexChanged(int _index);
+ void on_saveButton_clicked();
+
+private:
+ dev::eth::Client* ethereum() const;
+ void fillBlocks();
+ void fillContracts();
+ void generateJSON();
+
+private:
+ std::unique_ptr ui;
+ Main* m_main;
+ int m_recentBlocks = 0;
+ dev::eth::BlockNumber m_block = dev::eth::LatestBlock;
+};
diff --git a/alethzero/ExportState.ui b/alethzero/ExportState.ui
new file mode 100644
index 000000000..96256bc7f
--- /dev/null
+++ b/alethzero/ExportState.ui
@@ -0,0 +1,183 @@
+
+
+ ExportState
+
+
+
+ 0
+ 0
+ 490
+ 522
+
+
+
+ Export State
+
+
+ true
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ &Block
+
+
+ block
+
+
+
+ -
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ &Accounts
+
+
+ accounts
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 1
+
+
+
+ QAbstractItemView::MultiSelection
+
+
+
+ -
+
+
+ &Contracts
+
+
+ contracts
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 1
+
+
+
+ QAbstractItemView::MultiSelection
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ &JSON
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ json
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 2
+
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+ &Save...
+
+
+ Esc
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ &Close
+
+
+ Esc
+
+
+
+
+
+
+
+
+
+
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 1fd9669e9..ee46017f5 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -160,6 +160,8 @@
+
+