From a068543f21db9efd7e659aa4848d7e959bc711ba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Dec 2014 21:43:38 +0100 Subject: [PATCH 1/4] State reworked slightly. Additional experimentation for State to demo how easily it is to create states. --- exp/main.cpp | 80 ++++++++------------------------------------- libethereum/State.h | 16 ++++----- 2 files changed, 21 insertions(+), 75 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 8be79cad5..6192ab96c 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include using namespace std; @@ -36,7 +37,7 @@ using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; -#if 1 +#if 0 int main() { DownloadMan man; @@ -72,72 +73,17 @@ int main() cnote << i;*/ return 0; } -#endif - -/*int other(bool& o_started) +#else +int main() { - setThreadName("other"); - - short listenPort = 30300; - - Host ph("Test", NetworkPreferences(listenPort, "", false, true)); - auto wh = ph.registerCapability(new WhisperHost()); - - ph.start(); - - o_started = true; - - /// Only interested in odd packets - auto w = wh->installWatch(BuildTopicMask()("odd")); - - unsigned last = 0; - unsigned total = 0; - - for (int i = 0; i < 100 && last < 81; ++i) - { - for (auto i: wh->checkWatch(w)) - { - Message msg = wh->envelope(i).open(); - last = RLP(msg.payload()).toInt(); - cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); - total += last; - } - this_thread::sleep_for(chrono::milliseconds(50)); - } - return total; + KeyPair u = KeyPair::create(); + KeyPair cb = KeyPair::create(); + OverlayDB db; + State s(cb.address(), db); + cnote << s.rootHash(); + s.addBalance(u.address(), 1000 * ether); + s.commit(); + cnote << s.rootHash(); } +#endif -int main(int, char**) -{ - g_logVerbosity = 0; - - bool started = false; - unsigned result; - std::thread listener([&](){ return (result = other(started)); }); - while (!started) - this_thread::sleep_for(chrono::milliseconds(50)); - - short listenPort = 30303; - string remoteHost = "127.0.0.1"; - short remotePort = 30300; - - Host ph("Test", NetworkPreferences(listenPort, "", false, true)); - auto wh = ph.registerCapability(new WhisperHost()); - - ph.start(); - - if (!remoteHost.empty()) - ph.connect(remoteHost, remotePort); - - KeyPair us = KeyPair::create(); - for (int i = 0; i < 10; ++i) - { - wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even")); - this_thread::sleep_for(chrono::milliseconds(250)); - } - - listener.join(); - assert(result == 1 + 9 + 25 + 49 + 81); - - return 0; -}*/ diff --git a/libethereum/State.h b/libethereum/State.h index 611647566..b071e7674 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -244,6 +244,12 @@ public: /// the block since all state changes are ultimately reversed. void cleanup(bool _fullCommit); + /// Commit all changes waiting in the address cache to the DB. + void commit(); + + /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). + void resetCurrent(); + private: /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -257,25 +263,19 @@ private: /// Retrieve all information about a given address into a cache. void ensureCached(std::map& _cache, Address _a, bool _requireCode, bool _forceCreate) const; - /// Commit all changes waiting in the address cache to the DB. - void commit(); - /// Execute the given block, assuming it corresponds to m_currentBlock. If _bc is passed, it will be used to check the uncles. /// Throws on failure. u256 enact(bytesConstRef _block, BlockChain const* _bc = nullptr, bool _checkNonce = true); - /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). - void resetCurrent(); - /// Finalise the block, applying the earned rewards. void applyRewards(Addresses const& _uncleAddresses); - void refreshManifest(RLPStream* _txs = nullptr); - /// @returns gas used by transactions thus far executed. u256 gasUsed() const { return m_receipts.size() ? m_receipts.back().gasUsed() : 0; } + /// Debugging only. Good for checking the Trie is in shape. bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const; + /// Debugging only. Good for checking the Trie is in shape. void paranoia(std::string const& _when, bool _enforceRefs = false) const; OverlayDB m_db; ///< Our overlay for the state tree. From 4a0ac1f4c2f294052e052e1a1533302f2509a189 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Dec 2014 21:48:23 +0100 Subject: [PATCH 2/4] Silly windows fix. --- test/solidityEndToEndTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 2c1885ad8..15722abe1 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -402,7 +402,7 @@ BOOST_AUTO_TEST_CASE(empty_string_on_stack) " }\n" "}\n"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction(0, bytes({0x02})) == bytes({0x00, 0x02, 0x61/*'a'*/, 0x62/*'b'*/, 0x63/*'c'*/, 0x00})); + BOOST_CHECK(callContractFunction(0, bytes(1, 0x02)) == bytes({0x00, 0x02, 0x61/*'a'*/, 0x62/*'b'*/, 0x63/*'c'*/, 0x00})); } BOOST_AUTO_TEST_CASE(state_smoke_test) From 0cd39343eb086ac277fba92c0815894aa0aedb31 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Dec 2014 22:40:57 +0100 Subject: [PATCH 3/4] Demonstration of how to create a completely custom state for execution of transactions. --- exp/main.cpp | 13 +++++++++++-- libethcore/BlockInfo.cpp | 19 +++++++++++++++++++ libethcore/BlockInfo.h | 2 ++ libethereum/ExtVM.h | 1 + libethereum/State.cpp | 39 +++++++++++++++++++++++++++++++++------ libethereum/State.h | 7 ++++++- 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 6192ab96c..aee6e6efd 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include using namespace std; @@ -79,11 +80,19 @@ int main() KeyPair u = KeyPair::create(); KeyPair cb = KeyPair::create(); OverlayDB db; - State s(cb.address(), db); + State s(cb.address(), db, BaseState::Empty); cnote << s.rootHash(); - s.addBalance(u.address(), 1000 * ether); + s.addBalance(u.address(), 1 * ether); + Address c = s.newContract(1000 * ether, compileLLL("(suicide (caller))")); s.commit(); cnote << s.rootHash(); + State before = s; + cnote << s; + Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret()); + cnote << s.balance(c); + s.execute(t.rlp()); + cnote << before.diff(s); + cnote << s; } #endif diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index bf973b565..6c08bb346 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -40,6 +40,25 @@ BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce) populate(_block, _checkNonce); } +void BlockInfo::setEmpty() +{ + parentHash = h256(); + sha3Uncles = EmptyListSHA3; + coinbaseAddress = Address(); + stateRoot = EmptyTrie; + transactionsRoot = EmptyTrie; + receiptsRoot = EmptyTrie; + logBloom = LogBloom(); + difficulty = 0; + number = 0; + gasLimit = 0; + gasUsed = 0; + timestamp = 0; + extraData.clear(); + nonce = h256(); + hash = headerHash(WithNonce); +} + BlockInfo BlockInfo::fromHeader(bytesConstRef _block) { BlockInfo ret; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 18dd53ff3..99efc6a17 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -108,6 +108,8 @@ public: } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } + void setEmpty(); + void populateFromHeader(RLP const& _header, bool _checkNonce = true); void populate(bytesConstRef _block, bool _checkNonce = true); void populate(bytes const& _block, bool _checkNonce = true) { populate(&_block, _checkNonce); } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index 9699a68ad..cfe40874f 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -73,6 +73,7 @@ public: virtual void suicide(Address _a) override final { m_s.addBalance(_a, m_s.balance(myAddress)); + m_s.subBalance(myAddress, m_s.balance(myAddress)); ExtVMFace::suicide(_a); } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 64210f20a..fd00761e1 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -63,7 +63,7 @@ OverlayDB State::openDB(std::string _path, bool _killExisting) return OverlayDB(db); } -State::State(Address _coinbaseAddress, OverlayDB const& _db): +State::State(Address _coinbaseAddress, OverlayDB const& _db, BaseState _bs): m_db(_db), m_state(&m_db), m_ourAddress(_coinbaseAddress), @@ -74,12 +74,19 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db): paranoia("beginning of normal construction.", true); - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); + if (_bs == BaseState::Genesis) + { + dev::eth::commit(genesisState(), m_db, m_state); + m_db.commit(); - paranoia("after DB commit of normal construction.", true); + paranoia("after DB commit of normal construction.", true); + m_previousBlock = BlockChain::genesis(); + } + else + { + m_previousBlock.setEmpty(); + } - m_previousBlock = BlockChain::genesis(); resetCurrent(); assert(m_state.root() == m_previousBlock.stateRoot); @@ -857,6 +864,23 @@ void State::subBalance(Address _id, bigint _amount) it->second.addBalance(-_amount); } +Address State::newContract(u256 _balance, bytes const& _code) +{ + auto h = sha3(_code); + m_db.insert(h, &_code); + while (true) + { + Address ret = Address::random(); + ensureCached(ret, false, false); + auto it = m_cache.find(ret); + if (it == m_cache.end()) + { + m_cache[ret] = Account(0, _balance, EmptyTrie, h); + return ret; + } + } +} + u256 State::transactionsFrom(Address _id) const { ensureCached(_id, false, false); @@ -993,8 +1017,11 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif - +#if ETH_TRACE e.go(e.simpleTrace()); +#else + e.go(); +#endif e.finalize(); #if ETH_PARANOIA diff --git a/libethereum/State.h b/libethereum/State.h index b071e7674..763a67451 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -53,6 +53,8 @@ struct StateTrace: public LogChannel { static const char* name() { return "=S="; struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; }; struct StateSafeExceptions: public LogChannel { static const char* name() { return "(S)"; } static const int verbosity = 21; }; +enum class BaseState { Empty, Genesis }; + /** * @brief Model of the current state of the ledger. * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). @@ -66,7 +68,7 @@ class State public: /// Construct state object. - State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB()); + State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB(), BaseState _bs = BaseState::Genesis); /// Construct state object from arbitrary point in blockchain. State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash); @@ -183,6 +185,9 @@ public: /// Set the value of a storage position of an account. void setStorage(Address _contract, u256 _location, u256 _value) { m_cache[_contract].setStorage(_location, _value); } + /// Create a new contract. + Address newContract(u256 _balance, bytes const& _code); + /// Get the storage of an account. /// @note This is expensive. Don't use it unless you need to. /// @returns std::map if no account exists at that address. From bf3fbae3979d2d8d3efacb7f50abf4eac7ab7412 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Dec 2014 22:44:28 +0100 Subject: [PATCH 4/4] Demonstration readability improved. Clear how the State diff works. --- exp/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index aee6e6efd..3c4a1b207 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,14 +85,14 @@ int main() s.addBalance(u.address(), 1 * ether); Address c = s.newContract(1000 * ether, compileLLL("(suicide (caller))")); s.commit(); - cnote << s.rootHash(); State before = s; - cnote << s; + cnote << "State before transaction: " << before; Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret()); + cnote << "Transaction: " << t; cnote << s.balance(c); s.execute(t.rlp()); + cnote << "State after transaction: " << s; cnote << before.diff(s); - cnote << s; } #endif