From dc686aa542d8c3697ea3a9f44c11ac18286a61cd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 25 Feb 2014 11:11:54 +0000 Subject: [PATCH 01/24] Cleanup executeBare(). --- libethereum/State.cpp | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 13c826bb2..74db7aeb4 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -624,12 +624,21 @@ void State::unapplyRewards(Addresses const& _uncleAddresses) void State::executeBare(Transaction const& _t, Address _sender) { +#if ETH_DEBUG + commit(); + clog(StateChat) << "State:" << rootHash(); + clog(StateChat) << "Executing TX:" << _t; +#endif + // Entry point for a contract-originated transaction. // Ignore invalid transactions. auto nonceReq = transactionsFrom(_sender); if (_t.nonce != nonceReq) + { + clog(StateChat) << "Invalid Nonce."; throw InvalidNonce(nonceReq, _t.nonce); + } unsigned nonZeroData = 0; for (auto i: _t.data) @@ -639,13 +648,17 @@ void State::executeBare(Transaction const& _t, Address _sender) // Not considered invalid - just pointless. if (balance(_sender) < _t.value + fee) + { + clog(StateChat) << "Not enough cash."; throw NotEnoughCash(); + } if (_t.receiveAddress) { // Increment associated nonce for sender. noteSending(_sender); + // Pay... subBalance(_sender, _t.value + fee); addBalance(_t.receiveAddress, _t.value); @@ -659,37 +672,36 @@ void State::executeBare(Transaction const& _t, Address _sender) } catch (VMException const& _e) { - cnote << "VM Exception: " << _e.description(); + clog(StateChat) << "VM Exception: " << _e.description(); } catch (Exception const& _e) { - cnote << "Exception in VM: " << _e.description(); + clog(StateChat) << "Exception in VM: " << _e.description(); } catch (std::exception const& _e) { - cnote << "std::exception in VM: " << _e.what(); + clog(StateChat) << "std::exception in VM: " << _e.what(); } } } else { -#if ETH_SENDER_PAYS_SETUP - if (balance(_sender) < _t.value + fee) -#else - if (_t.value < fee) -#endif - throw NotEnoughCash(); - Address newAddress = right160(_t.sha3()); if (isContractAddress(newAddress) || isNormalAddress(newAddress)) + { + clog(StateChat) << "Contract address collision."; throw ContractAddressCollision(); + } // Increment associated nonce for sender. noteSending(_sender); - // All OK - set it up. - m_cache[newAddress] = AddressState(0, 0, AddressType::Contract); + // Pay out of sender... + subBalance(_sender, _t.value + fee); + + // Set up new account... + m_cache[newAddress] = AddressState(_t.value, 0, AddressType::Contract); auto& mem = m_cache[newAddress].memory(); for (uint i = 0; i < _t.data.size(); ++i) #ifdef __clang__ @@ -700,15 +712,12 @@ void State::executeBare(Transaction const& _t, Address _sender) #else mem[i] = _t.data[i]; #endif + } -#if ETH_SENDER_PAYS_SETUP - subBalance(_sender, _t.value + fee); - addBalance(newAddress, _t.value); -#else - subBalance(_sender, _t.value); - addBalance(newAddress, _t.value - fee); +#if ETH_DEBUG + commit(); + clog(StateChat) << "New state:" << rootHash(); #endif - } } void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256s const& _txData, u256* _totalFee) From 31bda990b633a5444db6af41973a22c4ec1970c7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 25 Feb 2014 11:12:54 +0000 Subject: [PATCH 02/24] Fix State.h. --- libethereum/State.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libethereum/State.h b/libethereum/State.h index 30ab9686d..0ccc94164 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -44,10 +44,10 @@ class BlockChain; extern u256 c_genesisDifficulty; std::map const& genesisState(); -#define ETH_SENDER_PAYS_SETUP 1 - static const std::map EmptyMapU256U256; +struct StateChat: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 4; }; + class ExtVM; /** From 7bfe57e2e031b87191c4b7db7dbaecde7c244ac1 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Tue, 25 Feb 2014 14:57:04 +0000 Subject: [PATCH 03/24] Fix bug where buffer was being deleted underneath async_write operation. Fix bug where member function called from async callback without holding valid shared_ptr to class. --- libethereum/PeerNetwork.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libethereum/PeerNetwork.cpp b/libethereum/PeerNetwork.cpp index 828caec46..c77af38eb 100644 --- a/libethereum/PeerNetwork.cpp +++ b/libethereum/PeerNetwork.cpp @@ -483,19 +483,21 @@ bool PeerSession::checkPacket(bytesConstRef _msg) void PeerSession::sendDestroy(bytes& _msg) { clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8)); - std::shared_ptr buffer = std::make_shared(); - swap(*buffer, _msg); - if (!checkPacket(bytesConstRef(&*buffer))) + + if (!checkPacket(bytesConstRef(&_msg))) { cwarn << "INVALID PACKET CONSTRUCTED!"; - } - ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length) + + auto self(shared_from_this()); + bytes* buffer = new bytes(std::move(_msg)); + ba::async_write(m_socket, ba::buffer(*buffer), [self,buffer](boost::system::error_code ec, std::size_t length) { + delete buffer; if (ec) { cwarn << "Error sending: " << ec.message(); - dropped(); + self->dropped(); } // cbug << length << " bytes written (EC: " << ec << ")"; }); @@ -504,17 +506,21 @@ void PeerSession::sendDestroy(bytes& _msg) void PeerSession::send(bytesConstRef _msg) { clogS(NetLeft) << RLP(_msg.cropped(8)); - std::shared_ptr buffer = std::make_shared(_msg.toBytes()); + if (!checkPacket(_msg)) { cwarn << "INVALID PACKET CONSTRUCTED!"; } - ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length) + + auto self(shared_from_this()); + bytes* buffer = new bytes(_msg.toBytes()); + ba::async_write(m_socket, ba::buffer(*buffer), [self,buffer](boost::system::error_code ec, std::size_t length) { + delete buffer; if (ec) { cwarn << "Error sending: " << ec.message(); - dropped(); + self->dropped(); } // cbug << length << " bytes written (EC: " << ec << ")"; }); @@ -568,7 +574,7 @@ void PeerSession::start() void PeerSession::doRead() { auto self(shared_from_this()); - m_socket.async_read_some(boost::asio::buffer(m_data), [this, self](boost::system::error_code ec, std::size_t length) + m_socket.async_read_some(boost::asio::buffer(m_data), [this,self](boost::system::error_code ec, std::size_t length) { if (ec) { From 95a954dbb2c34cbdbacdeb62378e38f19f60ea74 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Feb 2014 09:33:18 -0600 Subject: [PATCH 04/24] Example of how to use std::hash_map Please enter the commit message for your changes. Lines starting --- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 4 +++- libethereum/Common.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 872026d90..bcb893d54 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -271,7 +271,7 @@ bytesConstRef BlockChain::block(h256 _hash) const BlockDetails const& BlockChain::details(h256 _h) const { - std::map::const_iterator it; + BlockDetailsHash::const_iterator it; bool fetchRequired; { lock_guard l(m_lock); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 9b77de24d..56906d32e 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -48,6 +48,8 @@ struct BlockDetails h256s children; }; +typedef std::hash_map BlockDetailsHash; + static const BlockDetails NullBlockDetails; static const h256s NullH256s; @@ -101,7 +103,7 @@ private: void checkConsistency(); /// Get fully populated from disk DB. - mutable std::map m_details; + mutable BlockDetailsHash m_details; mutable std::map m_cache; mutable std::mutex m_lock; diff --git a/libethereum/Common.h b/libethereum/Common.h index efdf825db..c8f15f599 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -181,6 +182,43 @@ using HexMap = std::map; static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; +// This is the helper class for the std::hash_map lookup; it converts the input 256bit hash into a size_t sized hash value +// and does an exact comparison of two hash entries. +class H256Hash +{ +public: + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + + // Compute the size_t hash of this hash + size_t operator()(const h256 &index) const + { + const uint64_t *data = (const uint64_t *)index.data(); + uint64_t hash = data[0]; + hash ^= data[1]; + hash ^= data[2]; + hash ^= data[3]; + return (size_t)hash; + } + + // Return true if hash s1 is less than hash s2 + bool operator()(const h256 &s1, const h256 &s2) const + { + const uint64_t *hash1 = (const uint64_t *)s1.data(); + const uint64_t *hash2 = (const uint64_t *)s2.data(); + + if (hash1[0] < hash2[0]) return true; + if (hash1[0] > hash2[0]) return false; + + if (hash1[1] < hash2[1]) return true; + if (hash1[1] > hash2[1]) return false; + + if (hash1[2] < hash2[2]) return true; + if (hash1[2] > hash2[2]) return false; + + return hash1[3] < hash2[3]; + } +}; /// Logging class NullOutputStream From 762b563b4f7ce93f1382ba395984c0182aa087c5 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Tue, 25 Feb 2014 16:05:07 +0000 Subject: [PATCH 05/24] Be more helpful and create a branch when checking out cpp-ethereum. --- windows/bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/bootstrap.sh b/windows/bootstrap.sh index 12935a91f..a3d643b53 100644 --- a/windows/bootstrap.sh +++ b/windows/bootstrap.sh @@ -12,7 +12,7 @@ if [[ ! $@ ]] || [ $1 == "fetch" ]; then if [ ! -d cpp-ethereum ]; then (set -x; git clone https://github.com/ethereum/cpp-ethereum.git) cd cpp-ethereum - (set -x; git checkout origin/develop) + (set -x; git checkout -b develop origin/develop) cd .. echo fi From 025a27ef3fdf3b698b1e2906346aa33dba42b370 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Tue, 25 Feb 2014 16:42:57 +0000 Subject: [PATCH 06/24] Check required binaries are present. --- windows/bootstrap.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/windows/bootstrap.sh b/windows/bootstrap.sh index a3d643b53..126889732 100644 --- a/windows/bootstrap.sh +++ b/windows/bootstrap.sh @@ -7,6 +7,19 @@ # - Visual Studio Express 2013 for Desktop # - On PATH: bash, git, git-svn, curl, sed, 7z +error_exit() { + echo $1 1>&2 + exit 1 +} + +for i in python perl curl git sed 7z; do + which $i &>/dev/null || error_exit "Could not find $i on PATH" +done + +if [ ! -d "$VS120COMNTOOLS" ]; then + error_exit "Couldn't find Visual Studio 2013" +fi + if [[ ! $@ ]] || [ $1 == "fetch" ]; then # fetch ethereum (develop branch) if [ ! -d cpp-ethereum ]; then From e44615cdc666e26399a1f2eb2e1692929848fde2 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 26 Feb 2014 01:22:17 +0000 Subject: [PATCH 07/24] use std::unordered_map for blockchain + minor fixes - hashing class defined in Common.h (credit JW Ratcliff) - fix m_stack/m_temp in VM clang sections - explicit namespace for std::make_pair calls --- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 4 ++-- libethereum/Common.h | 7 +++---- libethereum/State.h | 2 +- libethereum/VM.h | 16 ++++++++-------- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bcb893d54..7bf7606da 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -290,7 +290,7 @@ BlockDetails const& BlockChain::details(h256 _h) const { lock_guard l(m_lock); bool ok; - tie(it, ok) = m_details.insert(make_pair(_h, BlockDetails(RLP(s)))); + tie(it, ok) = m_details.insert(std::make_pair(_h, BlockDetails(RLP(s)))); } } return it->second; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 56906d32e..ef1cab753 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -48,7 +48,7 @@ struct BlockDetails h256s children; }; -typedef std::hash_map BlockDetailsHash; +typedef std::unordered_map BlockDetailsHash; static const BlockDetails NullBlockDetails; static const h256s NullH256s; @@ -74,7 +74,7 @@ public: /// (Potentially) renders invalid existing bytesConstRef returned by lastBlock. /// To be called from main loop every 100ms or so. void process(); - + /// Attempt to import the given block. bool attemptImport(bytes const& _block, Overlay const& _stateDB); diff --git a/libethereum/Common.h b/libethereum/Common.h index c8f15f599..d54aa6c75 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -182,7 +181,7 @@ using HexMap = std::map; static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; -// This is the helper class for the std::hash_map lookup; it converts the input 256bit hash into a size_t sized hash value +// This is the helper class for the std::unordered_map lookup; it converts the input 256bit hash into a size_t sized hash value // and does an exact comparison of two hash entries. class H256Hash { @@ -262,8 +261,8 @@ public: { time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); char buf[24]; - if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0) - buf[0] = '\0'; // empty if case strftime fails + if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0) + buf[0] = '\0'; // empty if case strftime fails sstr << Id::name() << " [ " << buf << " | " << *(t_logThreadName.m_name.get()) << (_term ? " ] " : ""); } } diff --git a/libethereum/State.h b/libethereum/State.h index 0ccc94164..e3670fe98 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -266,7 +266,7 @@ public: #ifdef __clang__ auto it = m_store->find(_n); if (it == m_store->end()) - m_store->insert(make_pair(_n, _v)); + m_store->insert(std::make_pair(_n, _v)); else m_store->at(_n) = _v; #else diff --git a/libethereum/VM.h b/libethereum/VM.h index 8e36886c5..6e97d5497 100644 --- a/libethereum/VM.h +++ b/libethereum/VM.h @@ -482,11 +482,11 @@ template void eth::VM::go(Ext& _ext, uint64_t _steps) { require(1); #ifdef __clang__ - auto mFinder = tempMem.find(stack.back()); - if (mFinder != tempMem.end()) - stack.back() = mFinder->second; + auto mFinder = m_temp.find(m_stack.back()); + if (mFinder != m_temp.end()) + m_stack.back() = mFinder->second; else - stack.back() = 0; + m_stack.back() = 0; #else m_stack.back() = m_temp[m_stack.back()]; #endif @@ -496,11 +496,11 @@ template void eth::VM::go(Ext& _ext, uint64_t _steps) { require(2); #ifdef __clang__ - auto mFinder = tempMem.find(stack.back()); - if (mFinder == tempMem.end()) - tempMem.insert(make_pair(stack.back(), stack[stack.size() - 2])); + auto mFinder = m_temp.find(m_stack.back()); + if (mFinder == m_temp.end()) + m_temp.insert(std::make_pair(m_stack.back(), m_stack[m_stack.size() - 2])); else - mFinder->second = stack[stack.size() - 2]; + mFinder->second = m_stack[m_stack.size() - 2]; #else m_temp[m_stack.back()] = m_stack[m_stack.size() - 2]; #endif From ca8ac5bd5984694be0be448122ee9e91c0568cf5 Mon Sep 17 00:00:00 2001 From: Daniel Hams Date: Wed, 26 Feb 2014 11:43:49 +0000 Subject: [PATCH 08/24] Workaround OSX clang broken map operator[] using ifdef guards and manual find/insert. --- test/vm.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 9fe858e12..137803a3e 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -43,8 +43,34 @@ public: ExtVMFace(Address(), Address(), 0, u256s(), _fees, _previousBlock, _currentBlock, _currentNumber) {} - u256 store(u256 _n) { return get<3>(addresses[myAddress])[_n]; } - void setStore(u256 _n, u256 _v) { get<3>(addresses[myAddress])[_n] = _v; } + u256 store(u256 _n) + { +#ifdef __clang__ + tuple > & address = addresses[myAddress]; + map & third = get<3>(address); + auto sFinder = third.find(_n); + if (sFinder != third.end()) + return sFinder->second; + else + return 0; +#else + return get<3>(addresses[myAddress])[_n]; +#endif + } + void setStore(u256 _n, u256 _v) + { +#ifdef __clang__ + tuple > & address = addresses[myAddress]; + map & third = get<3>(address); + auto sFinder = third.find(_n); + if (sFinder != third.end()) + sFinder->second = _v; + else + third.insert(std::make_pair(_n, _v)); +#else + get<3>(addresses[myAddress])[_n] = _v; +#endif + } void mktx(Transaction& _t) { if (get<0>(addresses[myAddress]) >= _t.value) @@ -58,7 +84,20 @@ public: u256 balance(Address _a) { return get<0>(addresses[_a]); } void payFee(bigint _fee) { get<0>(addresses[myAddress]) = (u256)(get<0>(addresses[myAddress]) - _fee); } u256 txCount(Address _a) { return get<1>(addresses[_a]); } - u256 extro(Address _a, u256 _pos) { return get<3>(addresses[_a])[_pos]; } + u256 extro(Address _a, u256 _pos) + { +#ifdef __clang__ + tuple > & address = addresses[_a]; + map & third = get<3>(address); + auto sFinder = third.find(_pos); + if (sFinder != third.end()) + return sFinder->second; + else + return 0; +#else + return get<3>(addresses[_a])[_pos]; +#endif + } u256 extroPrice(Address _a) { return get<2>(addresses[_a]); } void suicide(Address _a) { @@ -86,7 +125,19 @@ public: get<1>(addresses[_a]) = _myNonce; get<2>(addresses[_a]) = 0; for (unsigned i = 0; i < _myData.size(); ++i) +#ifdef __clang__ + { + tuple > & address = addresses[_a]; + map & third = get<3>(address); + auto sFinder = third.find(i); + if (sFinder != third.end()) + sFinder->second = _myData[i]; + else + third.insert(std::make_pair(i, _myData[i])); + } +#else get<3>(addresses[_a])[i] = _myData[i]; +#endif } mObject exportEnv() @@ -194,13 +245,36 @@ public: { u256 adr(j.first); for (auto const& k: j.second.get_array()) +#ifdef __clang__ + { + map & third = get<3>(a); + auto sFinder = third.find(adr); + if (sFinder != third.end()) + sFinder->second = toInt(k); + else + third.insert(std::make_pair(adr, toInt(k))); + adr++; + } +#else get<3>(a)[adr++] = toInt(k); +#endif } if (o.count("code")) { u256s d = compileLisp(o["code"].get_str()); for (unsigned i = 0; i < d.size(); ++i) +#ifdef __clang__ + { + map & third = get<3>(a); + auto sFinder = third.find(i); + if (sFinder != third.end()) + sFinder->second = d[i]; + else + third.insert(std::make_pair(i, d[i])); + } +#else get<3>(a)[(u256)i] = d[i]; +#endif } } } From 7e12281c9b37f80fdc0e7e00f73e3e2a44b97319 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 26 Feb 2014 15:18:33 +0000 Subject: [PATCH 09/24] Switch back to normal map for the moment. --- libethereum/BlockChain.h | 2 +- libethereum/Common.h | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index ef1cab753..ee208e508 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -48,7 +48,7 @@ struct BlockDetails h256s children; }; -typedef std::unordered_map BlockDetailsHash; +typedef std::map BlockDetailsHash; static const BlockDetails NullBlockDetails; static const h256s NullH256s; diff --git a/libethereum/Common.h b/libethereum/Common.h index d54aa6c75..d1eed99f8 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -199,24 +199,6 @@ public: hash ^= data[3]; return (size_t)hash; } - - // Return true if hash s1 is less than hash s2 - bool operator()(const h256 &s1, const h256 &s2) const - { - const uint64_t *hash1 = (const uint64_t *)s1.data(); - const uint64_t *hash2 = (const uint64_t *)s2.data(); - - if (hash1[0] < hash2[0]) return true; - if (hash1[0] > hash2[0]) return false; - - if (hash1[1] < hash2[1]) return true; - if (hash1[1] > hash2[1]) return false; - - if (hash1[2] < hash2[2]) return true; - if (hash1[2] > hash2[2]) return false; - - return hash1[3] < hash2[3]; - } }; /// Logging From e182b3293dcc1cdfd1c3a3d9cae0132077a240b1 Mon Sep 17 00:00:00 2001 From: Tim Hughes Date: Wed, 26 Feb 2014 15:31:58 +0000 Subject: [PATCH 10/24] Implement optimised hash and equality operators for h256, and specialise std::hash. --- libethereum/Common.h | 54 ++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/libethereum/Common.h b/libethereum/Common.h index d1eed99f8..6613b70ba 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -145,10 +145,41 @@ public: std::array& asArray() { return m_data; } std::array const& asArray() const { return m_data; } + // generic std::hash compatible function object + struct hash + { + size_t operator()(FixedHash const& value) const + { + size_t h = 0; + for (i: in m_data) h = (h<<5 - h) + i; + return h; + } + }; + private: std::array m_data; }; + +// fast equality for h256 +template<> bool FixedHash<32>::operator==(FixedHash<32> const& _other) const +{ + const uint64_t* hash1 = (const uint64_t*)this->data(); + const uint64_t* hash2 = (const uint64_t*)_other.data(); + return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) && (hash1[3] == hash2[3]); +} + +// fast std::hash compatible hash function object for h256 +template<> size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const +{ + const uint64_t*data = (const uint64_t*)value.data(); + uint64_t hash = data[0]; + hash ^= data[1]; + hash ^= data[2]; + hash ^= data[3]; + return (size_t)hash; +} + template inline std::ostream& operator<<(std::ostream& _out, FixedHash const& _h) { @@ -181,26 +212,6 @@ using HexMap = std::map; static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; -// This is the helper class for the std::unordered_map lookup; it converts the input 256bit hash into a size_t sized hash value -// and does an exact comparison of two hash entries. -class H256Hash -{ -public: - static const size_t bucket_size = 4; - static const size_t min_buckets = 8; - - // Compute the size_t hash of this hash - size_t operator()(const h256 &index) const - { - const uint64_t *data = (const uint64_t *)index.data(); - uint64_t hash = data[0]; - hash ^= data[1]; - hash ^= data[2]; - hash ^= data[3]; - return (size_t)hash; - } -}; - /// Logging class NullOutputStream { @@ -667,3 +678,6 @@ bytes contents(std::string const& _file); void writeFile(std::string const& _file, bytes const& _data); } + +// forward std::hash to eth::h256::hash +template<> struct std::hash : eth::h256::hash {}; From 0731c3ae7a471d420a17777bb34261b76f19efdb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 26 Feb 2014 17:00:21 +0000 Subject: [PATCH 11/24] Hash instructions require at least one on stack. --- libethereum/VM.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libethereum/VM.h b/libethereum/VM.h index 6e97d5497..caafc64b0 100644 --- a/libethereum/VM.h +++ b/libethereum/VM.h @@ -264,6 +264,7 @@ template void eth::VM::go(Ext& _ext, uint64_t _steps) break; case Instruction::SHA256: { + require(1); uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); m_stack.pop_back(); @@ -282,6 +283,7 @@ template void eth::VM::go(Ext& _ext, uint64_t _steps) } case Instruction::RIPEMD160: { + require(1); uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); m_stack.pop_back(); @@ -419,6 +421,7 @@ template void eth::VM::go(Ext& _ext, uint64_t _steps) } case Instruction::SHA3: { + require(1); uint s = (uint)std::min(m_stack.back(), (u256)(m_stack.size() - 1) * 32); m_stack.pop_back(); From 32d333441771956e4c2d868bd5cd7a10be6a92fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 26 Feb 2014 17:06:44 +0000 Subject: [PATCH 12/24] Fixed hash so compiles in a C++ compiler. Not sure what compiler Tim was using. --- libethereum/Common.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libethereum/Common.h b/libethereum/Common.h index 6613b70ba..df4af0fca 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -151,7 +151,8 @@ public: size_t operator()(FixedHash const& value) const { size_t h = 0; - for (i: in m_data) h = (h<<5 - h) + i; + for (auto i: m_data) + h = (h << 5 - h) + i; return h; } }; @@ -162,7 +163,7 @@ private: // fast equality for h256 -template<> bool FixedHash<32>::operator==(FixedHash<32> const& _other) const +template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const { const uint64_t* hash1 = (const uint64_t*)this->data(); const uint64_t* hash2 = (const uint64_t*)_other.data(); @@ -170,7 +171,7 @@ template<> bool FixedHash<32>::operator==(FixedHash<32> const& _other) const } // fast std::hash compatible hash function object for h256 -template<> size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const +template<> inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const { const uint64_t*data = (const uint64_t*)value.data(); uint64_t hash = data[0]; @@ -679,5 +680,8 @@ void writeFile(std::string const& _file, bytes const& _data); } -// forward std::hash to eth::h256::hash -template<> struct std::hash : eth::h256::hash {}; +namespace std +{ + // forward std::hash to eth::h256::hash + template<> struct hash: eth::h256::hash {}; +} From c5304c2e1ae9067d9d0a27def99430b2672ff46d Mon Sep 17 00:00:00 2001 From: Muharem Hrnjadovic Date: Thu, 27 Feb 2014 10:13:38 +0100 Subject: [PATCH 13/24] removed unused class (DBFace) --- libethereum/TrieDB.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libethereum/TrieDB.h b/libethereum/TrieDB.h index e2543548c..36fede58b 100644 --- a/libethereum/TrieDB.h +++ b/libethereum/TrieDB.h @@ -31,14 +31,6 @@ namespace ldb = leveldb; namespace eth { -class DBFace -{ -public: - virtual std::string node(h256 _h) const = 0; - virtual void insertNode(h256 _h, bytesConstRef _v) = 0; - virtual void killNode(h256 _h) = 0; -}; - class BasicMap { public: From 607ba1577db935f9981b3c97508eaf173995e8d4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 10:25:01 +0000 Subject: [PATCH 14/24] Hash fix. --- libethereum/Common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Common.h b/libethereum/Common.h index df4af0fca..1396cd6aa 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -151,7 +151,7 @@ public: size_t operator()(FixedHash const& value) const { size_t h = 0; - for (auto i: m_data) + for (auto i: value.m_data) h = (h << 5 - h) + i; return h; } From 9b86e3764cbaaec48ec4c3ae60fe821f0d171027 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 11:29:39 +0000 Subject: [PATCH 15/24] Make good arithmetic operations. --- json_spirit/json_spirit_writer_template.h | 5 +++- libethereum/Instruction.cpp | 33 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/json_spirit/json_spirit_writer_template.h b/json_spirit/json_spirit_writer_template.h index c99375655..dbd0f45da 100644 --- a/json_spirit/json_spirit_writer_template.h +++ b/json_spirit/json_spirit_writer_template.h @@ -25,7 +25,9 @@ namespace json_spirit return 'A' - 10 + ch; } - template< class String_type > +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-local-typedefs") + template< class String_type > String_type non_printable_to_string( unsigned int c ) { typedef typename String_type::value_type Char_type; @@ -41,6 +43,7 @@ namespace json_spirit return result; } +#pragma GCC diagnostic pop template< typename Char_type, class String_type > bool add_esc_char( Char_type c, String_type& s ) diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 8b7eae18d..41cbf7fe2 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -138,12 +138,15 @@ static void appendCode(u256s& o_code, vector& o_locs, u256s _code, vec static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256s& o_code, vector& o_locs) { + std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } }; + std::set const c_allowed = { '+', '-', '*', '/', '%' }; + bool exec = false; while (d != e) { // skip to next token - for (; d != e && !isalnum(*d) && *d != '(' && *d != ')' && *d != '_' && *d != '"'; ++d) {} + for (; d != e && !isalnum(*d) && *d != '(' && *d != ')' && *d != '_' && *d != '"' && !c_allowed.count(*d); ++d) {} if (d == e) break; @@ -186,7 +189,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 else { char const* s = d; - for (; d != e && (isalnum(*d) || *d == '_'); ++d) {} + for (; d != e && (isalnum(*d) || *d == '_' || c_allowed.count(*d)); ++d) {} t = string(s, d - s); if (isdigit(t[0])) { @@ -360,8 +363,30 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 o_code.push_back(it->second); } } - else if (!_quiet) - cwarn << "Unknown assembler token" << t; + else + { + auto it = c_arith.find(t); + if (it != c_arith.end()) + { + int i = 0; + while (d != e) + { + u256s codes; + vector locs; + if (compileLispFragment(d, e, _quiet, codes, locs)) + { + appendCode(o_code, o_locs, codes, locs); + if (i) + o_code.push_back((u256)it->second); + ++i; + } + else + break; + } + } + else if (!_quiet) + cwarn << "Unknown assembler token" << t; + } } } From 87f9d5bd3980105f5e335ffea104d78b9430bbc4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 12:37:50 +0000 Subject: [PATCH 16/24] Comments and boolean operators. --- libethereum/Instruction.cpp | 106 +++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 41cbf7fe2..bf8d02f4e 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -146,12 +146,15 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 while (d != e) { // skip to next token - for (; d != e && !isalnum(*d) && *d != '(' && *d != ')' && *d != '_' && *d != '"' && !c_allowed.count(*d); ++d) {} + for (; d != e && !isalnum(*d) && *d != '(' && *d != ')' && *d != '_' && *d != '"' && !c_allowed.count(*d) && *d != ';'; ++d) {} if (d == e) break; switch (*d) { + case ';': + for (; d != e && *d != '\n'; ++d) {} + break; case '(': exec = true; ++d; @@ -343,6 +346,107 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 break; } } + else if (t == "AND") + { + vector codes; + vector> locs; + while (d != e) + { + codes.resize(codes.size() + 1); + locs.resize(locs.size() + 1); + if (!compileLispFragment(d, e, _quiet, codes.back(), locs.back())) + break; + } + + // last one is empty. + if (codes.size() < 2) + return false; + + codes.pop_back(); + locs.pop_back(); + + vector ends; + + if (codes.size() > 1) + { + o_code.push_back(Instruction::PUSH); + o_code.push_back(0); + + for (unsigned i = 1; i < codes.size(); ++i) + { + // Push the false location. + o_code.push_back(Instruction::PUSH); + ends.push_back((unsigned)o_code.size()); + o_locs.push_back(ends.back()); + o_code.push_back(0); + + // Check if true - predicate + appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]); + + // Jump to end... + o_code.push_back(Instruction::NOT); + o_code.push_back(Instruction::JMPI); + } + o_code.push_back(Instruction::POP); + } + + // Check if true - predicate + appendCode(o_code, o_locs, codes.back(), locs.back()); + + // At end now. + for (auto i: ends) + o_code[i] = o_code.size(); + } + else if (t == "OR") + { + vector codes; + vector> locs; + while (d != e) + { + codes.resize(codes.size() + 1); + locs.resize(locs.size() + 1); + if (!compileLispFragment(d, e, _quiet, codes.back(), locs.back())) + break; + } + + // last one is empty. + if (codes.size() < 2) + return false; + + codes.pop_back(); + locs.pop_back(); + + vector ends; + + if (codes.size() > 1) + { + o_code.push_back(Instruction::PUSH); + o_code.push_back(1); + + for (unsigned i = 1; i < codes.size(); ++i) + { + // Push the false location. + o_code.push_back(Instruction::PUSH); + ends.push_back((unsigned)o_code.size()); + o_locs.push_back(ends.back()); + o_code.push_back(0); + + // Check if true - predicate + appendCode(o_code, o_locs, codes[i - 1], locs[i - 1]); + + // Jump to end... + o_code.push_back(Instruction::JMPI); + } + o_code.push_back(Instruction::POP); + } + + // Check if true - predicate + appendCode(o_code, o_locs, codes.back(), locs.back()); + + // At end now. + for (auto i: ends) + o_code[i] = o_code.size(); + } else { auto it = c_instructions.find(t); From 9bb6645cac297d8478aabbf56c1d9eb766583366 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 13:12:21 +0000 Subject: [PATCH 17/24] Binary operators. --- libethereum/Instruction.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index bf8d02f4e..9d2b4170c 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -139,7 +139,8 @@ static void appendCode(u256s& o_code, vector& o_locs, u256s _code, vec static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256s& o_code, vector& o_locs) { std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } }; - std::set const c_allowed = { '+', '-', '*', '/', '%' }; + std::map const c_binary = { { "<", Instruction::LT }, { "<=", Instruction::LE }, { ">", Instruction::GT }, { ">=", Instruction::GE }, { "=", Instruction::EQ }, { "!=", Instruction::NOT } }; + std::set const c_allowed = { '+', '-', '*', '/', '%', '<', '>', '=', '!' }; bool exec = false; @@ -488,8 +489,28 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 break; } } - else if (!_quiet) - cwarn << "Unknown assembler token" << t; + else + { + auto it = c_binary.find(t); + if (it != c_binary.end()) + { + vector>> codes(1); + while (d != e && compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second)) + codes.push_back(pair>()); + codes.pop_back(); + int i = codes.size(); + if (i > 2) + cwarn << "Greater than two arguments given to binary operator" << t << "; using first two"; + for (auto it = codes.rbegin(); it != codes.rend(); ++it) + if (--i < 2) + appendCode(o_code, o_locs, it->first, it->second); + if (it->second == Instruction::NOT) + o_code.push_back(Instruction::EQ); + o_code.push_back((u256)it->second); + } + else if (!_quiet) + cwarn << "Unknown assembler token" << t; + } } } } From 24bc3e5c6e89013022a5e715f21a14bd48a5090d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 13:54:32 +0000 Subject: [PATCH 18/24] Unary operators. --- libethereum/Instruction.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index 9d2b4170c..8ed8cc43f 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -140,6 +140,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 { std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD } }; std::map const c_binary = { { "<", Instruction::LT }, { "<=", Instruction::LE }, { ">", Instruction::GT }, { ">=", Instruction::GE }, { "=", Instruction::EQ }, { "!=", Instruction::NOT } }; + std::map const c_unary = { { "!", Instruction::NOT } }; std::set const c_allowed = { '+', '-', '*', '/', '%', '<', '>', '=', '!' }; bool exec = false; @@ -500,7 +501,7 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 codes.pop_back(); int i = codes.size(); if (i > 2) - cwarn << "Greater than two arguments given to binary operator" << t << "; using first two"; + cwarn << "Greater than two arguments given to binary operator" << t << "; using first two only."; for (auto it = codes.rbegin(); it != codes.rend(); ++it) if (--i < 2) appendCode(o_code, o_locs, it->first, it->second); @@ -508,8 +509,26 @@ static bool compileLispFragment(char const*& d, char const* e, bool _quiet, u256 o_code.push_back(Instruction::EQ); o_code.push_back((u256)it->second); } - else if (!_quiet) - cwarn << "Unknown assembler token" << t; + else + { + auto it = c_unary.find(t); + if (it != c_unary.end()) + { + vector>> codes(1); + while (d != e && compileLispFragment(d, e, _quiet, codes.back().first, codes.back().second)) + codes.push_back(pair>()); + codes.pop_back(); + int i = codes.size(); + if (i > 1) + cwarn << "Greater than one argument given to unary operator" << t << "; using first only."; + for (auto it = codes.rbegin(); it != codes.rend(); ++it) + if (--i < 1) + appendCode(o_code, o_locs, it->first, it->second); + o_code.push_back(it->second); + } + else if (!_quiet) + cwarn << "Unknown assembler token" << t; + } } } } From 2744fea24e2e17f23d04e5228b202760870171e2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 27 Feb 2014 20:24:08 +0000 Subject: [PATCH 19/24] More VM tests. --- test/vm.cpp | 2 +- test/vmtests.json | 82 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/test/vm.cpp b/test/vm.cpp index 137803a3e..1ba54d30b 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -343,7 +343,7 @@ public: Transactions txs; }; -#define CREATE_TESTS 0 +#define CREATE_TESTS 1 template <> class UnitTest<1> { diff --git a/test/vmtests.json b/test/vmtests.json index 52e31f4ec..3b1d2db11 100644 --- a/test/vmtests.json +++ b/test/vmtests.json @@ -1,29 +1,83 @@ { "suicide": { - "env" : { + "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousNonce" : "9c9c6567b5ec0c5f3f25df79be42707090f1e62e9db84cbb556ae2a2f6ccccae", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "feeMultiplier" : 1 - }, - "pre" : { + }, + "pre" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { - "balance" : 1000000000000000000, - "nonce" : 0, - "code" : "(suicide (txsender))" + "balance" : 1000000000000000000, + "nonce" : 0, + "code" : "(suicide (txsender))" } - }, - "exec" : [ + }, + "exec" : [ { - "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - "sender" : "cd1722f3947def4cf144679da39c4c32bdc35681", - "value" : 1000000000000000000, - "data" : [ - ] + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "sender" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : 1000000000000000000, + "data" : [ + ] } - ] + ] + }, + + "arith": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "previousNonce" : "9c9c6567b5ec0c5f3f25df79be42707090f1e62e9db84cbb556ae2a2f6ccccae", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "feeMultiplier" : 1 + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : 1000000000000000000, + "nonce" : 0, + "code" : "(seq (mktx (txsender) (+ 2 2 (* 4 4 4) (/ 2 2) (% 3 2) (- 8 2 2)) 0) )" + } + }, + "exec" : [ + { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "sender" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : 1000000000000000000, + "data" : [ + ] + } + ] + }, + + "boolean": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "previousNonce" : "9c9c6567b5ec0c5f3f25df79be42707090f1e62e9db84cbb556ae2a2f6ccccae", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "feeMultiplier" : 1 + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : 1000000000000000000, + "nonce" : 0, + "code" : "(seq (when (and 1 1) (mktx (txsender) 2 0)) (when (and 1 0) (mktx (txsender) 3 0)) (when (and 0 1) (mktx (txsender) 4 0)) (when (and 0 0) (mktx (txsender) 5 0)) (when (or 1 1) (mktx (txsender) 12 0)) (when (or 1 0) (mktx (txsender) 13 0)) (when (or 0 1) (mktx (txsender) 14 0)) (when (or 0 0) (mktx (txsender) 15 0)) )" + } + }, + "exec" : [ + { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "sender" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : 1000000000000000000, + "data" : [ + ] + } + ] }, "mktx": { From db9a09716fa9e6275f48596911312c181c8b81b8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Feb 2014 12:55:30 +0000 Subject: [PATCH 20/24] Tests. --- test/crypto.cpp | 1 + test/dagger.cpp | 1 + test/hexPrefix.cpp | 69 ++++++++++++++++++++--------------- test/main.cpp | 18 +++++----- test/rlp.cpp | 90 ++++++++++++++++++++++++++++------------------ test/state.cpp | 2 ++ test/trie.cpp | 54 ++++++++++++++++++++++++++++ test/vm.cpp | 3 +- 8 files changed, 167 insertions(+), 71 deletions(-) diff --git a/test/crypto.cpp b/test/crypto.cpp index 3d565dd73..8a57e1d57 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -30,6 +30,7 @@ using namespace eth; int cryptoTest() { + cnote << "Testing Crypto..."; secp256k1_start(); KeyPair p(Secret(fromUserHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); diff --git a/test/dagger.cpp b/test/dagger.cpp index cc22baa13..8f7df77d3 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -28,6 +28,7 @@ using namespace eth; int daggerTest() { + cnote << "Testing Dagger..."; // Test dagger { auto s = steady_clock::now(); diff --git a/test/hexPrefix.cpp b/test/hexPrefix.cpp index a579f3f02..10b839a75 100644 --- a/test/hexPrefix.cpp +++ b/test/hexPrefix.cpp @@ -20,38 +20,51 @@ * Main test functions. */ +#include +#include "../json_spirit/json_spirit_reader_template.h" +#include "../json_spirit/json_spirit_writer_template.h" #include "TrieCommon.h" using namespace std; using namespace eth; +namespace js = json_spirit; -int hexPrefixTest() +namespace eth +{ + +template <> class UnitTest<3> { - /* - * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1 - * [0,0,1,2,3,4,5] 0x10012345 - * [0,1,2,3,4,5] 0x00012345 - * [1,2,3,4,5] 0x112345 - * [0,0,1,2,3,4] 0x00001234 - * [0,1,2,3,4] 0x101234 - * [1,2,3,4] 0x001234 - * [0,0,1,2,3,4,5,T] 0x30012345 - * [0,0,1,2,3,4,T] 0x20001234 - * [0,1,2,3,4,5,T] 0x20012345 - * [1,2,3,4,5,T] 0x312345 - * [1,2,3,4,T] 0x201234 - */ - assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, false)) == "10012345"); - assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, false)) == "00012345"); - assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, false)) == "112345"); - assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, false)) == "00001234"); - assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4}, false)) == "101234"); - assert(asHex(hexPrefixEncode({1, 2, 3, 4}, false)) == "001234"); - assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, true)) == "30012345"); - assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, true)) == "20001234"); - assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, true)) == "20012345"); - assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, true)) == "312345"); - assert(asHex(hexPrefixEncode({1, 2, 3, 4}, true)) == "201234"); - - return 0; +public: + int operator()() + { + js::mValue v; + string s = asString(contents("../../tests/hexencodetest.json")); + js::read_string(s, v); + bool passed = true; + for (auto& i: v.get_obj()) + { + js::mObject& o = i.second.get_obj(); + cnote << i.first; + bytes v; + for (auto& i: o["seq"].get_array()) + v.push_back(i.get_int()); + auto e = hexPrefixEncode(v, o["term"].get_bool()); + if (!o["out"].is_null() && o["out"].get_str() != asHex(e)) + { + cwarn << "Test failed."; + cwarn << "Test says:" << o["out"].get_str(); + cwarn << "Impl says:" << asHex(e); + passed = false; + } + } + return passed ? 0 : 1; + } + +}; + } +int hexPrefixTest() +{ + cnote << "Testing Hex-Prefix-Encode..."; + return UnitTest<3>()(); +} diff --git a/test/main.cpp b/test/main.cpp index ed0ea76e7..311a43701 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -42,14 +42,16 @@ int main(int, char**) std::cout << asHex(s.out()) << std::endl; std::cout << sha3(s.out()) << std::endl;*/ - hexPrefixTest(); - rlpTest(); - trieTest(); - daggerTest(); - cryptoTest(); - vmTest(); -// stateTest(); -// peerTest(argc, argv); + int r = 0; + r += hexPrefixTest(); + r += rlpTest(); + r += trieTest(); + r += vmTest(); + r += cryptoTest(); // TODO: Put in tests repo. +// r += daggerTest(); +// r += stateTest(); +// r += peerTest(argc, argv); + assert(!r); return 0; } diff --git a/test/rlp.cpp b/test/rlp.cpp index 744c3d33c..bc8fb6031 100644 --- a/test/rlp.cpp +++ b/test/rlp.cpp @@ -20,48 +20,70 @@ * RLP test functions. */ +#include +#include "../json_spirit/json_spirit_reader_template.h" +#include "../json_spirit/json_spirit_writer_template.h" #include using namespace std; using namespace eth; +namespace js = json_spirit; -int rlpTest() +namespace eth { - // int of value 15 - assert(RLP("\x0f") == 15); - assert(asString(rlp(15)) == "\x0f"); - - // 3-character string - assert(RLP("\x83""dog") == "dog"); - assert(asString(rlp("dog")) == "\x83""dog"); - - // 2-item list - string twoItemListString = "\xc5\x0f\x83""dog"; - RLP twoItemList(twoItemListString); - assert(twoItemList.itemCount() == 2); - assert(twoItemList[0] == 15); - assert(twoItemList[1] == "dog"); - assert(asString(rlpList(15, "dog")) == "\xc5\x0f\x83""dog"); - - // null - assert(RLP("\x80") == ""); - assert(asString(rlp("")) == "\x80"); - - // 1-byte (8-bit) int - assert(RLP("\x81\x80") == 128); - assert(asString(rlp(128)) == "\x81\x80"); - // 2-byte (16-bit) int - assert(RLP("\x82\x01\x01") == 257); - assert(asString(rlp(257)) == "\x82\x01\x01"); +template <> class UnitTest<2> +{ +public: + static void buildRLP(js::mValue& _v, RLPStream& _rlp) + { + if (_v.type() == js::array_type) + { + RLPStream s; + for (auto& i: _v.get_array()) + buildRLP(i, s); + _rlp.appendList(s.out()); + } + else if (_v.type() == js::int_type) + _rlp.append(_v.get_uint64()); + else if (_v.type() == js::str_type) + { + auto s = _v.get_str(); + if (s.size() && s[0] == '#') + _rlp.append(bigint(s.substr(1))); + else + _rlp.append(s); + } + } - // 32-byte (256-bit) int - assert(RLP("\xa0\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")); - assert(asString(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"))) == "\xa0\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); + int operator()() + { + js::mValue v; + string s = asString(contents("../../tests/rlptest.json")); + js::read_string(s, v); + bool passed = true; + for (auto& i: v.get_obj()) + { + js::mObject& o = i.second.get_obj(); + cnote << i.first; + RLPStream s; + buildRLP(o["in"], s); + if (!o["out"].is_null() && o["out"].get_str() != asHex(s.out())) + { + cwarn << "Test failed."; + cwarn << "Test says:" << o["out"].get_str(); + cwarn << "Impl says:" << asHex(s.out()); + passed = false; + } + } + return passed ? 0 : 1; + } - // 56-character string. - assert(RLP("\xb8\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit"); - assert(asString(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit")) == "\xb8\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit"); +}; - return 0; } +int rlpTest() +{ + cnote << "Testing RLP..."; + return UnitTest<2>()(); +} diff --git a/test/state.cpp b/test/state.cpp index a3ea2aea2..60d68b936 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -30,6 +30,8 @@ using namespace eth; int stateTest() { + cnote << "Testing State..."; + KeyPair me = sha3("Gav Wood"); KeyPair myMiner = sha3("Gav's Miner"); // KeyPair you = sha3("123"); diff --git a/test/trie.cpp b/test/trie.cpp index 5cce3d0f4..26a072600 100644 --- a/test/trie.cpp +++ b/test/trie.cpp @@ -20,6 +20,9 @@ * Trie test functions. */ +#include +#include "../json_spirit/json_spirit_reader_template.h" +#include "../json_spirit/json_spirit_writer_template.h" #include #include #include @@ -27,6 +30,53 @@ using namespace std; using namespace eth; +namespace js = json_spirit; + +namespace eth +{ + +unsigned fac(unsigned _i) { return _i > 2 ? _i * fac(_i - 1) : _i; } + +template <> class UnitTest<4> +{ +public: + int operator()() + { + js::mValue v; + string s = asString(contents("../../tests/trietest.json")); + js::read_string(s, v); + bool passed = true; + for (auto& i: v.get_obj()) + { + js::mObject& o = i.second.get_obj(); + cnote << i.first; + vector> ss; + for (auto& i: o["in"].get_obj()) + ss.push_back(make_pair(i.first, i.second.get_str())); + for (unsigned j = 0; j < fac(ss.size()); ++j) + { + next_permutation(ss.begin(), ss.end()); + BasicMap m; + GenericTrieDB t(&m); + t.init(); + for (auto const& k: ss) + t.insert(k.first, k.second); + if (!o["root"].is_null() && o["root"].get_str() != asHex(t.root().asArray())) + { + cwarn << "Test failed on permutation " << j; + cwarn << "Test says:" << o["root"].get_str(); + cwarn << "Impl says:" << asHex(t.root().asArray()); + passed = false; + } + } + } + return passed ? 0 : 1; + } + +}; + +} + inline h256 stringMapHash256(StringMap const& _s) { return hash256(_s); @@ -34,6 +84,10 @@ inline h256 stringMapHash256(StringMap const& _s) int trieTest() { + cnote << "Testing Trie..."; + return UnitTest<4>()(); + + // More tests... { BasicMap m; GenericTrieDB t(&m); diff --git a/test/vm.cpp b/test/vm.cpp index 1ba54d30b..55299f906 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -343,7 +343,7 @@ public: Transactions txs; }; -#define CREATE_TESTS 1 +#define CREATE_TESTS 0 template <> class UnitTest<1> { @@ -446,6 +446,7 @@ public: int vmTest() { + cnote << "Testing VM..."; return UnitTest<1>()(); } From f8a2733f10adeed79ff06e5892a5a1d8836d0a1e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Feb 2014 12:55:41 +0000 Subject: [PATCH 21/24] Version bump and automation. --- alethzero/MainWin.cpp | 4 ++-- libethereum/Common.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1b8db3bcf..5314a9444 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -122,7 +122,7 @@ Main::Main(QWidget *parent) : { m_servers = QString::fromUtf8(_r->readAll()).split("\n", QString::SkipEmptyParts); }); - QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc3.txt")); + QNetworkRequest r(QUrl("http://www.ethereum.org/servers.poc" + QString(ADD_QUOTES(ETH_VERSION)).section('.', 1, 1) + ".txt")); r.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1712.0 Safari/537.36"); m_webCtrl.get(r); srand(time(0)); @@ -181,7 +181,7 @@ Address Main::fromString(QString const& _a) const void Main::on_about_triggered() { - QMessageBox::about(this, "About AlethZero PoC-3", "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Alex Leverington, Tim Hughes and several others."); + QMessageBox::about(this, "About AlethZero PoC-" + QString(ADD_QUOTES(ETH_VERSION)).section('.', 1, 1), "AlethZero/v" ADD_QUOTES(ETH_VERSION) "/" ADD_QUOTES(ETH_BUILD_TYPE) "/" ADD_QUOTES(ETH_BUILD_PLATFORM) "\nBy Gav Wood, 2014.\nBased on a design by Vitalik Buterin.\n\nTeam Ethereum++ includes: Eric Lombrozo, Marko Simovic, Alex Leverington, Tim Hughes and several others."); } void Main::writeSettings() diff --git a/libethereum/Common.h b/libethereum/Common.h index 1396cd6aa..cfe37c1b1 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -24,7 +24,7 @@ #pragma once // define version -#define ETH_VERSION 0.3.7 +#define ETH_VERSION 0.4.0 // way to many uint to size_t warnings in 32 bit build #ifdef _M_IX86 From 82f32d1e7fd4be7faef2dbc64549a5a6031881b1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Feb 2014 13:22:51 +0000 Subject: [PATCH 22/24] Version bump ready for release. --- libethereum/Common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Common.h b/libethereum/Common.h index 1396cd6aa..a92b4034c 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -24,7 +24,7 @@ #pragma once // define version -#define ETH_VERSION 0.3.7 +#define ETH_VERSION 0.3.8 // way to many uint to size_t warnings in 32 bit build #ifdef _M_IX86 From 201f4f7bebdd13ffcae6d7fbe42218a88adc05d3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Feb 2014 13:36:48 +0000 Subject: [PATCH 23/24] Release script supports branches. --- release.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release.sh b/release.sh index 64ad39b4c..7b9aa96a1 100755 --- a/release.sh +++ b/release.sh @@ -2,6 +2,7 @@ dist="saucy" version=$1 +branch="$(git branch | grep \* | cut -c 3-)" if [[ ! "$3" == "" ]]; then if [[ ! "$4" == "" ]]; then @@ -25,6 +26,7 @@ cd /tmp echo Checking out... git clone $opwd cd cpp-ethereum +git checkout "$branch" if [ "$1" == "" ]; then archdir="cpp-ethereum-$(date +%Y%m%d)" From 7a2d610bed21e6660df0e2e598808a9d76d4c5b0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Feb 2014 13:52:46 +0000 Subject: [PATCH 24/24] Release script is more intelligent and README somewhat more informative. --- README.md | 20 +++++++++++++------- release.sh | 12 ++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a3c7622f6..80b31c7b8 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,27 @@ -# cpp-ethereum +## Ethereum C++ Client. -Ethereum C++ Client. +By Gav Wood, 2014. -Gav Wood, 2014. +Based on a design by Vitalik Buterin. -## Building +Contributors, builders and testers include Eric Lombrozo (cross-compilation), Tim Hughes (MSVC compilation & Dagger testing), Alex Leverington (Clang & Mac building), Marko Simovic (CI) and several others. + +### Building See https://github.com/ethereum/cpp-ethereum/wiki/Building and https://github.com/ethereum/cpp-ethereum/wiki/Compatibility-Info-and-Build-Tips . -## Yet To Do +### Testing + +To run the tests, make sure you clone the tests repository from github.com/ethereum to tests is a sibling to cpp-ethereum-build. + +### Yet To Do See TODO -## License +### License See LICENSE -## Contributing +### Contributing Please read CodingStandards.txt thoroughly before making alterations to the code base. Please do *NOT* use an editor that automatically reformats whitespace away from astylerc or the formating guidelines as describled in CodingStandards.txt. diff --git a/release.sh b/release.sh index 7b9aa96a1..8cf59acf5 100755 --- a/release.sh +++ b/release.sh @@ -1,9 +1,13 @@ #!/bin/bash dist="saucy" -version=$1 +version=$(grep "define ETH_VERSION" libethereum/Common.h | cut -d ' ' -f 3) branch="$(git branch | grep \* | cut -c 3-)" +if [[ ! "$1" == "" ]]; then + version=$1 +fi + if [[ ! "$3" == "" ]]; then if [[ ! "$4" == "" ]]; then dist=$4 @@ -28,11 +32,7 @@ git clone $opwd cd cpp-ethereum git checkout "$branch" -if [ "$1" == "" ]; then - archdir="cpp-ethereum-$(date +%Y%m%d)" -else - archdir="cpp-ethereum-$version" -fi +archdir="cpp-ethereum-$version" archfile="$archdir.tar.bz2" echo Cleaning backup files...