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();
}
NetworkPreferences ret;
if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
ret = NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
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()
@ -776,6 +783,30 @@ void Main::writeSettings()
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
{
while (true)
@ -852,8 +883,7 @@ void Main::readSettings(bool _skipGeometry)
ui->listenIP->setText(s.value("listenIP", "").toString());
ui->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString();
ui->usePrivate->setChecked(m_privateChain.size());
setPrivateChain(s.value("privateChain", "").toString());
ui->verbosity->setValue(s.value("verbosity", 1).toInt());
#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()
{
QString pc;
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)));
if (m_privateChain.isEmpty())
{
if (ui->usePrivate->isChecked())
ui->usePrivate->setChecked(false);
else
// was cancelled.
return;
}
bool ok;
pc = QInputDialog::getText(this, "Enter Name", "Enter the name of your private chain", QLineEdit::Normal, QString("NewChain-%1").arg(time(0)), &ok);
if (!ok)
return;
}
else
m_privateChain.clear();
on_killBlockchain_triggered();
setPrivateChain(pc);
}
void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); }
@ -2015,7 +2039,7 @@ void Main::on_net_triggered()
{
web3()->setIdealPeerCount(ui->idealPeers->value());
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();
ui->downloadView->setEthereum(ethereum());
ui->enode->setText(QString::fromStdString(web3()->enode()));

2
alethzero/MainWin.h

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

15
exp/main.cpp

@ -284,6 +284,21 @@ int main()
return 0;
}
#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)
{
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)
{
@ -203,7 +203,7 @@ Public dev::recover(Signature const& _sig, h256 const& _message)
int pubkeylen;
if (!secp256k1_ecdsa_recover_compact(_message.data(), h256::size, _sig.data(), o.data(), &pubkeylen, false, _sig[64]))
return Public();
ret = FixedHash<64>(o.data()+1, Public::ConstructFromPointer);
ret = FixedHash<64>(o.data() + 1, Public::ConstructFromPointer);
#else
ret = s_secp256k1pp.recover(_sig, _message.ref());
#endif

23
libethereum/BlockChain.cpp

@ -146,8 +146,12 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p):
m_genesisState(_genesisState)
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
{
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.
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.
m_genesisBlock = _genesisBlock;
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.
upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion)
if (openDatabase(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p);
}
@ -169,7 +174,7 @@ BlockChain::~BlockChain()
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 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()
{
cnote << "Closing blockchain DB";
// Not thread safe...
delete m_extrasDB;
delete m_blocksDB;
m_lastBlockHash = m_genesisHash;
m_lastBlockNumber = 0;
m_details.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)

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();
/// Attempt a database re-open.
void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust) { close(); open(_path, _we); }
/// Reopen everything.
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.
/// To be called from main loop every 100ms or so.
@ -291,7 +291,11 @@ public:
protected:
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();
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;
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;
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):
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()
{
RLPStream block(3);
@ -87,7 +94,7 @@ bytes CanonBlockChain<Ethash>::createGenesisBlock()
<< gasLimit
<< 0 // gasUsed
<< timestamp
<< extraData
<< (s_genesisExtraData.empty() ? extraData : s_genesisExtraData)
<< mixHash
<< nonce;
block.appendRaw(RLPEmptyList);
@ -108,7 +115,9 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
u256 balance;
if (account.second.get_obj().count("wei"))
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;
if (account.second.get_obj().count("code"))
{
@ -129,6 +138,13 @@ void CanonBlockChain<Ethash>::setGenesis(std::string const& _json)
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()
{
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() {}
/// Reopen everything.
virtual void reopen(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback());
/// @returns the genesis block header.
static Ethash::BlockHeader const& genesis();
@ -90,12 +93,12 @@ public:
static std::unordered_map<Address, Account> createGenesisState();
/// 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
/// program, before anything has had the chance to use this class at all.
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:
/// Static genesis info and its lock.
@ -103,6 +106,7 @@ private:
static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce;
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();
if (wasMining)
@ -348,8 +348,8 @@ void Client::killChain()
m_working = State();
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
bc().reopen(Defaults::dbPath(), WithExisting::Kill);
bc().reopen(Defaults::dbPath(), _we);
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), _we);
m_preMine = bc().genesisState(m_stateDB);
m_postMine = m_preMine;

4
libethereum/Client.h

@ -176,7 +176,9 @@ public:
/// Clears pending transactions. Just for debug use.
void clearPending();
/// 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.
void retryUnknown() { m_bq.retryAllUnknown(); }
/// Get a report of activity.

Loading…
Cancel
Save