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/DappLoader.cpp b/alethzero/DappLoader.cpp
index 69555521d..7c754f8f5 100644
--- a/alethzero/DappLoader.cpp
+++ b/alethzero/DappLoader.cpp
@@ -39,13 +39,10 @@ using namespace dev;
using namespace dev::eth;
using namespace dev::crypto;
-Address c_registrar = Address("0000000000000000000000000000000000000a28");
-Address c_urlHint = Address("0000000000000000000000000000000000000a29");
-
QString contentsOfQResource(std::string const& res);
-DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3):
- QObject(_parent), m_web3(_web3)
+DappLoader::DappLoader(QObject* _parent, WebThreeDirect* _web3, Address _nameReg):
+ QObject(_parent), m_web3(_web3), m_nameReg(_nameReg)
{
connect(&m_net, &QNetworkAccessManager::finished, this, &DappLoader::downloadComplete);
}
@@ -61,31 +58,35 @@ DappLocation DappLoader::resolveAppUri(QString const& _uri)
std::reverse(parts.begin(), parts.end());
parts.append(url.path().split('/', QString::SkipEmptyParts));
- Address address = c_registrar;
+ Address address = m_nameReg;
Address lastAddress;
int partIndex = 0;
h256 contentHash;
-
while (address && partIndex < parts.length())
{
lastAddress = address;
string32 name = ZeroString32;
QByteArray utf8 = parts[partIndex].toUtf8();
std::copy(utf8.data(), utf8.data() + utf8.size(), name.data());
- address = abiOut
(web3()->ethereum()->call(address, abiIn("addr(string32)", name)).output);
+ address = abiOut(web3()->ethereum()->call(address, abiIn("subRegistrar(bytes32)", name)).output);
domainParts.append(parts[partIndex]);
if (!address)
{
//we have the address of the last part, try to get content hash
- contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(string32)", name)).output);
+ contentHash = abiOut(web3()->ethereum()->call(lastAddress, abiIn("content(bytes32)", name)).output);
if (!contentHash)
throw dev::Exception() << errinfo_comment("Can't resolve address");
}
++partIndex;
}
- string32 contentUrl = abiOut(web3()->ethereum()->call(c_urlHint, abiIn("url(hash256)", contentHash)).output);
+ string32 urlHintName = ZeroString32;
+ QByteArray utf8 = QString("urlhint").toUtf8();
+ std::copy(utf8.data(), utf8.data() + utf8.size(), urlHintName.data());
+
+ Address urlHint = abiOut(web3()->ethereum()->call(m_nameReg, abiIn("addr(bytes32)", urlHintName)).output);
+ string32 contentUrl = abiOut(web3()->ethereum()->call(urlHint, abiIn("url(bytes32)", contentHash)).output);
QString domain = domainParts.join('/');
parts.erase(parts.begin(), parts.begin() + partIndex);
QString path = parts.join('/');
@@ -237,6 +238,7 @@ void DappLoader::loadDapp(QString const& _uri)
DappLocation location = resolveAppUri(_uri);
contentUri = location.contentUri;
hash = location.contentHash;
+ uri = contentUri;
}
QNetworkRequest request(contentUri);
m_uriHashes[uri] = hash;
diff --git a/alethzero/DappLoader.h b/alethzero/DappLoader.h
index deba62c68..f2d3ee5e5 100644
--- a/alethzero/DappLoader.h
+++ b/alethzero/DappLoader.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
namespace dev
{
@@ -69,7 +70,7 @@ class DappLoader: public QObject
{
Q_OBJECT
public:
- DappLoader(QObject* _parent, dev::WebThreeDirect* _web3);
+ DappLoader(QObject* _parent, dev::WebThreeDirect* _web3, dev::Address _nameReg);
///Load a new DApp. Resolves a name with a name reg contract. Asynchronous. dappReady is emitted once everything is read, dappError othervise
///@param _uri Eth name path
void loadDapp(QString const& _uri);
@@ -97,5 +98,6 @@ private:
std::map m_uriHashes;
std::set m_pageUrls;
QByteArray m_web3Js;
+ dev::Address m_nameReg;
};
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 @@
+
+