Browse Source

Private chains redux:

- Can switching between them and main chain without losing either.
- No discovery on network when private.
- Private chain id encoded in genesis block and network id remains same.
cl-refactor
Gav Wood 10 years ago
parent
commit
fb99a503e0
  1. 58
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 15
      exp/main.cpp
  4. 4
      libdevcrypto/Common.cpp
  5. 23
      libethereum/BlockChain.cpp
  6. 10
      libethereum/BlockChain.h
  7. 24
      libethereum/CanonBlockChain.cpp
  8. 8
      libethereum/CanonBlockChain.h
  9. 6
      libethereum/Client.cpp
  10. 4
      libethereum/Client.h

58
alethzero/MainWin.cpp

@ -378,10 +378,17 @@ NetworkPreferences Main::netPrefs() const
publicIP.clear(); publicIP.clear();
} }
NetworkPreferences ret;
if (isPublicAddress(publicIP)) if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked()); ret = NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
else else
return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked()); ret = NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked());
ret.discovery = m_privateChain.isEmpty();
ret.pin = m_privateChain.isEmpty();
return ret;
} }
void Main::onKeysChanged() void Main::onKeysChanged()
@ -776,6 +783,30 @@ void Main::writeSettings()
s.setValue("windowState", saveState()); s.setValue("windowState", saveState());
} }
void Main::setPrivateChain(QString const& _private, bool _forceConfigure)
{
if (m_privateChain == _private && !_forceConfigure)
return;
m_privateChain = _private;
ui->usePrivate->setChecked(!m_privateChain.isEmpty());
CanonBlockChain<Ethash>::forceGenesisExtraData(m_privateChain.isEmpty() ? bytes() : sha3(m_privateChain.toStdString()).asBytes());
// rejig blockchain now.
writeSettings();
ui->mine->setChecked(false);
ui->net->setChecked(false);
web3()->stopNetwork();
web3()->setNetworkPreferences(netPrefs());
ethereum()->reopenChain();
readSettings(true);
installWatches();
refreshAll();
}
Secret Main::retrieveSecret(Address const& _address) const Secret Main::retrieveSecret(Address const& _address) const
{ {
while (true) while (true)
@ -852,8 +883,7 @@ void Main::readSettings(bool _skipGeometry)
ui->listenIP->setText(s.value("listenIP", "").toString()); ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString()); ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString(); setPrivateChain(s.value("privateChain", "").toString());
ui->usePrivate->setChecked(m_privateChain.size());
ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->verbosity->setValue(s.value("verbosity", 1).toInt());
#if ETH_EVMJIT // We care only if JIT is enabled. Otherwise it can cause misconfiguration. #if ETH_EVMJIT // We care only if JIT is enabled. Otherwise it can cause misconfiguration.
@ -1036,21 +1066,15 @@ void Main::on_exportState_triggered()
void Main::on_usePrivate_triggered() void Main::on_usePrivate_triggered()
{ {
QString pc;
if (ui->usePrivate->isChecked()) if (ui->usePrivate->isChecked())
{ {
m_privateChain = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0))); bool ok;
if (m_privateChain.isEmpty()) pc = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)), &ok);
{ if (!ok)
if (ui->usePrivate->isChecked()) return;
ui->usePrivate->setChecked(false);
else
// was cancelled.
return;
}
} }
else setPrivateChain(pc);
m_privateChain.clear();
on_killBlockchain_triggered();
} }
void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); } void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); }
@ -2015,7 +2039,7 @@ void Main::on_net_triggered()
{ {
web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); ethereum()->setNetworkId((h256)(u256)(int)c_network);
web3()->startNetwork(); web3()->startNetwork();
ui->downloadView->setEthereum(ethereum()); ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode())); ui->enode->setText(QString::fromStdString(web3()->enode()));

2
alethzero/MainWin.h

@ -226,6 +226,8 @@ private:
void readSettings(bool _skipGeometry = false); void readSettings(bool _skipGeometry = false);
void writeSettings(); void writeSettings();
void setPrivateChain(QString const& _private, bool _forceConfigure = false);
unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f); unsigned installWatch(dev::eth::LogFilter const& _tf, WatchHandler const& _f);
unsigned installWatch(dev::h256 _tf, WatchHandler const& _f); unsigned installWatch(dev::h256 _tf, WatchHandler const& _f);
void uninstallWatch(unsigned _w); void uninstallWatch(unsigned _w);

15
exp/main.cpp

@ -284,6 +284,21 @@ int main()
return 0; return 0;
} }
#elif 1 #elif 1
int main()
{
bytes tx = fromHex("f84c01028332dcd58004801ba024843272ee176277535489859cbd275686023fe64aabd158b6fcdf2ae6a1ab6ba02f252a5016a48e5ec8d17aefaf4324d29b9e123fa623dc5a60539b3ad3610c95");
Transaction t(tx, CheckTransaction::None);
Public p = recover(t.signature(), t.sha3(WithoutSignature));
cnote << t.signature().r;
cnote << t.signature().s;
cnote << t.signature().v;
cnote << p;
cnote << toAddress(p);
cnote << t.sender();
}
#elif 0
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
{ {
s.commitToMine(_bc); s.commitToMine(_bc);

4
libdevcrypto/Common.cpp

@ -193,7 +193,7 @@ bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _ci
} }
} }
static const Public c_zeroKey = toPublic(Secret()); static const Public c_zeroKey("3f17f1962b36e491b30a40b2405849e597ba5fb5");
Public dev::recover(Signature const& _sig, h256 const& _message) Public dev::recover(Signature const& _sig, h256 const& _message)
{ {
@ -203,7 +203,7 @@ Public dev::recover(Signature const& _sig, h256 const& _message)
int pubkeylen; int pubkeylen;
if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64])) if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64]))
return Public(); return Public();
ret = FixedHash<64>(o.data()+1, Public::ConstructFromPointer); ret = FixedHash<64>(o.data() + 1, Public::ConstructFromPointer);
#else #else
ret = s_secp256k1pp.recover(_sig, _message.ref()); ret = s_secp256k1pp.recover(_sig, _message.ref());
#endif #endif

23
libethereum/BlockChain.cpp

@ -146,8 +146,12 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif #endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
m_genesisState(_genesisState) {
open(_genesisBlock, _genesisState, _path, _we, _p);
}
void BlockChain::open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
{ {
// initialise deathrow. // initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize); m_cacheUsage.resize(c_collectionQueueSize);
@ -156,11 +160,12 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, A
// Initialise with the genesis as the last block on the longest chain. // Initialise with the genesis as the last block on the longest chain.
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
m_genesisState = _genesisState;
// remove the next line real soon. we don't need to be supporting this forever. // remove the next line real soon. we don't need to be supporting this forever.
upgradeDatabase(_path, genesisHash()); upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion) if (openDatabase(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p); rebuild(_path, _p);
} }
@ -169,7 +174,7 @@ BlockChain::~BlockChain()
close(); close();
} }
unsigned BlockChain::open(std::string const& _path, WithExisting _we) unsigned BlockChain::openDatabase(std::string const& _path, WithExisting _we)
{ {
string path = _path.empty() ? Defaults::get()->m_dbPath : _path; string path = _path.empty() ? Defaults::get()->m_dbPath : _path;
string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4)); string chainPath = path + "/" + toHex(m_genesisHash.ref().cropped(0, 4));
@ -243,12 +248,22 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we)
void BlockChain::close() void BlockChain::close()
{ {
cnote << "Closing blockchain DB"; cnote << "Closing blockchain DB";
// Not thread safe...
delete m_extrasDB; delete m_extrasDB;
delete m_blocksDB; delete m_blocksDB;
m_lastBlockHash = m_genesisHash; m_lastBlockHash = m_genesisHash;
m_lastBlockNumber = 0; m_lastBlockNumber = 0;
m_details.clear(); m_details.clear();
m_blocks.clear(); m_blocks.clear();
m_logBlooms.clear();
m_receipts.clear();
m_transactionAddresses.clear();
m_blockHashes.clear();
m_blocksBlooms.clear();
m_cacheUsage.clear();
m_inUse.clear();
m_lastLastHashes.clear();
m_lastLastHashesNumber = (unsigned)-1;
} }
void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW) void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned, unsigned)> const& _progress, bool _prepPoW)

10
libethereum/BlockChain.h

@ -106,8 +106,8 @@ public:
BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback());
~BlockChain(); ~BlockChain();
/// Attempt a database re-open. /// Reopen everything.
void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust) { close(); open(_path, _we); } virtual void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()) { close(); open(m_genesisBlock, m_genesisState, _path, _we, _pc); }
/// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock.
/// To be called from main loop every 100ms or so. /// To be called from main loop every 100ms or so.
@ -291,7 +291,11 @@ public:
protected: protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); /// Initialise everything and open the database.
void open(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p);
/// Open the database.
unsigned openDatabase(std::string const& _path, WithExisting _we = WithExisting::Trust);
/// Finalise everything and close the database.
void close(); void close();
template<class T, class K, unsigned N> T queryExtras(K const& _h, std::unordered_map<K, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const template<class T, class K, unsigned N> T queryExtras(K const& _h, std::unordered_map<K, T>& _m, boost::shared_mutex& _x, T const& _n, ldb::DB* _extrasDB = nullptr) const

24
libethereum/CanonBlockChain.cpp

@ -38,16 +38,23 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
std::unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis; unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis; boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
Nonce CanonBlockChain<Ethash>::s_nonce(u64(42)); Nonce CanonBlockChain<Ethash>::s_nonce(u64(42));
std::string CanonBlockChain<Ethash>::s_genesisStateJSON; string CanonBlockChain<Ethash>::s_genesisStateJSON;
bytes CanonBlockChain<Ethash>::s_genesisExtraData;
CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc) FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc)
{ {
} }
void CanonBlockChain<Ethash>::reopen(std::string const& _path, WithExisting _we, ProgressCallback const& _pc)
{
close();
open(createGenesisBlock(), createGenesisState(), _path, _we, _pc);
}
bytes CanonBlockChain<Ethash>::createGenesisBlock() bytes CanonBlockChain<Ethash>::createGenesisBlock()
{ {
RLPStream block(3); RLPStream block(3);
@ -87,7 +94,7 @@ bytes CanonBlockChain<Ethash>::createGenesisBlock()
<< gasLimit << gasLimit
<< 0 // gasUsed << 0 // gasUsed
<< timestamp << timestamp
<< extraData << (s_genesisExtraData.empty() ? extraData : s_genesisExtraData)
<< mixHash << mixHash
<< nonce; << nonce;
block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList);
@ -108,7 +115,9 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
u256 balance; u256 balance;
if (account.second.get_obj().count("wei")) if (account.second.get_obj().count("wei"))
balance = u256(account.second.get_obj()["wei"].get_str()); balance = u256(account.second.get_obj()["wei"].get_str());
else else if (account.second.get_obj().count("balance"))
balance = u256(account.second.get_obj()["balance"].get_str());
else if (account.second.get_obj().count("finney"))
balance = u256(account.second.get_obj()["finney"].get_str()) * finney; balance = u256(account.second.get_obj()["finney"].get_str()) * finney;
if (account.second.get_obj().count("code")) if (account.second.get_obj().count("code"))
{ {
@ -129,6 +138,13 @@ void CanonBlockChain<Ethash>::setGenesis(std::string const& _json)
s_genesis.reset(); s_genesis.reset();
} }
void CanonBlockChain<Ethash>::forceGenesisExtraData(bytes const& _genesisExtraData)
{
WriteGuard l(x_genesis);
s_genesisExtraData = _genesisExtraData;
s_genesis.reset();
}
Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis() Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis()
{ {
UpgradableGuard l(x_genesis); UpgradableGuard l(x_genesis);

8
libethereum/CanonBlockChain.h

@ -78,6 +78,9 @@ public:
CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()); CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
~CanonBlockChain() {} ~CanonBlockChain() {}
/// Reopen everything.
virtual void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
/// @returns the genesis block header. /// @returns the genesis block header.
static Ethash::BlockHeader const& genesis(); static Ethash::BlockHeader const& genesis();
@ -90,12 +93,12 @@ public:
static std::unordered_map<Address, Account> createGenesisState(); static std::unordered_map<Address, Account> createGenesisState();
/// Alter all the genesis block's state by giving a JSON string with account details. /// Alter all the genesis block's state by giving a JSON string with account details.
/// @TODO implement.
/// @warning Unless you're very careful, make sure you call this right at the start of the /// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all. /// program, before anything has had the chance to use this class at all.
static void setGenesis(std::string const& _genesisInfoJSON); static void setGenesis(std::string const& _genesisInfoJSON);
// TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, /// Override the genesis block's extraData field.
static void forceGenesisExtraData(bytes const& _genesisExtraData);
private: private:
/// Static genesis info and its lock. /// Static genesis info and its lock.
@ -103,6 +106,7 @@ private:
static std::unique_ptr<Ethash::BlockHeader> s_genesis; static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce; static Nonce s_nonce;
static std::string s_genesisStateJSON; static std::string s_genesisStateJSON;
static bytes s_genesisExtraData;
}; };
} }

6
libethereum/Client.cpp

@ -327,7 +327,7 @@ void Client::doneWorking()
} }
} }
void Client::killChain() void Client::reopenChain(WithExisting _we)
{ {
bool wasMining = isMining(); bool wasMining = isMining();
if (wasMining) if (wasMining)
@ -348,8 +348,8 @@ void Client::killChain()
m_working = State(); m_working = State();
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); bc().reopen(Defaults::dbPath(), _we);
bc().reopen(Defaults::dbPath(), WithExisting::Kill); m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), _we);
m_preMine = bc().genesisState(m_stateDB); m_preMine = bc().genesisState(m_stateDB);
m_postMine = m_preMine; m_postMine = m_preMine;

4
libethereum/Client.h

@ -176,7 +176,9 @@ public:
/// Clears pending transactions. Just for debug use. /// Clears pending transactions. Just for debug use.
void clearPending(); void clearPending();
/// Kills the blockchain. Just for debug use. /// Kills the blockchain. Just for debug use.
void killChain(); void killChain() { reopenChain(WithExisting::Kill); }
/// Reloads the blockchain. Just for debug use.
void reopenChain(WithExisting _we = WithExisting::Trust);
/// Retries all blocks with unknown parents. /// Retries all blocks with unknown parents.
void retryUnknown() { m_bq.retryAllUnknown(); } void retryUnknown() { m_bq.retryAllUnknown(); }
/// Get a report of activity. /// Get a report of activity.

Loading…
Cancel
Save